diff --git a/src/Makefile b/src/Makefile index 9acfd6d3c..f97fa7e62 100644 --- a/src/Makefile +++ b/src/Makefile @@ -181,7 +181,8 @@ objdir:=$(makedir)/objs # very sophisticated dependency sources+=\ - $(call List,Sourcefile) + $(call List,Sourcefile)\ + $(call List,core/Sourcefile) sources+=\ $(call List,blua/Sourcefile) @@ -262,12 +263,10 @@ opts+=$(debug_opts) opts+=$(foreach v,$(passthru_opts),$(if $($(v)),-D$(v))) opts+=$(WFLAGS) $(CPPFLAGS) $(CFLAGS) -libs+=$(LDFLAGS) -lstdc++ -asflags:=$(ASFLAGS) -x assembler-with-cpp +cxxopts:=$(opts) $(CXXFLAGS) -std=c++17 -cxxopts:=$(opts) -cxxopts+=-std=c++17 -cxxopts+=$(CXXFLAGS) +libs+=$(LDFLAGS) -lstdc++ -lpthread +asflags:=$(ASFLAGS) -x assembler-with-cpp cc=$(CC) cxx=$(CXX) @@ -288,6 +287,7 @@ ifndef SILENT ifndef MAKE_RESTARTS ifndef destructive $(shell $(CC) -v) +#$(shell $(CXX) -v) define flags = SHELL ..... $(SHELL) @@ -315,6 +315,7 @@ endif LD:=$(CC) cc:=$(cc) $(opts) +cxx:=$(cxx) $(cxxopts) ifdef UPX upx=$(UPX) $(UPX_OPTS) endif @@ -377,19 +378,6 @@ endif $(.)$(cc) -MM -MF $$@ -MT $(objdir)/$$*.o $(2) $$< endef -# dependency recipe template (C++) -# 1: source file suffix -# 2: extra flags to gcc -define _recipecxx = -$(depdir)/%.d : %.$(1) | $$$$(@D)/ -ifndef WINDOWSHELL -ifdef Echo_name - @printf '%-20.20s\r' $$< -endif -endif - $(.)$(cxx) -MM -MF $$@ -MT $(objdir)/$$*.o $(2) $$< -endef - $(eval $(call _recipe,c)) $(eval $(call _recipe,cpp)) $(eval $(call _recipe,s,$(asflags))) diff --git a/src/Makefile.d/dedicated.mk b/src/Makefile.d/dedicated.mk index fef452467..a421b465d 100644 --- a/src/Makefile.d/dedicated.mk +++ b/src/Makefile.d/dedicated.mk @@ -4,8 +4,6 @@ sources+=$(call List,dedicated/Sourcefile) opts+=-DDEDICATED -libs+=-lpthread - ifdef MINGW libs+=-mconsole endif diff --git a/src/Makefile.d/sdl.mk b/src/Makefile.d/sdl.mk index 9f2074d9d..c704a83eb 100644 --- a/src/Makefile.d/sdl.mk +++ b/src/Makefile.d/sdl.mk @@ -10,8 +10,8 @@ makedir:=$(makedir)/SDL -sources+=$(call List,sdl/Sourcefile) opts+=-DDIRECTFULLSCREEN -DHAVE_SDL +sources+=$(call List,sdl/Sourcefile) NOUPNP=1 diff --git a/src/Makefile.d/versions.mk b/src/Makefile.d/versions.mk index a3cdbbd4b..ce23c3e4e 100644 --- a/src/Makefile.d/versions.mk +++ b/src/Makefile.d/versions.mk @@ -16,6 +16,9 @@ $(foreach v,$(join $(wordlist 2,$(_n),- $(gcc_versions)),\ $(and $(findstring =,$(v)),\ $(eval $(call _predecessor,$(subst =, ,$(v)))))) +# aggregate returns seem to happen alot in c++ so just supress em lel +CXXFLAGS+= -Wno-aggregate-return + # -W -Wno-unused ifdef GCC150 diff --git a/src/Sourcefile b/src/Sourcefile index 227e6c95a..4895adc1d 100644 --- a/src/Sourcefile +++ b/src/Sourcefile @@ -49,14 +49,15 @@ r_bsp.c r_data.c r_draw.c r_fps.c -r_main.c +r_main.cpp r_patch.c r_patchrotation.c -r_plane.c -r_segs.c +r_plane.cpp +r_segs.cpp +r_skins.c r_sky.c r_splats.c -r_things.c +r_things.cpp r_portal.c p_ceilng.c p_enemy.c diff --git a/src/am_map.c b/src/am_map.c index 11b3796b0..fe0b5e9a5 100644 --- a/src/am_map.c +++ b/src/am_map.c @@ -341,7 +341,7 @@ static void AM_FrameBufferInit(void) f_x = f_y = 0; f_w = vid.width; f_h = vid.height; - am_buf = screens[0]; + am_buf = vid.screens[0]; } // diff --git a/src/android/i_video.c b/src/android/i_video.c index 8b4bee314..4db66afe0 100644 --- a/src/android/i_video.c +++ b/src/android/i_video.c @@ -46,7 +46,6 @@ INT32 VID_SetMode(INT32 modenum) vid.modenum = 0; vid.width = 320; vid.height = 240; - vid.bpp = 1; vid.buffer = android_surface; return 0; } diff --git a/src/byteptr.h b/src/byteptr.h index 0345038b8..205884acc 100644 --- a/src/byteptr.h +++ b/src/byteptr.h @@ -28,6 +28,7 @@ #define WRITEUINT8(p,b) do { UINT8 *p_tmp = (void *)p; const UINT8 tv = ( UINT8)(b); memcpy(p, &tv, sizeof( UINT8)); p_tmp++; p = (void *)p_tmp; } while (0) #define WRITESINT8(p,b) do { SINT8 *p_tmp = (void *)p; const SINT8 tv = ( UINT8)(b); memcpy(p, &tv, sizeof( UINT8)); p_tmp++; p = (void *)p_tmp; } while (0) #define WRITEINT16(p,b) do { INT16 *p_tmp = (void *)p; const INT16 tv = ( INT16)(b); memcpy(p, &tv, sizeof( INT16)); p_tmp++; p = (void *)p_tmp; } while (0) +#define WRITEINT16_2(p,b) do { INT16 *p_tmp = ( INT16 *)p; const INT16 tv = ( INT16)(b); memcpy(p, &tv, sizeof( INT16)); p_tmp++; *(void**)(&(p)) = (void *)p_tmp; } while (0) // dumb hack for mumble #define WRITEUINT16(p,b) do { UINT16 *p_tmp = (void *)p; const UINT16 tv = ( UINT16)(b); memcpy(p, &tv, sizeof( UINT16)); p_tmp++; p = (void *)p_tmp; } while (0) #define WRITEINT32(p,b) do { INT32 *p_tmp = (void *)p; const INT32 tv = ( INT32)(b); memcpy(p, &tv, sizeof( INT32)); p_tmp++; p = (void *)p_tmp; } while (0) #define WRITEUINT32(p,b) do { UINT32 *p_tmp = (void *)p; const UINT32 tv = ( UINT32)(b); memcpy(p, &tv, sizeof( UINT32)); p_tmp++; p = (void *)p_tmp; } while (0) @@ -38,6 +39,7 @@ #define WRITEUINT8(p,b) do { UINT8 *p_tmp = ( UINT8 *)p; *p_tmp = ( UINT8)(b); p_tmp++; p = (void *)p_tmp; } while (0) #define WRITESINT8(p,b) do { SINT8 *p_tmp = ( SINT8 *)p; *p_tmp = ( SINT8)(b); p_tmp++; p = (void *)p_tmp; } while (0) #define WRITEINT16(p,b) do { INT16 *p_tmp = ( INT16 *)p; *p_tmp = ( INT16)(b); p_tmp++; p = (void *)p_tmp; } while (0) +#define WRITEINT16_2(p,b) do { INT16 *p_tmp = ( INT16 *)p; *p_tmp = ( INT16)(b); p_tmp++; *(void**)(&(p)) = (void *)p_tmp; } while (0) // dumb hack for mumble #define WRITEUINT16(p,b) do { UINT16 *p_tmp = ( UINT16 *)p; *p_tmp = ( UINT16)(b); p_tmp++; p = (void *)p_tmp; } while (0) #define WRITEINT32(p,b) do { INT32 *p_tmp = ( INT32 *)p; *p_tmp = ( INT32)(b); p_tmp++; p = (void *)p_tmp; } while (0) #define WRITEUINT32(p,b) do { UINT32 *p_tmp = ( UINT32 *)p; *p_tmp = ( UINT32)(b); p_tmp++; p = (void *)p_tmp; } while (0) diff --git a/src/command.h b/src/command.h index 2276a0ae2..6d1944f9a 100644 --- a/src/command.h +++ b/src/command.h @@ -13,6 +13,10 @@ #ifndef __COMMAND_H__ #define __COMMAND_H__ +#ifdef __cplusplus +extern "C" { +#endif + #include #include "doomdef.h" @@ -189,4 +193,8 @@ UINT8 CV_CheatsEnabled(void); // Returns cvar by name. Exposed here for Lua. consvar_t *CV_FindVar(const char *name); +#ifdef __cplusplus +} // extern "C" +#endif + #endif // __COMMAND_H__ diff --git a/src/console.c b/src/console.c index 8c1824456..bb86d444b 100644 --- a/src/console.c +++ b/src/console.c @@ -1321,13 +1321,6 @@ void CONS_Debug(INT32 debugflags, const char *fmt, ...) // void CONS_Error(const char *msg) { -#ifdef RPC_NO_WINDOWS_H - if (!graphics_started) - { - MessageBoxA(vid.WndParent, msg, "SRB2Kart Warning", MB_OK); - return; - } -#endif CONS_Printf("\x82%s", msg); // write error msg in different colour CONS_Printf(M_GetText("Press ENTER to continue\n")); diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt new file mode 100644 index 000000000..db8bc5a15 --- /dev/null +++ b/src/core/CMakeLists.txt @@ -0,0 +1 @@ +target_sourcefile(cpp) diff --git a/src/core/Sourcefile b/src/core/Sourcefile new file mode 100644 index 000000000..e8701d507 --- /dev/null +++ b/src/core/Sourcefile @@ -0,0 +1,2 @@ +memory.cpp +thread_pool.cpp diff --git a/src/core/memory.cpp b/src/core/memory.cpp new file mode 100644 index 000000000..e75cf91f7 --- /dev/null +++ b/src/core/memory.cpp @@ -0,0 +1,71 @@ +// BLANKART +//----------------------------------------------------------------------------- +// Copyright (C) 2024 by Ronald "Eidolon" Kinard +// Copyright (C) 2024 by Kart Krew +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- + +#include "memory.h" + +#include +#include + +#include "../z_zone.h" + +namespace +{ + +class LinearMemory +{ + size_t size_; + size_t height_; + void* memory_; + +public: + constexpr explicit LinearMemory(size_t size) noexcept; + + void* allocate(size_t size); + void reset() noexcept; +}; + +constexpr LinearMemory::LinearMemory(size_t size) noexcept : size_(size), height_{0}, memory_{nullptr} {} + +void* LinearMemory::allocate(size_t size) +{ + size_t aligned_size = (size + 15) & ~15; + if (height_ + aligned_size > size_) + { + throw std::bad_alloc(); + } + + if (memory_ == nullptr) + { + memory_ = Z_Malloc(size_, PU_STATIC, nullptr); + } + + void* ptr = (void*)((uintptr_t)(memory_) + height_); + height_ += aligned_size; + return ptr; +} + +void LinearMemory::reset() noexcept +{ + height_ = 0; +} + +} // namespace + +static LinearMemory g_frame_memory {4 * 1024 * 1024}; + +void* Z_Frame_Alloc(size_t size) +{ + return g_frame_memory.allocate(size); +} + +void Z_Frame_Reset() +{ + g_frame_memory.reset(); +} diff --git a/src/core/memory.h b/src/core/memory.h new file mode 100644 index 000000000..ba49e3d51 --- /dev/null +++ b/src/core/memory.h @@ -0,0 +1,32 @@ +// BLANKART +//----------------------------------------------------------------------------- +// Copyright (C) 2024 by Ronald "Eidolon" Kinard +// Copyright (C) 2024 by Kart Krew +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- + +#ifndef __SRB2_CORE_MEMORY_H__ +#define __SRB2_CORE_MEMORY_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif // __cpluspplus + +/// @brief Allocate a block of memory with a lifespan of the current main-thread frame. +/// This function is NOT thread-safe, but the allocated memory may be used across threads. +/// @return a pointer to a block of memory aligned with libc malloc alignment, or null if allocation fails +void* Z_Frame_Alloc(size_t size); + +/// @brief Resets per-frame memory. Not thread safe. +void Z_Frame_Reset(void); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif // __SRB2_CORE_MEMORY_H__ diff --git a/src/core/spmc_queue.hpp b/src/core/spmc_queue.hpp new file mode 100644 index 000000000..d85e1300d --- /dev/null +++ b/src/core/spmc_queue.hpp @@ -0,0 +1,192 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +// This class is derived from Conor Williams' implementation of a concurrent deque +// https://github.com/ConorWilliams/ConcurrentDeque +// Copyright (C) 2021 Conor Williams + +// The original version was for C++23. This one has been shrunk slightly and adapted to our conventions. + +#ifndef __SRB2_CORE_SPMC_QUEUE_HPP__ +#define __SRB2_CORE_SPMC_QUEUE_HPP__ + +#include +#include +#include +#include +#include + +//#include + +#include "../cxxutil.hpp" + +namespace srb2 +{ + +template +class SpMcQueue +{ + struct RingBuff { + public: + explicit RingBuff(int64_t cap) : _cap{cap}, _mask{cap - 1} + { + SRB2_ASSERT(cap && (!(cap & (cap - 1))) && "Capacity must be buf power of 2!"); + _buff = std::unique_ptr(new T[_cap]); + } + + std::int64_t capacity() const noexcept { return _cap; } + + // Store (copy) at modulo index + void store(int64_t i, T&& x) noexcept + { + _buff[i & _mask] = std::move(x); + } + + // Load (copy) at modulo index + T load(int64_t i) const noexcept + { + return _buff[i & _mask]; + } + + // Allocates and returns a new ring buffer, copies elements in range [b, t) into the new buffer. + RingBuff* resize(std::int64_t b, std::int64_t t) const + { + //ZoneScoped; + RingBuff* ptr = new RingBuff{2 * _cap}; + for (std::int64_t i = t; i != b; ++i) { + ptr->store(i, load(i)); + } + return ptr; + } + + private: + int64_t _cap; // Capacity of the buffer + int64_t _mask; // Bit mask to perform modulo capacity operations + + std::unique_ptr _buff; + }; + + alignas(64) std::atomic bottom_; + alignas(64) std::atomic top_; + alignas(64) std::atomic buffer_; + + std::vector> garbage_; + +public: + SpMcQueue(size_t capacity) : bottom_(0), top_(0), buffer_(new RingBuff(capacity)) + { + garbage_.reserve(32); + } + ~SpMcQueue() noexcept + { + delete buffer_.load(std::memory_order_relaxed); + }; + + size_t size() const noexcept + { + int64_t bottom = bottom_.load(std::memory_order_relaxed); + int64_t top = top_.load(std::memory_order_relaxed); + return static_cast(bottom >= top ? bottom - top : 0); + } + + bool empty() const noexcept + { + return size() == 0; + } + + void push(T&& v) noexcept + { + int64_t bottom = bottom_.load(std::memory_order_relaxed); + int64_t top = top_.load(std::memory_order_acquire); + RingBuff* buf = buffer_.load(std::memory_order_relaxed); + + if (buf->capacity() < (bottom - top) + 1) + { + // Queue is full, build a new one + RingBuff* newbuf = buf->resize(bottom, top); + garbage_.emplace_back(buf); + buffer_.store(newbuf, std::memory_order_relaxed); + buf = newbuf; + } + + // Construct new object, this does not have to be atomic as no one can steal this item until after we + // store the new value of bottom, ordering is maintained by surrounding atomics. + buf->store(bottom, std::move(v)); + + std::atomic_thread_fence(std::memory_order_release); + bottom_.store(bottom + 1, std::memory_order_relaxed); + } + + std::optional pop() noexcept + { + int64_t bottom = bottom_.load(std::memory_order_relaxed) - 1; + RingBuff* buf = buffer_.load(std::memory_order_relaxed); + + bottom_.store(bottom, std::memory_order_relaxed); // Stealers can no longer steal + + std::atomic_thread_fence(std::memory_order_seq_cst); + int64_t top = top_.load(std::memory_order_relaxed); + + if (top <= bottom) + { + // Non-empty deque + if (top == bottom) + { + // The last item could get stolen, by a stealer that loaded bottom before our write above + if (!top_.compare_exchange_strong(top, top + 1, std::memory_order_seq_cst, std::memory_order_relaxed)) + { + // Failed race, thief got the last item. + bottom_.store(bottom + 1, std::memory_order_relaxed); + return std::nullopt; + } + bottom_.store(bottom + 1, std::memory_order_relaxed); + } + + // Can delay load until after acquiring slot as only this thread can push(), this load is not + // required to be atomic as we are the exclusive writer. + return buf->load(bottom); + + } + else + { + bottom_.store(bottom + 1, std::memory_order_relaxed); + return std::nullopt; + } + } + + std::optional steal() noexcept + { + int64_t top = top_.load(std::memory_order_acquire); + std::atomic_thread_fence(std::memory_order_seq_cst); + int64_t bottom = bottom_.load(std::memory_order_acquire); + + if (top < bottom) + { + // Must load *before* acquiring the slot as slot may be overwritten immediately after acquiring. + // This load is NOT required to be atomic even-though it may race with an overrite as we only + // return the value if we win the race below garanteeing we had no race during our read. If we + // loose the race then 'x' could be corrupt due to read-during-write race but as T is trivially + // destructible this does not matter. + T x = buffer_.load(std::memory_order_consume)->load(top); + + if (!top_.compare_exchange_strong(top, top + 1, std::memory_order_seq_cst, std::memory_order_relaxed)) + { + return std::nullopt; + } + + return x; + + } + else + { + return std::nullopt; + } + } +}; + +} // namespace srb2 + +#endif // __SRB2_CORE_SPMC_QUEUE_HPP__ diff --git a/src/core/static_vec.hpp b/src/core/static_vec.hpp new file mode 100644 index 000000000..a5a529564 --- /dev/null +++ b/src/core/static_vec.hpp @@ -0,0 +1,255 @@ +// BLANKART +//----------------------------------------------------------------------------- +// Copyright (C) 2024 by Ronald "Eidolon" Kinard +// Copyright (C) 2024 by Kart Krew +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- + +#ifndef __SRB2_CORE_STATIC_VEC_HPP__ +#define __SRB2_CORE_STATIC_VEC_HPP__ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../cxxutil.hpp" + +namespace srb2 +{ + +template +class StaticVec; + +template +class StaticVec +{ + std::array arr_ {{}}; + size_t size_ = 0; + +public: + using value_type = T; + + constexpr StaticVec() {} + + StaticVec(const StaticVec& rhs) + { + for (size_t i = size_; i > 0; i--) + { + arr_[i] = T(); + } + size_ = rhs.size(); + for (size_t i = 0; i < size_; i++) + { + arr_[i] = rhs.arr_[i]; + } + } + + StaticVec(StaticVec&& rhs) noexcept(std::is_nothrow_move_assignable_v) + { + for (size_t i = size_; i > 0; i--) + { + arr_[i] = T(); + } + size_ = rhs.size(); + for (size_t i = 0; i < size_; i++) + { + arr_[i] = std::move(rhs.arr_[i]); + } + while (rhs.size() > 0) + { + rhs.pop_back(); + } + } + + constexpr StaticVec(std::initializer_list list) noexcept(std::is_nothrow_move_assignable_v) + { + size_ = list.size(); + size_t i = 0; + for (auto itr = list.begin(); itr != list.end(); itr++) + { + arr_[i] = *itr; + i++; + } + } + + ~StaticVec() = default; + + StaticVec& operator=(const StaticVec& rhs) + { + for (size_t i = size_; i > 0; i--) + { + arr_[i] = T(); + } + size_ = rhs.size(); + for (size_t i = 0; i < size_; i++) + { + arr_[i] = rhs.arr_[i]; + } + return *this; + } + + StaticVec& operator=(StaticVec&& rhs) noexcept(std::is_nothrow_move_constructible_v) + { + for (size_t i = size_; i > 0; i--) + { + arr_[i] = T(); + } + size_ = rhs.size(); + for (size_t i = 0; i < size_; i++) + { + arr_[i] = std::move(rhs.arr_[i]); + } + while (rhs.size() > 0) + { + rhs.pop_back(); + } + return *this; + } + + void push_back(const T& value) { arr_[size_++] = value; } + + void pop_back() { arr_[--size_] = T(); } + + void resize(size_t size, T value = T()) + { + if (size >= Limit) + { + throw std::length_error("new size >= Capacity"); + } + + if (size == size_) + { + return; + } + else if (size < size_) + { + while (size_ > size) + { + pop_back(); + } + } + else + { + while (size_ < size) + { + push_back(value); + } + } + } + + void clear() + { + arr_ = {{}}; + size_ = 0; + } + + using iterator = typename std::array::iterator; + using const_iterator = typename std::array::const_iterator; + + constexpr iterator begin() noexcept { return arr_.begin(); } + + constexpr const_iterator begin() const noexcept { return arr_.cbegin(); } + + constexpr const_iterator cbegin() const noexcept { return arr_.cbegin(); } + + constexpr iterator end() noexcept { return std::next(arr_.begin(), size_); } + + constexpr const_iterator end() const noexcept { return cend(); } + + constexpr const_iterator cend() const noexcept { return std::next(arr_.cbegin(), size_); } + + constexpr std::reverse_iterator rbegin() noexcept { return std::reverse_iterator(this->end()); } + + constexpr std::reverse_iterator crbegin() const noexcept { return std::reverse_iterator(this->cend()); } + + constexpr std::reverse_iterator rend() noexcept { return std::reverse_iterator(this->begin()); } + + constexpr std::reverse_iterator crend() const noexcept { return std::reverse_iterator(this->cbegin()); } + + constexpr bool empty() const noexcept { return size_ == 0; } + + constexpr size_t size() const noexcept { return size_; } + + constexpr size_t capacity() const noexcept { return Limit; } + + constexpr size_t max_size() const noexcept { return Limit; } + + constexpr T& operator[](size_t index) noexcept { return arr_[index]; } + + T& at(size_t index) + { + if (index >= size_) + { + throw std::out_of_range("index >= size"); + } + return this[index]; + } + + constexpr const T& operator[](size_t index) const noexcept { return arr_[index]; } + + const T& at(size_t index) const + { + if (index >= size_) + { + throw std::out_of_range("index >= size"); + } + return this[index]; + } + + T& front() { return *arr_[0]; } + + T& back() { return *arr_[size_ - 1]; } +}; + +} // namespace srb2 + +template +bool operator==(const srb2::StaticVec& lhs, const srb2::StaticVec& rhs) +{ + const size_t size = lhs.size(); + if (size != rhs.size()) + { + return false; + } + for (size_t i = 0; i < lhs; i++) + { + if (rhs[i] != lhs[i]) + { + return false; + } + } + return true; +} + +template +bool operator!=(const srb2::StaticVec& lhs, const srb2::StaticVec& rhs) +{ + return !(lhs == rhs); +} + +template +struct std::hash> +{ + size_t operator()(const srb2::StaticVec& input) const + { + constexpr size_t prime = sizeof(size_t) == 8 ? 0x00000100000001B3 : 0x01000193; + constexpr size_t basis = sizeof(size_t) == 8 ? 0xcbf29ce484222325 : 0x811c9dc5; + + size_t ret = basis; + for (auto itr = input.begin(); itr != input.end(); itr++) + { + ret = (ret * prime) ^ std::hash(*itr); + } + return ret; + } +}; + +#endif // __SRB2_CORE_STATIC_VEC_HPP__ diff --git a/src/core/thread_pool.cpp b/src/core/thread_pool.cpp new file mode 100644 index 000000000..11aa6f1bb --- /dev/null +++ b/src/core/thread_pool.cpp @@ -0,0 +1,346 @@ +// BLANKART +//----------------------------------------------------------------------------- +// Copyright (C) 2024 by Ronald "Eidolon" Kinard +// Copyright (C) 2024 by Kart Krew +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- + +#include "thread_pool.h" + +#include +#include +#include +#include +#include +#include + +//#include +//#include + +#include "../cxxutil.hpp" +#include "../m_argv.h" + +using namespace srb2; + +static void do_work(ThreadPool::Task& work) +{ + try + { + //ZoneScoped; + (work.thunk)(work.raw.data()); + } + catch (...) + { + // can't do anything + } + + (work.deleter)(work.raw.data()); + if (work.pseudosema) + { + work.pseudosema->fetch_sub(1, std::memory_order_relaxed); + } +} + +static void pool_executor( + //int thread_index, + std::shared_ptr> pool_alive, + std::shared_ptr worker_ready_mutex, + std::shared_ptr worker_ready_condvar, + std::shared_ptr my_wq, + std::vector> other_wqs +) +{ + { + //std::string thread_name = fmt::format("Thread Pool Thread {}", thread_index); + //tracy::SetThreadName(thread_name.c_str()); + } + + int spins = 0; + while (true) + { + std::optional work = my_wq->steal(); + bool did_work = false; + if (work) + { + do_work(*work); + + did_work = true; + spins = 0; + } + else + { + for (auto& q : other_wqs) + { + work = q->steal(); + if (work) + { + do_work(*work); + + did_work = true; + spins = 0; + + // We only want to steal one work item at a time, to prioritize our own queue + break; + } + } + } + + if (!did_work) + { + // Spin a few loops to avoid yielding, then wait for the ready lock + spins += 1; + if (spins > 100) + { + std::unique_lock ready_lock {*worker_ready_mutex}; + while (my_wq->empty() && pool_alive->load()) + { + worker_ready_condvar->wait(ready_lock); + } + + if (!pool_alive->load()) + { + break; + } + } + } + } +} + +ThreadPool::ThreadPool() +{ + immediate_mode_ = true; +} + +ThreadPool::ThreadPool(size_t threads) +{ + next_queue_index_ = 0; + pool_alive_ = std::make_shared>(true); + + for (size_t i = 0; i < threads; i++) + { + std::shared_ptr wsq = std::make_shared(2048); + work_queues_.push_back(wsq); + + std::shared_ptr mutex = std::make_shared(); + worker_ready_mutexes_.push_back(std::move(mutex)); + std::shared_ptr condvar = std::make_shared(); + worker_ready_condvars_.push_back(std::move(condvar)); + } + + for (size_t i = 0; i < threads; i++) + { + std::shared_ptr my_queue = work_queues_[i]; + std::vector> other_queues; + for (size_t j = 0; j < threads; j++) + { + // Order the other queues starting from the next adjacent worker + // i.e. if this is worker 2 of 8, then other queues is 3, 4, 5, 6, 7, 0, 1 + // This tries to balance out work stealing behavior + + size_t other_index = j + i; + if (other_index >= threads) + { + other_index -= threads; + } + + if (other_index != i) + { + other_queues.push_back(work_queues_[other_index]); + } + } + + std::thread thread; + try + { + thread = std::thread + { + pool_executor, + //i, + pool_alive_, + worker_ready_mutexes_[i], + worker_ready_condvars_[i], + my_queue, + other_queues + }; + } + catch (const std::system_error& error) + { + // Safe shutdown and rethrow + pool_alive_->store(false); + for (auto& t : threads_) + { + t.join(); + } + throw error; + } + + threads_.push_back(std::move(thread)); + } +} + +ThreadPool::ThreadPool(ThreadPool&&) = default; +ThreadPool::~ThreadPool() = default; + +ThreadPool& ThreadPool::operator=(ThreadPool&&) = default; + +void ThreadPool::begin_sema() +{ + sema_begun_ = true; +} + +ThreadPool::Sema ThreadPool::end_sema() +{ + Sema ret = Sema(std::move(cur_sema_)); + cur_sema_ = nullptr; + sema_begun_ = false; + return ret; +} + +void ThreadPool::notify() +{ + for (size_t i = 0; i < work_queues_.size(); i++) + { + auto& q = work_queues_[i]; + size_t count = q->size(); + if (count > 0) + { + worker_ready_condvars_[i]->notify_one(); + } + } +} + +void ThreadPool::notify_sema(const ThreadPool::Sema& sema) +{ + if (!sema.pseudosema_) + { + return; + } + notify(); +} + +void ThreadPool::wait_idle() +{ + if (immediate_mode_) + { + return; + } + + //ZoneScoped; + + for (size_t i = 0; i < work_queues_.size(); i++) + { + auto& q = work_queues_[i]; + + std::optional work; + while ((work = q->pop()).has_value()) + { + do_work(*work); + } + } +} + +void ThreadPool::wait_sema(const Sema& sema) +{ + if (!sema.pseudosema_) + { + return; + } + + //ZoneScoped; + + while (sema.pseudosema_->load(std::memory_order_seq_cst) > 0) + { + // spin to win + for (size_t i = 0; i < work_queues_.size(); i++) + { + auto& q = work_queues_[i]; + + std::optional work; + if ((work = q->pop()).has_value()) + { + do_work(*work); + break; + } + } + } + + if (sema.pseudosema_->load(std::memory_order_seq_cst) != 0) + { + throw std::exception(); + } +} + +void ThreadPool::shutdown() +{ + if (immediate_mode_) + { + return; + } + + wait_idle(); + + pool_alive_->store(false); + + for (auto& condvar : worker_ready_condvars_) + { + condvar->notify_all(); + } + for (auto& t : threads_) + { + t.join(); + } +} + +std::unique_ptr srb2::g_main_threadpool; + +void I_ThreadPoolInit(void) +{ + SRB2_ASSERT(g_main_threadpool == nullptr); + size_t thread_count = std::min(static_cast(9), std::thread::hardware_concurrency()); + if (thread_count > 1) + { + // The main thread will act as a worker when waiting for pool idle + // Make one less worker thread to avoid unnecessary context switching + thread_count -= 1; + } + + if (M_CheckParm("-singlethreaded")) + { + g_main_threadpool = std::make_unique(); + } + else + { + g_main_threadpool = std::make_unique(thread_count); + } +} + +void I_ThreadPoolShutdown(void) +{ + if (!g_main_threadpool) + { + return; + } + + g_main_threadpool->shutdown(); + g_main_threadpool = nullptr; +} + +void I_ThreadPoolSubmit(srb2cthunk_t thunk, void* data) +{ + SRB2_ASSERT(g_main_threadpool != nullptr); + + g_main_threadpool->schedule([=]() { + (thunk)(data); + }); + g_main_threadpool->notify(); +} + +void I_ThreadPoolWaitIdle(void) +{ + SRB2_ASSERT(g_main_threadpool != nullptr); + + g_main_threadpool->wait_idle(); +} diff --git a/src/core/thread_pool.h b/src/core/thread_pool.h new file mode 100644 index 000000000..75961614e --- /dev/null +++ b/src/core/thread_pool.h @@ -0,0 +1,163 @@ +// BLANKART +//----------------------------------------------------------------------------- +// Copyright (C) 2024 by Ronald "Eidolon" Kinard +// Copyright (C) 2024 by Kart Krew +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- + +#ifndef __SRB2_CORE_THREAD_POOL_H__ +#define __SRB2_CORE_THREAD_POOL_H__ + +#include + +#ifdef __cplusplus + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "spmc_queue.hpp" + +namespace srb2 +{ + +class ThreadPool +{ +public: + struct Task + { + void (*thunk)(void*); + void (*deleter)(void*); + std::shared_ptr> pseudosema; + std::array>)> raw; + }; + + using Queue = SpMcQueue; + + class Sema + { + std::shared_ptr> pseudosema_; + + explicit Sema(std::shared_ptr> sema) : pseudosema_(sema) {} + + friend class ThreadPool; + public: + Sema() = default; + }; + +private: + std::shared_ptr> pool_alive_; + std::vector> worker_ready_mutexes_; + std::vector> worker_ready_condvars_; + std::vector> work_queues_; + std::vector threads_; + size_t next_queue_index_ = 0; + std::shared_ptr> cur_sema_; + + bool immediate_mode_ = false; + bool sema_begun_ = false; + +public: + ThreadPool(); + explicit ThreadPool(size_t threads); + ThreadPool(const ThreadPool&) = delete; + ThreadPool(ThreadPool&&); + ~ThreadPool(); + + ThreadPool& operator=(const ThreadPool&) = delete; + ThreadPool& operator=(ThreadPool&&); + + void begin_sema(); + ThreadPool::Sema end_sema(); + + /// Enqueue but don't notify + template void schedule(T&& thunk); + /// Notify threads after several schedules + void notify(); + void notify_sema(const Sema& sema); + void wait_idle(); + void wait_sema(const Sema& sema); + void shutdown(); +}; + +extern std::unique_ptr g_main_threadpool; + +template +void callable_caller(F* f) +{ + (*f)(); +} + +template +void callable_destroyer(F* f) +{ + f->~F(); +} + +template +void ThreadPool::schedule(T&& thunk) +{ + static_assert(sizeof(T) <= sizeof(std::declval().raw)); + + if (immediate_mode_) + { + (thunk)(); + return; + } + + if (sema_begun_) + { + if (cur_sema_ == nullptr) + { + cur_sema_ = std::make_shared>(0); + } + cur_sema_->fetch_add(1, std::memory_order_relaxed); + } + + size_t qi = next_queue_index_; + + { + std::shared_ptr q = work_queues_[qi]; + Task task; + task.thunk = reinterpret_cast(callable_caller); + task.deleter = reinterpret_cast(callable_destroyer); + task.pseudosema = cur_sema_; + new (reinterpret_cast(task.raw.data())) T(std::move(thunk)); + + q->push(std::move(task)); + } + // worker_ready_condvars_[qi]->notify_one(); + + next_queue_index_ += 1; + if (next_queue_index_ >= threads_.size()) + { + next_queue_index_ = 0; + } +} + +} // namespace srb2 + +extern "C" { + +#endif // __cplusplus + +typedef void (*srb2cthunk_t)(void*); + +void I_ThreadPoolInit(void); +void I_ThreadPoolShutdown(void); +void I_ThreadPoolSubmit(srb2cthunk_t thunk, void* data); +void I_ThreadPoolWaitIdle(void); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // __SRB2_CORE_THREAD_POOL_H__ diff --git a/src/cxxutil.hpp b/src/cxxutil.hpp new file mode 100644 index 000000000..545d38dfd --- /dev/null +++ b/src/cxxutil.hpp @@ -0,0 +1,152 @@ +#ifndef __SRB2_CXXUTIL_HPP__ +#define __SRB2_CXXUTIL_HPP__ + +#include +#include +#include + +#include "doomdef.h" + +namespace srb2 { + +template +class Finally { +public: + explicit Finally(const F& f) noexcept : f_(f) {} + explicit Finally(F&& f) noexcept : f_(f) {} + + Finally(Finally&& from) noexcept : f_(std::move(from.f_)), call_(std::exchange(from.call_, false)) {} + + Finally(const Finally& from) = delete; + void operator=(const Finally& from) = delete; + void operator=(Finally&& from) = delete; + + ~Finally() noexcept { + if (call_) + f_(); + } + +private: + F f_; + bool call_ = true; +}; + +template +Finally> finally(F&& f) noexcept { + return Finally {std::forward(f)}; +} + +struct SourceLocation { + const char* file_name; + unsigned int line_number; +}; + +#define SRB2_SOURCE_LOCATION \ + srb2::SourceLocation { __FILE__, __LINE__ } + +#ifndef SRB2_ASSERT_HANDLER +#define SRB2_ASSERT_HANDLER srb2::IErrorAssertHandler +#endif + +#if !defined(NDEBUG) || defined(PARANOIA) +// An assertion level of 2 will activate all invocations of the SRB2_ASSERT macro +#define SRB2_ASSERTION_LEVEL 2 +#else +// The minimum assertion level is 1 +#define SRB2_ASSERTION_LEVEL 1 +#endif + +/// Assert a precondition expression in debug builds. +#define SRB2_ASSERT(expr) srb2::do_assert<2, SRB2_ASSERT_HANDLER>([&] { return (expr); }, SRB2_SOURCE_LOCATION, #expr) + +class IErrorAssertHandler { +public: + static void handle(const SourceLocation& source_location, const char* expression) { + I_Error("Assertion failed at %s:%u: %s != true", + source_location.file_name, + source_location.line_number, + expression); + } +}; + +class NoOpAssertHandler { +public: + static void handle(const SourceLocation& source_location, const char* expression) {(void)source_location; (void)expression;} +}; + +/// @brief Assert a precondition expression, aborting the application if it fails. +/// @tparam Expr +/// @tparam Level the level of this assertion; if it is less than or equal to SRB2_ASSERTION_LEVEL, this overload will +/// activate. +/// @param expr a callable which returns a bool +/// @param source_location a struct containing the source location of the assertion, e.g. SRB2_SOURCE_LOCATION +/// @param expression the expression evaluated in the expression callable +/// @param message an optional message to display for the assertion +template +std::enable_if_t<(Level <= SRB2_ASSERTION_LEVEL), void> +do_assert(const Expr& expr, const SourceLocation& source_location, const char* expression = "") noexcept { + static_assert(Level > 0, "level of an assertion must not be 0"); + if (!expr()) { + Handler::handle(source_location, expression); + std::abort(); + } +} + +template +std::enable_if_t<(Level > SRB2_ASSERTION_LEVEL), void> +do_assert(const Expr&, const SourceLocation&, const char* = "") noexcept { +} + +template +class NotNull final { + T ptr_; + +public: + static_assert(std::is_convertible_v() != nullptr), bool>, + "T is not comparable with nullptr_t"); + + /// @brief Move-construct from the pointer value U, asserting that it is not null. Allows construction of a + /// NotNull from any compatible pointer U, for example with polymorphic classes. + template >> + constexpr NotNull(U&& rhs) : ptr_(std::forward(rhs)) { + SRB2_ASSERT(ptr_ != nullptr); + } + + /// @brief Wrap the pointer type T, asserting that the pointer is not null. + template >> + constexpr NotNull(T rhs) : ptr_(std::move(rhs)) { + SRB2_ASSERT(ptr_ != nullptr); + } + + /// @brief Copy construction from NotNull of convertible type U. Only if the incoming pointer is NotNull already. + template >> + constexpr NotNull(const NotNull& rhs) : NotNull(rhs.get()) { + // Value is guaranteed to be not null by construction; no assertion necessary + } + + NotNull(const NotNull& rhs) = default; + NotNull& operator=(const NotNull& rhs) = default; + + /// @brief Get the stored pointer. + constexpr T get() const { return ptr_; } + + /// @brief Convert to T (the pointer type). + constexpr operator T() const { return get(); } + + /// @brief Arrow-dereference to *T (the actual value pointed to). + constexpr decltype(auto) operator->() const { return get(); } + + /// @brief Dereference to *T (the actual value pointed to). + constexpr decltype(auto) operator*() const { return *get(); } + + // It is not allowed to construct NotNull with nullptr regardless of T. + NotNull(std::nullptr_t) = delete; + NotNull& operator=(std::nullptr_t) = delete; +}; + +template +NotNull(T) -> NotNull; + +} // namespace srb2 + +#endif // __SRB2_CXXUTIL_HPP__ diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 35c77ce12..7ba47cfd6 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -13,6 +13,10 @@ #ifndef __D_CLISRV__ #define __D_CLISRV__ +#ifdef __cplusplus +extern "C" { +#endif + #include "d_ticcmd.h" #include "d_net.h" #include "d_netcmd.h" @@ -694,4 +698,9 @@ typedef struct rewind_s { void CL_ClearRewinds(void); rewind_t *CL_SaveRewindPoint(size_t demopos); rewind_t *CL_RewindToTime(tic_t time); + +#ifdef __cplusplus +} // extern "C" +#endif + #endif diff --git a/src/d_main.c b/src/d_main.c index 75e4b02ef..176d11293 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -73,6 +73,8 @@ #include "m_perfstats.h" #include "k_kart.h" +#include "core/memory.h" + #include "lua_script.h" #ifdef CMAKECONFIG @@ -325,6 +327,39 @@ static void D_Renderview(void) R_ApplyLevelInterpolators(rendertimefrac); + if (rendermode == render_soft) + { + // if this is display player 1 + if (cv_homremoval.value) + { + if (cv_homremoval.value == 1) + { + // Clear the software screen buffer to remove HOM + memset(vid.screens[0], 31, vid.width * vid.height); + } + else if (cv_homremoval.value == 2) + { + //'development' HOM removal -- makes it blindingly obvious if HOM is spotted. + memset(vid.screens[0], 32+(timeinmap&15), vid.width * vid.height); + } + } + } + + // Draw over the fourth screen so you don't have to stare at a HOM :V + if (splitscreen == 2) + { + // V_DrawPatchFill, but for the fourth screen only + patch_t *pat = W_CachePatchName("SRB2BACK", PU_CACHE); + INT32 dupz = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy); + INT32 x, y, pw = SHORT(pat->width) * dupz, ph = SHORT(pat->height) * dupz; + + for (x = vid.width>>1; x < vid.width; x += pw) + { + for (y = vid.height>>1; y < vid.height; y += ph) + V_DrawScaledPatch(x, y, V_NOSCALESTART, pat); + } + } + for (i = 0; i <= splitscreen; i++) { const boolean issplitscreen = (i > 0); @@ -336,7 +371,6 @@ static void D_Renderview(void) if (!issplitscreen) // Initialize for P1 { viewwindowy = viewwindowx = 0; - topleft = screens[0]; objectsdrawn = 0; } @@ -350,8 +384,6 @@ static void D_Renderview(void) #endif if (issplitscreen) // Splitscreen-specific { - const INT32 len = viewheight*sizeof(ylookup[0]); - switch (i) { case 1: @@ -365,28 +397,20 @@ static void D_Renderview(void) viewwindowx = 0; viewwindowy = viewheight; } - M_Memcpy(ylookup, ylookup2, len); break; case 2: viewwindowx = 0; viewwindowy = viewheight; - M_Memcpy(ylookup, ylookup3, len); break; case 3: viewwindowx = viewwidth; viewwindowy = viewheight; - M_Memcpy(ylookup, ylookup4, len); default: break; } - - topleft = screens[0] + viewwindowy*vid.width + viewwindowx; } R_RenderPlayerView(&players[displayplayers[i]]); - - if (issplitscreen) - M_Memcpy(ylookup, ylookup1, viewheight*sizeof (ylookup[0])); } if (!issplitscreen) @@ -584,7 +608,7 @@ static boolean D_Display(void) { if (rendermode == render_soft) { - VID_BlitLinearScreen(screens[0], screens[1], vid.width*vid.bpp, vid.height, vid.width*vid.bpp, vid.rowbytes); + VID_BlitLinearScreen(vid.screens[0], vid.screens[1], vid.width, vid.height, vid.width, vid.rowbytes); } lastdraw = false; @@ -618,7 +642,7 @@ static boolean D_Display(void) V_DrawFadeScreen(TC_RAINBOW, (leveltime & 0x20) ? SKINCOLOR_PASTEL : SKINCOLOR_MOONSLAM); // vid size change is now finished if it was on... - vid.recalc = 0; + vid.recalc = false; #ifdef HAVE_THREADS I_lock_mutex(&m_menu_mutex); @@ -750,6 +774,8 @@ void D_SRB2Loop(void) precise_t enterprecise = I_GetPreciseTime(); precise_t finishprecise = enterprecise; + Z_Frame_Reset(); + // Casting the return value of a function is bad practice (apparently) double budget = ((R_GetFramerateCap() == 0) ? 0.0 : round((1.0 / R_GetFramerateCap()) * I_GetPrecisePrecision())); capbudget = (precise_t)budget; diff --git a/src/d_main.h b/src/d_main.h index cb4049e54..1e2de572d 100644 --- a/src/d_main.h +++ b/src/d_main.h @@ -14,6 +14,10 @@ #ifndef __D_MAIN__ #define __D_MAIN__ +#ifdef __cplusplus +extern "C" { +#endif + #include "d_event.h" #include "w_wad.h" // for MAX_WADFILES @@ -90,4 +94,8 @@ const char *D_Home(void); // void D_StartTitle(void); +#ifdef __cplusplus +} // extern "C" +#endif + #endif //__D_MAIN__ diff --git a/src/d_net.h b/src/d_net.h index 1b6cd905c..caeb3c83f 100644 --- a/src/d_net.h +++ b/src/d_net.h @@ -18,6 +18,10 @@ #ifndef __D_NET__ #define __D_NET__ +#ifdef __cplusplus +extern "C" { +#endif + // Max computers in a game // 127 is probably as high as this can go, because // SINT8 is used for nodes sometimes >:( @@ -43,8 +47,6 @@ extern SINT8 nodetoplayer4[MAXNETNODES]; // Say the numplayer for this node if a extern UINT8 playerpernode[MAXNETNODES]; // Used specially for splitscreen extern boolean nodeingame[MAXNETNODES]; // Set false as nodes leave game -extern boolean serverrunning; - void Net_AckTicker(void); // If reliable return true if packet sent, 0 else @@ -65,4 +67,8 @@ void Net_SendAcks(INT32 node); void Net_WaitAllAckReceived(UINT32 timeout); const char *Net_GetPacketName(UINT8 packettype); +#ifdef __cplusplus +} // extern "C" +#endif + #endif diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 91ea8e945..310bac2b9 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -204,11 +204,6 @@ static void Command_Archivetest_f(void); // CLIENT VARIABLES // ========================================================================= -void SendWeaponPref(void); -void SendWeaponPref2(void); -void SendWeaponPref3(void); -void SendWeaponPref4(void); - static CV_PossibleValue_t usemouse_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Force"}, {0, NULL}}; static CV_PossibleValue_t autobalance_cons_t[] = {{0, "MIN"}, {4, "MAX"}, {0, NULL}}; @@ -1030,6 +1025,8 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_scr_width); CV_RegisterVar(&cv_scr_height); + CV_RegisterVar(&cv_parallelsoftware); + CV_RegisterVar(&cv_soundtest); CV_RegisterVar(&cv_perfstats); diff --git a/src/d_netcmd.h b/src/d_netcmd.h index b4ee22d93..657686af4 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -15,8 +15,17 @@ #ifndef __D_NETCMD__ #define __D_NETCMD__ +#ifdef __cplusplus +extern "C" { +#endif + #include "command.h" +void SendWeaponPref(void); +void SendWeaponPref2(void); +void SendWeaponPref3(void); +void SendWeaponPref4(void); + // console vars extern consvar_t cv_playername; extern consvar_t cv_playercolor; @@ -318,4 +327,8 @@ void D_SetPassword(const char *pw); // used for the player setup menu UINT8 CanChangeSkin(INT32 playernum); +#ifdef __cplusplus +} // extern "C" +#endif + #endif diff --git a/src/d_netfil.c b/src/d_netfil.c index 0650f3c34..d45570a0e 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -111,7 +111,9 @@ static fileused_t transferFiles[UINT8_MAX + 1]; // Receiver structure INT32 fileneedednum; // Number of files needed to join the server fileneeded_t fileneeded[MAX_WADFILES]; // List of needed files +#ifdef HAVE_THREADS static I_mutex downloadmutex; +#endif char downloaddir[512] = "DOWNLOAD"; file_download_t filedownload; @@ -1351,14 +1353,18 @@ void CURLAbortFile(void) { filedownload.http_running = false; +#ifdef HAVE_THREADS // lock and unlock to wait for the download thread to exit I_lock_mutex(&downloadmutex); I_unlock_mutex(downloadmutex); +#endif } void CURLGetFile(void) { +#ifdef HAVE_THREADS I_lock_mutex(&downloadmutex); +#endif CURLMcode mc; /* return code used by curl_multi_wait() */ CURLcode easyres; /* Return from easy interface */ CURLMsg *m; /* for picking up messages with the transfer status */ @@ -1453,7 +1459,9 @@ void CURLGetFile(void) } filedownload.http_running = false; +#ifdef HAVE_THREADS I_unlock_mutex(downloadmutex); +#endif } HTTP_login * diff --git a/src/d_netfil.h b/src/d_netfil.h index 464d885b3..b84c83391 100644 --- a/src/d_netfil.h +++ b/src/d_netfil.h @@ -13,6 +13,10 @@ #ifndef __D_NETFIL__ #define __D_NETFIL__ +#ifdef __cplusplus +extern "C" { +#endif + #include "d_clisrv.h" #include "w_wad.h" @@ -125,4 +129,8 @@ HTTP_login * CURLGetLogin (const char *url, HTTP_login ***return_prev_next); size_t curlwrite_data(void *ptr, size_t size, size_t nmemb, FILE *stream); #endif +#ifdef __cplusplus +} // extern "C" +#endif + #endif // __D_NETFIL__ diff --git a/src/doomdef.h b/src/doomdef.h index f9467199b..ce846ee27 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -58,6 +58,9 @@ // warning C4152: nonstandard extension, function/data pointer conversion in expression // warning C4213: nonstandard extension used : cast on l-value +#ifdef __cplusplus +extern "C" { +#endif #include "doomtype.h" @@ -524,12 +527,15 @@ UINT32 quickncasehash (const char *p, size_t n) return x; } +#ifndef __cplusplus #ifndef min // Double-Check with WATTCP-32's cdefs.h #define min(x, y) (((x) < (y)) ? (x) : (y)) #endif #ifndef max // Double-Check with WATTCP-32's cdefs.h #define max(x, y) (((x) > (y)) ? (x) : (y)) #endif +#endif + #ifndef CLAMP #define CLAMP(x, y, z) ((x) < (y) ? (y) : ((x) > (z) ? (z) : (x))) #endif @@ -560,6 +566,14 @@ UINT32 quickncasehash (const char *p, size_t n) #define UNLIKELY(x) (x) #endif +#ifdef __cplusplus +#if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER) + #define restrict __restrict +#else + #define restrict +#endif +#endif + // An assert-type mechanism. #ifdef PARANOIA #define I_Assert(e) ((e) ? (void)0 : I_Error("assert failed: %s, file %s, line %d", #e, __FILE__, __LINE__)) @@ -657,4 +671,8 @@ extern const char *compdate, *comptime, *comprevision, *compbranch; #undef UPDATE_ALERT #endif +#ifdef __cplusplus +} // extern "C" +#endif + #endif // __DOOMDEF__ diff --git a/src/doomstat.h b/src/doomstat.h index f8a3899ca..171b49edc 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -125,7 +125,7 @@ extern boolean lastdraw; extern INT32 postimgparam[MAXSPLITSCREENPLAYERS]; extern INT32 viewwindowx, viewwindowy; -extern INT32 viewwidth, scaledviewwidth; +extern INT32 viewwidth; extern boolean gamedataloaded; diff --git a/src/doomtype.h b/src/doomtype.h index 174bba5b1..ac41a4413 100644 --- a/src/doomtype.h +++ b/src/doomtype.h @@ -17,6 +17,10 @@ #ifndef __DOOMTYPE__ #define __DOOMTYPE__ +#ifdef __cplusplus +extern "C" { +#endif + #if defined (_WIN32) //#define WIN32_LEAN_AND_MEAN #define RPC_NO_WINDOWS_H @@ -100,8 +104,10 @@ typedef long ssize_t; #define strnicmp(x,y,n) strncasecmp(x,y,n) #endif +#ifndef __cplusplus char *strcasestr(const char *in, const char *what); #define stristr strcasestr +#endif #if defined (macintosh) //|| defined (__APPLE__) //skip all boolean/Boolean crap #define true 1 @@ -156,22 +162,19 @@ size_t strlcpy(char *dst, const char *src, size_t siz); /* Boolean type definition */ -// \note __BYTEBOOL__ used to be set above if "macintosh" was defined, -// if macintosh's version of boolean type isn't needed anymore, then isn't this macro pointless now? -#ifndef __BYTEBOOL__ - #define __BYTEBOOL__ - - //faB: clean that up !! - #if defined( _MSC_VER) && (_MSC_VER >= 1800) // MSVC 2013 and forward - #include "stdbool.h" - #elif defined (_WIN32) - #define false FALSE // use windows types - #define true TRUE - #define boolean BOOL - #else - typedef enum {false, true} boolean; - #endif -#endif // __BYTEBOOL__ +#ifndef _WIN32 +#include +// dont use stdbools _BOOL type +// its smaller (1 byte) than the old interger bool (4 bytes) +// which results in packed struct sizes being mismatched between vanilla and this +// however we gotta still include stdbool cause since c23 true and false are keywords +// which we cant use as enumeration constants +typedef int32_t boolean; +#else +#define false FALSE +#define true TRUE +#define boolean BOOL +#endif /* 7.18.2.1 Limits of exact-width integer types */ #ifndef INT8_MIN @@ -385,4 +388,8 @@ unset_bit_array (bitarray_t * const array, const int value) typedef UINT64 precise_t; +#ifdef __cplusplus +} // extern "C" +#endif + #endif //__DOOMTYPE__ diff --git a/src/f_wipe.c b/src/f_wipe.c index 1523ca1d3..cbb411b8b 100644 --- a/src/f_wipe.c +++ b/src/f_wipe.c @@ -313,7 +313,7 @@ void F_WipeStartScreen(void) return; } #endif - wipe_scr_start = screens[3]; + wipe_scr_start = vid.screens[3]; I_ReadScreen(wipe_scr_start); #endif } @@ -330,7 +330,7 @@ void F_WipeEndScreen(void) return; } #endif - wipe_scr_end = screens[4]; + wipe_scr_end = vid.screens[4]; I_ReadScreen(wipe_scr_end); V_DrawBlock(0, 0, 0, vid.width, vid.height, wipe_scr_start); #endif @@ -353,7 +353,7 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu) // Init the wipe WipeInAction = true; - wipe_scr = screens[0]; + wipe_scr = vid.screens[0]; // lastwipetic should either be 0 or the tic we last wiped // on for fade-to-black diff --git a/src/filesrch.h b/src/filesrch.h index 76d5700c0..075895cb0 100644 --- a/src/filesrch.h +++ b/src/filesrch.h @@ -4,6 +4,10 @@ #ifndef __FILESRCH_H__ #define __FILESRCH_H__ +#ifdef __cplusplus +extern "C" { +#endif + #include "doomdef.h" #include "d_netfil.h" #include "m_menu.h" // MAXSTRINGLENGTH @@ -96,4 +100,8 @@ void closefilemenu(boolean validsize); void searchfilemenu(char *tempname); boolean preparefilemenu(boolean samedepth, boolean replayhut); +#ifdef __cplusplus +} // extern "C" +#endif + #endif // __FILESRCH_H__ diff --git a/src/g_game.h b/src/g_game.h index 5714097b2..e59ba0609 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -14,6 +14,10 @@ #ifndef __G_GAME__ #define __G_GAME__ +#ifdef __cplusplus +extern "C" { +#endif + #include "doomdef.h" #include "doomstat.h" #include "d_event.h" @@ -484,4 +488,8 @@ void G_AddMapToBuffer(INT16 map); void G_FixCamera(UINT8 view); +#ifdef __cplusplus +} // extern "C" +#endif + #endif diff --git a/src/hardware/hw_batching.c b/src/hardware/hw_batching.c index 801442b6f..c861bba71 100644 --- a/src/hardware/hw_batching.c +++ b/src/hardware/hw_batching.c @@ -129,7 +129,6 @@ void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPt } } - static int comparePolygons(const void *p1, const void *p2) { const PolygonArrayEntry *poly1 = *(PolygonArrayEntry *const *)p1; @@ -378,8 +377,8 @@ void HWR_RenderBatches(void) currentSurfaceInfo.TintColor.rgba != nextSurfaceInfo.TintColor.rgba || currentSurfaceInfo.FadeColor.rgba != nextSurfaceInfo.FadeColor.rgba || currentSurfaceInfo.LightInfo.light_level != nextSurfaceInfo.LightInfo.light_level || - currentSurfaceInfo.LightInfo.fade_start != nextSurfaceInfo.LightInfo.fade_start || - currentSurfaceInfo.LightInfo.fade_end != nextSurfaceInfo.LightInfo.fade_end || + currentSurfaceInfo.LightInfo.fade_start != nextSurfaceInfo.LightInfo.fade_start || + currentSurfaceInfo.LightInfo.fade_end != nextSurfaceInfo.LightInfo.fade_end || currentSurfaceInfo.LightInfo.directional != nextSurfaceInfo.LightInfo.directional) { changeState = true; diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index 7e996e083..5c13cf9ff 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -96,12 +96,12 @@ void HWR_DrawPatch(patch_t *gpatch, INT32 x, INT32 y, INT32 option) pdupx = pdupy = 2.0f; break; case V_SMALLSCALEPATCH: - pdupx = 2.0f * FIXED_TO_FLOAT(vid.fsmalldupx); - pdupy = 2.0f * FIXED_TO_FLOAT(vid.fsmalldupy); + pdupx = 2.0f * FIXED_TO_FLOAT(vid.smalldupx*FRACUNIT); + pdupy = 2.0f * FIXED_TO_FLOAT(vid.smalldupy*FRACUNIT); break; case V_MEDSCALEPATCH: - pdupx = 2.0f * FIXED_TO_FLOAT(vid.fmeddupx); - pdupy = 2.0f * FIXED_TO_FLOAT(vid.fmeddupy); + pdupx = 2.0f * FIXED_TO_FLOAT(vid.meddupx*FRACUNIT); + pdupy = 2.0f * FIXED_TO_FLOAT(vid.meddupx*FRACUNIT); break; } diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 43cb25aed..c3cd01ad7 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -548,7 +548,7 @@ static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, bool size_t len; float tempxsow, tempytow; - float scrollx = 0.0f, scrolly = 0.0f; + float scrollx = 0.0f, scrolly = 0.0f, anglef = 0.0f; angle_t angle = 0; static FOutVector *planeVerts = NULL; @@ -668,14 +668,11 @@ static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, bool if (angle) // Only needs to be done if there's an altered angle { - angle = InvAngle(angle)>>ANGLETOFINESHIFT; - - // This needs to be done so everything aligns after rotation - // It would be done so that rotation is done, THEN the translation, but I couldn't get it to rotate AND scroll like software does - tempxsow = FloatToFixed(flatxref); - tempytow = FloatToFixed(flatyref); - flatxref = (FixedToFloat(FixedMul(tempxsow, FINECOSINE(angle)) - FixedMul(tempytow, FINESINE(angle)))); - flatyref = (FixedToFloat(FixedMul(tempxsow, FINESINE(angle)) + FixedMul(tempytow, FINECOSINE(angle)))); + tempxsow = flatxref; + tempytow = flatyref; + anglef = ANG2RAD(InvAngle(angle)); + flatxref = (tempxsow * cos(anglef)) - (tempytow * sin(anglef)); + flatyref = (tempxsow * sin(anglef)) + (tempytow * cos(anglef)); } #define SETUP3DVERT(vert, vx, vy) {\ @@ -686,10 +683,10 @@ static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, bool /* Need to rotate before translate */\ if (angle) /* Only needs to be done if there's an altered angle */\ {\ - tempxsow = FloatToFixed(vert->s);\ - tempytow = FloatToFixed(vert->t);\ - vert->s = (FixedToFloat(FixedMul(tempxsow, FINECOSINE(angle)) - FixedMul(tempytow, FINESINE(angle))));\ - vert->t = (FixedToFloat(FixedMul(tempxsow, FINESINE(angle)) + FixedMul(tempytow, FINECOSINE(angle))));\ + tempxsow = vert->s;\ + tempytow = vert->t;\ + vert->s = (tempxsow * cos(anglef)) - (tempytow * sin(anglef));\ + vert->t = (tempxsow * sin(anglef)) + (tempytow * cos(anglef));\ }\ \ vert->x = (vx);\ @@ -5567,28 +5564,12 @@ static void HWR_RenderFrame(player_t *player, boolean skybox) gl_viewwindowx += gl_viewwidth; } - if (splitscreen == 2 && player == &players[displayplayers[2]]) - { - // V_DrawPatchFill, but for the fourth screen only - patch_t *gpatch = W_CachePatchName("SRB2BACK", PU_PATCH); - INT32 dupz = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy); - INT32 x, y, pw = (gpatch->width * dupz), ph = (gpatch->height * dupz); - - for (x = vid.width >> 1; x < vid.width; x += pw) - { - for (y = vid.height >> 1; y < vid.height; y += ph) - HWR_DrawStretchyFixedPatch(gpatch, (x)<next; @@ -125,8 +126,7 @@ void HWR_PortalFrame(gl_portal_t* portal) if (portal->clipline != -1) { portalclipline = &lines[portal->clipline]; - portalcullsector = portalclipline->frontsector; - viewsector = portalclipline->frontsector; + portalcullsector = viewsector = portalclipline->frontsector; } else { diff --git a/src/i_joy.h b/src/i_joy.h index 01f29c2cd..20252b54d 100644 --- a/src/i_joy.h +++ b/src/i_joy.h @@ -13,6 +13,10 @@ #ifndef __I_JOY_H__ #define __I_JOY_H__ +#ifdef __cplusplus +extern "C" { +#endif + #include "g_input.h" /*! @@ -55,4 +59,8 @@ typedef struct JoyType_s JoyType_t; extern JoyType_t Joystick[MAXSPLITSCREENPLAYERS]; +#ifdef __cplusplus +} // extern "C" +#endif + #endif // __I_JOY_H__ diff --git a/src/i_net.h b/src/i_net.h index 098a6563d..70d8f0384 100644 --- a/src/i_net.h +++ b/src/i_net.h @@ -14,6 +14,10 @@ #ifndef __I_NET__ #define __I_NET__ +#ifdef __cplusplus +extern "C" { +#endif + #ifdef __GNUG__ #pragma interface #endif @@ -180,4 +184,8 @@ extern bannednode_t *bannednode; /// \brief Called by D_SRB2Main to be defined by extern network driver boolean I_InitNetwork(void); +#ifdef __cplusplus +} // extern "C" +#endif + #endif diff --git a/src/i_sound.h b/src/i_sound.h index 925be7596..9c6cf20d7 100644 --- a/src/i_sound.h +++ b/src/i_sound.h @@ -13,6 +13,10 @@ #ifndef __I_SOUND__ #define __I_SOUND__ +#ifdef __cplusplus +extern "C" { +#endif + #include "doomdef.h" #include "sounds.h" #include "command.h" @@ -241,4 +245,8 @@ boolean I_FadeSong(UINT8 target_volume, UINT32 ms, void (*callback)(void)); boolean I_FadeOutStopSong(UINT32 ms); boolean I_FadeInPlaySong(UINT32 ms, boolean looping); +#ifdef __cplusplus +} // extern "C" +#endif + #endif diff --git a/src/i_system.h b/src/i_system.h index e7fb26a41..b26db7a82 100644 --- a/src/i_system.h +++ b/src/i_system.h @@ -14,6 +14,10 @@ #ifndef __I_SYSTEM__ #define __I_SYSTEM__ +#ifdef __cplusplus +extern "C" { +#endif + #include "d_ticcmd.h" #include "d_event.h" @@ -256,4 +260,8 @@ const char *I_ClipboardPaste(void); void I_RegisterSysCommands(void); +#ifdef __cplusplus +} // extern "C" +#endif + #endif diff --git a/src/i_threads.h b/src/i_threads.h index 45a3dcc3e..17500aeca 100644 --- a/src/i_threads.h +++ b/src/i_threads.h @@ -14,6 +14,10 @@ #ifndef I_THREADS_H #define I_THREADS_H +#ifdef __cplusplus +extern "C" { +#endif + typedef void (*I_thread_fn)(void *userdata); typedef void * I_mutex; @@ -35,5 +39,9 @@ void I_hold_cond (I_cond *, I_mutex); void I_wake_one_cond (I_cond *); void I_wake_all_cond (I_cond *); +#ifdef __cplusplus +} // extern "C" +#endif + #endif/*I_THREADS_H*/ #endif/*HAVE_THREADS*/ diff --git a/src/i_video.h b/src/i_video.h index 70321d138..68042a654 100644 --- a/src/i_video.h +++ b/src/i_video.h @@ -14,6 +14,10 @@ #ifndef __I_VIDEO__ #define __I_VIDEO__ +#ifdef __cplusplus +extern "C" { +#endif + #include "doomtype.h" #ifdef __GNUG__ @@ -149,4 +153,8 @@ boolean UseScreenFBO(void); extern boolean downsample; #endif +#ifdef __cplusplus +} // extern "C" +#endif + #endif diff --git a/src/k_kart.h b/src/k_kart.h index 411bb0512..b10989618 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -6,6 +6,10 @@ #ifndef __K_KART__ #define __K_KART__ +#ifdef __cplusplus +extern "C" { +#endif + #include "doomdef.h" #include "d_player.h" // Need for player_t @@ -132,5 +136,9 @@ INT32 K_getMinimapTrans(void); void K_getLapsDrawinfo(drawinfo_t *out); void K_getMinimapDrawinfo(drawinfo_t *out); +#ifdef __cplusplus +} // extern "C" +#endif + // ========================================================================= #endif // __K_KART__ diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 0ccc7d8ed..3e4ab9da0 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -16,6 +16,7 @@ #include "p_slopes.h" // P_GetZAt #include "z_zone.h" #include "r_main.h" +#include "r_skins.h" #include "r_things.h" #include "m_random.h" #include "s_sound.h" diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index a0f795985..401a18654 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -14,6 +14,7 @@ #include "doomstat.h" #include "p_mobj.h" #include "g_game.h" +#include "r_skins.h" #include "r_things.h" #include "b_bot.h" #include "z_zone.h" diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index 504a1e130..4103bce99 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -15,6 +15,7 @@ #include "doomdef.h" #include "fastcmp.h" #include "r_things.h" +#include "r_skins.h" #include "r_main.h" #include "p_local.h" #include "g_game.h" diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 9562c5679..665512aef 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -13,6 +13,7 @@ #include "doomdef.h" #include "fastcmp.h" #include "r_main.h" +#include "r_skins.h" #include "r_things.h" #include "p_mobj.h" #include "d_player.h" diff --git a/src/lua_skinlib.c b/src/lua_skinlib.c index 403ac834e..4425f125c 100644 --- a/src/lua_skinlib.c +++ b/src/lua_skinlib.c @@ -12,6 +12,7 @@ #include "doomdef.h" #include "fastcmp.h" +#include "r_skins.h" #include "r_things.h" #include "sounds.h" @@ -277,4 +278,4 @@ int LUA_SkinLib(lua_State *L) lua_setglobal(L, "skins"); return 0; -} \ No newline at end of file +} diff --git a/src/m_anigif.c b/src/m_anigif.c index 05b1f8287..2d3f9c4e6 100644 --- a/src/m_anigif.c +++ b/src/m_anigif.c @@ -495,7 +495,7 @@ static void GIF_rgbconvert(UINT8 *linear, UINT8 *scr) static void GIF_framewrite(void) { UINT8 *p; - UINT8 *movie_screen = screens[2]; + UINT8 *movie_screen = vid.screens[2]; INT32 blitx, blity, blitw, blith; if (!gifframe_data) @@ -509,7 +509,7 @@ static void GIF_framewrite(void) if (gif_optimize && gif_frames > 0) { // before blit movie_screen points to last frame, cur_screen points to this frame - UINT8 *cur_screen = screens[0]; + UINT8 *cur_screen = vid.screens[0]; GIF_optimizeregion(cur_screen, movie_screen, &blitx, &blity, &blitw, &blith); // blit to temp screen @@ -535,7 +535,7 @@ static void GIF_framewrite(void) if (rendermode == render_opengl) { UINT8 *linear = HWR_GetScreenshot(); - GIF_rgbconvert(linear, screens[0]); + GIF_rgbconvert(linear, vid.screens[0]); //free(linear); // Allocated 'statically', no need to free now } #endif @@ -545,7 +545,7 @@ static void GIF_framewrite(void) if (gif_frames == 0 && rendermode == render_soft) I_ReadScreen(movie_screen); - movie_screen = screens[0]; + movie_screen = vid.screens[0]; } // screen regions are handled in GIF_lzw diff --git a/src/m_argv.h b/src/m_argv.h index f31a531d0..8f1a08ec4 100644 --- a/src/m_argv.h +++ b/src/m_argv.h @@ -14,6 +14,10 @@ #ifndef __M_ARGV__ #define __M_ARGV__ +#ifdef __cplusplus +extern "C" { +#endif + // // MISC // @@ -42,4 +46,8 @@ const char *M_GetNextParm(void); // Finds and loads a response file (@moreargs.txt) void M_FindResponseFile(void); +#ifdef __cplusplus +} // extern "C" +#endif + #endif //__M_ARGV__ diff --git a/src/m_fixed.h b/src/m_fixed.h index 3f1acd7ae..ae77c83b9 100644 --- a/src/m_fixed.h +++ b/src/m_fixed.h @@ -49,6 +49,20 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FloatToFixed(float f) return (fixed_t)(f * FRACUNIT); } +/*! + \brief convert fixed_t into double-precision floating number +*/ + +FUNCMATH FUNCINLINE static ATTRINLINE double FixedToDouble(fixed_t x) +{ + return x / (double)FRACUNIT; +} + +FUNCMATH FUNCINLINE static ATTRINLINE fixed_t DoubleToFixed(double f) +{ + return (fixed_t)(f * FRACUNIT); +} + // for backwards compat #define FIXED_TO_FLOAT(x) FixedToFloat(x) // (((float)(x)) / ((float)FRACUNIT)) #define FLOAT_TO_FIXED(f) FloatToFixed(f) // (fixed_t)((f) * ((float)FRACUNIT)) diff --git a/src/m_menu.h b/src/m_menu.h index 126d59e1b..4cea66d2c 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -15,6 +15,11 @@ #ifndef __X_MENU__ #define __X_MENU__ +#ifdef __cplusplus +extern "C" { +#endif + +#include "r_skins.h" #include "d_event.h" #include "command.h" #include "i_threads.h" @@ -433,4 +438,8 @@ if (currentMenu == &menu)\ }\ } +#ifdef __cplusplus +} // extern "C" +#endif + #endif //__X_MENU__ diff --git a/src/m_misc.c b/src/m_misc.c index 8a68e25cb..6a0ef82a6 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -14,6 +14,10 @@ #ifdef __GNUC__ +#ifdef __cplusplus +extern "C" { +#endif + #if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) // Ignore "argument might be clobbered by longjmp" warning in GCC // (if libpng is compiled with setjmp error handling) @@ -1060,7 +1064,7 @@ static boolean M_SetupaPNG(png_const_charp filename, png_bytep pal) png_init_io(apng_ptr, apng_FILE); #ifdef PNG_SET_USER_LIMITS_SUPPORTED - png_set_user_limits(apng_ptr, MAXPNGWIDTH, MAXPNGHEIGHT); + png_set_user_limits(apng_ptr, MAXVIDWIDTH, MAXVIDHEIGHT); #endif //png_set_filter(apng_ptr, 0, PNG_ALL_FILTERS); @@ -1237,7 +1241,7 @@ void M_SaveFrame(void) if (rendermode == render_soft) { // munge planar buffer to linear - linear = screens[2]; + linear = vid.screens[2]; I_ReadScreen(linear); } #ifdef HWRENDER @@ -1375,7 +1379,7 @@ boolean M_SavePNG(const char *filename, void *data, int width, int height, const png_init_io(png_ptr, png_FILE); #ifdef PNG_SET_USER_LIMITS_SUPPORTED - png_set_user_limits(png_ptr, MAXPNGWIDTH, MAXPNGHEIGHT); + png_set_user_limits(png_ptr, MAXVIDWIDTH, MAXVIDHEIGHT); #endif //png_set_filter(png_ptr, 0, PNG_ALL_FILTERS); @@ -1539,7 +1543,7 @@ void M_DoScreenShot(void) if (rendermode == render_soft) { // munge planar buffer to linear - linear = screens[2]; + linear = vid.screens[2]; I_ReadScreen(linear); } @@ -2210,3 +2214,8 @@ void M_MkdirEach(const char *path, int start, int mode) { M_MkdirEachUntil(path, start, -1, mode); } + + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/src/m_misc.h b/src/m_misc.h index 98fbdaee7..ae5eb3ba4 100644 --- a/src/m_misc.h +++ b/src/m_misc.h @@ -15,6 +15,10 @@ #ifndef __M_MISC__ #define __M_MISC__ +#ifdef __cplusplus +extern "C" { +#endif + #include "doomtype.h" #include "tables.h" @@ -116,4 +120,8 @@ FUNCMATH UINT8 M_CountBits(UINT32 num, UINT8 size); #include "w_wad.h" extern char configfile[MAX_WADPATH]; +#ifdef __cplusplus +} // extern "C" +#endif + #endif diff --git a/src/p_enemy.c b/src/p_enemy.c index d500a0cb2..8cf62935a 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -16,6 +16,7 @@ #include "g_game.h" #include "p_local.h" #include "r_main.h" +#include "r_skins.h" #include "r_state.h" #include "s_sound.h" #include "m_random.h" diff --git a/src/p_mobj.c b/src/p_mobj.c index 06cbd3b17..70f4dbacf 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -20,6 +20,7 @@ #include "p_setup.h" #include "r_fps.h" #include "r_main.h" +#include "r_skins.h" #include "r_things.h" #include "r_sky.h" #include "r_splats.h" diff --git a/src/p_mobj.h b/src/p_mobj.h index 733153017..cd4033157 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -14,6 +14,10 @@ #ifndef __P_MOBJ__ #define __P_MOBJ__ +#ifdef __cplusplus +extern "C" { +#endif + // Basics. #include "tables.h" #include "m_fixed.h" @@ -536,4 +540,9 @@ extern mapthing_t *huntemeralds[MAXHUNTEMERALDS]; extern INT32 numhuntemeralds; extern boolean runemeraldmanager; extern INT32 numstarposts; + +#ifdef __cplusplus +} // extern "C" +#endif + #endif diff --git a/src/p_saveg.c b/src/p_saveg.c index 3d17a14de..e8a5971ca 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -24,6 +24,7 @@ #include "r_fps.h" #include "r_things.h" #include "r_state.h" +#include "r_skins.h" #include "w_wad.h" #include "y_inter.h" #include "z_zone.h" diff --git a/src/p_setup.c b/src/p_setup.c index a69390961..8218e045e 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -580,9 +580,6 @@ static void P_LoadRawSegs(UINT8 *data) else li->backsector = 0; - li->numlights = 0; - li->rlights = NULL; - P_UpdateSegLightOffset(li); } } @@ -675,6 +672,21 @@ INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat) levelflat->lumpnum = R_GetFlatNumForName(flatname); levelflat->baselumpnum = LUMPERROR; + // check if our flat contains cyan pixels + // not sure if this is the best way to do it but it works + { + const UINT8 *flat = (UINT8 *)W_CacheLumpNum(levelflat->lumpnum, PU_LEVEL); + size_t size = W_LumpLength(levelflat->lumpnum); + for (size_t steppy = 0; steppy < size; steppy++) + { + if (flat[steppy] == TRANSPARENTPIXEL) + { + levelflat->cyan = true; + break; + } + } + } + #ifndef ZDEBUG CONS_Debug(DBG_SETUP, "flat #%03d: %s\n", atoi(sizeu1(numlevelflats)), levelflat->name); #endif @@ -720,6 +732,21 @@ INT32 P_AddLevelFlatRuntime(const char *flatname) levelflat->lumpnum = R_GetFlatNumForName(flatname); levelflat->baselumpnum = LUMPERROR; + // check if our flat contains cyan pixels + // not sure if this is the best way to do it but it works + { + const UINT8 *flat = (UINT8 *)W_CacheLumpNum(levelflat->lumpnum, PU_LEVEL); + size_t size = W_LumpLength(levelflat->lumpnum); + for (size_t steppy = 0; steppy < size; steppy++) + { + if (flat[steppy] == TRANSPARENTPIXEL) + { + levelflat->cyan = true; + break; + } + } + } + #ifndef ZDEBUG CONS_Debug(DBG_SETUP, "flat #%03d: %s\n", atoi(sizeu1(numlevelflats)), levelflat->name); #endif diff --git a/src/p_setup.h b/src/p_setup.h index 97209e154..646415d28 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -14,6 +14,10 @@ #ifndef __P_SETUP__ #define __P_SETUP__ +#ifdef __cplusplus +extern "C" { +#endif + #include "doomdata.h" #include "doomstat.h" #include "r_defs.h" @@ -48,6 +52,7 @@ typedef struct INT32 animseq; // start pos. in the anim sequence INT32 numpics; INT32 speed; + boolean cyan; } levelflat_t; extern size_t numlevelflats; @@ -116,4 +121,8 @@ UINT8 P_GetGrade(UINT32 pscore, INT16 map, UINT8 mare); UINT8 P_HasGrades(INT16 map, UINT8 mare); UINT32 P_GetScoreForGrade(INT16 map, UINT8 mare, UINT8 grade); +#ifdef __cplusplus +} // extern "C" +#endif + #endif diff --git a/src/qs22j.h b/src/qs22j.h index c388b9c46..cf522b73d 100644 --- a/src/qs22j.h +++ b/src/qs22j.h @@ -16,6 +16,15 @@ #ifndef __QS22J__ #define __QS22J__ + +#ifdef __cplusplus +extern "C" { +#endif + void qs22j(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)); + +#ifdef __cplusplus +} // extern "C" +#endif #endif diff --git a/src/r_bsp.c b/src/r_bsp.cpp similarity index 86% rename from src/r_bsp.c rename to src/r_bsp.cpp index 427a6367c..f0fb7cb4e 100644 --- a/src/r_bsp.c +++ b/src/r_bsp.cpp @@ -35,6 +35,7 @@ sector_t *backsector; // very ugly realloc() of drawsegs at run-time, I upped it to 512 // instead of 256.. and someone managed to send me a level with // 896 drawsegs! So too bad here's a limit removal a-la-Boom +drawseg_t *curdrawsegs = NULL; /**< This is used to handle multiple lists for masked drawsegs. */ drawseg_t *drawsegs = NULL; drawseg_t *ds_p = NULL; @@ -73,165 +74,96 @@ void R_ClearDrawSegs(void) ds_p = drawsegs; } -// Fix from boom. -#define MAXSEGS (MAXVIDWIDTH/2+1) +// CPhipps - +// Instead of clipsegs, let's try using an array with one entry for each column, +// indicating whether it's blocked by a solid wall yet or not. +UINT8 *solidcol; -// newend is one past the last valid seg -static cliprange_t *newend; -static cliprange_t solidsegs[MAXSEGS]; - -// -// R_ClipSolidWallSegment -// Does handle solid walls, -// e.g. single sided LineDefs (middle texture) -// that entirely block the view. -// -static void R_ClipSolidWallSegment(INT32 first, INT32 last) +void R_AllocClipSegMemory(void) { - cliprange_t *next; - cliprange_t *start; + solidcol = static_cast(Z_Realloc(solidcol, sizeof(*solidcol) * viewwidth, PU_STATIC, NULL)); +} - // Find the first range that touches the range (adjacent pixels are touching). - start = solidsegs; - while (start->last < first - 1) - start++; +namespace +{ - if (first < start->first) +enum class ClipType +{ + // Does handle solid walls, + // e.g. single sided LineDefs (middle texture) + // that entirely block the view. + kSolid, + kSolidDontRender, + + // Clips the given range of columns, but does not include it in the clip list. + // Does handle windows, e.g. LineDefs with upper and lower texture. + kPass, +}; + +// CPhipps - +// R_ClipWallSegment +// +// Replaces the old R_Clip*WallSegment functions. It draws bits of walls in those +// columns which aren't solid, and updates the solidcol[] array appropriately +template +static void R_ClipWallSegment(int first, int last) +{ + while (first < last) { - if (last < start->first - 1) - { - // Post is entirely visible (above start), so insert a new clippost. - R_StoreWallRange(first, last); - next = newend; - newend++; - // NO MORE CRASHING! - if (newend - solidsegs > MAXSEGS) - I_Error("R_ClipSolidWallSegment: Solid Segs overflow!\n"); + UINT8 *p; - while (next != start) + if (solidcol[first]) + { + p = static_cast(memchr(solidcol+first, 0, last-first)); + if (!p) + return; // All solid + + first = p - solidcol; + } + else + { + p = static_cast(memchr(solidcol+first, 1, last-first)); + + int to; + if (!p) + to = last; + else + to = p - solidcol; + + if constexpr (Type != ClipType::kSolidDontRender) { - *next = *(next-1); - next--; + R_StoreWallRange(first, to-1); } - next->first = first; - next->last = last; - return; - } - // There is a fragment above *start. - R_StoreWallRange(first, start->first - 1); - // Now adjust the clip size. - start->first = first; - } + if constexpr (Type != ClipType::kPass) + { + memset(solidcol+first, 1, to-first); + } - // Bottom contained in start? - if (last <= start->last) - return; - - next = start; - while (last >= (next+1)->first - 1) - { - // There is a fragment between two posts. - R_StoreWallRange(next->last + 1, (next+1)->first - 1); - next++; - - if (last <= next->last) - { - // Bottom is contained in next. - // Adjust the clip size. - start->last = next->last; - goto crunch; + first = to; } } - - // There is a fragment after *next. - R_StoreWallRange(next->last + 1, last); - // Adjust the clip size. - start->last = last; - - // Remove start+1 to next from the clip list, because start now covers their area. -crunch: - if (next == start) - return; // Post just extended past the bottom of one post. - - while (next++ != newend) - *++start = *next; // Remove a post. - - newend = start + 1; - - // NO MORE CRASHING! - if (newend - solidsegs > MAXSEGS) - I_Error("R_ClipSolidWallSegment: Solid Segs overflow!\n"); } -// -// R_ClipPassWallSegment -// Clips the given range of columns, but does not include it in the clip list. -// Does handle windows, e.g. LineDefs with upper and lower texture. -// -static inline void R_ClipPassWallSegment(INT32 first, INT32 last, boolean soliddontrender) -{ - cliprange_t *start; - - // Find the first range that touches the range - // (adjacent pixels are touching). - start = solidsegs; - while (start->last < first - 1) - start++; - - if (first < start->first) - { - if (last < start->first - 1) - { - // Post is entirely visible (above start). - if (!soliddontrender) - R_StoreWallRange(first, last); - return; - } - - // There is a fragment above *start. - if (!soliddontrender) - R_StoreWallRange(first, start->first - 1); - } - - // Bottom contained in start? - if (last <= start->last) - return; - - while (last >= (start+1)->first - 1) - { - // There is a fragment between two posts. - if (!soliddontrender) - R_StoreWallRange(start->last + 1, (start+1)->first - 1); - start++; - - if (last <= start->last) - return; - } - - // There is a fragment after *next. - if (!soliddontrender) - R_StoreWallRange(start->last + 1, last); -} +}; // namespace // // R_ClearClipSegs // void R_ClearClipSegs(void) { - solidsegs[0].first = -0x7fffffff; - solidsegs[0].last = -1; - solidsegs[1].first = viewwidth; - solidsegs[1].last = 0x7fffffff; - newend = solidsegs + 2; + memset(solidcol, 0, viewwidth); } + void R_PortalClearClipSegs(INT32 start, INT32 end) { - solidsegs[0].first = -0x7fffffff; - solidsegs[0].last = start-1; - solidsegs[1].first = end; - solidsegs[1].last = 0x7fffffff; - newend = solidsegs + 2; + R_ClearClipSegs(); + + if (start > 0) + memset(solidcol, 1, start); + + if (end < viewwidth) + memset(solidcol + end, 1, viewwidth - end); } // @@ -389,6 +321,7 @@ static void R_AddLine(seg_t *line) INT32 x1, x2; angle_t angle1, angle2, span, tspan; static sector_t tempsec; + boolean bothfloorssky = false; g_portal = NULL; @@ -405,7 +338,7 @@ static void R_AddLine(seg_t *line) span = angle1 - angle2; // Back side? i.e. backface culling? - if (span >= ANGLE_180 || !line->linedef) + if (span >= ANGLE_180) return; // Global angle needed by segcalc. @@ -424,6 +357,7 @@ static void R_AddLine(seg_t *line) angle1 = clipangle; } + tspan = clipangle - angle2; if (tspan > doubleclipangle) { @@ -439,6 +373,8 @@ static void R_AddLine(seg_t *line) // The seg is in the view range, but not necessarily visible. angle1 = (angle1+ANGLE_90)>>ANGLETOFINESHIFT; angle2 = (angle2+ANGLE_90)>>ANGLETOFINESHIFT; + + // killough 1/31/98: Here is where "slime trails" can SOMETIMES occur: x1 = viewangletox[angle1]; x2 = viewangletox[angle2]; @@ -455,8 +391,10 @@ static void R_AddLine(seg_t *line) { // Find the other side! INT32 line2 = P_FindSpecialLineFromTag(40, line->linedef->tag, -1); + if (line->linedef == &lines[line2]) line2 = P_FindSpecialLineFromTag(40, line->linedef->tag, line2); + if (line2 >= 0) // found it! { Portal_Add2Lines(line->linedef-lines, line2, x1, x2); // Remember the lines for later rendering @@ -476,6 +414,10 @@ static void R_AddLine(seg_t *line) doorclosed = 0; + // likewise, but for floors and upper textures + if (backsector->floorpic == skyflatnum && frontsector->floorpic == skyflatnum) + bothfloorssky = true; + fixed_t frontf1,frontf2, frontc1, frontc2; // front floor/ceiling ends fixed_t backf1, backf2, backc1, backc2; // back floor ceiling ends @@ -503,19 +445,19 @@ static void R_AddLine(seg_t *line) if (viewsector != backsector && viewsector != frontsector) { // here we're talking about a CEILING lower than a floor. ...yeah we don't even need to bother. - if (backc1 <= frontf1 && backc2 <= frontf2) + const boolean ceillow = (backc1 <= frontf1 && backc2 <= frontf2); + + // this tries to fix some skyboxes drawing a black void as a midtexture lel + if (ceillow && (!bothfloorssky && backsector->ceilingpic == skyflatnum && frontsector->ceilingpic != skyflatnum) // double sided with back ceiling sky but not front ceiling sky + && !line->sidedef->midtexture && !line->sidedef->bottomtexture && !line->sidedef->toptexture && !line->polyseg) // effectively empty { - goto clipsolid; - } - - // here we're talking about floors higher than ceilings, don't even bother either. - if (backf1 >= frontc1 && backf2 >= frontc2) - { - goto clipsolid; + goto clippass; } + doorclosed = ceillow + || (backf1 >= frontc1 && backf2 >= frontc2) // Check for automap fix. Store in doorclosed for r_segs.c - doorclosed = (backc1 <= backf1 && backc2 <= backf2 + || (backc1 <= backf1 && backc2 <= backf2 && ((backc1 >= frontc1 && backc2 >= frontc2) || curline->sidedef->toptexture) && ((backf1 <= frontf1 && backf2 >= frontf2) || curline->sidedef->bottomtexture) && (backsector->ceilingpic != skyflatnum || frontsector->ceilingpic != skyflatnum)); @@ -540,15 +482,15 @@ static void R_AddLine(seg_t *line) clippass: g_walloffscreen = false; - R_ClipPassWallSegment(x1, x2 - 1, false); + R_ClipWallSegment(x1, x2); if (g_walloffscreen) - R_ClipPassWallSegment(x1, x2 - 1, true); + R_ClipWallSegment(x1, x2); return; clipsolid: g_walloffscreen = false; - R_ClipSolidWallSegment(x1, x2 - 1); + R_ClipWallSegment(x1, x2); } // @@ -581,22 +523,11 @@ static boolean R_CheckBBox(const fixed_t *bspcoord) angle_t angle1, angle2; INT32 sx1, sx2, boxpos; const INT32* check; - cliprange_t *start; - // Find the corners of the box that define the edges from current viewpoint. - if (viewx <= bspcoord[BOXLEFT]) - boxpos = 0; - else if (viewx < bspcoord[BOXRIGHT]) - boxpos = 1; - else - boxpos = 2; - - if (viewy >= bspcoord[BOXTOP]) - boxpos |= 0; - else if (viewy > bspcoord[BOXBOTTOM]) - boxpos |= 1<<2; - else - boxpos |= 2<<2; + // 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; @@ -607,18 +538,23 @@ static boolean R_CheckBBox(const fixed_t *bspcoord) angle1 = R_PointToAngle64(bspcoord[check[0]], bspcoord[check[1]]) - viewangle; angle2 = R_PointToAngle64(bspcoord[check[2]], bspcoord[check[3]]) - viewangle; - if ((signed)angle1 < (signed)angle2) + // cph - replaced old code, which was unclear and badly commented + // Much more efficient code now + if ((signed)angle1 < (signed)angle2) /* it's "behind" us */ { + /* Either angle1 or angle2 is behind us, so it doesn't matter if we + * change it to the corect sign + */ if ((angle1 >= ANGLE_180) && (angle1 < ANGLE_270)) angle1 = ANGLE_180-1; else angle2 = ANGLE_180; } - if ((signed)angle2 >= (signed)clipangle) return false; - if ((signed)angle1 <= -(signed)clipangle) return false; - if ((signed)angle1 >= (signed)clipangle) angle1 = clipangle; - if ((signed)angle2 <= -(signed)clipangle) angle2 = 0-clipangle; + if ((signed)angle2 >= (signed)clipangle) return false; // Both off left edge + if ((signed)angle1 <= -(signed)clipangle) return false; // Both off right edge + if ((signed)angle1 >= (signed)clipangle) angle1 = clipangle; // Clip at left edge + if ((signed)angle2 <= -(signed)clipangle) angle2 = -(signed)clipangle; // Clip at right edge // Find the first clippost that touches the source post (adjacent pixels are touching). angle1 = (angle1+ANGLE_90)>>ANGLETOFINESHIFT; @@ -630,20 +566,18 @@ static boolean R_CheckBBox(const fixed_t *bspcoord) if (sx1 >= sx2) return false; - start = solidsegs; - while (start->last < sx2) - start++; - - if (sx1 >= start->first && sx2 <= start->last) - return false; // The clippost contains the new span. + if (!memchr(solidcol+sx1, 0, sx2-sx1)) + { + // All columns it covers are already solidly covered + return false; + } return true; } - size_t numpolys; // number of polyobjects in current subsector size_t num_po_ptrs; // number of polyobject pointers allocated -polyobj_t **po_ptrs; // temp ptr array to sort polyobject pointers +polyobj_t **po_ptrs; // temp ptr array to sort polyobject pointers // // R_PolyobjCompare @@ -681,8 +615,7 @@ void R_SortPolyObjects(subsector_t *sub) { // use free instead realloc since faster (thanks Lee ^_^) free(po_ptrs); - po_ptrs = malloc((num_po_ptrs = numpolys*2) - * sizeof(*po_ptrs)); + po_ptrs = static_cast(malloc((num_po_ptrs = numpolys*2)* sizeof(*po_ptrs))); } po = sub->polyList; @@ -699,8 +632,7 @@ void R_SortPolyObjects(subsector_t *sub) // 03/10/06: only bother if there are actually polys to sort if (numpolys >= 2) { - qs22j(po_ptrs, numpolys, sizeof(polyobj_t *), - R_PolyobjCompare); + qs22j(po_ptrs, numpolys, sizeof(polyobj_t *), R_PolyobjCompare); } } } @@ -726,8 +658,8 @@ static int R_PolysegCompare(const void *p1, const void *p2) dist2v1 = vxdist(seg2->v1); dist2v2 = vxdist(seg2->v2); - if (min(dist1v1, dist1v2) != min(dist2v1, dist2v2)) - return min(dist1v1, dist1v2) - min(dist2v1, dist2v2); + if (std::min(dist1v1, dist1v2) != std::min(dist2v1, dist2v2)) + return std::min(dist1v1, dist1v2) - std::min(dist2v1, dist2v2); { // That didn't work, so now let's try this....... fixed_t delta1, delta2, x1, y1, x2, y2; @@ -828,14 +760,15 @@ static void R_Subsector(size_t num) fixed_t floorcenterz, ceilingcenterz; ffloor_t *rover; -#ifdef RANGECHECK - if (num >= numsubsectors) - I_Error("R_Subsector: ss %s with numss = %s\n", sizeu1(num), sizeu2(numsubsectors)); -#endif - // subsectors added at run-time if (num >= numsubsectors) + { +#ifdef RANGECHECK + I_Error("R_Subsector: ss %s with numss = %s\n", sizeu1(num), sizeu2(numsubsectors)); +#else return; +#endif + } sub = &subsectors[num]; frontsector = sub->sector; @@ -1144,7 +1077,7 @@ void R_Prep3DFloors(sector_t *sector) if (count != sector->numlights) { Z_Free(sector->lightlist); - sector->lightlist = Z_Calloc(sizeof (*sector->lightlist) * count, PU_LEVEL, NULL); + sector->lightlist = static_cast(Z_Calloc(sizeof (*sector->lightlist) * count, PU_LEVEL, NULL)); sector->numlights = count; } else @@ -1194,6 +1127,7 @@ void R_Prep3DFloors(sector_t *sector) } } } + if (!best) { sector->numlights = i; diff --git a/src/r_bsp.h b/src/r_bsp.h index 7ba6c330c..b9e4e291d 100644 --- a/src/r_bsp.h +++ b/src/r_bsp.h @@ -14,6 +14,10 @@ #ifndef __R_BSP__ #define __R_BSP__ +#ifdef __cplusplus +extern "C" { +#endif + #ifdef __GNUG__ #pragma interface #endif @@ -32,14 +36,17 @@ extern portal_t *g_portal; // is curline a portal seg? extern INT32 checkcoord[12][4]; +extern drawseg_t *curdrawsegs; extern drawseg_t *drawsegs; extern drawseg_t *ds_p; extern INT32 doorclosed; +extern UINT8 *solidcol; extern boolean g_walloffscreen; // BSP? void R_ClearClipSegs(void); void R_PortalClearClipSegs(INT32 start, INT32 end); +void R_AllocClipSegMemory(void); void R_ClearDrawSegs(void); void R_RenderBSPNode(INT32 bspnum); @@ -59,4 +66,9 @@ boolean R_IsEmptyLine(seg_t *line, const sector_t *front, const sector_t *back); INT32 R_GetPlaneLight(sector_t *sector, fixed_t planeheight, boolean underside); void R_Prep3DFloors(sector_t *sector); + +#ifdef __cplusplus +} // extern "C" +#endif + #endif diff --git a/src/r_data.c b/src/r_data.c index 0b5b7badf..7ac8ffe2d 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -100,7 +100,7 @@ INT32 numtextures = 0; // total number of textures found, texture_t **textures = NULL; static UINT32 **texturecolumnofs; // column offset lookup table for each texture -static UINT8 **texturecache; // graphics data for each generated full-size texture +UINT8 **texturecache; // graphics data for each generated full-size texture // texture width is a power of 2, so it can easily repeat along sidedefs using a simple mask INT32 *texturewidthmask; @@ -296,7 +296,7 @@ static inline void R_DrawColumnInCache(column_t *patch, UINT8 *cache, INT32 orig // This is not optimised, but it's supposed to be executed only once // per level, when enough memory is available. // -static UINT8 *R_GenerateTexture(size_t texnum) +UINT8 *R_GenerateTexture(size_t texnum) { UINT8 *block; UINT8 *blocktex; @@ -649,6 +649,7 @@ void R_LoadTextures(void) M_Memcpy(texture->name, W_CheckNameForNumPwad(wadnum, lumpnum), sizeof(texture->name)); texture->width = SHORT(patchlump->width); texture->height = SHORT(patchlump->height); + texture->type = TEXTURETYPE_SINGLEPATCH; texture->patchcount = 1; texture->holes = false; @@ -915,19 +916,22 @@ static texture_t *R_ParseTexture(boolean actuallyLoadTexture) // Left Curly Brace texturesToken = M_GetToken(NULL); + if (texturesToken == NULL) { I_Error("Error parsing TEXTURES lump: Unexpected end of file where open curly brace for texture \"%s\" should be",newTextureName); } + if (strcmp(texturesToken,"{")==0) { if (actuallyLoadTexture) { // Allocate memory for a zero-patch texture. Obviously, we'll be adding patches momentarily. - resultTexture = (texture_t *)Z_Calloc(sizeof(texture_t),PU_STATIC,NULL); + resultTexture = (texture_t *)Z_Calloc(sizeof(texture_t), PU_STATIC, NULL); M_Memcpy(resultTexture->name, newTextureName, 8); resultTexture->width = newTextureWidth; resultTexture->height = newTextureHeight; + resultTexture->type = TEXTURETYPE_COMPOSITE; } Z_Free(texturesToken); texturesToken = M_GetToken(NULL); diff --git a/src/r_data.h b/src/r_data.h index f27dd0822..c3abab0c1 100644 --- a/src/r_data.h +++ b/src/r_data.h @@ -14,6 +14,10 @@ #ifndef __R_DATA__ #define __R_DATA__ +#ifdef __cplusplus +extern "C" { +#endif + #include "r_defs.h" #include "r_state.h" @@ -33,6 +37,14 @@ typedef struct UINT16 wad, lump; } texpatch_t; +// texture type +enum +{ + TEXTURETYPE_UNKNOWN, + TEXTURETYPE_SINGLEPATCH, + TEXTURETYPE_COMPOSITE, +}; + // A maptexturedef_t describes a rectangular texture, // which is composed of one or more mappatch_t structures // that arrange graphic patches. @@ -40,6 +52,7 @@ typedef struct { // Keep name for switch changing, etc. char name[8]; + UINT8 type; // TEXTURETYPE_ INT16 width, height; boolean holes; @@ -50,6 +63,7 @@ typedef struct // all loaded and prepared textures from the start of the game extern texture_t **textures; +extern UINT8 **texturecache; // graphics data for each generated full-size texture // texture width is a power of 2, so it can easily repeat along sidedefs using a simple mask extern INT32 *texturewidthmask; @@ -68,6 +82,8 @@ extern CV_PossibleValue_t Color_cons_t[]; void R_LoadTextures(void); void R_FlushTextureCache(void); +UINT8 *R_GenerateTexture(size_t texnum); + INT32 R_GetTextureNum(INT32 texnum); void R_CheckTextureCache(INT32 tex); @@ -108,4 +124,8 @@ UINT8 NearestPaletteColor(UINT8 r, UINT8 g, UINT8 b, RGBA_t *palette); extern INT32 numtextures; +#ifdef __cplusplus +} // extern "C" +#endif + #endif diff --git a/src/r_defs.h b/src/r_defs.h index a202b49ef..c130547db 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -68,6 +68,37 @@ typedef struct #endif } extracolormap_t; +typedef struct +{ + lighttable_t* colormap; + + INT32 x; + INT32 yl; + INT32 yh; + fixed_t iscale; + fixed_t texturemid; + + UINT8* source; // first pixel in a column + UINT8* lightmap; // lighting only + + // translucency stuff here + UINT8* transmap; + + // translation stuff here + UINT8* translation; + + struct r_lightlist_s* lightlist; + + INT32 numlights; + INT32 maxlights; + + //Fix TUTIFRUTI + INT32 texheight; + INT32 sourcelength; +} drawcolumndata_t; + +extern drawcolumndata_t g_dc; + // // INTERNAL MAP TYPES used by play and refresh // @@ -527,9 +558,6 @@ typedef struct seg_s float flength; // length of the seg, used by hardware renderer #endif - // Why slow things down by calculating lightlists for every thick side? - size_t numlights; - r_lightlist_t *rlights; polyobj_t *polyseg; boolean dontrenderme; @@ -610,11 +638,11 @@ typedef struct drawseg_s struct ffloor_s *thicksides[MAXFFLOORS]; INT16 *thicksidecol; INT32 numthicksides; - fixed_t frontscale[MAXVIDWIDTH]; + fixed_t *frontscale; UINT8 portalpass; // if > 0 and <= portalrender, do not affect sprite clipping - fixed_t maskedtextureheight[MAXVIDWIDTH]; // For handling sloped midtextures + fixed_t *maskedtextureheight; // For handling sloped midtextures vertex_t leftpos, rightpos; // Used for rendering FOF walls with slopes } drawseg_t; diff --git a/src/r_draw.c b/src/r_draw.cpp similarity index 73% rename from src/r_draw.c rename to src/r_draw.cpp index d54fe90ce..23d512a19 100644 --- a/src/r_draw.c +++ b/src/r_draw.cpp @@ -15,6 +15,8 @@ /// not the architecture of the frame buffer. /// The frame buffer is a linear one, and we need only the base address. +#include + #include "doomdef.h" #include "doomstat.h" #include "r_local.h" @@ -38,47 +40,14 @@ /** \brief view info */ -INT32 viewwidth, scaledviewwidth, viewheight, viewwindowx, viewwindowy; - -/** \brief pointer to the start of each line of the screen, -*/ -UINT8 *ylookup[MAXVIDHEIGHT*4]; - -/** \brief pointer to the start of each line of the screen, for view1 (splitscreen) -*/ -UINT8 *ylookup1[MAXVIDHEIGHT*4]; - -/** \brief pointer to the start of each line of the screen, for view2 (splitscreen) -*/ -UINT8 *ylookup2[MAXVIDHEIGHT*4]; - -/** \brief pointer to the start of each line of the screen, for view3 (splitscreen) -*/ -UINT8 *ylookup3[MAXVIDHEIGHT*4]; - -/** \brief pointer to the start of each line of the screen, for view4 (splitscreen) -*/ -UINT8 *ylookup4[MAXVIDHEIGHT*4]; - -/** \brief x byte offset for columns inside the viewwindow, - so the first column starts at (SCRWIDTH - VIEWWIDTH)/2 -*/ -INT32 columnofs[MAXVIDWIDTH*4]; - -UINT8 *topleft; +INT32 linesize, viewwidth, viewheight, viewwindowx, viewwindowy; +UINT8 *renderscreen; // haleyjd // ========================================================================= // COLUMN DRAWING CODE STUFF // ========================================================================= -lighttable_t *dc_colormap; -INT32 dc_x = 0, dc_yl = 0, dc_yh = 0; - -fixed_t dc_iscale, dc_texturemid; -UINT8 dc_hires; // under MSVC boolean is a byte, while on other systems, it a bit, - // soo lets make it a byte on all system for the ASM code -UINT8 *dc_source; -INT32 dc_sourcelength; +drawcolumndata_t g_dc; // ----------------------- // translucency stuff here @@ -88,42 +57,34 @@ INT32 dc_sourcelength; UINT8 *transtables; // translucency tables UINT8 *blendtables[NUMBLENDMAPS]; -/** \brief R_DrawTransColumn uses this -*/ -UINT8 *dc_transmap; // one of the translucency tables +// -------------------------------------------- +// c drawer routines +// -------------------------------------------- -// ---------------------- -// translation stuff here -// ---------------------- - - -/** \brief R_DrawTranslatedColumn uses this -*/ -UINT8 *dc_translation; - -struct r_lightlist_s *dc_lightlist = NULL; -INT32 dc_numlights = 0, dc_maxlights, dc_texheight; +coldrawfunc_t *colfunc; +coldrawfunc_t *colfuncs[COLDRAWFUNC_MAX]; +int colfunctype; // ========================================================================= // SPAN DRAWING CODE STUFF // ========================================================================= -INT32 ds_y, ds_x1, ds_x2; -lighttable_t *ds_colormap; -fixed_t ds_xfrac, ds_yfrac, ds_xstep, ds_ystep; - -UINT8 *ds_source; // points to the start of a flat -UINT8 *ds_transmap; // one of the translucency tables +drawspandata_t g_ds; // Vectors for Software's tilted slope drawers floatv3_t *ds_su, *ds_sv, *ds_sz; -floatv3_t *ds_sup, *ds_svp, *ds_szp; -float focallengthf, zeroheight; -/** \brief Variable flat sizes -*/ +float focallengthf; -UINT32 nflatxshift, nflatyshift, nflatshiftup, nflatmask; +// For, uh, tilted lighting, duh. +//static INT32 *tiltlighting; + +// -------------------------------------------- +// c drawer routines +// -------------------------------------------- + +spandrawfunc_t *spanfunc; +spandrawfunc_t *spanfuncs[SPANDRAWFUNC_MAX]; // ========================================================================== // OLD DOOM FUZZY EFFECT @@ -147,73 +108,10 @@ UINT32 nflatxshift, nflatyshift, nflatshiftup, nflatmask; static UINT8 **translationtablecache[TT_CACHE_SIZE] = {NULL}; static UINT8 **localtranslationtablecache[MAXLOCALSKINS] = {NULL}; - -// See also the enum skincolors_t -// TODO Callum: Can this be translated? -/* -const char *Color_Names[MAXSKINCOLORS] = -{ - "None", // SKINCOLOR_NONE - "White", // SKINCOLOR_WHITE - "Silver", // SKINCOLOR_SILVER - "Grey", // SKINCOLOR_GREY - "Black", // SKINCOLOR_BLACK - "Cyan", // SKINCOLOR_CYAN - "Teal", // SKINCOLOR_TEAL - "Steel_Blue",// SKINCOLOR_STEEL - "Blue", // SKINCOLOR_BLUE - "Peach", // SKINCOLOR_PEACH - "Tan", // SKINCOLOR_TAN - "Pink", // SKINCOLOR_PINK - "Lavender", // SKINCOLOR_LAVENDER - "Purple", // SKINCOLOR_PURPLE - "Orange", // SKINCOLOR_ORANGE - "Rosewood", // SKINCOLOR_ROSEWOOD - "Beige", // SKINCOLOR_BEIGE - "Brown", // SKINCOLOR_BROWN - "Red", // SKINCOLOR_RED - "Dark_Red", // SKINCOLOR_DARKRED - "Neon_Green",// SKINCOLOR_NEONGREEN - "Green", // SKINCOLOR_GREEN - "Zim", // SKINCOLOR_ZIM - "Olive", // SKINCOLOR_OLIVE - "Yellow", // SKINCOLOR_YELLOW - "Gold" // SKINCOLOR_GOLD -}; - -const UINT8 Color_Opposite[MAXSKINCOLORS*2] = -{ - SKINCOLOR_NONE,8, // SKINCOLOR_NONE - SKINCOLOR_BLACK,10, // SKINCOLOR_WHITE - SKINCOLOR_GREY,4, // SKINCOLOR_SILVER - SKINCOLOR_SILVER,12,// SKINCOLOR_GREY - SKINCOLOR_WHITE,8, // SKINCOLOR_BLACK - SKINCOLOR_NONE,8, // SKINCOLOR_CYAN - SKINCOLOR_NONE,8, // SKINCOLOR_TEAL - SKINCOLOR_NONE,8, // SKINCOLOR_STEEL - SKINCOLOR_ORANGE,9, // SKINCOLOR_BLUE - SKINCOLOR_NONE,8, // SKINCOLOR_PEACH - SKINCOLOR_NONE,8, // SKINCOLOR_TAN - SKINCOLOR_NONE,8, // SKINCOLOR_PINK - SKINCOLOR_NONE,8, // SKINCOLOR_LAVENDER - SKINCOLOR_NONE,8, // SKINCOLOR_PURPLE - SKINCOLOR_BLUE,12, // SKINCOLOR_ORANGE - SKINCOLOR_NONE,8, // SKINCOLOR_ROSEWOOD - SKINCOLOR_NONE,8, // SKINCOLOR_BEIGE - SKINCOLOR_NONE,8, // SKINCOLOR_BROWN - SKINCOLOR_GREEN,5, // SKINCOLOR_RED - SKINCOLOR_NONE,8, // SKINCOLOR_DARKRED - SKINCOLOR_NONE,8, // SKINCOLOR_NEONGREEN - SKINCOLOR_RED,11, // SKINCOLOR_GREEN - SKINCOLOR_PURPLE,3, // SKINCOLOR_ZIM - SKINCOLOR_NONE,8, // SKINCOLOR_OLIVE - SKINCOLOR_NONE,8, // SKINCOLOR_YELLOW - SKINCOLOR_NONE,8 // SKINCOLOR_GOLD -}; -*/ - CV_PossibleValue_t Color_cons_t[MAXSKINCOLORS+1]; +static void R_GenerateBlendTables(void); + /** \brief Initializes the translucency tables used by the Software renderer. */ void R_InitTranslucencyTables(void) @@ -221,8 +119,7 @@ void R_InitTranslucencyTables(void) // Load here the transparency lookup tables 'TRANSx0' // NOTE: the TRANSx0 resources MUST BE aligned on 64k for the asm // optimised code (in other words, transtables pointer low word is 0) - transtables = Z_MallocAlign(NUMTRANSTABLES*0x10000, PU_STATIC, - NULL, 16); + transtables = static_cast(Z_MallocAlign(NUMTRANSTABLES*0x10000, PU_STATIC, NULL, 16)); W_ReadLump(W_GetNumForName("TRANS10"), transtables); W_ReadLump(W_GetNumForName("TRANS20"), transtables+0x10000); @@ -283,10 +180,10 @@ static void BlendTab_Subtractive(UINT8 *table, int style, UINT8 blendamt) RGBA_t frontrgba = V_GetColor(fg); RGBA_t result; - result.rgba = ASTBlendPixel(backrgba, frontrgba, style, 0xFF); - result.s.red = max(0, result.s.red - blendamt); - result.s.green = max(0, result.s.green - blendamt); - result.s.blue = max(0, result.s.blue - blendamt); + result.rgba = ASTBlendPixel(backrgba, frontrgba, style, 0xFF); + result.s.red = std::max(0, result.s.red - blendamt); + result.s.green = std::max(0, result.s.green - blendamt); + result.s.blue = std::max(0, result.s.blue - blendamt); table[((bg * 0x100) + fg)] = GetColorLUT(&transtab_lut, result.s.red, result.s.green, result.s.blue); } @@ -339,17 +236,17 @@ static void BlendTab_GenerateMaps(INT32 tab, INT32 style, void (*genfunc)(UINT8 for (; i < num; i++) { const size_t offs = (0x10000 * i); - const UINT16 alpha = min(amtmul * i, 0xFF); + const UINT16 alpha = std::fmin(amtmul * i, 0xFF); genfunc(blendtables[tab] + offs, style, alpha); } } -void R_GenerateBlendTables(void) +static void R_GenerateBlendTables(void) { INT32 i; for (i = 0; i < NUMBLENDMAPS; i++) - blendtables[i] = Z_MallocAlign(BlendTab_Count[i] * 0x10000, PU_STATIC, NULL, 16); + blendtables[i] = static_cast(Z_MallocAlign(BlendTab_Count[i] * 0x10000, PU_STATIC, NULL, 16)); InitColorLUT(&transtab_lut, pLocalPalette, false); @@ -370,8 +267,8 @@ void R_GenerateBlendTables(void) BlendTab_Modulative(blendtables[blendtab_modulate]); } -#define ClipBlendLevel(style, trans) max(min((trans), BlendTab_Count[BlendTab_FromStyle[style]]-1), 0) -#define ClipTransLevel(trans) max(min((trans), NUMTRANSMAPS-2), 0) +#define ClipBlendLevel(style, trans) std::max(std::min((trans), BlendTab_Count[BlendTab_FromStyle[style]]-1), 0) +#define ClipTransLevel(trans) std::max(std::min((trans), NUMTRANSMAPS-2), 0) UINT8 *R_GetTranslucencyTable(INT32 alphalevel) { @@ -458,7 +355,7 @@ static UINT8* RGetTranslationColormap(INT32 skinnum, skincolors_t color, UINT8 f { // Allocate table for skin if necessary if (!tt[skintableindex]) - tt[skintableindex] = Z_Calloc(MAXTRANSLATIONS * sizeof(UINT8**), PU_STATIC, NULL); + tt[skintableindex] = static_cast(Z_Calloc(MAXTRANSLATIONS * sizeof(UINT8**), PU_STATIC, NULL)); // Get colormap ret = tt[skintableindex][color]; @@ -468,7 +365,7 @@ static UINT8* RGetTranslationColormap(INT32 skinnum, skincolors_t color, UINT8 f // Generate the colormap if necessary if (!ret) { - ret = Z_MallocAlign(NUM_PALETTE_ENTRIES, (flags & GTC_CACHE) ? PU_LEVEL : PU_STATIC, NULL, 8); + ret = static_cast(Z_MallocAlign(NUM_PALETTE_ENTRIES, (flags & GTC_CACHE) ? PU_LEVEL : PU_STATIC, NULL, 8)); K_GenerateKartColormap(ret, skinnum, color, local); //R_GenerateTranslationColormap(ret, skinnum, color); // SRB2kart // Cache the colormap if desired @@ -540,19 +437,6 @@ void R_FlushTranslationColormapCache(void) memset(localtranslationtablecache[i], 0, MAXTRANSLATIONS * sizeof(UINT8**)); } -/* -UINT8 R_GetColorByName(const char *name) -{ - UINT8 color = (UINT8)atoi(name); - if (color > 0 && color < MAXSKINCOLORS) - return color; - for (color = 1; color < MAXSKINCOLORS; color++) - if (!stricmp(Color_Names[color], name)) - return color; - return 0; -} -*/ - // ========================================================================== // COMMON DRAWER FOR 8 AND 16 BIT COLOR MODES // ========================================================================== @@ -572,39 +456,44 @@ UINT8 R_GetColorByName(const char *name) \param height hieght of buffer \return void - - */ +static void R_AllocViewMemory(void) +{ + negonearray = static_cast(Z_Realloc(negonearray, sizeof(*negonearray) * viewwidth, PU_STATIC, NULL)); + screenheightarray = static_cast(Z_Realloc(screenheightarray, sizeof(*screenheightarray) * viewwidth, PU_STATIC, NULL)); + + floorclip = static_cast(Z_Realloc(floorclip, sizeof(*floorclip) * viewwidth, PU_STATIC, NULL)); + ceilingclip = static_cast(Z_Realloc(ceilingclip, sizeof(*ceilingclip) * viewwidth, PU_STATIC, NULL)); + + frontscale = static_cast(Z_Realloc(frontscale, sizeof(*frontscale) * viewwidth, PU_STATIC, NULL)); + + xtoviewangle = static_cast(Z_Realloc(xtoviewangle, sizeof(*xtoviewangle) * (viewwidth + 1), PU_STATIC, NULL)); + + R_AllocSegMemory(); + R_AllocClipSegMemory(); + R_AllocPlaneMemory(); +#ifdef FLOORSPLATS + R_AllocFloorSpriteTables(); +#endif + R_AllocVisSpriteMemory(); +} + + void R_InitViewBuffer(INT32 width, INT32 height) { - INT32 i, bytesperpixel = vid.bpp; - if (width > MAXVIDWIDTH) width = MAXVIDWIDTH; if (height > MAXVIDHEIGHT) height = MAXVIDHEIGHT; - if (bytesperpixel < 1 || bytesperpixel > 4) - I_Error("R_InitViewBuffer: wrong bytesperpixel value %d\n", bytesperpixel); + + R_AllocViewMemory(); viewwindowx = 0; viewwindowy = 0; - // Column offset for those columns of the view window, but relative to the entire screen - for (i = 0; i < width; i++) - columnofs[i] = (viewwindowx + i) * bytesperpixel; - - // Precalculate all row offsets. - for (i = 0; i < height; i++) - { - ylookup[i] = ylookup1[i] = screens[0] + i*vid.width*bytesperpixel; - if (splitscreen == 1) - ylookup2[i] = screens[0] + (i+viewheight)*vid.width*bytesperpixel; - else - ylookup2[i] = screens[0] + i*vid.width*bytesperpixel + (viewwidth*bytesperpixel); - ylookup3[i] = screens[0] + (i+viewheight)*vid.width*bytesperpixel; - ylookup4[i] = screens[0] + (i+viewheight)*vid.width*bytesperpixel + (viewwidth*bytesperpixel); - } + linesize = vid.width; // killough 11/98 + renderscreen = vid.screens[0]; // haleyjd 07/02/14 } /** \brief viewborder patches lump numbers @@ -626,6 +515,28 @@ void R_InitViewBorder(void) viewborderlump[BRDR_BR] = W_GetNumForName("brdr_br"); } +/** \brief The R_VideoErase function + + Copy a screen buffer. + + \param ofs offest from buffer + \param count bytes to erase + + \return void + + +*/ +void R_VideoErase(size_t ofs, INT32 count) +{ + // LFB copy. + // This might not be a good idea if memcpy + // is not optimal, e.g. byte by byte on + // a 32bit CPU, as GNU GCC/Linux libc did + // at one point. + M_Memcpy(vid.screens[0] + ofs, vid.screens[1] + ofs, count); +} + + #if 0 /** \brief R_FillBackScreen @@ -648,7 +559,7 @@ void R_FillBackScreen(void) return; src = scr_borderpatch; - dest = screens[1]; + dest = vid.screens[1]; for (y = 0; y < vid.height; y++) { @@ -699,30 +610,7 @@ void R_FillBackScreen(void) V_DrawPatch(viewwindowx + scaledviewwidth, viewwindowy + viewheight, 1, W_CacheLumpNum(viewborderlump[BRDR_BR], PU_CACHE)); } -#endif -/** \brief The R_VideoErase function - - Copy a screen buffer. - - \param ofs offest from buffer - \param count bytes to erase - - \return void - - -*/ -void R_VideoErase(size_t ofs, INT32 count) -{ - // LFB copy. - // This might not be a good idea if memcpy - // is not optimal, e.g. byte by byte on - // a 32bit CPU, as GNU GCC/Linux libc did - // at one point. - M_Memcpy(screens[0] + ofs, screens[1] + ofs, count); -} - -#if 0 /** \brief The R_DrawViewBorder Draws the border around the view @@ -766,13 +654,14 @@ void R_DrawViewBorder(void) side <<= 1; // simpler using our VID_Blit routine - VID_BlitLinearScreen(screens[1] + ofs, screens[0] + ofs, side, viewheight - 1, + VID_BlitLinearScreen(vid.screens[1] + ofs, vid.screens[0] + ofs, side, viewheight - 1, vid.width, vid.width); } #endif // ========================================================================== -// INCLUDE 8bpp DRAWING CODE HERE +// INCLUDE DRAWING CODE HERE // ========================================================================== -#include "r_draw8.c" +#include "r_draw_column.cpp" +#include "r_draw_span.cpp" diff --git a/src/r_draw.h b/src/r_draw.h index 6e5758dd5..a28a09e79 100644 --- a/src/r_draw.h +++ b/src/r_draw.h @@ -14,72 +14,143 @@ #ifndef __R_DRAW__ #define __R_DRAW__ +#ifdef __cplusplus +extern "C" { +#endif + #include "r_defs.h" #include "r_things.h" +#include "r_skins.h" // ------------------------------- // COMMON STUFF FOR 8bpp AND 16bpp // ------------------------------- -extern UINT8 *ylookup[MAXVIDHEIGHT*4]; -extern UINT8 *ylookup1[MAXVIDHEIGHT*4]; -extern UINT8 *ylookup2[MAXVIDHEIGHT*4]; -extern UINT8 *ylookup3[MAXVIDHEIGHT*4]; -extern UINT8 *ylookup4[MAXVIDHEIGHT*4]; -extern INT32 columnofs[MAXVIDWIDTH*4]; -extern UINT8 *topleft; +extern UINT8 *renderscreen; +extern INT32 linesize; -// ------------------------- -// COLUMN DRAWING CODE STUFF -// ------------------------- +FUNCINLINE static ATTRINLINE UINT8 *R_Address(INT32 px, INT32 py) +{ + return renderscreen + (py + viewwindowy) * linesize + (viewwindowx + px); +} -extern lighttable_t *dc_colormap; -extern INT32 dc_x, dc_yl, dc_yh; -extern fixed_t dc_iscale, dc_texturemid; -extern UINT8 dc_hires; - -extern UINT8 *dc_source; // first pixel in a column - -// translucency stuff here -extern UINT8 *dc_transmap; - -// translation stuff here - -extern UINT8 *dc_translation; - -extern struct r_lightlist_s *dc_lightlist; -extern INT32 dc_numlights, dc_maxlights; - -//Fix TUTIFRUTI -extern INT32 dc_texheight; - -// ----------------------- -// SPAN DRAWING CODE STUFF -// ----------------------- - -extern INT32 ds_y, ds_x1, ds_x2; -extern lighttable_t *ds_colormap; -extern fixed_t ds_xfrac, ds_yfrac, ds_xstep, ds_ystep; -extern INT32 ds_waterofs, ds_bgofs; -extern UINT8 *ds_source; // start of a 64*64 tile image -extern INT32 dc_sourcelength; -extern UINT8 *ds_transmap; - -extern INT32 ds_bgofs; typedef struct { float x, y, z; } floatv3_t; +typedef struct +{ + INT32 y; + INT32 x1; + INT32 x2; + lighttable_t* colormap; + lighttable_t* translation; + + fixed_t xfrac; + fixed_t yfrac; + fixed_t xstep; + fixed_t ystep; + INT32 waterofs; + INT32 bgofs; + + fixed_t xoffs; + fixed_t yoffs; + + visplane_t *currentplane; + UINT8 *source; + UINT8 *transmap; + + float zeroheight; + + // Vectors for Software's tilted slope drawers + floatv3_t sup; + floatv3_t svp; + floatv3_t szp; + floatv3_t slope_origin; + floatv3_t slope_u; + floatv3_t slope_v; + + // Variable flat sizes + UINT32 nflatxshift; + UINT32 nflatyshift; + UINT32 nflatshiftup; + UINT32 nflatmask; + + fixed_t planeheight; + lighttable_t **planezlight; + + // + // Water ripple effect + // Needs the height of the plane, and the vertical position of the span. + // Sets planeripple.xfrac and planeripple.yfrac, added to ds_xfrac and ds_yfrac, if the span is not tilted. + // + struct + { + INT32 offset; + fixed_t xfrac, yfrac; + boolean active; + } planeripple; +} drawspandata_t; + +extern drawspandata_t g_ds; + +// Draws a single visplane. +void R_DrawSinglePlane(drawspandata_t* ds, visplane_t *pl, boolean allow_parallel); + // Vectors for Software's tilted slope drawers extern floatv3_t *ds_su, *ds_sv, *ds_sz; -extern floatv3_t *ds_sup, *ds_svp, *ds_szp; -extern float focallengthf, zeroheight; -// Variable flat sizes -extern UINT32 nflatxshift; -extern UINT32 nflatyshift; -extern UINT32 nflatshiftup; -extern UINT32 nflatmask; +extern float focallengthf; + + +typedef void (coldrawfunc_t)(drawcolumndata_t*); +typedef void (spandrawfunc_t)(drawspandata_t*); + +#define BASEDRAWFUNC 0 + +enum +{ + COLDRAWFUNC_BASE = BASEDRAWFUNC, + COLDRAWFUNC_FUZZY, + COLDRAWFUNC_TRANS, + COLDRAWFUNC_SHADOWED, + COLDRAWFUNC_TRANSTRANS, + COLDRAWFUNC_TWOSMULTIPATCH, + COLDRAWFUNC_TWOSMULTIPATCHTRANS, + COLDRAWFUNC_FOG, + + COLDRAWFUNC_MAX +}; + +extern int colfunctype; +extern coldrawfunc_t *colfunc; +extern coldrawfunc_t *colfuncs[COLDRAWFUNC_MAX]; + +enum +{ + SPANDRAWFUNC_BASE = BASEDRAWFUNC, + SPANDRAWFUNC_TRANS, + SPANDRAWFUNC_TILTED, + SPANDRAWFUNC_TILTEDTRANS, + + SPANDRAWFUNC_SPLAT, + SPANDRAWFUNC_TRANSSPLAT, + SPANDRAWFUNC_TILTEDSPLAT, + SPANDRAWFUNC_TILTEDTRANSSPLAT, + + SPANDRAWFUNC_WATER, + SPANDRAWFUNC_TILTEDWATER, + + SPANDRAWFUNC_FOG, + SPANDRAWFUNC_TILTEDFOG, + + SPANDRAWFUNC_MAX +}; + +extern spandrawfunc_t *spanfunc; +extern spandrawfunc_t *spanfuncs[SPANDRAWFUNC_MAX]; + +void R_DrawMaskedColumn(drawcolumndata_t* dc, column_t *column); /// \brief Top border #define BRDR_T 0 @@ -138,7 +209,6 @@ enum extern UINT8 *blendtables[NUMBLENDMAPS]; void R_InitTranslucencyTables(void); -void R_GenerateBlendTables(void); UINT8 *R_GetTranslucencyTable(INT32 alphalevel); UINT8 *R_GetBlendTable(int style, INT32 alphalevel); @@ -161,33 +231,44 @@ void R_DrawViewBorder(void); #define TRANSPARENTPIXEL 247 // ----------------- -// 8bpp DRAWING CODE +// DRAWING CODE // ----------------- -void R_DrawColumn_8(void); -#define R_DrawWallColumn_8 R_DrawColumn_8 -void R_DrawShadeColumn_8(void); -void R_DrawTranslucentColumn_8(void); +// column drawers +void R_DrawColumn(drawcolumndata_t* dc); +void R_DrawColumnShadowed(drawcolumndata_t* dc); -void R_DrawTranslatedColumn_8(void); -void R_DrawTranslatedTranslucentColumn_8(void); -void R_DrawSpan_8(void); -void R_CalcTiltedLighting(fixed_t start, fixed_t end); -void R_DrawTiltedSpan_8(void); -void R_DrawTiltedTranslucentSpan_8(void); -#ifndef NOWATER -void R_DrawTiltedTranslucentWaterSpan_8(void); +void R_DrawTranslucentColumn(drawcolumndata_t* dc); + +void R_DrawTranslatedColumn(drawcolumndata_t* dc); +void R_DrawTranslatedTranslucentColumn(drawcolumndata_t* dc); + +void R_Draw2sMultiPatchColumn(drawcolumndata_t* dc); +void R_Draw2sMultiPatchTranslucentColumn(drawcolumndata_t* dc); + +void R_DrawFogColumn(drawcolumndata_t* dc); + +// span drawers +void R_DrawSpan(drawspandata_t* ds); + +void R_DrawSpan_Tilted(drawspandata_t* ds); +void R_DrawTranslucentSpan_Tilted(drawspandata_t* ds); +void R_DrawTranslucentWaterSpan_Tilted(drawspandata_t* ds); + +void R_DrawTranslucentSpan(drawspandata_t* ds); +void R_DrawTranslucentWaterSpan(drawspandata_t* ds); + +void R_DrawFogSpan(drawspandata_t* ds); +void R_DrawFogSpan_Tilted(drawspandata_t* ds); + +void R_DrawSplat_Tilted(drawspandata_t* ds); +void R_DrawSplat(drawspandata_t* ds); +void R_DrawTranslucentSplat(drawspandata_t* ds); +void R_DrawTranslucentSplat_Tilted(drawspandata_t* ds); + +#ifdef __cplusplus +} // extern "C" #endif -void R_DrawTiltedSplat_8(void); -void R_DrawSplat_8(void); -void R_DrawTranslucentSplat_8(void); -void R_DrawTranslucentSpan_8(void); -void R_DrawTranslucentWaterSpan_8(void); -void R_Draw2sMultiPatchColumn_8(void); -void R_Draw2sMultiPatchTranslucentColumn_8(void); -void R_DrawFogSpan_8(void); -void R_DrawFogColumn_8(void); -void R_DrawColumnShadowed_8(void); // ========================================================================= #endif // __R_DRAW__ diff --git a/src/r_draw8.c b/src/r_draw8.c deleted file mode 100644 index 6edc9d6a6..000000000 --- a/src/r_draw8.c +++ /dev/null @@ -1,1814 +0,0 @@ -// SONIC ROBO BLAST 2 -//----------------------------------------------------------------------------- -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2018 by Sonic Team Junior. -// -// This program is free software distributed under the -// terms of the GNU General Public License, version 2. -// See the 'LICENSE' file for more details. -//----------------------------------------------------------------------------- -/// \file r_draw8.c -/// \brief 8bpp span/column drawer functions -/// \note no includes because this is included as part of r_draw.c - -// ========================================================================== -// COLUMNS -// ========================================================================== - -// A column is a vertical slice/span of a wall texture that uses -// a has a constant z depth from top to bottom. -// - -/** \brief The R_DrawColumn_8 function - Experiment to make software go faster. Taken from the Boom source -*/ -void R_DrawColumn_8(void) -{ - INT32 count; - UINT8 *restrict dest; - intptr_t frac; - intptr_t fracstep; - INT32 npow2min; - INT32 npow2max; - - count = dc_yh - dc_yl; - - if (count < 0) // Zero length, column does not exceed a pixel. - { - return; - } - - - if ((unsigned)dc_x >= (unsigned)vid.width || dc_yl < 0 || dc_yh >= vid.height) - { - return; - } - - // Framebuffer destination address. - // Use ylookup LUT to avoid multiply with ScreenWidth. - // Use columnofs LUT for subwindows? - dest = &topleft[dc_yl*vid.width + dc_x]; - - count++; - - // Determine scaling, which is the only mapping to be done. - fracstep = dc_iscale; - frac = (dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep))*(!dc_hires); - - // Inner loop that does the actual texture mapping, e.g. a DDA-like scaling. - // This is as fast as it gets. - const UINT8 *restrict source = dc_source; - const lighttable_t *restrict colormap = dc_colormap; - - intptr_t heightmask = dc_sourcelength-1; - npow2min = -1; - npow2max = dc_sourcelength; - - if (dc_sourcelength & heightmask) // not a power of 2 -- killough - { - heightmask = dc_texheight << FRACBITS; - - if (frac < 0) - { - while ((frac += heightmask) < 0) - { - ; - } - } - else - { - while (frac >= heightmask) - { - frac -= heightmask; - } - } - - do - { - // Re-map color indices from wall texture column - // using a lighting/special effects LUT. - // heightmask is the Tutti-Frutti fix - - // -1 is the lower clamp bound because column posts have a "safe" byte before the real data - // and a few bytes after as well - - // jartha: faster on my AMD FX-6300 CPU. - // Faster than ternaries, faster than std::min/std::max. Don't ask me why. - // I tested by viewing a non-PO2 texture from a consistent distance so it covered the entire screen. - // The framerate difference was about 50 frames at 640x400. - INT32 n = frac >> FRACBITS; - if (n < npow2min) - n = npow2min; - if (n > npow2max) - n = npow2max; - *dest = colormap[source[n]]; - - dest += vid.width; - - -#if __SIZEOF_POINTER__ < 8 // 64-bit systems have large enough numbers for this to be a non-issue - // Avoid overflow. - if (fracstep > 0x7FFFFFFF - frac) - { - frac += fracstep - heightmask; - } - else -#endif - { - frac += fracstep; - } - - while (frac >= heightmask) - { - frac -= heightmask; - } - } while (--count); - } - else - { - while ((count -= 2) >= 0) // texture height is a power of 2 - { - *dest = colormap[source[(frac>>FRACBITS) & heightmask]]; - - dest += vid.width; - frac += fracstep; - - *dest = colormap[source[(frac>>FRACBITS) & heightmask]]; - - dest += vid.width; - frac += fracstep; - } - - if (count & 1) - { - *dest = colormap[source[(frac>>FRACBITS) & heightmask]]; - } - } -} - - -void R_Draw2sMultiPatchColumn_8(void) -{ - INT32 count; - UINT8 *restrict dest; - intptr_t frac; - intptr_t fracstep; - - INT32 npow2min; - INT32 npow2max; - - count = dc_yh - dc_yl; - - if (count < 0) // Zero length, column does not exceed a pixel. - { - return; - } - - if ((unsigned)dc_x >= (unsigned)vid.width || dc_yl < 0 || dc_yh >= vid.height) - { - return; - } - - // Framebuffer destination address. - // Use ylookup LUT to avoid multiply with ScreenWidth. - // Use columnofs LUT for subwindows? - dest = &topleft[dc_yl*vid.width + dc_x]; - - count++; - - // Determine scaling, which is the only mapping to be done. - fracstep = dc_iscale; - frac = (dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep))*(!dc_hires); - - // Inner loop that does the actual texture mapping, e.g. a DDA-like scaling. - // This is as fast as it gets. - const UINT8 *restrict source = dc_source; - const lighttable_t *restrict colormap = dc_colormap; - intptr_t heightmask = dc_sourcelength-1; - UINT8 val; - - npow2min = -1; - npow2max = dc_sourcelength; - - if (dc_sourcelength & heightmask) // not a power of 2 -- killough - { - heightmask = dc_texheight << FRACBITS; - - if (frac < 0) - { - while ((frac += heightmask) < 0) - { - ; - } - } - else - { - while (frac >= heightmask) - { - frac -= heightmask; - } - } - - do - { - // Re-map color indices from wall texture column - // using a lighting/special effects LUT. - // heightmask is the Tutti-Frutti fix - - // -1 is the lower clamp bound because column posts have a "safe" byte before the real data - // and a few bytes after as well - - // jartha: faster on my AMD FX-6300 CPU. - // Faster than ternaries, faster than std::min/std::max. Don't ask me why. - // I tested by viewing a non-PO2 texture from a consistent distance so it covered the entire screen. - // The framerate difference was about 50 frames at 640x400. - INT32 n = frac >> FRACBITS; - if (n < npow2min) - n = npow2min; - if (n > npow2max) - n = npow2max; - - val = source[n]; - - if (val != TRANSPARENTPIXEL) - { - *dest = colormap[val]; - } - - dest += vid.width; - - // Avoid overflow. -#if __SIZEOF_POINTER__ < 8 - if (fracstep > 0x7FFFFFFF - frac) - { - frac += fracstep - heightmask; - } - else -#endif - { - frac += fracstep; - } - - while (frac >= heightmask) - { - frac -= heightmask; - } - } while (--count); - } - else - { - while ((count -= 2) >= 0) // texture height is a power of 2 - { - val = source[(frac>>FRACBITS) & heightmask]; - if (val != TRANSPARENTPIXEL) - { - *dest = colormap[val]; - } - - dest += vid.width; - frac += fracstep; - - val = source[(frac>>FRACBITS) & heightmask]; - if (val != TRANSPARENTPIXEL) - { - *dest = colormap[val]; - } - - dest += vid.width; - frac += fracstep; - } - - if (count & 1) - { - val = source[(frac>>FRACBITS) & heightmask]; - if (val != TRANSPARENTPIXEL) - { - *dest = colormap[val]; - } - } - } -} - -void R_Draw2sMultiPatchTranslucentColumn_8(void) -{ - INT32 count; - UINT8 *restrict dest; - intptr_t frac; - intptr_t fracstep; - - INT32 npow2min; - INT32 npow2max; - - count = dc_yh - dc_yl; - - if (count < 0) // Zero length, column does not exceed a pixel. - { - return; - } - - if ((unsigned)dc_x >= (unsigned)vid.width || dc_yl < 0 || dc_yh >= vid.height) - { - return; - } - - // Framebuffer destination address. - // Use ylookup LUT to avoid multiply with ScreenWidth. - // Use columnofs LUT for subwindows? - dest = &topleft[dc_yl*vid.width + dc_x]; - - count++; - - // Determine scaling, which is the only mapping to be done. - fracstep = dc_iscale; - frac = (dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep))*(!dc_hires); - - // Inner loop that does the actual texture mapping, e.g. a DDA-like scaling. - // This is as fast as it gets. - const UINT8 *restrict source = dc_source; - const UINT8 *transmap = dc_transmap; - const lighttable_t *restrict colormap = dc_colormap; - intptr_t heightmask = dc_sourcelength-1; - register UINT8 val; - - npow2min = -1; - npow2max = dc_sourcelength; - - if (dc_sourcelength & heightmask) // not a power of 2 -- killough - { - heightmask = dc_texheight << FRACBITS; - - if (frac < 0) - { - while ((frac += heightmask) < 0) - { - ; - } - } - else - { - while (frac >= heightmask) - { - frac -= heightmask; - } - } - - do - { - // Re-map color indices from wall texture column - // using a lighting/special effects LUT. - // heightmask is the Tutti-Frutti fix - - // -1 is the lower clamp bound because column posts have a "safe" byte before the real data - // and a few bytes after as well - - // jartha: faster on my AMD FX-6300 CPU. - // Faster than ternaries, faster than std::min/std::max. Don't ask me why. - // I tested by viewing a non-PO2 texture from a consistent distance so it covered the entire screen. - // The framerate difference was about 50 frames at 640x400. - INT32 n = frac >> FRACBITS; - if (n < npow2min) - n = npow2min; - if (n > npow2max) - n = npow2max; - - val = source[n]; - - if (val != TRANSPARENTPIXEL) - { - *dest = *(transmap + (colormap[val]<<8) + (*dest)); - } - - dest += vid.width; - - // Avoid overflow. -#if __SIZEOF_POINTER__ < 8 - if (fracstep > 0x7FFFFFFF - frac) - { - frac += fracstep - heightmask; - } - else -#endif - { - frac += fracstep; - } - - while (frac >= heightmask) - { - frac -= heightmask; - } - } while (--count); - } - else - { - while ((count -= 2) >= 0) // texture height is a power of 2 - { - val = source[(frac>>FRACBITS) & heightmask]; - if (val != TRANSPARENTPIXEL) - { - *dest = *(transmap + (colormap[val]<<8) + (*dest)); - } - - dest += vid.width; - frac += fracstep; - - val = source[(frac>>FRACBITS) & heightmask]; - if (val != TRANSPARENTPIXEL) - { - *dest = *(transmap + (colormap[val]<<8) + (*dest)); - } - - dest += vid.width; - frac += fracstep; - } - - if (count & 1) - { - val = source[(frac>>FRACBITS) & heightmask]; - if (val != TRANSPARENTPIXEL) - { - *dest = *(transmap + (colormap[val]<<8) + (*dest)); - } - } - } -} - -/** \brief The R_DrawShadeColumn_8 function - Experiment to make software go faster. Taken from the Boom source -*/ -void R_DrawShadeColumn_8(void) -{ - register INT32 count; - register UINT8 *dest; - register fixed_t frac, fracstep; - - // check out coords for src* - if ((dc_yl < 0) || (dc_x >= vid.width)) - return; - - count = dc_yh - dc_yl; - - if (count < 0) // Zero length, column does not exceed a pixel. - { - return; - } - - if ((unsigned)dc_x >= (unsigned)vid.width || dc_yl < 0 || dc_yh >= vid.height) - { - return; - } - - // FIXME. As above. - dest = &topleft[dc_yl*vid.width + dc_x]; - - // Looks familiar. - fracstep = dc_iscale; - frac = (dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep))*(!dc_hires); - - // Here we do an additional index re-mapping. - do - { - *dest = colormaps[(dc_source[frac>>FRACBITS] <<8) + (*dest)]; - dest += vid.width; - frac += fracstep; - } while (count--); -} - -/** \brief The R_DrawTranslucentColumn_8 function - I've made an asm routine for the transparency, because it slows down - a lot in 640x480 with big sprites (bfg on all screen, or transparent - walls on fullscreen) -*/ -void R_DrawTranslucentColumn_8(void) -{ - register INT32 count; - UINT8 *restrict dest; - intptr_t frac; - intptr_t fracstep; - - INT32 npow2min; - INT32 npow2max; - - count = dc_yh - dc_yl + 1; - - if (count <= 0) // Zero length, column does not exceed a pixel. - { - return; - } - - if ((unsigned)dc_x >= (unsigned)vid.width || dc_yl < 0 || dc_yh >= vid.height) - { - return; - } - - // FIXME. As above. - dest = &topleft[dc_yl*vid.width + dc_x]; - - // Looks familiar. - fracstep = dc_iscale; - frac = (dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep))*(!dc_hires); - - // Inner loop that does the actual texture mapping, e.g. a DDA-like scaling. - // This is as fast as it gets. - const UINT8 *restrict source = dc_source; - const UINT8 *transmap = dc_transmap; - const lighttable_t *restrict colormap = dc_colormap; - intptr_t heightmask = dc_sourcelength-1; - - npow2min = -1; - npow2max = dc_sourcelength; - - if (dc_sourcelength & heightmask) - { - heightmask = dc_texheight << FRACBITS; - - if (frac < 0) - { - while ((frac += heightmask) < 0) - { - ; - } - } - else - { - while (frac >= heightmask) - { - frac -= heightmask; - } - } - - do - { - // Re-map color indices from wall texture column - // using a lighting/special effects LUT. - // heightmask is the Tutti-Frutti fix - - // -1 is the lower clamp bound because column posts have a "safe" byte before the real data - // and a few bytes after as well - - // jartha: faster on my AMD FX-6300 CPU. - // Faster than ternaries, faster than std::min/std::max. Don't ask me why. - // I tested by viewing a non-PO2 texture from a consistent distance so it covered the entire screen. - // The framerate difference was about 50 frames at 640x400. - INT32 n = frac >> FRACBITS; - if (n < npow2min) - n = npow2min; - if (n > npow2max) - n = npow2max; - - *dest = *(transmap + (colormap[source[n]]<<8) + (*dest)); - - dest += vid.width; - - if ((frac += fracstep) >= heightmask) - { - frac -= heightmask; - } - } - while (--count); - } - else - { - while ((count -= 2) >= 0) // texture height is a power of 2 - { - *dest = *(transmap + (colormap[source[(frac>>FRACBITS)&heightmask]]<<8) + (*dest)); - dest += vid.width; - frac += fracstep; - - *dest = *(transmap + (colormap[source[(frac>>FRACBITS)&heightmask]]<<8) + (*dest)); - dest += vid.width; - frac += fracstep; - } - - if (count & 1) - { - *dest = *(transmap + (colormap[source[(frac>>FRACBITS)&heightmask]]<<8) + (*dest)); - } - } -} - -/** \brief The R_DrawTranslatedTranslucentColumn_8 function - Spiffy function. Not only does it colormap a sprite, but does translucency as well. - Uber-kudos to Cyan Helkaraxe -*/ -void R_DrawTranslatedTranslucentColumn_8(void) -{ - register INT32 count; - UINT8 *restrict dest; - intptr_t frac; - intptr_t fracstep; - - INT32 npow2min; - INT32 npow2max; - - count = dc_yh - dc_yl + 1; - - if (count <= 0) // Zero length, column does not exceed a pixel. - { - return; - } - - if ((unsigned)dc_x >= (unsigned)vid.width || dc_yl < 0 || dc_yh >= vid.height) - { - return; - } - - // FIXME. As above. - dest = &topleft[dc_yl*vid.width + dc_x]; - - // Looks familiar. - fracstep = dc_iscale; - frac = (dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep))*(!dc_hires); - - // Inner loop that does the actual texture mapping, e.g. a DDA-like scaling. - // This is as fast as it gets. - intptr_t heightmask = dc_sourcelength-1; - - npow2min = -1; - npow2max = dc_sourcelength; - - if (dc_sourcelength & heightmask) - { - heightmask = dc_texheight << FRACBITS; - - if (frac < 0) - { - while ((frac += heightmask) < 0) - { - ; - } - } - else - { - while (frac >= heightmask) - { - frac -= heightmask; - } - } - - do - { - // Re-map color indices from wall texture column - // using a lighting/special effects LUT. - // heightmask is the Tutti-Frutti fix - - // -1 is the lower clamp bound because column posts have a "safe" byte before the real data - // and a few bytes after as well - - // jartha: faster on my AMD FX-6300 CPU. - // Faster than ternaries, faster than std::min/std::max. Don't ask me why. - // I tested by viewing a non-PO2 texture from a consistent distance so it covered the entire screen. - // The framerate difference was about 50 frames at 640x400. - INT32 n = frac >> FRACBITS; - if (n < npow2min) - n = npow2min; - if (n > npow2max) - n = npow2max; - - *dest = *(dc_transmap + (dc_colormap[dc_translation[dc_source[n]]]<<8) + (*dest)); - - dest += vid.width; - - if ((frac += fracstep) >= heightmask) - { - frac -= heightmask; - } - } - while (--count); - } - else - { - while ((count -= 2) >= 0) // texture height is a power of 2 - { - *dest = *(dc_transmap + (dc_colormap[dc_translation[dc_source[(frac>>FRACBITS)&heightmask]]]<<8) + (*dest)); - dest += vid.width; - frac += fracstep; - - *dest = *(dc_transmap + (dc_colormap[dc_translation[dc_source[(frac>>FRACBITS)&heightmask]]]<<8) + (*dest)); - dest += vid.width; - frac += fracstep; - } - - if (count & 1) - { - *dest = *(dc_transmap + (dc_colormap[dc_translation[dc_source[(frac>>FRACBITS)&heightmask]]]<<8) + (*dest)); - } - } -} - -/** \brief The R_DrawTranslatedColumn_8 function - Draw columns up to 128 high but remap the green ramp to other colors - - \warning STILL NOT IN ASM, TO DO.. -*/ -void R_DrawTranslatedColumn_8(void) -{ - register INT32 count; - register UINT8 *dest; - register fixed_t frac, fracstep; - - count = dc_yh - dc_yl; - - if (count < 0) - { - return; - } - - if ((unsigned)dc_x >= (unsigned)vid.width || dc_yl < 0 || dc_yh >= vid.height) - { - return; - } - - // FIXME. As above. - dest = &topleft[dc_yl*vid.width + dc_x]; - - // Looks familiar. - fracstep = dc_iscale; - frac = (dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep))*(!dc_hires); - - // Here we do an additional index re-mapping. - do - { - // Translation tables are used - // to map certain colorramps to other ones, - // used with PLAY sprites. - // Thus the "green" ramp of the player 0 sprite - // is mapped to gray, red, black/indigo. - *dest = dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]]; - - dest += vid.width; - - frac += fracstep; - } while (count--); -} - -// ========================================================================== -// SPANS -// ========================================================================== - -#define SPANSIZE 16 -#define INVSPAN 0.0625f - -// 4194303 = (2048x2048)-1 (2048x2048 is maximum flat size) -#define MAXFLATBYTES 4194303 - -/** \brief The R_DrawSpan_8 function - Draws the actual span. -*/ -void R_DrawSpan_8 (void) -{ - uintptr_t xposition; - uintptr_t yposition; - uintptr_t xstep, ystep; - register UINT32 bit; - - UINT8 *restrict source = ds_source; - UINT8 *restrict colormap = ds_colormap; - UINT8 *restrict dest = ylookup[ds_y] + columnofs[ds_x1]; - const UINT8 *restrict deststop = screens[0] + vid.rowbytes * vid.height; - - register size_t count = (ds_x2 - ds_x1 + 1); - size_t i; - - xposition = ds_xfrac; yposition = ds_yfrac; - xstep = ds_xstep; ystep = ds_ystep; - - // SoM: we only need 6 bits for the integer part (0 thru 63) so the rest - // can be used for the fraction part. This allows calculation of the memory address in the - // texture with two shifts, an OR and one AND. (see below) - // for texture sizes > 64 the amount of precision we can allow will decrease, but only by one - // bit per power of two (obviously) - // Ok, because I was able to eliminate the variable spot below, this function is now FASTER - // than the original span renderer. Whodathunkit? - xposition <<= nflatshiftup; yposition <<= nflatshiftup; - xstep <<= nflatshiftup; ystep <<= nflatshiftup; - - if (dest+8 > deststop) - { - return; - } - - while (count >= 8) - { - // SoM: Why didn't I see this earlier? the spot variable is a waste now because we don't - // have the uber complicated math to calculate it now, so that was a memory write we didn't - // need! - for (i = 0; i < 8; i++) - { - bit = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); - dest[i] = colormap[source[bit]]; - - xposition += xstep; - yposition += ystep; - } - - dest += 8; - count -= 8; - } - while (count-- && dest <= deststop) - { - bit = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); - *dest++ = colormap[source[bit]]; - - xposition += xstep; - yposition += ystep; - } -} - -// R_CalcTiltedLighting -// Exactly what it says on the tin. I wish I wasn't too lazy to explain things properly. -static INT32 tiltlighting[MAXVIDWIDTH]; -void R_CalcTiltedLighting(fixed_t start, fixed_t end) -{ - // ZDoom uses a different lighting setup to us, and I couldn't figure out how to adapt their version - // of this function. Here's my own. - INT32 left = ds_x1, right = ds_x2; - fixed_t step = (end-start)/(ds_x2-ds_x1+1); - INT32 i; - - // I wanna do some optimizing by checking for out-of-range segments on either side to fill in all at once, - // but I'm too bad at coding to not crash the game trying to do that. I guess this is fast enough for now... - - for (i = left; i <= right; i++) - { - tiltlighting[i] = (start += step) >> FRACBITS; - - if (tiltlighting[i] < 0) - { - tiltlighting[i] = 0; - } - else if (tiltlighting[i] >= MAXLIGHTSCALE) - { - tiltlighting[i] = MAXLIGHTSCALE-1; - } - } -} - -#define PLANELIGHTFLOAT ((float)BASEVIDWIDTH * BASEVIDWIDTH / vid.width / (zeroheight - FIXED_TO_FLOAT(viewz)) / 21.0f * FIXED_TO_FLOAT(fovtan)) - -/** \brief The R_DrawTiltedSpan_8 function - Draw slopes! Holy sheit! -*/ -void R_DrawTiltedSpan_8(void) -{ - int width = ds_x2 - ds_x1; - double iz, uz, vz; - UINT32 u, v; - int i; - - UINT8 *source; - UINT8 *colormap; - register UINT8 *dest; - - double startz, startu, startv; - double izstep, uzstep, vzstep; - double endz, endu, endv; - UINT32 stepu, stepv; - register UINT32 bit; - - iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx); - - // Lighting is simple. It's just linear interpolation from start to end - { - float planelightfloat = PLANELIGHTFLOAT; - float lightstart, lightend; - - lightend = (iz + ds_szp->x*width) * planelightfloat; - lightstart = iz * planelightfloat; - - R_CalcTiltedLighting(FLOAT_TO_FIXED(lightstart), FLOAT_TO_FIXED(lightend)); - //CONS_Printf("tilted lighting %f to %f (foc %f)\n", lightstart, lightend, focallengthf); - } - - uz = ds_sup->z + ds_sup->y*(centery-ds_y) + ds_sup->x*(ds_x1-centerx); - vz = ds_svp->z + ds_svp->y*(centery-ds_y) + ds_svp->x*(ds_x1-centerx); - - dest = ylookup[ds_y] + columnofs[ds_x1]; - - source = ds_source; - -#if 0 // The "perfect" reference version of this routine. Pretty slow. - // Use it only to see how things are supposed to look. - i = 0; - do - { - double z = 1.f/iz; - u = (INT64)(uz*z) + viewx; - v = (INT64)(vz*z) + viewy; - - bit = ((v >> nflatyshift) & nflatmask) | (u >> nflatxshift); - colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); - *dest = colormap[source[bit]]; - - dest++; - iz += ds_szp->x; - uz += ds_sup->x; - vz += ds_svp->x; - } while (--width >= 0); -#else - startz = 1.f/iz; - startu = uz*startz; - startv = vz*startz; - - izstep = ds_szp->x * SPANSIZE; - uzstep = ds_sup->x * SPANSIZE; - vzstep = ds_svp->x * SPANSIZE; - width++; - - while (width >= SPANSIZE) - { - iz += izstep; - uz += uzstep; - vz += vzstep; - - endz = 1.f/iz; - endu = uz*endz; - endv = vz*endz; - stepu = (INT64)((endu - startu) * INVSPAN); - stepv = (INT64)((endv - startv) * INVSPAN); - u = (INT64)(startu) + viewx; - v = (INT64)(startv) + viewy; - - for (i = SPANSIZE-1; i >= 0; i--) - { - bit = ((v >> nflatyshift) & nflatmask) | (u >> nflatxshift); - colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); - *dest = colormap[source[bit]]; - - dest++; - u += stepu; - v += stepv; - } - startu = endu; - startv = endv; - width -= SPANSIZE; - } - if (width > 0) - { - if (width == 1) - { - u = (INT64)(startu); - v = (INT64)(startv); - bit = ((v >> nflatyshift) & nflatmask) | (u >> nflatxshift); - colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); - *dest = colormap[source[bit]]; - } - else - { - double left = width; - iz += ds_szp->x * left; - uz += ds_sup->x * left; - vz += ds_svp->x * left; - - endz = 1.f/iz; - endu = uz*endz; - endv = vz*endz; - left = 1.f/left; - stepu = (INT64)((endu - startu) * left); - stepv = (INT64)((endv - startv) * left); - u = (INT64)(startu) + viewx; - v = (INT64)(startv) + viewy; - - for (; width != 0; width--) - { - bit = ((v >> nflatyshift) & nflatmask) | (u >> nflatxshift); - colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); - *dest = colormap[source[bit]]; - - dest++; - u += stepu; - v += stepv; - } - } - } -#endif -} - -/** \brief The R_DrawTiltedTranslucentSpan_8 function - Like DrawTiltedSpan, but translucent -*/ -void R_DrawTiltedTranslucentSpan_8(void) -{ - int width = ds_x2 - ds_x1; - double iz, uz, vz; - UINT32 u, v; - int i; - - UINT8 *source; - UINT8 *colormap; - register UINT8 *dest; - - double startz, startu, startv; - double izstep, uzstep, vzstep; - double endz, endu, endv; - UINT32 stepu, stepv; - register UINT32 bit; - - iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx); - - // Lighting is simple. It's just linear interpolation from start to end - { - float planelightfloat = PLANELIGHTFLOAT; - float lightstart, lightend; - - lightend = (iz + ds_szp->x*width) * planelightfloat; - lightstart = iz * planelightfloat; - - R_CalcTiltedLighting(FLOAT_TO_FIXED(lightstart), FLOAT_TO_FIXED(lightend)); - //CONS_Printf("tilted lighting %f to %f (foc %f)\n", lightstart, lightend, focallengthf); - } - - uz = ds_sup->z + ds_sup->y*(centery-ds_y) + ds_sup->x*(ds_x1-centerx); - vz = ds_svp->z + ds_svp->y*(centery-ds_y) + ds_svp->x*(ds_x1-centerx); - - dest = ylookup[ds_y] + columnofs[ds_x1]; - - source = ds_source; - -#if 0 // The "perfect" reference version of this routine. Pretty slow. - // Use it only to see how things are supposed to look. - i = 0; - do - { - double z = 1.f/iz; - u = (INT64)(uz*z) + viewx; - v = (INT64)(vz*z) + viewy; - - bit = ((v >> nflatyshift) & nflatmask) | (u >> nflatxshift); - colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); - *dest = *(ds_transmap + (colormap[source[bit]] << 8) + *dest); - - dest++; - iz += ds_szp->x; - uz += ds_sup->x; - vz += ds_svp->x; - } while (--width >= 0); -#else - startz = 1.f/iz; - startu = uz*startz; - startv = vz*startz; - - izstep = ds_szp->x * SPANSIZE; - uzstep = ds_sup->x * SPANSIZE; - vzstep = ds_svp->x * SPANSIZE; - width++; - - while (width >= SPANSIZE) - { - iz += izstep; - uz += uzstep; - vz += vzstep; - - endz = 1.f/iz; - endu = uz*endz; - endv = vz*endz; - stepu = (INT64)((endu - startu) * INVSPAN); - stepv = (INT64)((endv - startv) * INVSPAN); - u = (INT64)(startu) + viewx; - v = (INT64)(startv) + viewy; - - for (i = SPANSIZE-1; i >= 0; i--) - { - bit = ((v >> nflatyshift) & nflatmask) | (u >> nflatxshift); - colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); - *dest = *(ds_transmap + (colormap[source[bit]] << 8) + *dest); - - dest++; - u += stepu; - v += stepv; - } - startu = endu; - startv = endv; - width -= SPANSIZE; - } - if (width > 0) - { - if (width == 1) - { - u = (INT64)(startu); - v = (INT64)(startv); - bit = ((v >> nflatyshift) & nflatmask) | (u >> nflatxshift); - colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); - *dest = *(ds_transmap + (colormap[source[bit]] << 8) + *dest); - } - else - { - double left = width; - iz += ds_szp->x * left; - uz += ds_sup->x * left; - vz += ds_svp->x * left; - - endz = 1.f/iz; - endu = uz*endz; - endv = vz*endz; - left = 1.f/left; - stepu = (INT64)((endu - startu) * left); - stepv = (INT64)((endv - startv) * left); - u = (INT64)(startu) + viewx; - v = (INT64)(startv) + viewy; - - for (; width != 0; width--) - { - bit = ((v >> nflatyshift) & nflatmask) | (u >> nflatxshift); - colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); - *dest = *(ds_transmap + (colormap[source[bit]] << 8) + *dest); - - dest++; - u += stepu; - v += stepv; - } - } - } -#endif -} - -#ifndef NOWATER -/** \brief The R_DrawTiltedTranslucentWaterSpan_8 function - Like DrawTiltedTranslucentSpan, but for water -*/ -void R_DrawTiltedTranslucentWaterSpan_8(void) -{ - int width = ds_x2 - ds_x1; - double iz, uz, vz; - UINT32 u, v; - int i; - - UINT8 *source; - UINT8 *colormap; - register UINT8 *dest; - UINT8 *dsrc; - - double startz, startu, startv; - double izstep, uzstep, vzstep; - double endz, endu, endv; - UINT32 stepu, stepv; - register UINT32 bit; - - iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx); - - // Lighting is simple. It's just linear interpolation from start to end - { - float planelightfloat = PLANELIGHTFLOAT; - float lightstart, lightend; - - lightend = (iz + ds_szp->x*width) * planelightfloat; - lightstart = iz * planelightfloat; - - R_CalcTiltedLighting(FLOAT_TO_FIXED(lightstart), FLOAT_TO_FIXED(lightend)); - //CONS_Printf("tilted lighting %f to %f (foc %f)\n", lightstart, lightend, focallengthf); - } - - uz = ds_sup->z + ds_sup->y*(centery-ds_y) + ds_sup->x*(ds_x1-centerx); - vz = ds_svp->z + ds_svp->y*(centery-ds_y) + ds_svp->x*(ds_x1-centerx); - - dest = ylookup[ds_y] + columnofs[ds_x1]; - dsrc = screens[1] + (ds_y+ds_bgofs)*vid.width + ds_x1; - - source = ds_source; - -#if 0 // The "perfect" reference version of this routine. Pretty slow. - // Use it only to see how things are supposed to look. - i = 0; - do - { - double z = 1.f/iz; - u = (INT64)(uz*z) + viewx; - v = (INT64)(vz*z) + viewy; - - bit = ((v >> nflatyshift) & nflatmask) | (u >> nflatxshift); - colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); - *dest = *(ds_transmap + (colormap[source[bit]] << 8) + *dsrc++); - - dest++; - iz += ds_szp->x; - uz += ds_sup->x; - vz += ds_svp->x; - } while (--width >= 0); -#else - startz = 1.f/iz; - startu = uz*startz; - startv = vz*startz; - - izstep = ds_szp->x * SPANSIZE; - uzstep = ds_sup->x * SPANSIZE; - vzstep = ds_svp->x * SPANSIZE; - width++; - - while (width >= SPANSIZE) - { - iz += izstep; - uz += uzstep; - vz += vzstep; - - endz = 1.f/iz; - endu = uz*endz; - endv = vz*endz; - stepu = (INT64)((endu - startu) * INVSPAN); - stepv = (INT64)((endv - startv) * INVSPAN); - u = (INT64)(startu) + viewx; - v = (INT64)(startv) + viewy; - - for (i = SPANSIZE-1; i >= 0; i--) - { - bit = ((v >> nflatyshift) & nflatmask) | (u >> nflatxshift); - colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); - *dest = *(ds_transmap + (colormap[source[bit]] << 8) + *dsrc++); - - dest++; - u += stepu; - v += stepv; - } - startu = endu; - startv = endv; - width -= SPANSIZE; - } - if (width > 0) - { - if (width == 1) - { - u = (INT64)(startu); - v = (INT64)(startv); - bit = ((v >> nflatyshift) & nflatmask) | (u >> nflatxshift); - colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); - *dest = *(ds_transmap + (colormap[source[bit]] << 8) + *dsrc++); - } - else - { - double left = width; - iz += ds_szp->x * left; - uz += ds_sup->x * left; - vz += ds_svp->x * left; - - endz = 1.f/iz; - endu = uz*endz; - endv = vz*endz; - left = 1.f/left; - stepu = (INT64)((endu - startu) * left); - stepv = (INT64)((endv - startv) * left); - u = (INT64)(startu) + viewx; - v = (INT64)(startv) + viewy; - - for (; width != 0; width--) - { - bit = ((v >> nflatyshift) & nflatmask) | (u >> nflatxshift); - colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); - *dest = *(ds_transmap + (colormap[source[bit]] << 8) + *dsrc++); - - dest++; - u += stepu; - v += stepv; - } - } - } -#endif -} -#endif // NOWATER - -void R_DrawTiltedSplat_8(void) -{ - // x1, x2 = ds_x1, ds_x2 - int width = ds_x2 - ds_x1; - double iz, uz, vz; - UINT32 u, v; - int i; - - UINT8 *source; - UINT8 *colormap; - register UINT8 *dest; - - UINT8 val; - - double startz, startu, startv; - double izstep, uzstep, vzstep; - double endz, endu, endv; - UINT32 stepu, stepv; - register UINT32 bit; - - iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx); - - // Lighting is simple. It's just linear interpolation from start to end - { - float planelightfloat = PLANELIGHTFLOAT; - float lightstart, lightend; - - lightend = (iz + ds_szp->x*width) * planelightfloat; - lightstart = iz * planelightfloat; - - R_CalcTiltedLighting(FLOAT_TO_FIXED(lightstart), FLOAT_TO_FIXED(lightend)); - //CONS_Printf("tilted lighting %f to %f (foc %f)\n", lightstart, lightend, focallengthf); - } - - uz = ds_sup->z + ds_sup->y*(centery-ds_y) + ds_sup->x*(ds_x1-centerx); - vz = ds_svp->z + ds_svp->y*(centery-ds_y) + ds_svp->x*(ds_x1-centerx); - - dest = ylookup[ds_y] + columnofs[ds_x1]; - - source = ds_source; - //colormap = ds_colormap; - -#if 0 // The "perfect" reference version of this routine. Pretty slow. - // Use it only to see how things are supposed to look. - i = 0; - do - { - double z = 1.f/iz; - u = (INT64)(uz*z) + viewx; - v = (INT64)(vz*z) + viewy; - - bit = ((v >> nflatyshift) & nflatmask) | (u >> nflatxshift); - val = source[bit]; - - if (val != TRANSPARENTPIXEL) - { - colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); - *dest = colormap[val]; - } - dest++; - iz += ds_szp->x; - uz += ds_sup->x; - vz += ds_svp->x; - } while (--width >= 0); -#else - startz = 1.f/iz; - startu = uz*startz; - startv = vz*startz; - - izstep = ds_szp->x * SPANSIZE; - uzstep = ds_sup->x * SPANSIZE; - vzstep = ds_svp->x * SPANSIZE; - //x1 = 0; - width++; - - while (width >= SPANSIZE) - { - iz += izstep; - uz += uzstep; - vz += vzstep; - - endz = 1.f/iz; - endu = uz*endz; - endv = vz*endz; - stepu = (INT64)((endu - startu) * INVSPAN); - stepv = (INT64)((endv - startv) * INVSPAN); - u = (INT64)(startu) + viewx; - v = (INT64)(startv) + viewy; - - for (i = SPANSIZE-1; i >= 0; i--) - { - bit = ((v >> nflatyshift) & nflatmask) | (u >> nflatxshift); - val = source[bit]; - if (val != TRANSPARENTPIXEL) - { - colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); - *dest = colormap[val]; - } - dest++; - u += stepu; - v += stepv; - } - startu = endu; - startv = endv; - width -= SPANSIZE; - } - if (width > 0) - { - if (width == 1) - { - u = (INT64)(startu); - v = (INT64)(startv); - bit = ((v >> nflatyshift) & nflatmask) | (u >> nflatxshift); - val = source[bit]; - if (val != TRANSPARENTPIXEL) - { - colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); - *dest = colormap[val]; - } - } - else - { - double left = width; - iz += ds_szp->x * left; - uz += ds_sup->x * left; - vz += ds_svp->x * left; - - endz = 1.f/iz; - endu = uz*endz; - endv = vz*endz; - left = 1.f/left; - stepu = (INT64)((endu - startu) * left); - stepv = (INT64)((endv - startv) * left); - u = (INT64)(startu) + viewx; - v = (INT64)(startv) + viewy; - - for (; width != 0; width--) - { - bit = ((v >> nflatyshift) & nflatmask) | (u >> nflatxshift); - val = source[bit]; - if (val != TRANSPARENTPIXEL) - { - colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); - *dest = colormap[val]; - } - dest++; - u += stepu; - v += stepv; - } - } - } -#endif -} - -/** \brief The R_DrawSplat_8 function - Just like R_DrawSpan_8, but skips transparent pixels. -*/ -void R_DrawSplat_8 (void) -{ - UINT32 xposition; - UINT32 yposition; - UINT32 xstep, ystep; - register UINT32 bit; - - UINT8 *source; - UINT8 *colormap; - register UINT8 *dest; - - register size_t count; - size_t i; - UINT32 val; - - // SoM: we only need 6 bits for the integer part (0 thru 63) so the rest - // can be used for the fraction part. This allows calculation of the memory address in the - // texture with two shifts, an OR and one AND. (see below) - // for texture sizes > 64 the amount of precision we can allow will decrease, but only by one - // bit per power of two (obviously) - // Ok, because I was able to eliminate the variable spot below, this function is now FASTER - // than the original span renderer. Whodathunkit? - xposition = ds_xfrac << nflatshiftup; yposition = ds_yfrac << nflatshiftup; - xstep = ds_xstep << nflatshiftup; ystep = ds_ystep << nflatshiftup; - - source = ds_source; - colormap = ds_colormap; - dest = ylookup[ds_y] + columnofs[ds_x1]; - count = ds_x2 - ds_x1 + 1; - - while (count >= 8) - { - // SoM: Why didn't I see this earlier? the spot variable is a waste now because we don't - // have the uber complicated math to calculate it now, so that was a memory write we didn't - // need! - // - // 4194303 = (2048x2048)-1 (2048x2048 is maximum flat size) - for (i = 0; i < 8; i++) - { - bit = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); - bit &= MAXFLATBYTES; - val = source[bit]; - if (val != TRANSPARENTPIXEL) - dest[i] = colormap[val]; - - xposition += xstep; - yposition += ystep; - } - - dest += 8; - count -= 8; - } - while (count--) - { - bit = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); - val = source[bit]; - if (val != TRANSPARENTPIXEL) - { - *dest = colormap[val]; - } - - dest++; - xposition += xstep; - yposition += ystep; - } -} - -/** \brief The R_DrawTranslucentSplat_8 function - Just like R_DrawSplat_8, but is translucent! -*/ -void R_DrawTranslucentSplat_8 (void) -{ - UINT32 xposition; - UINT32 yposition; - UINT32 xstep, ystep; - register UINT32 bit; - - UINT8 *source; - UINT8 *colormap; - register UINT8 *dest; - - register size_t count; - size_t i; - UINT8 val; - - // SoM: we only need 6 bits for the integer part (0 thru 63) so the rest - // can be used for the fraction part. This allows calculation of the memory address in the - // texture with two shifts, an OR and one AND. (see below) - // for texture sizes > 64 the amount of precision we can allow will decrease, but only by one - // bit per power of two (obviously) - // Ok, because I was able to eliminate the variable spot below, this function is now FASTER - // than the original span renderer. Whodathunkit? - xposition = ds_xfrac << nflatshiftup; yposition = ds_yfrac << nflatshiftup; - xstep = ds_xstep << nflatshiftup; ystep = ds_ystep << nflatshiftup; - - source = ds_source; - colormap = ds_colormap; - dest = ylookup[ds_y] + columnofs[ds_x1]; - count = ds_x2 - ds_x1 + 1; - - while (count >= 8) - { - // SoM: Why didn't I see this earlier? the spot variable is a waste now because we don't - // have the uber complicated math to calculate it now, so that was a memory write we didn't - // need! - for (i = 0; i < 8; i++) - { - bit = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); - val = source[bit]; - if (val != TRANSPARENTPIXEL) - dest[i] = *(ds_transmap + (colormap[val] << 8) + dest[i]); - - xposition += xstep; - yposition += ystep; - } - - dest += 8; - count -= 8; - } - while (count--) - { - bit = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); - val = source[bit]; - if (val != TRANSPARENTPIXEL) - *dest = *(ds_transmap + (colormap[val] << 8) + *dest); - - dest++; - xposition += xstep; - yposition += ystep; - } -} - -/** \brief The R_DrawTranslucentSpan_8 function - Draws the actual span with translucent. -*/ -void R_DrawTranslucentSpan_8 (void) -{ - fixed_t xposition; - fixed_t yposition; - fixed_t xstep, ystep; - register UINT32 bit; - - UINT8 *source; - UINT8 *colormap; - register UINT8 *dest; - const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height; - - register size_t count = (ds_x2 - ds_x1 + 1); - size_t i; - - xposition = ds_xfrac; yposition = ds_yfrac; - xstep = ds_xstep; ystep = ds_ystep; - - // SoM: we only need 6 bits for the integer part (0 thru 63) so the rest - // can be used for the fraction part. This allows calculation of the memory address in the - // texture with two shifts, an OR and one AND. (see below) - // for texture sizes > 64 the amount of precision we can allow will decrease, but only by one - // bit per power of two (obviously) - // Ok, because I was able to eliminate the variable spot below, this function is now FASTER - // than the original span renderer. Whodathunkit? - xposition <<= nflatshiftup; yposition <<= nflatshiftup; - xstep <<= nflatshiftup; ystep <<= nflatshiftup; - - source = ds_source; - colormap = ds_colormap; - dest = ylookup[ds_y] + columnofs[ds_x1]; - - while (count >= 8) - { - // SoM: Why didn't I see this earlier? the spot variable is a waste now because we don't - // have the uber complicated math to calculate it now, so that was a memory write we didn't - // need! - for (i = 0; i < 8; i++) - { - bit = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); - dest[i] = *(ds_transmap + (colormap[source[bit]] << 8) + dest[i]); - xposition += xstep; - yposition += ystep; - } - - dest += 8; - count -= 8; - } - while (count-- && dest <= deststop) - { - bit = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); - *dest = *(ds_transmap + (colormap[source[bit]] << 8) + *dest); - dest++; - xposition += xstep; - yposition += ystep; - } -} - -#ifndef NOWATER -void R_DrawTranslucentWaterSpan_8(void) -{ - UINT32 xposition; - UINT32 yposition; - UINT32 xstep, ystep; - register UINT32 bit; - - UINT8 *source; - UINT8 *colormap; - register UINT8 *dest; - UINT8 *dsrc; - - register size_t count; - size_t i; - - // SoM: we only need 6 bits for the integer part (0 thru 63) so the rest - // can be used for the fraction part. This allows calculation of the memory address in the - // texture with two shifts, an OR and one AND. (see below) - // for texture sizes > 64 the amount of precision we can allow will decrease, but only by one - // bit per power of two (obviously) - // Ok, because I was able to eliminate the variable spot below, this function is now FASTER - // than the original span renderer. Whodathunkit? - xposition = ds_xfrac << nflatshiftup; yposition = (ds_yfrac + ds_waterofs) << nflatshiftup; - xstep = ds_xstep << nflatshiftup; ystep = ds_ystep << nflatshiftup; - - source = ds_source; - colormap = ds_colormap; - dest = ylookup[ds_y] + columnofs[ds_x1]; - dsrc = screens[1] + (ds_y+ds_bgofs)*vid.width + ds_x1; - count = ds_x2 - ds_x1 + 1; - - while (count >= 8) - { - // SoM: Why didn't I see this earlier? the spot variable is a waste now because we don't - // have the uber complicated math to calculate it now, so that was a memory write we didn't - // need! - for (i = 0; i < 8; i++) - { - bit = ((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift); - dest[i] = colormap[*(ds_transmap + (source[bit] << 8) + *dsrc++)]; - xposition += xstep; - yposition += ystep; - } - - dest += 8; - count -= 8; - } - while (count--) - { - bit = ((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift); - *dest++ = colormap[*(ds_transmap + (source[bit] << 8) + *dsrc++)]; - - xposition += xstep; - yposition += ystep; - } -} -#endif - -/** \brief The R_DrawFogSpan_8 function - Draws the actual span with fogging. -*/ -void R_DrawFogSpan_8(void) -{ - UINT8 *colormap; - register UINT8 *dest; - - register size_t count; - - colormap = ds_colormap; - dest = &topleft[ds_y *vid.width + ds_x1]; - - count = ds_x2 - ds_x1 + 1; - - while (count >= 4) - { - dest[0] = colormap[dest[0]]; - dest[1] = colormap[dest[1]]; - dest[2] = colormap[dest[2]]; - dest[3] = colormap[dest[3]]; - - dest += 4; - count -= 4; - } - - while (count--) - { - *dest = colormap[*dest]; - dest++; - } -} - -/** \brief The R_DrawFogColumn_8 function - Fog wall. -*/ -void R_DrawFogColumn_8(void) -{ - register INT32 count; - register UINT8 *dest; - - count = dc_yh - dc_yl; - - // Zero length, column does not exceed a pixel. - if (count < 0) - return; - -#ifdef RANGECHECK - if ((unsigned)dc_x >= (unsigned)vid.width || dc_yl < 0 || dc_yh >= vid.height) - I_Error("R_DrawFogColumn_8: %d to %d at %d", dc_yl, dc_yh, dc_x); -#endif - - // Framebuffer destination address. - // Use ylookup LUT to avoid multiply with ScreenWidth. - // Use columnofs LUT for subwindows? - //dest = ylookup[dc_yl] + columnofs[dc_x]; - dest = &topleft[dc_yl*vid.width + dc_x]; - - // Determine scaling, which is the only mapping to be done. - do - { - // Simple. Apply the colormap to what's already on the screen. - *dest = dc_colormap[*dest]; - dest += vid.width; - } while (count--); -} - -/** \brief The R_DrawShadeColumn_8 function - This is for 3D floors that cast shadows on walls. - - This function just cuts the column up into sections and calls R_DrawColumn_8 -*/ -void R_DrawColumnShadowed_8(void) -{ - register INT32 count; - INT32 realyh, i, height, bheight = 0, solid = 0; - - realyh = dc_yh; - - count = dc_yh - dc_yl; - - // Zero length, column does not exceed a pixel. - if (count < 0) - return; - -#ifdef RANGECHECK - if ((unsigned)dc_x >= (unsigned)vid.width || dc_yl < 0 || dc_yh >= vid.height) - I_Error("R_DrawColumnShadowed_8: %d to %d at %d", dc_yl, dc_yh, dc_x); -#endif - - // This runs through the lightlist from top to bottom and cuts up the column accordingly. - for (i = 0; i < dc_numlights; i++) - { - // If the height of the light is above the column, get the colormap - // anyway because the lighting of the top should be affected. - solid = dc_lightlist[i].flags & FF_CUTSOLIDS; - - height = dc_lightlist[i].height >> LIGHTSCALESHIFT; - if (solid) - { - bheight = dc_lightlist[i].botheight >> LIGHTSCALESHIFT; - if (bheight < height) - { - // confounded slopes sometimes allow partial invertedness, - // even including cases where the top and bottom heights - // should actually be the same! - // swap the height values as a workaround for this quirk - INT32 temp = height; - height = bheight; - bheight = temp; - } - } - if (height <= dc_yl) - { - dc_colormap = dc_lightlist[i].rcolormap; - if (encoremap) - dc_colormap += COLORMAP_REMAPOFFSET; - if (solid && dc_yl < bheight) - dc_yl = bheight; - continue; - } - // Found a break in the column! - dc_yh = height; - - if (dc_yh > realyh) - dc_yh = realyh; - basecolfunc(); // R_DrawColumn_8 for the appropriate architecture - if (solid) - dc_yl = bheight; - else - dc_yl = dc_yh + 1; - - dc_colormap = dc_lightlist[i].rcolormap; - if (encoremap) - dc_colormap += COLORMAP_REMAPOFFSET; - } - dc_yh = realyh; - if (dc_yl <= realyh) - walldrawerfunc(); // R_DrawWallColumn_8 for the appropriate architecture -} diff --git a/src/r_draw_column.cpp b/src/r_draw_column.cpp new file mode 100644 index 000000000..dcc1a5b90 --- /dev/null +++ b/src/r_draw_column.cpp @@ -0,0 +1,356 @@ +// SONIC ROBO BLAST 2 KART +//----------------------------------------------------------------------------- +// Copyright (C) 2025 by Kart Krew. +// Copyright (C) 2020 by Sonic Team Junior. +// Copyright (C) 2000 by DooM Legacy Team. +// Copyright (C) 1996 by id Software, Inc. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file r_draw_column.cpp +/// \brief column drawer functions +/// \note no includes because this is included as part of r_draw.cpp + +// ========================================================================== +// COLUMNS +// ========================================================================== + +// A column is a vertical slice/span of a wall texture that uses +// a has a constant z depth from top to bottom. +// + +enum DrawColumnType +{ + DC_BASIC = 0x0000, + DC_COLORMAP = 0x0001, + DC_TRANSMAP = 0x0002, + DC_HOLES = 0x0004, + DC_LIGHTLIST = 0x0008, +}; + +template +static constexpr UINT8 R_GetColumnTranslated(drawcolumndata_t* dc, UINT8 col, const UINT8 * restrict colormap) +{ + if constexpr (Type & DrawColumnType::DC_COLORMAP) + { + col = dc->translation[col]; + } + + return colormap[col]; +} + +template +static constexpr UINT8 R_GetColumnTranslucent(drawcolumndata_t* dc, UINT8 * restrict dest, UINT8 col, const UINT8 * restrict colormap) +{ + col = R_GetColumnTranslated(dc, col, colormap); + + if constexpr (Type & DrawColumnType::DC_TRANSMAP) + { + return *(dc->transmap + (col << 8) + (*dest)); + } + else + { + return col; + } +} + +template +static constexpr UINT8 R_DrawColumnPixel(drawcolumndata_t* dc, UINT8 * restrict dest, UINT32 bit, const restrict UINT8 *source, const restrict UINT8 *colormap) +{ + UINT8 col = source[bit]; + + if constexpr (Type & DrawColumnType::DC_HOLES) + { + if (col == TRANSPARENTPIXEL) + { + return *dest; + } + } + + return R_GetColumnTranslucent(dc, dest, col, colormap); +} + +/** \brief The R_DrawColumn function + Experiment to make software go faster. Taken from the Boom source +*/ +template +static void R_DrawColumnTemplate(drawcolumndata_t *dc) +{ + INT32 count; + + count = dc->yh - dc->yl; + + if (count < 0) // Zero length, column does not exceed a pixel. + { + return; + } + + if ((unsigned)dc->x >= (unsigned)vid.width || dc->yl < 0 || dc->yh >= vid.height) + { + return; + } + + if constexpr (Type & DrawColumnType::DC_LIGHTLIST) + { + constexpr DrawColumnType NewType = static_cast(Type & ~DC_LIGHTLIST); + INT32 i, height, bheight = 0, solid = 0; + drawcolumndata_t dc_copy = *dc; + + const INT32 realyh = dc_copy.yh; + + // This runs through the lightlist from top to bottom and cuts up the column accordingly. + for (i = 0; i < dc_copy.numlights; i++) + { + // If the height of the light is above the column, get the colormap + // anyway because the lighting of the top should be affected. + solid = dc_copy.lightlist[i].flags & FF_CUTSOLIDS; + height = dc_copy.lightlist[i].height >> LIGHTSCALESHIFT; + + if (solid) + { + bheight = dc_copy.lightlist[i].botheight >> LIGHTSCALESHIFT; + + if (bheight < height) + { + // confounded slopes sometimes allow partial invertedness, + // even including cases where the top and bottom heights + // should actually be the same! + // swap the height values as a workaround for this quirk + INT32 temp = height; + height = bheight; + bheight = temp; + } + } + + if (height <= dc_copy.yl) + { + dc_copy.colormap = dc_copy.lightlist[i].rcolormap; + + if (encoremap) + { + dc_copy.colormap += COLORMAP_REMAPOFFSET; + } + + if (solid && dc_copy.yl < bheight) + { + dc_copy.yl = bheight; + } + + continue; + } + + // Found a break in the column! + dc_copy.yh = height; + + if (dc_copy.yh > realyh) + { + dc_copy.yh = realyh; + } + + R_DrawColumnTemplate(&dc_copy); + if (solid) + { + dc_copy.yl = bheight; + } + else + { + dc_copy.yl = dc_copy.yh + 1; + } + + dc_copy.colormap = dc_copy.lightlist[i].rcolormap; + + if (encoremap) + { + dc_copy.colormap += COLORMAP_REMAPOFFSET; + } + } + + dc_copy.yh = realyh; + + if (dc_copy.yl <= realyh) + { + R_DrawColumnTemplate(&dc_copy); + } + } + else + { + // Inner loop that does the actual texture mapping, + // e.g. a DDA-lile scaling. + // This is as fast as it gets. (Yeah, right!!! -- killough) + // + // killough 2/1/98: more performance tuning + + intptr_t frac; + const intptr_t fracstep = dc->iscale; + const intptr_t heightmask = dc->sourcelength-1; + constexpr INT32 npow2min = -1; + const INT32 npow2max = dc->sourcelength; + const INT32 stride = vid.width; + + const UINT8 * restrict source = dc->source; + const lighttable_t * restrict colormap = dc->colormap; + + // Framebuffer destination address. + UINT8 * restrict dest = R_Address(dc->x, dc->yl); + + count++; + + // Determine scaling, which is the only mapping to be done. + frac = (dc->texturemid + FixedMul((dc->yl << FRACBITS) - centeryfrac, fracstep)); + + switch (heightmask) + { + case 255: + case 127: + { + while(count--) + { + *dest = R_DrawColumnPixel(dc, dest, (frac>>FRACBITS) & heightmask, source, colormap); + dest += stride; + frac += fracstep; + } + } + break; + case -1: + { + if (frac < 0) + // adjust in case we underread + frac += FRACUNIT; + + // texture has no height, so just go + while (--count >= 0) + { + *dest = R_DrawColumnPixel(dc, dest, frac>>FRACBITS, source, colormap); + dest += stride; + frac += fracstep; + } + } + break; + default: + { + if (!(dc->sourcelength & heightmask)) // power of 2 -- killough + { + while ((count -= 2) >= 0) // texture height is a power of 2 -- killough + { + *dest = R_DrawColumnPixel(dc, dest, (frac>>FRACBITS) & heightmask, source, colormap); + dest += stride; + frac += fracstep; + + *dest = R_DrawColumnPixel(dc, dest, (frac>>FRACBITS) & heightmask, source, colormap); + dest += stride; + frac += fracstep; + } + + if (count & 1) + { + *dest = R_DrawColumnPixel(dc, dest, (frac>>FRACBITS) & heightmask, source, colormap); + } + } + else + { + const intptr_t fixed_heightmask = dc->texheight << FRACBITS; + + if (frac < 0) + { + while ((frac += fixed_heightmask) < 0) + { + ; + } + } + else + { + while (frac >= fixed_heightmask) + { + frac -= fixed_heightmask; + } + } + + do + { + // Re-map color indices from wall texture column + // using a lighting/special effects LUT. + // heightmask is the Tutti-Frutti fix + + // -1 is the lower clamp bound because column posts have a "safe" byte before the real data + // and a few bytes after as well + *dest = R_DrawColumnPixel(dc, dest, CLAMP((frac >> FRACBITS), npow2min, npow2max), source, colormap); + + dest += stride; + +#if __SIZEOF_POINTER__ < 8 // 64-bit systems have large enough numbers for this to be a non-issue + // Avoid overflow. + if (fracstep > 0x7FFFFFFF - frac) + { + frac += fracstep - fixed_heightmask; + } + else +#endif + { + frac += fracstep; + } + + while (frac >= fixed_heightmask) + { + frac -= fixed_heightmask; + } + } + while (--count); + } + } + break; + } + } +} + +#define DEFINE_COLUMN_FUNC(name, flags) \ + void name(drawcolumndata_t *dc) \ + { \ + constexpr DrawColumnType opt = static_cast(flags); \ + R_DrawColumnTemplate(dc); \ + } + +DEFINE_COLUMN_FUNC(R_DrawColumn, DC_BASIC) +DEFINE_COLUMN_FUNC(R_DrawTranslucentColumn, DC_TRANSMAP) +DEFINE_COLUMN_FUNC(R_DrawTranslatedColumn, DC_COLORMAP) +DEFINE_COLUMN_FUNC(R_DrawColumnShadowed, DC_LIGHTLIST) +DEFINE_COLUMN_FUNC(R_DrawTranslatedTranslucentColumn, DC_COLORMAP|DC_TRANSMAP) +DEFINE_COLUMN_FUNC(R_Draw2sMultiPatchColumn, DC_HOLES) +DEFINE_COLUMN_FUNC(R_Draw2sMultiPatchTranslucentColumn, DC_HOLES|DC_TRANSMAP) + +/** \brief The R_DrawFogColumn function + Fog wall. +*/ +void R_DrawFogColumn(drawcolumndata_t* dc) +{ + INT32 count; + UINT8 * restrict dest; + + count = dc->yh - dc->yl; + + // Zero length, column does not exceed a pixel. + if (count < 0) + { + return; + } + + if ((unsigned)dc->x >= (unsigned)vid.width || dc->yl < 0 || dc->yh >= vid.height) + { + return; + } + + // Framebuffer destination address. + dest = R_Address(dc->x, dc->yl); + + const INT32 stride = vid.width; + const lighttable_t * restrict colormap = dc->colormap; + + // Determine scaling, which is the only mapping to be done. + do + { + // Simple. Apply the colormap to what's already on the screen. + *dest = colormap[*dest]; + dest += stride; + } while (count--); +} diff --git a/src/r_draw_span.cpp b/src/r_draw_span.cpp new file mode 100644 index 000000000..cf7878184 --- /dev/null +++ b/src/r_draw_span.cpp @@ -0,0 +1,446 @@ +// SONIC ROBO BLAST 2 KART +//----------------------------------------------------------------------------- +// Copyright (C) 2025 by Kart Krew. +// Copyright (C) 2020 by Sonic Team Junior. +// Copyright (C) 2000 by DooM Legacy Team. +// Copyright (C) 1996 by id Software, Inc. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file r_draw_span.cpp +/// \brief span drawer functions +/// \note no includes because this is included as part of r_draw.cpp + +#ifdef HAVE_THREADS +#ifdef _WIN32 +#include +#define local_for_thread static __thread +#else +#include +#define local_for_thread thread_local static +#endif +#else +#define local_for_thread static +#endif + +// ========================================================================== +// SPANS +// ========================================================================== + +#define SPANSIZE 16 +#define INVSPAN 0.0625f + +// 4194303 = (2048x2048)-1 (2048x2048 is maximum flat size) +#define MAXFLATBYTES 4194303 + +#define PLANELIGHTFLOAT ((float)BASEVIDWIDTH * BASEVIDWIDTH / stride / ds->zeroheight / 21.0f * FIXED_TO_FLOAT(fovtan)) + +enum DrawSpanType +{ + DS_BASIC = 0x0000, + DS_COLORMAP = 0x0001, + DS_TRANSMAP = 0x0002, + DS_HOLES = 0x0004, + DS_RIPPLE = 0x0008, +}; + +template +static constexpr UINT8 R_GetSpanTranslucent(drawspandata_t* ds, UINT8 *dsrc, const UINT8 *colormap, UINT8 col) +{ + col = colormap[col]; + + if constexpr (Type & DrawSpanType::DS_TRANSMAP) + { + return *(ds->transmap + (col << 8) + (*dsrc)); + } + else + { + return col; + } +} + +template +static constexpr UINT8 R_DrawSpanPixel(drawspandata_t* ds, UINT8 *dsrc, const UINT8 *colormap, UINT32 bit, const UINT8 *source) +{ + UINT8 col = source[bit]; + + if constexpr (Type & DrawSpanType::DS_HOLES) + { + if (col == TRANSPARENTPIXEL) + { + return *dsrc; + } + } + + return R_GetSpanTranslucent(ds, dsrc, colormap, col); +} + +/** \brief The R_DrawSpan_8 function + Draws the actual span. +*/ +template +static void R_DrawSpanTemplate(drawspandata_t* ds) +{ + UINT32 xposition; + UINT32 yposition; + UINT32 xstep, ystep; + UINT32 bit; + + UINT8 * restrict dest = R_Address(ds->x1, ds->y); + UINT8 * restrict dsrc; + + const UINT8 * restrict deststop = vid.screens[0] + vid.rowbytes * vid.height; + + if (dest+8 > deststop) + { + return; + } + + intptr_t count = (ds->x2 - ds->x1 + 1); + size_t i; + + xposition = ds->xfrac; yposition = ds->yfrac; + xstep = ds->xstep; ystep = ds->ystep; + + const UINT8 * restrict source = ds->source; + const UINT8 * restrict colormap = ds->colormap; + + if constexpr (Type & DS_RIPPLE) + { + yposition += ds->waterofs; + } + + // SoM: we only need 6 bits for the integer part (0 thru 63) so the rest + // can be used for the fraction part. This allows calculation of the memory address in the + // texture with two shifts, an OR and one AND. (see below) + // for texture sizes > 64 the amount of precision we can allow will decrease, but only by one + // bit per power of two (obviously) + // Ok, because I was able to eliminate the variable spot below, this function is now FASTER + // than the original span renderer. Whodathunkit? + xposition <<= ds->nflatshiftup; yposition <<= ds->nflatshiftup; + xstep <<= ds->nflatshiftup; ystep <<= ds->nflatshiftup; + + if constexpr (Type & DS_RIPPLE) + { + dsrc = vid.screens[1] + (ds->y + ds->bgofs) * vid.width + ds->x1; + } + else + { + dsrc = dest; + } + + while (count >= 8) + { + // SoM: Why didn't I see this earlier? the spot variable is a waste now because we don't + // have the uber complicated math to calculate it now, so that was a memory write we didn't + // need! + + for (i = 0; i < 8; i++) + { + bit = ((yposition >> ds->nflatyshift) & ds->nflatmask) | (xposition >> ds->nflatxshift); + + dest[i] = R_DrawSpanPixel(ds, &dsrc[i], colormap, bit, source); + + xposition += xstep; + yposition += ystep; + } + + dest += 8; + dsrc += 8; + + count -= 8; + } + + while (count-- && dest <= deststop) + { + bit = ((yposition >> ds->nflatyshift) & ds->nflatmask) | (xposition >> ds->nflatxshift); + + *dest = R_DrawSpanPixel(ds, dsrc, colormap, bit, source); + + dest++; + dsrc++; + + xposition += xstep; + yposition += ystep; + } +} + +// R_CalcTiltedLighting +// Exactly what it says on the tin. I wish I wasn't too lazy to explain things properly. +static void R_CalcTiltedLighting(INT32 *lightbuffer, INT32 x1, INT32 x2, fixed_t start, fixed_t end) +{ + // ZDoom uses a different lighting setup to us, and I couldn't figure out how to adapt their version + // of this function. Here's my own. + INT32 i, left = x1, right = x2; + const fixed_t step = (end-start)/(x2 - x1 + 1); + + // I wanna do some optimizing by checking for out-of-range segments on either side to fill in all at once, + // but I'm too bad at coding to not crash the game trying to do that. I guess this is fast enough for now... + + for (i = left; i <= right; i++) + { + lightbuffer[i] = (start += step) >> FRACBITS; + + if (lightbuffer[i] < 0) + { + lightbuffer[i] = 0; + } + else if (lightbuffer[i] >= MAXLIGHTSCALE) + { + lightbuffer[i] = MAXLIGHTSCALE-1; + } + } +} + +template +static void R_DrawTiltedSpanTemplate(drawspandata_t* ds) +{ + int width = ds->x2 - ds->x1; + float iz, uz, vz; + UINT32 u, v; + int i; + + UINT8 * restrict dest = R_Address(ds->x1, ds->y); + UINT8 * restrict dsrc; + + float startz, startu, startv; + float izstep, uzstep, vzstep; + float endz, endu, endv; + UINT32 stepu, stepv; + UINT32 bit; + local_for_thread INT32 *tiltlighting = NULL; + local_for_thread INT32 oldviewwidth = 0; + + // dont realloc every frame pls thx + if (tiltlighting == NULL || oldviewwidth != viewwidth) + { + tiltlighting = static_cast(realloc(tiltlighting, sizeof(*tiltlighting) * viewwidth)); + oldviewwidth = viewwidth; + } + + INT32 x1 = ds->x1; + const INT32 nflatxshift = ds->nflatxshift; + const INT32 nflatyshift = ds->nflatyshift; + const INT32 nflatmask = ds->nflatmask; + const INT32 stride = vid.width; + + iz = ds->szp.z + ds->szp.y*(centery-ds->y) + ds->szp.x*(ds->x1-centerx); + + // Lighting is simple. It's just linear interpolation from start to end + { + float planelightfloat = PLANELIGHTFLOAT; + float lightstart, lightend; + + lightend = (iz + ds->szp.x*width) * planelightfloat; + lightstart = iz * planelightfloat; + + R_CalcTiltedLighting(tiltlighting, ds->x1, ds->x2, FLOAT_TO_FIXED(lightstart), FLOAT_TO_FIXED(lightend)); + //CONS_Printf("tilted lighting %f to %f (foc %f)\n", lightstart, lightend, focallengthf); + } + + uz = ds->sup.z + ds->sup.y*(centery-ds->y) + ds->sup.x*(ds->x1-centerx); + vz = ds->svp.z + ds->svp.y*(centery-ds->y) + ds->svp.x*(ds->x1-centerx); + + const UINT8 *source = ds->source; + const UINT8 *colormap = ds->colormap; + + if constexpr (Type & DS_RIPPLE) + { + dsrc = vid.screens[1] + (ds->y + ds->bgofs) * stride + ds->x1; + } + else + { + dsrc = dest; + } + +#if 0 // The "perfect" reference version of this routine. Pretty slow. + // Use it only to see how things are supposed to look. + i = 0; + do + { + double z = 1.f/iz; + u = (INT64)(uz*z); + v = (INT64)(vz*z); + + bit = ((v >> nflatyshift) & nflatmask) | (u >> nflatxshift); + colormap = planezlight[tiltlighting[ds->x1]] + (ds->colormap - colormaps); + + *dest = R_DrawSpanPixel(ds, dsrc, colormap, bit); + dest++; + ds->x1++; + dsrc++; + iz += ds_szp->x; + uz += ds_sup->x; + vz += ds_svp->x; + } while (--width >= 0); +#else + startz = 1.f/iz; + startu = uz*startz; + startv = vz*startz; + + izstep = ds->szp.x * SPANSIZE; + uzstep = ds->sup.x * SPANSIZE; + vzstep = ds->svp.x * SPANSIZE; + //x1 = 0; + width++; + + while (width >= SPANSIZE) + { + iz += izstep; + uz += uzstep; + vz += vzstep; + + endz = 1.f/iz; + endu = uz*endz; + endv = vz*endz; + stepu = (INT64)((endu - startu) * INVSPAN); + stepv = (INT64)((endv - startv) * INVSPAN); + u = (INT64)(startu); + v = (INT64)(startv); + + x1 = ds->x1; + + for (i = 0; i < SPANSIZE; i++) + { + bit = (((v + stepv * i) >> nflatyshift) & nflatmask) | ((u + stepu * i) >> nflatxshift); + colormap = ds->planezlight[tiltlighting[x1 + i]] + (ds->colormap - colormaps); + dest[i] = R_DrawSpanPixel(ds, &dsrc[i], colormap, bit, source); + } + + ds->x1 += SPANSIZE; + dest += SPANSIZE; + dsrc += SPANSIZE; + startu = endu; + startv = endv; + width -= SPANSIZE; + } + + if (width > 0) + { + if (width == 1) + { + u = (INT64)(startu); + v = (INT64)(startv); + bit = ((v >> nflatyshift) & nflatmask) | (u >> nflatxshift); + colormap = ds->planezlight[tiltlighting[ds->x1]] + (ds->colormap - colormaps); + *dest = R_DrawSpanPixel(ds, dsrc, colormap, bit, source); + ds->x1++; + } + else + { + double left = width; + iz += ds->szp.x * left; + uz += ds->sup.x * left; + vz += ds->svp.x * left; + + endz = 1.f/iz; + endu = uz*endz; + endv = vz*endz; + left = 1.f/left; + stepu = (INT64)((endu - startu) * left); + stepv = (INT64)((endv - startv) * left); + u = (INT64)(startu); + v = (INT64)(startv); + + for (; width != 0; width--) + { + bit = ((v >> ds->nflatyshift) & ds->nflatmask) | (u >> ds->nflatxshift); + colormap = ds->planezlight[tiltlighting[ds->x1]] + (ds->colormap - colormaps); + *dest = R_DrawSpanPixel(ds, dsrc, colormap, bit, source); + dest++; + ds->x1++; + dsrc++; + u += stepu; + v += stepv; + } + } + } +#endif +} + +#define DEFINE_SPAN_FUNC(name, flags, template) \ +void name(drawspandata_t* ds) \ +{ \ + constexpr DrawSpanType opt = static_cast(flags); \ + template(ds); \ +} + +#define DEFINE_SPAN_COMBO(name, flags) \ +DEFINE_SPAN_FUNC(name, flags, R_DrawSpanTemplate) \ +DEFINE_SPAN_FUNC(name ## _Tilted, flags, R_DrawTiltedSpanTemplate) \ + +DEFINE_SPAN_COMBO(R_DrawSpan, DS_BASIC) +DEFINE_SPAN_COMBO(R_DrawTranslucentSpan, DS_TRANSMAP) +DEFINE_SPAN_COMBO(R_DrawSplat, DS_HOLES) +DEFINE_SPAN_COMBO(R_DrawTranslucentSplat, DS_TRANSMAP|DS_HOLES) +DEFINE_SPAN_COMBO(R_DrawTranslucentWaterSpan, DS_TRANSMAP|DS_RIPPLE) + +/** \brief The R_DrawFogSpan function + Draws the actual span with fogging. +*/ +void R_DrawFogSpan(drawspandata_t* ds) +{ + const UINT8 * restrict colormap = ds->colormap; + UINT8 * restrict dest = R_Address(ds->x1, ds->y); + + intptr_t count = ds->x2 - ds->x1 + 1; + + while (count >= 4) + { + dest[0] = colormap[dest[0]]; + dest[1] = colormap[dest[1]]; + dest[2] = colormap[dest[2]]; + dest[3] = colormap[dest[3]]; + + dest += 4; + count -= 4; + } + + while (count--) + { + *dest = colormap[*dest]; + dest++; + } +} + +void R_DrawFogSpan_Tilted(drawspandata_t* ds) +{ + int width = ds->x2 - ds->x1; + float iz = ds->szp.z + ds->szp.y*(centery-ds->y) + ds->szp.x*(ds->x1-centerx); + UINT8 * restrict dest; + + local_for_thread INT32 *tiltlighting = NULL; + local_for_thread INT32 oldviewwidth = 0; + + // dont realloc every frame pls thx + if (tiltlighting == NULL || oldviewwidth != viewwidth) + { + tiltlighting = static_cast(realloc(tiltlighting, sizeof(*tiltlighting) * viewwidth)); + oldviewwidth = viewwidth; + } + + dest = R_Address(ds->x1, ds->y); + const INT32 stride = vid.width; + + // Lighting is simple. It's just linear interpolation from start to end + { + float planelightfloat = PLANELIGHTFLOAT; + float lightstart, lightend; + + lightend = (iz + ds->szp.x*width) * planelightfloat; + lightstart = iz * planelightfloat; + + R_CalcTiltedLighting(tiltlighting, ds->x1, ds->x2, FLOAT_TO_FIXED(lightstart), FLOAT_TO_FIXED(lightend)); + //CONS_Printf("tilted lighting %f to %f (foc %f)\n", lightstart, lightend, focallengthf); + } + + do + { + UINT8 *colormap = ds->planezlight[tiltlighting[ds->x1++]] + (ds->colormap - colormaps); + *dest = colormap[*dest]; + dest++; + } + while (--width >= 0); +} diff --git a/src/r_fps.c b/src/r_fps.c index 4938988dc..1d5cc1baf 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -173,7 +173,7 @@ static vector3_t *R_LerpVector3(const vector3_t *from, const vector3_t *to, fixe // recalc necessary stuff for mouseaiming // slopes are already calculated for the full possible view (which is 4*viewheight). -// 18/08/18: (No it's actually 16*viewheight, thanks Jimita for finding this out) +// 18/08/18: (No it's actually 16*viewheight, thanks Lactozilla for finding this out) static void R_SetupFreelook(void) { // clip it in the case we are looking a hardware 90 degrees full aiming @@ -494,8 +494,8 @@ void R_CreateInterpolator_Polyobj(thinker_t *thinker, polyobj_t *polyobj) interp->polyobj.polyobj = polyobj; interp->polyobj.vertices_size = polyobj->numVertices; - interp->polyobj.oldvertices = Z_CallocAlign(sizeof(fixed_t) * 2 * polyobj->numVertices, PU_LEVEL, NULL, 32); - interp->polyobj.bakvertices = Z_CallocAlign(sizeof(fixed_t) * 2 * polyobj->numVertices, PU_LEVEL, NULL, 32); + interp->polyobj.oldvertices = Z_Calloc(sizeof(fixed_t) * 2 * polyobj->numVertices, PU_LEVEL, NULL); + interp->polyobj.bakvertices = Z_Calloc(sizeof(fixed_t) * 2 * polyobj->numVertices, PU_LEVEL, NULL); for (size_t i = 0; i < polyobj->numVertices; i++) { interp->polyobj.oldvertices[i * 2 ] = interp->polyobj.bakvertices[i * 2 ] = polyobj->vertices[i]->x; diff --git a/src/r_fps.h b/src/r_fps.h index 7ed55c848..870fa70f1 100644 --- a/src/r_fps.h +++ b/src/r_fps.h @@ -15,6 +15,10 @@ #ifndef __R_FPS_H__ #define __R_FPS_H__ +#ifdef __cplusplus +extern "C" { +#endif + #include "m_fixed.h" #include "p_local.h" #include "r_state.h" @@ -175,4 +179,8 @@ void R_UpdateMobjInterpolators(void); void R_ResetMobjInterpolationState(mobj_t *mobj); void R_ResetPrecipitationMobjInterpolationState(precipmobj_t *mobj); +#ifdef __cplusplus +} // extern "C" +#endif + #endif diff --git a/src/r_local.h b/src/r_local.h index 1d3187750..4701cb400 100644 --- a/src/r_local.h +++ b/src/r_local.h @@ -14,6 +14,10 @@ #ifndef __R_LOCAL__ #define __R_LOCAL__ +#ifdef __cplusplus +extern "C" { +#endif + // Screen size related parameters. #include "doomdef.h" @@ -38,4 +42,8 @@ extern drawseg_t *firstseg; void SplitScreen_OnChange(void); +#ifdef __cplusplus +} // extern "C" +#endif + #endif // __R_LOCAL__ diff --git a/src/r_main.c b/src/r_main.cpp similarity index 78% rename from src/r_main.c rename to src/r_main.cpp index 459ad6883..ebea32638 100644 --- a/src/r_main.c +++ b/src/r_main.cpp @@ -13,6 +13,8 @@ /// utility functions (BSP, geometry, trigonometry). /// See tables.c, too. +#include + #include "doomdef.h" #include "g_game.h" #include "g_input.h" @@ -88,7 +90,7 @@ INT32 viewangletox[FINEANGLES/2]; // The xtoviewangleangle[] table maps a screen pixel // to the lowest viewangle that maps back to x ranges // from clipangle to -clipangle. -angle_t xtoviewangle[MAXVIDWIDTH+1]; +angle_t *xtoviewangle; lighttable_t *scalelight[LIGHTLEVELS][MAXLIGHTSCALE]; lighttable_t *scalelightfixed[MAXLIGHTSCALE]; @@ -100,23 +102,23 @@ extracolormap_t extra_colormaps[MAXCOLORMAPS]; // Performance stats precise_t ps_prevframetime = 0; -ps_metric_t ps_rendercalltime = {0}; -ps_metric_t ps_otherrendertime = {0}; -ps_metric_t ps_uitime = {0}; -ps_metric_t ps_swaptime = {0}; +ps_metric_t ps_rendercalltime = {}; +ps_metric_t ps_otherrendertime = {}; +ps_metric_t ps_uitime = {}; +ps_metric_t ps_swaptime = {}; -ps_metric_t ps_skyboxtime = {0}; -ps_metric_t ps_bsptime = {0}; +ps_metric_t ps_skyboxtime = {}; +ps_metric_t ps_bsptime = {}; -ps_metric_t ps_sw_spritecliptime = {0}; -ps_metric_t ps_sw_portaltime = {0}; -ps_metric_t ps_sw_planetime = {0}; -ps_metric_t ps_sw_maskedtime = {0}; +ps_metric_t ps_sw_spritecliptime = {}; +ps_metric_t ps_sw_portaltime = {}; +ps_metric_t ps_sw_planetime = {}; +ps_metric_t ps_sw_maskedtime = {}; -ps_metric_t ps_numbspcalls = {0}; -ps_metric_t ps_numsprites = {0}; -ps_metric_t ps_numdrawnodes = {0}; -ps_metric_t ps_numpolyobjects = {0}; +ps_metric_t ps_numbspcalls = {}; +ps_metric_t ps_numsprites = {}; +ps_metric_t ps_numdrawnodes = {}; +ps_metric_t ps_numpolyobjects = {}; static CV_PossibleValue_t drawdist_cons_t[] = { /*{256, "256"},*/ {512, "512"}, {768, "768"}, @@ -157,10 +159,6 @@ static void FlipCam_OnChange(void); static void FlipCam2_OnChange(void); static void FlipCam3_OnChange(void); static void FlipCam4_OnChange(void); -void SendWeaponPref(void); -void SendWeaponPref2(void); -void SendWeaponPref3(void); -void SendWeaponPref4(void); static void DirLight_OnChange(void); @@ -185,38 +183,37 @@ consvar_t cv_flipcam[MAXSPLITSCREENPLAYERS] = { {"flipcam4", "No", CV_SAVE|CV_CALL|CV_NOINIT, CV_YesNo, FlipCam4_OnChange, 0, NULL, NULL, 0, 0, NULL} }; -consvar_t cv_shadow = {"shadow", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_shadowoffs = {"offsetshadows", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_skybox = {"skybox", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_ffloorclip = {"r_ffloorclip", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_spriteclip = {"r_spriteclip", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_soniccd = {"soniccd", "Off", CV_NETVAR|CV_NOSHOWHELP, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_allowmlook = {"allowmlook", "Yes", CV_NETVAR, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_showhud = {"showhud", "Yes", CV_CALL, CV_YesNo, R_SetViewSize, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_translucenthud = {"translucenthud", "10", CV_SAVE, translucenthud_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_uncappedhud = {"uncappedhud", "Yes", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; - -consvar_t cv_translucency = {"translucency", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_drawdist = {"drawdist", "Infinite", CV_SAVE, drawdist_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_shadow = {"shadow", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_shadowoffs = {"offsetshadows", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_skybox = {"skybox", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_ffloorclip = {"r_ffloorclip", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_spriteclip = {"r_spriteclip", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_softcyancut = {"softwarecyancut", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_translucency = {"translucency", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_drawdist = {"drawdist", "Infinite", CV_SAVE, drawdist_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_drawdist_precip = {"drawdist_precip", "1024", CV_SAVE|CV_CALL|CV_NOINIT, drawdist_precip_cons_t, Precipstuff_OnChange, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_lessprecip = {"lessweathereffects", "Off", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, Precipstuff_OnChange, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_lessprecip = {"lessweathereffects", "Off", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, Precipstuff_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_mobjscaleprecip = {"scaleprecipmobjscale", "Off", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, Precipstuff_OnChange, 0, NULL, NULL, 0, 0, NULL}; - -consvar_t cv_maxinterpdist = {"maxinterpdist", "Infinite", CV_SAVE, maxinterpdist_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; - -consvar_t cv_ripplewater = {"waterripples", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; - -// cap fov, fov too high tears software apart. -consvar_t cv_fov = {"fov", "90", CV_FLOAT|CV_CALL|CV_SAVE, fov_cons_t, Fov_OnChange, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_fovchange = {"fovchange", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_maxinterpdist = {"maxinterpdist", "Infinite", CV_SAVE, maxinterpdist_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_ripplewater = {"waterripples", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; // Okay, whoever said homremoval causes a performance hit should be shot. -consvar_t cv_homremoval = {"homremoval", "Yes", CV_SAVE, homremoval_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_homremoval = {"homremoval", "Yes", CV_SAVE, homremoval_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_maxportals = {"maxportals", "2", CV_SAVE, maxportals_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_maxportals = {"maxportals", "2", CV_SAVE, maxportals_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; + +// cap fov, fov too high tears software apart. +consvar_t cv_fov = {"fov", "90", CV_FLOAT|CV_CALL|CV_SAVE, fov_cons_t, Fov_OnChange, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_fovchange = {"fovchange", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; // randomized directional lightning -consvar_t cv_randomdirlight = {"randomdirectionallight", "Off", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, DirLight_OnChange, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_randomdirlight = {"randomdirectionallight", "Off", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, DirLight_OnChange, 0, NULL, NULL, 0, 0, NULL}; + +consvar_t cv_showhud = {"showhud", "Yes", CV_CALL, CV_YesNo, R_SetViewSize, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_translucenthud = {"translucenthud", "10", CV_SAVE, translucenthud_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_uncappedhud = {"uncappedhud", "Yes", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_soniccd = {"soniccd", "Off", CV_NETVAR|CV_NOSHOWHELP, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_allowmlook = {"allowmlook", "Yes", CV_NETVAR, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; // tells to reset the maplight at next map change static void DirLight_OnChange(void) @@ -494,7 +491,7 @@ boolean R_DoCulling(line_t *cullheight, line_t *viewcullheight, fixed_t vz, fixe // Returns search dimensions within a blockmap, in the direction of viewangle and out to a certain distance. void R_GetRenderBlockMapDimensions(fixed_t drawdist, INT32 *xl, INT32 *xh, INT32 *yl, INT32 *yh) { - const angle_t left = viewangle - clipangle; + const angle_t left = viewangle - clipangle; const angle_t right = viewangle + clipangle; const fixed_t vxleft = viewx + FixedMul(drawdist, FCOS(left)); @@ -504,10 +501,10 @@ void R_GetRenderBlockMapDimensions(fixed_t drawdist, INT32 *xl, INT32 *xh, INT32 const fixed_t vyright = viewy + FixedMul(drawdist, FSIN(right)); // Try to narrow the search to within only the field of view - *xl = (unsigned)(min(viewx, min(vxleft, vxright)) - bmaporgx)>>MAPBLOCKSHIFT; - *xh = (unsigned)(max(viewx, max(vxleft, vxright)) - bmaporgx)>>MAPBLOCKSHIFT; - *yl = (unsigned)(min(viewy, min(vyleft, vyright)) - bmaporgy)>>MAPBLOCKSHIFT; - *yh = (unsigned)(max(viewy, max(vyleft, vyright)) - bmaporgy)>>MAPBLOCKSHIFT; + *xl = (unsigned)(std::min(viewx, std::min(vxleft, vxright)) - bmaporgx)>>MAPBLOCKSHIFT; + *xh = (unsigned)(std::max(viewx, std::max(vxleft, vxright)) - bmaporgx)>>MAPBLOCKSHIFT; + *yl = (unsigned)(std::min(viewy, std::min(vyleft, vyright)) - bmaporgy)>>MAPBLOCKSHIFT; + *yh = (unsigned)(std::max(viewy, std::max(vyleft, vyright)) - bmaporgy)>>MAPBLOCKSHIFT; if (*xh >= bmapwidth) *xh = bmapwidth - 1; @@ -631,7 +628,7 @@ static struct { INT32 scrmapsize; INT32 x1; // clip rendering horizontally for efficiency - INT16 ceilingclip[MAXVIDWIDTH], floorclip[MAXVIDWIDTH]; + INT16 *ceilingclip, *floorclip; boolean use; } viewmorph = { @@ -642,7 +639,7 @@ static struct { 0, 0, - {}, {}, + NULL, NULL, false }; @@ -660,7 +657,6 @@ void R_CheckViewMorph(void) rollangle >>= ANGLETOFINESHIFT; rollangle = ((rollangle+2) & ~3) & FINEMASK; // Limit the distinct number of angles to reduce recalcs from angles changing a lot. - if (rollangle == viewmorph.rollangle && viewmorph.scrmapsize == vid.width*vid.height) return; // No change @@ -680,10 +676,10 @@ void R_CheckViewMorph(void) if (viewmorph.scrmapsize != vid.width*vid.height) { - if (viewmorph.scrmap) - free(viewmorph.scrmap); - viewmorph.scrmap = malloc(vid.width*vid.height * sizeof(INT32)); viewmorph.scrmapsize = vid.width*vid.height; + viewmorph.scrmap = static_cast(realloc(viewmorph.scrmap, vid.width*vid.height * sizeof(INT32))); + viewmorph.ceilingclip = static_cast(realloc(viewmorph.ceilingclip, vid.width * sizeof(INT16))); + viewmorph.floorclip = static_cast(realloc(viewmorph.floorclip, vid.width * sizeof(INT16))); } temp = FINECOSINE(rollangle); @@ -695,7 +691,7 @@ void R_CheckViewMorph(void) x1 = (vid.width*fabsf(rollcos) + vid.height*fabsf(rollsin)) / vid.width; y1 = (vid.height*fabsf(rollcos) + vid.width*fabsf(rollsin)) / vid.height; - temp = max(x1, y1)*FRACUNIT; + temp = std::max(x1, y1)*FRACUNIT; if (temp < FRACUNIT) temp = FRACUNIT; else @@ -741,10 +737,10 @@ void R_CheckViewMorph(void) xb = vid.width-1-xa; yb = vid.height-1-ya; - viewmorph.ceilingclip[xa] = min(viewmorph.ceilingclip[xa], ya); - viewmorph.floorclip[xa] = max(viewmorph.floorclip[xa], ya); - viewmorph.ceilingclip[xb] = min(viewmorph.ceilingclip[xb], yb); - viewmorph.floorclip[xb] = max(viewmorph.floorclip[xb], yb); + viewmorph.ceilingclip[xa] = std::min(viewmorph.ceilingclip[xa], ya); + viewmorph.floorclip[xa] = std::max(viewmorph.floorclip[xa], ya); + viewmorph.ceilingclip[xb] = std::min(viewmorph.ceilingclip[xb], yb); + viewmorph.floorclip[xb] = std::max(viewmorph.floorclip[xb], yb); x2 += rollcos; y2 += rollsin; } @@ -758,10 +754,10 @@ void R_CheckViewMorph(void) xb = vid.width-1-xa; yb = vid.height-1-ya; - viewmorph.ceilingclip[xa] = min(viewmorph.ceilingclip[xa], ya); - viewmorph.floorclip[xa] = max(viewmorph.floorclip[xa], ya); - viewmorph.ceilingclip[xb] = min(viewmorph.ceilingclip[xb], yb); - viewmorph.floorclip[xb] = max(viewmorph.floorclip[xb], yb); + viewmorph.ceilingclip[xa] = std::min(viewmorph.ceilingclip[xa], ya); + viewmorph.floorclip[xa] = std::max(viewmorph.floorclip[xa], ya); + viewmorph.ceilingclip[xb] = std::min(viewmorph.ceilingclip[xb], yb); + viewmorph.floorclip[xb] = std::max(viewmorph.floorclip[xb], yb); x2 -= rollsin; y2 += rollcos; } @@ -799,8 +795,8 @@ void R_CheckViewMorph(void) void R_ApplyViewMorph(void) { - UINT8 *tmpscr = screens[4]; - UINT8 *srcscr = screens[0]; + UINT8 *tmpscr = vid.screens[4]; + UINT8 *srcscr = vid.screens[0]; INT32 p, end = vid.width * vid.height; if (!viewmorph.use) @@ -835,8 +831,7 @@ void R_ApplyViewMorph(void) for (p = 0; p < end; p++) tmpscr[p] = srcscr[viewmorph.scrmap[p]]; - VID_BlitLinearScreen(tmpscr, screens[0], - vid.width*vid.bpp, vid.height, vid.width*vid.bpp, vid.width); + VID_BlitLinearScreen(tmpscr, vid.screens[0], vid.width, vid.height, vid.width, vid.width); } angle_t R_ViewRollAngle(const player_t *player) @@ -889,6 +884,8 @@ void R_SetViewSize(void) setsizeneeded = true; } +static void R_SetupViewBuffers(void); + // // R_ExecuteSetViewSize // @@ -907,18 +904,15 @@ void R_ExecuteSetViewSize(void) // status bar overlay st_overlay = cv_showhud.value; - scaledviewwidth = vid.width; + viewwidth = vid.width; viewheight = vid.height; if (splitscreen) viewheight >>= 1; - viewwidth = scaledviewwidth; - if (splitscreen > 1) { viewwidth >>= 1; - scaledviewwidth >>= 1; } centerx = viewwidth/2; @@ -926,9 +920,7 @@ void R_ExecuteSetViewSize(void) centerxfrac = centerx<fovadd; - return max(MINFOV*FRACUNIT, min(fov, MAXFOV*FRACUNIT)); + return std::max(MINFOV*FRACUNIT, std::min(fov, MAXFOV*FRACUNIT)); } -static void R_SetFov(fixed_t playerfov) +static void R_CalcFov(fixed_t playerfov) { angle_t fov = FixedAngle(playerfov/2) + ANGLE_90; fovtan = FixedMul(FINETANGENT(fov >> ANGLETOFINESHIFT), viewmorph.zoomneeded); if (splitscreen == 1) // Splitscreen FOV should be adjusted to maintain expected vertical view fovtan = 17*fovtan/10; - // this is only used for planes rendering in software mode - INT32 j = viewheight*16; - for (INT32 i = 0; i < j; i++) - { - fixed_t dy = (i - viewheight*8)<skybox_scalex && !mh->skybox_scaley && !mh->skybox_scalez) + return; + + auto setup_skyscale = [&](fixed_t mox, fixed_t moy, fixed_t zscale) + { + if (skyboxmo[1]) + { + angle_t ang; + fixed_t x = 0, y = 0; + + if (mh->skybox_scalex > 0) + x = (mox - skyboxmo[1]->x) / mh->skybox_scalex; + else if (mh->skybox_scalex < 0) + x = (mox - skyboxmo[1]->x) * -mh->skybox_scalex; + + if (mh->skybox_scaley > 0) + y = (moy - skyboxmo[1]->y) / mh->skybox_scaley; + else if (mh->skybox_scaley < 0) + y = (moy - skyboxmo[1]->y) * -mh->skybox_scaley; + + switch (viewmobj->angle) + { + case 0: + newview->x += x; + newview->y += y; + break; + case ANGLE_90: + newview->x -= y; + newview->y += x; + break; + case ANGLE_180: + newview->x -= x; + newview->y -= y; + break; + case ANGLE_270: + newview->x += y; + newview->y -= x; + break; + default: + ang = viewmobj->angle>>ANGLETOFINESHIFT; + newview->x += FixedMul(x,FINECOSINE(ang)) - FixedMul(y, FINESINE(ang)); + newview->y += FixedMul(x, FINESINE(ang)) + FixedMul(y,FINECOSINE(ang)); + break; + } + } + + if (mh->skybox_scalez > 0) + newview->z += zscale / mh->skybox_scalez; + else if (mh->skybox_scalez < 0) + newview->z += zscale * -mh->skybox_scalez; + }; + + if (player->awayviewtics && player->awayviewmobj) + { + setup_skyscale(player->awayviewmobj->x, player->awayviewmobj->y, (player->awayviewmobj->z + 20*FRACUNIT)); + } + else if (thiscam && thiscam->chase) + { + setup_skyscale(thiscam->x, thiscam->y, (thiscam->z + (thiscam->height>>1))); + } + else + { + setup_skyscale(player->mo->x, player->mo->y, player->viewz); + } +} + void R_SkyboxFrame(int s) { player_t *player = &players[displayplayers[s]]; camera_t *thiscam = &camera[s]; subsector_t * subsector = NULL; + mapheader_t *mh = mapheaderinfo[gamemap-1]; - R_SetViewContext(VIEWCONTEXT_SKY1 + s); + R_SetViewContext(static_cast(VIEWCONTEXT_SKY1 + s)); // cut-away view stuff newview->sky = true; viewmobj = skyboxmo[0]; + #ifdef PARANOIA if (P_MobjWasRemoved(viewmobj)) { @@ -1103,78 +1183,19 @@ void R_SkyboxFrame(int s) I_Error("R_SkyboxFrame: viewmobj null (player %s)", sizeu1(playeri)); } #endif + R_SetupAimingFrame(player, thiscam); newview->angle += viewmobj->angle; newview->x = viewmobj->x; newview->y = viewmobj->y; - newview->z = 0; - if (viewmobj->spawnpoint) - newview->z = ((fixed_t)viewmobj->spawnpoint->angle)<z = (viewmobj->spawnpoint) ? (((fixed_t)viewmobj->spawnpoint->angle)<skybox_scalex > 0)\ - x = (viewmo->x - skyboxmo[1]->x) / mh->skybox_scalex;\ - else if (mh->skybox_scalex < 0)\ - x = (viewmo->x - skyboxmo[1]->x) * -mh->skybox_scalex;\ - if (mh->skybox_scaley > 0)\ - y = (viewmo->y - skyboxmo[1]->y) / mh->skybox_scaley;\ - else if (mh->skybox_scaley < 0)\ - y = (viewmo->y - skyboxmo[1]->y) * -mh->skybox_scaley;\ - if (viewmobj->angle == 0)\ - {\ - newview->x += x;\ - newview->y += y;\ - }\ - else if (viewmobj->angle == ANGLE_90)\ - {\ - newview->x -= y;\ - newview->y += x;\ - }\ - else if (viewmobj->angle == ANGLE_180)\ - {\ - newview->x -= x;\ - newview->y -= y;\ - }\ - else if (viewmobj->angle == ANGLE_270)\ - {\ - newview->x += y;\ - newview->y -= x;\ - }\ - else\ - {\ - angle_t ang = viewmobj->angle>>ANGLETOFINESHIFT;\ - newview->x += FixedMul(x,FINECOSINE(ang)) - FixedMul(y, FINESINE(ang));\ - newview->y += FixedMul(x, FINESINE(ang)) + FixedMul(y,FINECOSINE(ang));\ - }\ - }\ - if (mh->skybox_scalez > 0)\ - newview->z += zscale / mh->skybox_scalez;\ - else if (mh->skybox_scalez < 0)\ - newview->z += zscale * -mh->skybox_scalez; - - if (mapheaderinfo[gamemap-1]) + if (mh) { - mapheader_t *mh = mapheaderinfo[gamemap-1]; - - if (player->awayviewtics && player->awayviewmobj) - { - SETUPSKYVIEW(player->awayviewmobj, (player->awayviewmobj->z + 20*FRACUNIT)); - } - else if (thiscam->chase) - { - SETUPSKYVIEW(thiscam, (thiscam->z + (thiscam->height>>1))); - } - else - { - SETUPSKYVIEW(player->mo, player->viewz); - } + R_SetupSkyScale(player, thiscam, mh); } -#undef SETUPSKYVIEW if (!P_MobjWasRemoved(viewmobj) && viewmobj->subsector && viewmobj->subsector->sector) subsector = viewmobj->subsector; @@ -1189,7 +1210,8 @@ void R_SetupFrame(int s, boolean skybox) boolean chasecam = (cv_chasecam[s].value); sector_t * sector = NULL; - R_SetViewContext(VIEWCONTEXT_PLAYER1 + s); + R_SetViewContext(static_cast(VIEWCONTEXT_PLAYER1 + s)); + if (thiscam->reset) { R_ResetViewInterpolation(s); @@ -1235,12 +1257,13 @@ void R_SetupFrame(int s, boolean skybox) else if (thiscam && chasecam) // use outside cam view { viewmobj = NULL; + I_Assert(thiscam != NULL); newview->x = thiscam->x; newview->y = thiscam->y; newview->z = thiscam->z + (thiscam->height>>1); - if (thiscam != NULL && thiscam->subsector && thiscam->subsector->sector) + if (thiscam->subsector && thiscam->subsector->sector) sector = thiscam->subsector->sector; R_SetupCommonFrame(player, sector); @@ -1268,8 +1291,8 @@ static void R_PortalFrame(portal_t *portal) viewz = portal->viewz; viewangle = portal->viewangle; - // viewsin = FINESINE(viewangle>>ANGLETOFINESHIFT); - // viewcos = FINECOSINE(viewangle>>ANGLETOFINESHIFT); + //viewsin = FINESINE(viewangle>>ANGLETOFINESHIFT); + //viewcos = FINECOSINE(viewangle>>ANGLETOFINESHIFT); portalclipstart = portal->start; portalclipend = portal->end; @@ -1277,8 +1300,7 @@ static void R_PortalFrame(portal_t *portal) if (portal->clipline != -1) { portalclipline = &lines[portal->clipline]; - portalcullsector = portalclipline->frontsector; - viewsector = portalclipline->frontsector; + viewsector = portalcullsector = portalclipline->frontsector; } else { @@ -1288,10 +1310,41 @@ static void R_PortalFrame(portal_t *portal) } } +static void Mask_Pre (maskcount_t* m) +{ + m->drawsegs[0] = ds_p - drawsegs; + m->vissprites[0] = visspritecount; + m->viewx = viewx; + m->viewy = viewy; + m->viewz = viewz; + m->viewsector = viewsector; +} + +static void Mask_Post (maskcount_t* m) +{ + m->drawsegs[1] = ds_p - drawsegs; + m->vissprites[1] = visspritecount; +} + // ================ // R_RenderView // ================ +// viewx, viewy, viewangle, all that good stuff must be set +static void R_RenderViewpoint(maskcount_t* mask, boolean drawprecip) +{ + Mask_Pre(mask); + + curdrawsegs = ds_p; + + R_RenderBSPNode((INT32)numnodes - 1); + + if (drawprecip) + R_AddPrecipitationSprites(); + + Mask_Post(mask); +} + // FAB NOTE FOR WIN32 PORT !! I'm not finished already, // but I suspect network may have problems with the video buffer being locked // for all duration of rendering, and being released only once at the end.. @@ -1302,52 +1355,19 @@ static fixed_t viewfov[MAXSPLITSCREENPLAYERS]; void R_RenderPlayerView(player_t *player) { - const boolean skybox = (skyboxmo[0] && cv_skybox.value); - UINT8 i; - - // if this is display player 1 - if (cv_homremoval.value && player == &players[displayplayers[0]]) - { - if (cv_homremoval.value == 1) - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); // No HOM effect! - else //'development' HOM removal -- makes it blindingly obvious if HOM is spotted. - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 128+(timeinmap&15)); - } - // Draw over the fourth screen so you don't have to stare at a HOM :V - else if (splitscreen == 2 && player == &players[displayplayers[2]]) - { - // V_DrawPatchFill, but for the fourth screen only - patch_t *pat = W_CachePatchName("SRB2BACK", PU_CACHE); - INT32 dupz = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy); - INT32 x, y, pw = SHORT(pat->width) * dupz, ph = SHORT(pat->height) * dupz; - - for (x = vid.width>>1; x < vid.width; x += pw) - { - for (y = vid.height>>1; y < vid.height; y += ph) - V_DrawScaledPatch(x, y, V_NOSCALESTART, pat); - } - } + INT32 nummasks = 1; + maskcount_t* masks = static_cast(malloc(sizeof(maskcount_t))); + const boolean skybox = (skyboxmo[0] && cv_skybox.value); // load previous saved value of skyVisible for the player - for (i = 0; i <= splitscreen; i++) + skyVisible = skyVisiblePerPlayer[viewssnum]; + + const fixed_t fov = R_GetPlayerFov(player); + + if (viewfov[viewssnum] != fov) { - if (player != &players[displayplayers[i]]) - continue; - - skyVisible = skyVisiblePerPlayer[i]; - break; - } - - fixed_t fov = R_GetPlayerFov(player); - - for (UINT8 j = 0; j <= splitscreen; j++) - { - if (player == &players[displayplayers[j]] - && viewfov[j] != fov) - { - viewfov[j] = fov; - R_SetFov(fov); - } + viewfov[viewssnum] = fov; + R_SetFov(fov); } Portal_InitList(); @@ -1361,17 +1381,13 @@ void R_RenderPlayerView(player_t *player) R_ClearDrawSegs(); R_ClearPlanes(); R_ClearSprites(); -#ifdef FLOORSPLATS - R_ClearVisibleFloorSplats(); -#endif - R_RenderBSPNode((INT32)numnodes - 1); - R_ClipSprites(); + R_RenderViewpoint(&masks[nummasks - 1], false); + + R_ClipSprites(drawsegs, NULL); + R_DrawSkyPlanes(); // draw the fucker again to prevent some artifacts R_DrawPlanes(); -#ifdef FLOORSPLATS - R_DrawVisibleFloorSplats(); -#endif - R_DrawMasked(); + R_DrawMasked(masks, nummasks); } PS_STOP_TIMING(ps_skyboxtime); @@ -1398,22 +1414,16 @@ void R_RenderPlayerView(player_t *player) } R_ClearDrawSegs(); R_ClearSprites(); -#ifdef FLOORSPLATS - R_ClearVisibleFloorSplats(); -#endif // check for new console commands. NetUpdate(); - // The head node is the last node output. - ps_numbspcalls.value.i = ps_numpolyobjects.value.i = ps_numdrawnodes.value.i = 0; PS_START_TIMING(ps_bsptime); - R_RenderBSPNode((INT32)numnodes - 1); + R_RenderViewpoint(&masks[nummasks - 1], true); PS_STOP_TIMING(ps_bsptime); - R_AddPrecipitationSprites(); PS_START_TIMING(ps_sw_spritecliptime); - R_ClipSprites(); + R_ClipSprites(drawsegs, NULL); PS_STOP_TIMING(ps_sw_spritecliptime); ps_numsprites.value.i = numvisiblesprites; @@ -1442,43 +1452,40 @@ void R_RenderPlayerView(player_t *player) // that were previously stored. Portal_ClipApply(portal); + validcount++; + + masks = static_cast(realloc(masks, (++nummasks)*sizeof(maskcount_t))); + // Render the BSP from the new viewpoint, and clip // any sprites with the new clipsegs and window. - R_RenderBSPNode((INT32)numnodes - 1); - R_ClipSprites(); + R_RenderViewpoint(&masks[nummasks - 1], true); + + R_ClipSprites(ds_p - (masks[nummasks - 1].drawsegs[1] - masks[nummasks - 1].drawsegs[0]), portal); Portal_Remove(portal); - - validcount++; } } PS_STOP_TIMING(ps_sw_portaltime); PS_START_TIMING(ps_sw_planetime); + if (!skybox) + R_DrawSkyPlanes(); R_DrawPlanes(); PS_STOP_TIMING(ps_sw_planetime); -#ifdef FLOORSPLATS - R_DrawVisibleFloorSplats(); -#endif // draw mid texture and sprite // And now 3D floors/sides! PS_START_TIMING(ps_sw_maskedtime); - R_DrawMasked(); + R_DrawMasked(masks, nummasks); PS_STOP_TIMING(ps_sw_maskedtime); + free(masks); + // Check for new console commands. NetUpdate(); // save value to skyVisiblePerPlayer // this is so that P1 can't affect whether P2 can see a skybox or not, or vice versa - for (i = 0; i <= splitscreen; i++) - { - if (player != &players[displayplayers[i]]) - continue; - - skyVisiblePerPlayer[i] = skyVisible; - break; - } + skyVisiblePerPlayer[viewssnum] = skyVisible; } // ========================================================================= @@ -1519,11 +1526,13 @@ void R_RegisterEngineStuff(void) { CV_RegisterVar(&cv_chasecam[i]); } + CV_RegisterVar(&cv_shadow); CV_RegisterVar(&cv_shadowoffs); CV_RegisterVar(&cv_skybox); CV_RegisterVar(&cv_ffloorclip); CV_RegisterVar(&cv_spriteclip); + CV_RegisterVar(&cv_softcyancut); for (i = 0; i < MAXSPLITSCREENPLAYERS; i++) { diff --git a/src/r_main.h b/src/r_main.h index d3284764d..29a6b308e 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -14,6 +14,10 @@ #ifndef __R_MAIN__ #define __R_MAIN__ +#ifdef __cplusplus +extern "C" { +#endif + #include "d_player.h" #include "r_data.h" #include "m_perfstats.h" @@ -84,7 +88,7 @@ extern lighttable_t *zlight[LIGHTLEVELS][MAXLIGHTZ]; // // killough 5/2/98: reformatted // -FUNCINLINE static ATTRINLINE PUREFUNC INT32 R_PointOnSide(fixed_t x, fixed_t y, const node_t *restrict node) +FUNCINLINE static ATTRINLINE PUREFUNC INT32 R_PointOnSide(fixed_t x, fixed_t y, const node_t * restrict node) { if (!node->dx) return x <= node->x ? node->dy > 0 : node->dy < 0; @@ -207,6 +211,7 @@ extern consvar_t cv_chasecam[MAXSPLITSCREENPLAYERS]; extern consvar_t cv_flipcam[MAXSPLITSCREENPLAYERS]; extern consvar_t cv_shadow, cv_shadowoffs; extern consvar_t cv_ffloorclip, cv_spriteclip; +extern consvar_t cv_softcyancut; extern consvar_t cv_translucency; extern consvar_t cv_drawdist, cv_drawdist_precip, cv_lessprecip, cv_mobjscaleprecip; extern consvar_t cv_fov, cv_fovchange; @@ -245,4 +250,9 @@ void R_RegisterEngineStuff(void); INT32 R_GetHudUncap(void); // same as above but keeps interpolation during pause INT32 R_GetMenuUncap(void); + +#ifdef __cplusplus +} // extern "C" +#endif + #endif diff --git a/src/r_patch.c b/src/r_patch.c index 21f59401c..f48996ea4 100644 --- a/src/r_patch.c +++ b/src/r_patch.c @@ -16,6 +16,7 @@ #include "doomdef.h" #include "r_patch.h" #include "r_things.h" +#include "r_skins.h" #include "z_zone.h" #include "w_wad.h" diff --git a/src/r_patchrotation.h b/src/r_patchrotation.h index d387ae20f..b3bcd7a97 100644 --- a/src/r_patchrotation.h +++ b/src/r_patchrotation.h @@ -12,6 +12,10 @@ #ifndef __R_PATCHROTATION__ #define __R_PATCHROTATION__ +#ifdef __cplusplus +extern "C" { +#endif + #include "r_fps.h" // Sprite rotation @@ -27,4 +31,8 @@ extern fixed_t rollcosang[ROTANGLES]; extern fixed_t rollsinang[ROTANGLES]; #endif +#ifdef __cplusplus +} // extern "C" +#endif + #endif // __R_PATCHROTATION__ diff --git a/src/r_plane.c b/src/r_plane.c deleted file mode 100644 index 37930e89e..000000000 --- a/src/r_plane.c +++ /dev/null @@ -1,1204 +0,0 @@ -// SONIC ROBO BLAST 2 -//----------------------------------------------------------------------------- -// Copyright (C) 1993-1996 by id Software, Inc. -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2018 by Sonic Team Junior. -// -// This program is free software distributed under the -// terms of the GNU General Public License, version 2. -// See the 'LICENSE' file for more details. -//----------------------------------------------------------------------------- -/// \file r_plane.c -/// \brief Here is a core component: drawing the floors and ceilings, -/// while maintaining a per column clipping list only. -/// Moreover, the sky areas have to be determined. - -#include "doomdef.h" -#include "console.h" -#include "g_game.h" -#include "p_setup.h" // levelflats -#include "p_slopes.h" -#include "r_data.h" -#include "r_local.h" -#include "r_state.h" -#include "r_splats.h" // faB(21jan):testing -#include "r_sky.h" -#include "v_video.h" -#include "w_wad.h" -#include "z_zone.h" -#include "p_tick.h" -#include "r_fps.h" -#include "r_portal.h" - -// -// opening -// - -// Quincunx antialiasing of flats! -//#define QUINCUNX - -// good night sweet prince -//#define SHITPLANESPARENCY - -static visplane_t *visplanes[MAXVISPLANES]; -static visplane_t *freetail; -static visplane_t **freehead = &freetail; - -visplane_t *floorplane; -visplane_t *ceilingplane; -static visplane_t *currentplane; - -visffloor_t ffloor[MAXFFLOORS]; -INT32 numffloors; - -//SoM: 3/23/2000: Boom visplane hashing routine. -#define visplane_hash(picnum,lightlevel,height) \ - ((unsigned)((picnum)*3+(lightlevel)+(height)*7) & VISPLANEHASHMASK) - -//SoM: 3/23/2000: Use boom opening limit removal -size_t maxopenings; -INT16 *openings, *lastopening; /// \todo free leak - -// -// Clip values are the solid pixel bounding the range. -// floorclip starts out SCREENHEIGHT -// ceilingclip starts out -1 -// -INT16 floorclip[MAXVIDWIDTH], ceilingclip[MAXVIDWIDTH]; -fixed_t frontscale[MAXVIDWIDTH]; - -// -// spanstart holds the start of a plane span -// initialized to 0 at start -// -static INT32 spanstart[MAXVIDHEIGHT]; - -// -// texture mapping -// -lighttable_t **planezlight; -static fixed_t planeheight; - -//added : 10-02-98: yslopetab is what yslope used to be, -// yslope points somewhere into yslopetab, -// now (viewheight/2) slopes are calculated above and -// below the original viewheight for mouselook -// (this is to calculate yslopes only when really needed) -// (when mouselookin', yslope is moving into yslopetab) -// Check R_SetupFrame, R_SetViewSize for more... -fixed_t yslopetab[MAXVIDHEIGHT*16]; -fixed_t *yslope; - -fixed_t basexscale, baseyscale; - -fixed_t cachedheight[MAXVIDHEIGHT]; -fixed_t cacheddistance[MAXVIDHEIGHT]; -fixed_t cachedxstep[MAXVIDHEIGHT]; -fixed_t cachedystep[MAXVIDHEIGHT]; - -static fixed_t xoffs, yoffs; - -// -// R_InitPlanes -// Only at game startup. -// -void R_InitPlanes(void) -{ - // FIXME: unused -} - -// -// Water ripple effect!! -// Needs the height of the plane, and the vertical position of the span. -// Sets planeripple.xfrac and planeripple.yfrac, added to ds_xfrac and ds_yfrac, if the span is not tilted. -// - -#ifndef NOWATER -INT32 ds_bgofs; -INT32 ds_waterofs; - -struct -{ - INT32 offset; - fixed_t xfrac, yfrac; - boolean active; -} planeripple; - -static void R_CalculatePlaneRipple(visplane_t *plane, INT32 y, fixed_t plheight, boolean calcfrac) -{ - fixed_t distance = FixedMul(plheight, yslope[y]); - const INT32 yay = (planeripple.offset + (distance>>9)) & 8191; - - // ripples da water texture - ds_bgofs = FixedDiv(FINESINE(yay), (1<<12) + (distance>>11))>>FRACBITS; - - if (calcfrac) - { - angle_t angle = (plane->viewangle + plane->plangle)>>ANGLETOFINESHIFT; - angle = (angle + 2048) & 8191; // 90 degrees - planeripple.xfrac = FixedMul(FINECOSINE(angle), (ds_bgofs<= viewwidth || y > viewheight) - I_Error("R_MapPlane: %d, %d at %d", x1, x2, y); -#endif - - if (x1 >= vid.width) - x1 = vid.width - 1; - - if (!currentplane->slope) - { - angle = (currentplane->viewangle + currentplane->plangle)>>ANGLETOFINESHIFT; - planecos = FINECOSINE(angle); - planesin = FINESINE(angle); - - if (planeheight != cachedheight[y]) - { - cachedheight[y] = planeheight; - cacheddistance[y] = distance = FixedMul(planeheight, yslope[y]); - span = abs(centery - y); - - if (span) // don't divide by zero - { - ds_xstep = FixedMul(planesin, planeheight) / span; - ds_ystep = FixedMul(planecos, planeheight) / span; - } - else - { - ds_xstep = FixedMul(distance, basexscale); - ds_ystep = FixedMul(distance, baseyscale); - } - - cachedxstep[y] = ds_xstep; - cachedystep[y] = ds_ystep; - } - else - { - distance = cacheddistance[y]; - ds_xstep = cachedxstep[y]; - ds_ystep = cachedystep[y]; - } - - ds_xfrac = xoffs + FixedMul(planecos, distance) + (x1 - centerx) * ds_xstep; - ds_yfrac = yoffs - FixedMul(planesin, distance) + (x1 - centerx) * ds_ystep; - } - -#ifndef NOWATER - if (planeripple.active) - { - // Needed for ds_bgofs - R_CalculatePlaneRipple(currentplane, y, planeheight, (!currentplane->slope)); - - if (currentplane->slope) - { - ds_sup = &ds_su[y]; - ds_svp = &ds_sv[y]; - ds_szp = &ds_sz[y]; - } - else - { - ds_xfrac += planeripple.xfrac; - ds_yfrac += planeripple.yfrac; - } - - if ((y + ds_bgofs) >= viewheight) - ds_bgofs = viewheight-y-1; - if ((y + ds_bgofs) < 0) - ds_bgofs = -y; - } -#endif - - if (currentplane->slope) - ds_colormap = colormaps; - else - { - pindex = distance >> LIGHTZSHIFT; - if (pindex >= MAXLIGHTZ) - pindex = MAXLIGHTZ - 1; - ds_colormap = planezlight[pindex]; - } - if (encoremap && !currentplane->noencore) - ds_colormap += COLORMAP_REMAPOFFSET; - - if (currentplane->extra_colormap) - ds_colormap = currentplane->extra_colormap->colormap + (ds_colormap - colormaps); - - ds_y = y; - ds_x1 = x1; - ds_x2 = x2; - - spanfunc(); -} - -void R_ClearFFloorClips (void) -{ - INT32 i, p; - - // opening / clipping determination - for (i = 0; i < viewwidth; i++) - { - for (p = 0; p < MAXFFLOORS; p++) - { - ffloor[p].f_clip[i] = (INT16)viewheight; - ffloor[p].c_clip[i] = -1; - } - } - - numffloors = 0; -} - -// -// R_ClearPlanes -// At begining of frame. -// -void R_ClearPlanes(void) -{ - INT32 i, p; - angle_t angle; - - // opening / clipping determination - for (i = 0; i < viewwidth; i++) - { - floorclip[i] = (INT16)viewheight; - ceilingclip[i] = -1; - frontscale[i] = INT32_MAX; - for (p = 0; p < MAXFFLOORS; p++) - { - ffloor[p].f_clip[i] = (INT16)viewheight; - ffloor[p].c_clip[i] = -1; - } - } - - numffloors = 0; - - for (i = 0; i < MAXVISPLANES; i++) - { - for (*freehead = visplanes[i], visplanes[i] = NULL; - freehead && *freehead ;) - { - freehead = &(*freehead)->next; - } - } - - lastopening = openings; - - // texture calculation - memset(cachedheight, 0, sizeof (cachedheight)); - - // left to right mapping - angle = (viewangle-ANGLE_90)>>ANGLETOFINESHIFT; - - // scale will be unit scale at SCREENWIDTH/2 distance - basexscale = FixedDiv (FINECOSINE(angle),centerxfrac); - baseyscale = -FixedDiv (FINESINE(angle),centerxfrac); -} - -static visplane_t *new_visplane(unsigned hash) -{ - visplane_t *check = freetail; - if (!check) - { - check = malloc(sizeof (*check)); - if (check == NULL) I_Error("%s: Out of memory", "new_visplane"); // FIXME: ugly - } - else - { - freetail = freetail->next; - if (!freetail) - freehead = &freetail; - } - check->next = visplanes[hash]; - visplanes[hash] = check; - return check; -} - -// -// R_FindPlane: Seek a visplane having the identical values: -// Same height, same flattexture, same lightlevel. -// If not, allocates another of them. -// -visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, - fixed_t xoff, fixed_t yoff, angle_t plangle, extracolormap_t *planecolormap, - ffloor_t *pfloor - , polyobj_t *polyobj - , pslope_t *slope - , boolean noencore - , boolean reverseLight, const sector_t *lighting_sector) -{ - visplane_t *check; - unsigned hash; - - if (slope); else // Don't mess with this right now if a slope is involved - { - xoff += viewx; - yoff -= viewy; - if (plangle != 0) - { - // Add the view offset, rotated by the plane angle. - fixed_t cosinecomponent = FINECOSINE(plangle>>ANGLETOFINESHIFT); - fixed_t sinecomponent = FINESINE(plangle>>ANGLETOFINESHIFT); - fixed_t oldxoff = xoff; - xoff = FixedMul(xoff,cosinecomponent)+FixedMul(yoff,sinecomponent); - yoff = -FixedMul(oldxoff,sinecomponent)+FixedMul(yoff,cosinecomponent); - } - } - - if (polyobj) - { - if (polyobj->angle != 0) - { - float ang = ANG2RAD(polyobj->angle); - float x = FixedToFloat(polyobj->centerPt.x); - float y = FixedToFloat(polyobj->centerPt.y); - xoff -= FloatToFixed(x * cos(ang) + y * sin(ang)); - yoff -= FloatToFixed(x * sin(ang) - y * cos(ang)); - } - else - { - xoff -= polyobj->centerPt.x; - yoff += polyobj->centerPt.y; - } - } - - if (slope != NULL && P_ApplyLightOffset(lightlevel >> LIGHTSEGSHIFT, lighting_sector)) - { - if (reverseLight) - { - lightlevel -= slope->lightOffset * 8; - } - else - { - lightlevel += slope->lightOffset * 8; - } - } - - // This appears to fix the Nimbus Ruins sky bug. - if (picnum == skyflatnum && pfloor) - { - height = 0; // all skies map together - lightlevel = 0; - } - - if (!pfloor) - { - hash = visplane_hash(picnum, lightlevel, height); - for (check = visplanes[hash]; check; check = check->next) - { - if (polyobj != check->polyobj) - continue; - if (height == check->height && picnum == check->picnum - && lightlevel == check->lightlevel - && xoff == check->xoffs && yoff == check->yoffs - && planecolormap == check->extra_colormap - && check->viewx == viewx && check->viewy == viewy && check->viewz == viewz - && check->viewangle == viewangle - && check->plangle == plangle - && check->slope == slope - && check->noencore == noencore) - { - return check; - } - } - } - else - { - hash = MAXVISPLANES - 1; - } - - check = new_visplane(hash); - - check->height = height; - check->picnum = picnum; - check->lightlevel = lightlevel; - check->minx = vid.width; - check->maxx = -1; - check->xoffs = xoff; - check->yoffs = yoff; - check->extra_colormap = planecolormap; - check->ffloor = pfloor; - check->viewx = viewx; - check->viewy = viewy; - check->viewz = viewz; - check->viewangle = viewangle; - check->plangle = plangle; - check->polyobj = polyobj; - check->slope = slope; - check->noencore = noencore; - - memset(check->top, 0xff, sizeof (check->top)); - memset(check->bottom, 0x00, sizeof (check->bottom)); - - return check; -} - -// -// R_CheckPlane: return same visplane or alloc a new one if needed -// -visplane_t *R_CheckPlane(visplane_t *pl, INT32 start, INT32 stop) -{ - INT32 intrl, intrh; - INT32 unionl, unionh; - INT32 x; - - if (start < pl->minx) - { - intrl = pl->minx; - unionl = start; - } - else - { - unionl = pl->minx; - intrl = start; - } - - if (stop > pl->maxx) - { - intrh = pl->maxx; - unionh = stop; - } - else - { - unionh = pl->maxx; - intrh = stop; - } - - // 0xff is not equal to -1 with shorts... - for (x = intrl; x <= intrh; x++) - if (pl->top[x] != 0xffff || pl->bottom[x] != 0x0000) - break; - - if (x > intrh) /* Can use existing plane; extend range */ - { - pl->minx = unionl; - pl->maxx = unionh; - } - else /* Cannot use existing plane; create a new one */ - { - visplane_t *new_pl; - if (pl->ffloor) - { - new_pl = new_visplane(MAXVISPLANES - 1); - } - else - { - unsigned hash = visplane_hash(pl->picnum, pl->lightlevel, pl->height); - new_pl = new_visplane(hash); - } - - new_pl->height = pl->height; - new_pl->picnum = pl->picnum; - new_pl->lightlevel = pl->lightlevel; - new_pl->xoffs = pl->xoffs; - new_pl->yoffs = pl->yoffs; - new_pl->extra_colormap = pl->extra_colormap; - new_pl->ffloor = pl->ffloor; - new_pl->viewx = pl->viewx; - new_pl->viewy = pl->viewy; - new_pl->viewz = pl->viewz; - new_pl->viewangle = pl->viewangle; - new_pl->plangle = pl->plangle; - new_pl->polyobj = pl->polyobj; - new_pl->slope = pl->slope; - new_pl->noencore = pl->noencore; - pl = new_pl; - pl->minx = start; - pl->maxx = stop; - memset(pl->top, 0xff, sizeof pl->top); - memset(pl->bottom, 0x00, sizeof pl->bottom); - } - return pl; -} - - -// -// R_ExpandPlane -// -// This function basically expands the visplane or I_Errors. -// The reason for this is that when creating 3D floor planes, there is no -// need to create new ones with R_CheckPlane, because 3D floor planes -// are created by subsector and there is no way a subsector can graphically -// overlap. -void R_ExpandPlane(visplane_t *pl, INT32 start, INT32 stop) -{ - INT32 unionl, unionh; -// INT32 x; - - // Don't expand polyobject planes here - we do that on our own. - if (pl->polyobj) - return; - - if (start < pl->minx) - { - unionl = start; - } - else - { - unionl = pl->minx; - } - - if (stop > pl->maxx) - { - unionh = stop; - } - else - { - unionh = pl->maxx; - } -/* - for (x = start; x <= stop; x++) - if (pl->top[x] != 0xffff || pl->bottom[x] != 0x0000) - break; - - if (x <= stop) - I_Error("R_ExpandPlane: planes in same subsector overlap?!\nminx: %d, maxx: %d, start: %d, stop: %d\n", pl->minx, pl->maxx, start, stop); -*/ - pl->minx = unionl, pl->maxx = unionh; -} - -// -// R_MakeSpans -// -void R_MakeSpans(INT32 x, INT32 t1, INT32 b1, INT32 t2, INT32 b2) -{ - // Alam: from r_splats's R_RenderFloorSplat - if (t1 >= vid.height) t1 = vid.height-1; - if (b1 >= vid.height) b1 = vid.height-1; - if (t2 >= vid.height) t2 = vid.height-1; - if (b2 >= vid.height) b2 = vid.height-1; - if (x-1 >= vid.width) x = vid.width; - - while (t1 < t2 && t1 <= b1) - { - R_MapPlane(t1, spanstart[t1], x - 1); - t1++; - } - while (b1 > b2 && b1 >= t1) - { - R_MapPlane(b1, spanstart[b1], x - 1); - b1--; - } - - while (t2 < t1 && t2 <= b2) - spanstart[t2++] = x; - while (b2 > b1 && b2 >= t2) - spanstart[b2--] = x; -} - -void R_DrawPlanes(void) -{ - visplane_t *pl; - INT32 i; - - spanfunc = basespanfunc; - wallcolfunc = walldrawerfunc; - - for (i = 0; i < MAXVISPLANES; i++, pl++) - { - for (pl = visplanes[i]; pl; pl = pl->next) - { - if (pl->ffloor != NULL || pl->polyobj != NULL) - continue; - - R_DrawSinglePlane(pl); - } - } - -#ifndef NOWATER - R_UpdatePlaneRipple(); -#endif -} - -static void R_DrawSkyPlane(visplane_t *pl) -{ - INT32 x; - INT32 angle; - - if (!newview->sky) - { - skyVisible = true; - return; - } - - wallcolfunc = walldrawerfunc; - - // use correct aspect ratio scale - dc_iscale = skyscale; - // Sky is always drawn full bright, - // i.e. colormaps[0] is used. - // Because of this hack, sky is not affected - // by INVUL inverse mapping. - dc_colormap = colormaps; - - if (encoremap) - dc_colormap += COLORMAP_REMAPOFFSET; - - dc_texturemid = skytexturemid; - dc_texheight = textureheight[skytexture] >>FRACBITS; - dc_sourcelength = dc_texheight; - - for (x = pl->minx; x <= pl->maxx; x++) - { - dc_yl = pl->top[x]; - dc_yh = pl->bottom[x]; - - if (!(dc_yl <= dc_yh)) - continue; - - angle = (pl->viewangle + xtoviewangle[x])>>ANGLETOSKYSHIFT; - dc_iscale = FixedMul(skyscale, FINECOSINE(xtoviewangle[x]>>ANGLETOFINESHIFT)); - dc_x = x; - dc_source = R_GetColumn(texturetranslation[skytexture], angle); - wallcolfunc(); - } -} - -// Potentially override other stuff for now cus we're mean. :< But draw a slope plane! -// I copied ZDoom's code and adapted it to SRB2... -Red -void R_CalculateSlopeVectors(pslope_t *slope, fixed_t planeviewx, fixed_t planeviewy, fixed_t planeviewz, fixed_t planexscale, fixed_t planeyscale, fixed_t planexoffset, fixed_t planeyoffset, angle_t planeviewangle, angle_t planeangle, float fudge) -{ - floatv3_t p, m, n; - float ang; - float vx, vy, vz; - float xscale = FIXED_TO_FLOAT(planexscale); - float yscale = FIXED_TO_FLOAT(planeyscale); - // compiler complains when P_GetSlopeZAt is used in FLOAT_TO_FIXED directly - // use this as a temp var to store P_GetSlopeZAt's return value each time - fixed_t temp; - - vx = FIXED_TO_FLOAT(planeviewx+planexoffset); - vy = FIXED_TO_FLOAT(planeviewy-planeyoffset); - vz = FIXED_TO_FLOAT(planeviewz); - - temp = P_GetSlopeZAt(slope, planeviewx, planeviewy); - zeroheight = FIXED_TO_FLOAT(temp); - - // p is the texture origin in view space - // Don't add in the offsets at this stage, because doing so can result in - // errors if the flat is rotated. - ang = ANG2RAD(ANGLE_270 - planeviewangle); - p.x = vx * cos(ang) - vy * sin(ang); - p.z = vx * sin(ang) + vy * cos(ang); - temp = P_GetSlopeZAt(slope, -planexoffset, planeyoffset); - p.y = FIXED_TO_FLOAT(temp) - vz; - - // m is the v direction vector in view space - ang = ANG2RAD(ANGLE_180 - (planeviewangle + planeangle)); - m.x = yscale * cos(ang); - m.z = yscale * sin(ang); - - // n is the u direction vector in view space - n.x = xscale * sin(ang); - n.z = -xscale * cos(ang); - - ang = ANG2RAD(planeangle); - temp = P_GetSlopeZAt(slope, planeviewx + FLOAT_TO_FIXED(yscale * sin(ang)), planeviewy + FLOAT_TO_FIXED(yscale * cos(ang))); - m.y = FIXED_TO_FLOAT(temp) - zeroheight; - temp = P_GetSlopeZAt(slope, planeviewx + FLOAT_TO_FIXED(xscale * cos(ang)), planeviewy - FLOAT_TO_FIXED(xscale * sin(ang))); - n.y = FIXED_TO_FLOAT(temp) - zeroheight; - - m.x /= fudge; - m.y /= fudge; - m.z /= fudge; - - n.x *= fudge; - n.y *= fudge; - n.z *= fudge; - - // Eh. I tried making this stuff fixed-point and it exploded on me. Here's a macro for the only floating-point vector function I recall using. -#define CROSS(d, v1, v2) \ -d->x = (v1.y * v2.z) - (v1.z * v2.y);\ -d->y = (v1.z * v2.x) - (v1.x * v2.z);\ -d->z = (v1.x * v2.y) - (v1.y * v2.x) - CROSS(ds_sup, p, m); - CROSS(ds_svp, p, n); - CROSS(ds_szp, m, n); -#undef CROSS - - ds_sup->z *= focallengthf; - ds_svp->z *= focallengthf; - ds_szp->z *= focallengthf; - - // Premultiply the texture vectors with the scale factors -#define SFMULT 65536.f - ds_sup->x *= (SFMULT * (1<y *= (SFMULT * (1<z *= (SFMULT * (1<x *= (SFMULT * (1<y *= (SFMULT * (1<z *= (SFMULT * (1<slope, pl->viewx, pl->viewy, pl->viewz, FRACUNIT, FRACUNIT, xoff, yoff, pl->viewangle, pl->plangle, fudge); -} - - -void R_DrawSinglePlane(visplane_t *pl) -{ - INT32 light = 0; - INT32 x; - INT32 stop, angle; - size_t size; - ffloor_t *rover; - - if (!(pl->minx <= pl->maxx)) - return; - - // sky flat - if (pl->picnum == skyflatnum) - { - R_DrawSkyPlane(pl); - return; - } - -#ifndef NOWATER - planeripple.active = false; -#endif - spanfunc = basespanfunc; - - if (pl->polyobj && pl->polyobj->translucency != 0) - { - spanfunc = R_DrawTranslucentSpan_8; - - // Hacked up support for alpha value in software mode Tails 09-24-2002 (sidenote: ported to polys 10-15-2014, there was no time travel involved -Red) - if (pl->polyobj->translucency >= 10) - return; // Don't even draw it - else if (pl->polyobj->translucency > 0) - ds_transmap = R_GetTranslucencyTable(pl->polyobj->translucency); - else // Opaque, but allow transparent flat pixels - spanfunc = splatfunc; - -#ifdef SHITPLANESPARENCY - if (spanfunc == splatfunc || (pl->extra_colormap && pl->extra_colormap->fog)) -#else - if (!pl->extra_colormap || !(pl->extra_colormap->fog & 2)) -#endif - light = (pl->lightlevel >> LIGHTSEGSHIFT); - else - light = LIGHTLEVELS-1; - - } - else - { - if (pl->ffloor) - { - // Don't draw planes that shouldn't be drawn. - for (rover = pl->ffloor->target->ffloors; rover; rover = rover->next) - { - if ((pl->ffloor->flags & FF_CUTEXTRA) && (rover->flags & FF_EXTRA)) - { - if (!(rover->flags & FF_EXTRA)) - continue; - - // The plane is from an extra 3D floor... Check the flags so - // there are no undesired cuts. - if (((pl->ffloor->flags & (FF_FOG|FF_SWIMMABLE)) == (rover->flags & (FF_FOG|FF_SWIMMABLE))) - && pl->height < *rover->topheight - && pl->height > *rover->bottomheight) - return; - } - } - - if (pl->ffloor->flags & FF_TRANSLUCENT) - { - spanfunc = R_DrawTranslucentSpan_8; - - // Hacked up support for alpha value in software mode Tails 09-24-2002 - // ...unhacked by toaster 04-01-2021, re-hacked a little by sphere 19-11-2021 - // and mercilessly shoved into saturn by chearii 02-02-2025 - { - INT32 trans = (10*((256+12) - pl->ffloor->alpha))/255; - if (trans >= 10) - return; // Don't even draw it - if (pl->ffloor->blend) // additive, (reverse) subtractive, modulative - ds_transmap = R_GetBlendTable(pl->ffloor->blend, trans); - else if (!(ds_transmap = R_GetTranslucencyTable(trans)) || trans == 0) - spanfunc = splatfunc; // Opaque, but allow transparent flat pixels - } - -#ifdef SHITPLANESPARENCY - if (spanfunc == splatfunc || (pl->extra_colormap && pl->extra_colormap->fog)) -#else - if (!pl->extra_colormap || !(pl->extra_colormap->fog & 2)) -#endif - light = (pl->lightlevel >> LIGHTSEGSHIFT); - else - light = LIGHTLEVELS-1; - } - else if (pl->ffloor->flags & FF_FOG) - { - spanfunc = R_DrawFogSpan_8; - light = (pl->lightlevel >> LIGHTSEGSHIFT); - } - else light = (pl->lightlevel >> LIGHTSEGSHIFT); - -#ifndef NOWATER - if (pl->ffloor->flags & FF_RIPPLE) - { - INT32 top, bottom; - UINT8 *scr; - - if (cv_ripplewater.value) - { - planeripple.active = true; - - if (spanfunc == R_DrawTranslucentSpan_8) - { - spanfunc = R_DrawTranslucentWaterSpan_8; - - // Copy the current scene, ugh - top = pl->high-8; - bottom = pl->low+8; - - if (top < 0) - top = 0; - if (bottom > vid.height) - bottom = vid.height; - - if (splitscreen > 2 && viewplayer == &players[displayplayers[3]]) // Only copy the part of the screen we need - scr = (screens[0] + (top+(viewheight))*vid.width + viewwidth); - else if ((splitscreen == 1 && viewplayer == &players[displayplayers[1]]) - || (splitscreen > 1 && viewplayer == &players[displayplayers[2]])) - scr = (screens[0] + (top+(viewheight))*vid.width); - else if (splitscreen > 1 && viewplayer == &players[displayplayers[1]]) - scr = (screens[0] + ((top)*vid.width) + viewwidth); - else - scr = (screens[0] + ((top)*vid.width)); - - VID_BlitLinearScreen(scr, screens[1]+((top)*vid.width), - vid.width, bottom-top, - vid.width, vid.width); - } - } - else - { - planeripple.active = false; - } - } -#endif - } - else light = (pl->lightlevel >> LIGHTSEGSHIFT); - } - - if (!pl->slope && viewangle != pl->viewangle+pl->plangle) // Don't mess with angle on slopes! We'll handle this ourselves later - { - memset(cachedheight, 0, sizeof (cachedheight)); - angle = (pl->viewangle+pl->plangle-ANGLE_90)>>ANGLETOFINESHIFT; - basexscale = FixedDiv(FINECOSINE(angle),centerxfrac); - baseyscale = -FixedDiv(FINESINE(angle),centerxfrac); - viewangle = pl->viewangle+pl->plangle; - } - - currentplane = pl; - - ds_source = (UINT8 *) - W_CacheLumpNum(levelflats[pl->picnum].lumpnum, - PU_STATIC); // Stay here until Z_ChangeTag - - size = W_LumpLength(levelflats[pl->picnum].lumpnum); - - switch (size) - { - case 4194304: // 2048x2048 lump - nflatmask = 0x3FF800; - nflatxshift = 21; - nflatyshift = 10; - nflatshiftup = 5; - break; - case 1048576: // 1024x1024 lump - nflatmask = 0xFFC00; - nflatxshift = 22; - nflatyshift = 12; - nflatshiftup = 6; - break; - case 262144:// 512x512 lump' - nflatmask = 0x3FE00; - nflatxshift = 23; - nflatyshift = 14; - nflatshiftup = 7; - break; - case 65536: // 256x256 lump - nflatmask = 0xFF00; - nflatxshift = 24; - nflatyshift = 16; - nflatshiftup = 8; - break; - case 16384: // 128x128 lump - nflatmask = 0x3F80; - nflatxshift = 25; - nflatyshift = 18; - nflatshiftup = 9; - break; - case 1024: // 32x32 lump - nflatmask = 0x3E0; - nflatxshift = 27; - nflatyshift = 22; - nflatshiftup = 11; - break; - default: // 64x64 lump - nflatmask = 0xFC0; - nflatxshift = 26; - nflatyshift = 20; - nflatshiftup = 10; - break; - } - - xoffs = pl->xoffs; - yoffs = pl->yoffs; - planeheight = abs(pl->height - pl->viewz); - - if (light >= LIGHTLEVELS) - light = LIGHTLEVELS-1; - - if (light < 0) - light = 0; - - if (pl->slope) - { - float fudgecanyon = 0; - fixed_t temp; - // Okay, look, don't ask me why this works, but without this setup there's a disgusting-looking misalignment with the textures. -fickle - fudgecanyon = ((1<plangle & (ANGLE_90-1)); - - if (hack) - { - /* - Essentially: We can't & the components along the regular axes when the plane is rotated. - This is because the distance on each regular axis in order to loop is different. - We rotate them, & the components, add them together, & them again, and then rotate them back. - These three seperate & operations are done per axis in order to prevent overflows. - toast 10/04/17 - --- - ...of coooourse, this still isn't perfect. but it looks... merely kind of grody, rather than - completely wrong? idk. i'm just backporting this to kart right now. if anyone else wants to - ever try dig around: it's drifting towards 0,0, and no, multiplying by fudge doesn't fix it. - toast 27/09/18 - */ - - const fixed_t cosinecomponent = FINECOSINE(hack>>ANGLETOFINESHIFT); - const fixed_t sinecomponent = FINESINE(hack>>ANGLETOFINESHIFT); - - const fixed_t modmask = ((1 << (32-nflatshiftup)) - 1); - - fixed_t ox = (FixedMul(pl->slope->o.x,cosinecomponent) & modmask) - (FixedMul(pl->slope->o.y,sinecomponent) & modmask); - fixed_t oy = (-FixedMul(pl->slope->o.x,sinecomponent) & modmask) - (FixedMul(pl->slope->o.y,cosinecomponent) & modmask); - - temp = ox & modmask; - oy &= modmask; - ox = FixedMul(temp,cosinecomponent)+FixedMul(oy,-sinecomponent); // negative sine for opposite direction - oy = -FixedMul(temp,-sinecomponent)+FixedMul(oy,cosinecomponent); - - temp = xoffs; - xoffs = (FixedMul(temp,cosinecomponent) & modmask) + (FixedMul(yoffs,sinecomponent) & modmask); - yoffs = (-FixedMul(temp,sinecomponent) & modmask) + (FixedMul(yoffs,cosinecomponent) & modmask); - - temp = xoffs & modmask; - yoffs &= modmask; - xoffs = FixedMul(temp,cosinecomponent)+FixedMul(yoffs,-sinecomponent); // ditto - yoffs = -FixedMul(temp,-sinecomponent)+FixedMul(yoffs,cosinecomponent); - - xoffs -= (pl->slope->o.x - ox); - yoffs += (pl->slope->o.y + oy); - } - else - { - xoffs &= ((1 << (32-nflatshiftup))-1); - yoffs &= ((1 << (32-nflatshiftup))-1); - xoffs -= (pl->slope->o.x + (1 << (31-nflatshiftup))) & ~((1 << (32-nflatshiftup))-1); - yoffs += (pl->slope->o.y + (1 << (31-nflatshiftup))) & ~((1 << (32-nflatshiftup))-1); - } - - xoffs = (fixed_t)(xoffs*fudgecanyon); - yoffs = (fixed_t)(yoffs/fudgecanyon); - -#ifndef NOWATER - if (planeripple.active) - { - fixed_t plheight = abs(P_GetSlopeZAt(pl->slope, pl->viewx, pl->viewy) - pl->viewz); - - R_PlaneBounds(pl); - - for (x = pl->high; x < pl->low; x++) - { - R_CalculatePlaneRipple(pl, x, plheight, true); - R_SetSlopePlaneVectors(pl, x, (xoffs + planeripple.xfrac), (yoffs + planeripple.yfrac), fudgecanyon); - } - } - else -#endif - R_SetSlopePlaneVectors(pl, 0, xoffs, yoffs, fudgecanyon); - -#ifndef NOWATER - if (spanfunc == R_DrawTranslucentWaterSpan_8) - spanfunc = R_DrawTiltedTranslucentWaterSpan_8; - else -#endif - if (spanfunc == R_DrawTranslucentSpan_8) - spanfunc = R_DrawTiltedTranslucentSpan_8; - else if (spanfunc == splatfunc) - spanfunc = R_DrawTiltedSplat_8; - else - spanfunc = R_DrawTiltedSpan_8; - - planezlight = scalelight[light]; - } - else - planezlight = zlight[light]; - - // set the maximum value for unsigned - pl->top[pl->maxx+1] = 0xffff; - pl->top[pl->minx-1] = 0xffff; - pl->bottom[pl->maxx+1] = 0x0000; - pl->bottom[pl->minx-1] = 0x0000; - - stop = pl->maxx + 1; - - if (viewx != pl->viewx || viewy != pl->viewy) - { - viewx = pl->viewx; - viewy = pl->viewy; - } - if (viewz != pl->viewz) - viewz = pl->viewz; - - for (x = pl->minx; x <= stop; x++) - { - R_MakeSpans(x, pl->top[x-1], pl->bottom[x-1], - pl->top[x], pl->bottom[x]); - } - -/* -QUINCUNX anti-aliasing technique (sort of) - -Normally, Quincunx antialiasing staggers pixels -in a 5-die pattern like so: - -o o - o -o o - -To simulate this, we offset the plane by -FRACUNIT/4 in each direction, and draw -at 50% translucency. The result is -a 'smoothing' of the texture while -using the palette colors. -*/ -#ifdef QUINCUNX - if (spanfunc == R_DrawSpan_8) - { - INT32 i; - ds_transmap = R_GetTranslucencyTable(tr_trans50); - spanfunc = R_DrawTranslucentSpan_8; - for (i=0; i<4; i++) - { - xoffs = pl->xoffs; - yoffs = pl->yoffs; - - switch(i) - { - case 0: - xoffs -= FRACUNIT/4; - yoffs -= FRACUNIT/4; - break; - case 1: - xoffs -= FRACUNIT/4; - yoffs += FRACUNIT/4; - break; - case 2: - xoffs += FRACUNIT/4; - yoffs -= FRACUNIT/4; - break; - case 3: - xoffs += FRACUNIT/4; - yoffs += FRACUNIT/4; - break; - } - planeheight = abs(pl->height - pl->viewz); - - if (light >= LIGHTLEVELS) - light = LIGHTLEVELS-1; - - if (light < 0) - light = 0; - - planezlight = zlight[light]; - - // set the maximum value for unsigned - pl->top[pl->maxx+1] = 0xffff; - pl->top[pl->minx-1] = 0xffff; - pl->bottom[pl->maxx+1] = 0x0000; - pl->bottom[pl->minx-1] = 0x0000; - - stop = pl->maxx + 1; - - for (x = pl->minx; x <= stop; x++) - R_MakeSpans(x, pl->top[x-1], pl->bottom[x-1], - pl->top[x], pl->bottom[x]); - } - } -#endif - - Z_ChangeTag(ds_source, PU_CACHE); -} - -void R_PlaneBounds(visplane_t *plane) -{ - INT32 i; - INT32 hi, low; - - hi = plane->top[plane->minx]; - low = plane->bottom[plane->minx]; - - for (i = plane->minx + 1; i <= plane->maxx; i++) - { - if (plane->top[i] < hi) - hi = plane->top[i]; - if (plane->bottom[i] > low) - low = plane->bottom[i]; - } - plane->high = hi; - plane->low = low; -} diff --git a/src/r_plane.cpp b/src/r_plane.cpp new file mode 100644 index 000000000..653353a2b --- /dev/null +++ b/src/r_plane.cpp @@ -0,0 +1,1408 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1993-1996 by id Software, Inc. +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2018 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file r_plane.c +/// \brief Here is a core component: drawing the floors and ceilings, +/// while maintaining a per column clipping list only. +/// Moreover, the sky areas have to be determined. + +#include + +#include "doomdef.h" +#include "console.h" +#include "g_game.h" +#include "p_setup.h" // levelflats +#include "p_slopes.h" +#include "r_data.h" +#include "r_local.h" +#include "r_state.h" +#include "r_splats.h" // faB(21jan):testing +#include "r_sky.h" +#include "v_video.h" +#include "w_wad.h" +#include "z_zone.h" +#include "p_tick.h" +#include "r_fps.h" +#include "r_portal.h" + +#ifdef HAVE_THREADS +#include "core/thread_pool.h" +#endif + +// +// opening +// + +// Quincunx antialiasing of flats! +//#define QUINCUNX + +// good night sweet prince +//#define SHITPLANESPARENCY + +visplane_t *visplanes[MAXVISPLANES]; +static visplane_t *freetail; +static visplane_t **freehead = &freetail; + +visplane_t *floorplane; +visplane_t *ceilingplane; + +visffloor_t ffloor[MAXFFLOORS]; +INT32 numffloors; + +//SoM: 3/23/2000: Boom visplane hashing routine. +#define visplane_hash(picnum,lightlevel,height) \ + ((unsigned)((picnum)*3+(lightlevel)+(height)*7) & VISPLANEHASHMASK) + +//SoM: 3/23/2000: Use boom opening limit removal +size_t maxopenings; +INT16 *openings, *lastopening; /// \todo free leak + +// +// Clip values are the solid pixel bounding the range. +// floorclip starts out SCREENHEIGHT +// ceilingclip starts out -1 +// +INT16 *floorclip, *ceilingclip; +fixed_t *frontscale; + +// +// spanstart holds the start of a plane span +// initialized to 0 at start +// +static INT32 *spanstart; + +//added : 10-02-98: yslopetab is what yslope used to be, +// yslope points somewhere into yslopetab, +// now (viewheight/2) slopes are calculated above and +// below the original viewheight for mouselook +// (this is to calculate yslopes only when really needed) +// (when mouselookin', yslope is moving into yslopetab) +// Check R_SetupFrame, R_SetViewSize for more... +fixed_t *yslopetab; +fixed_t *yslope; + +fixed_t basexscale, baseyscale; + +static INT16 *ffloor_f_clip; +static INT16 *ffloor_c_clip; + +static void R_SetTiltedSpan(drawspandata_t* ds, INT32 span); +static void R_SetSlopePlaneVectors(drawspandata_t* ds, visplane_t *pl, INT32 y, fixed_t xoff, fixed_t yoff); + +static void R_ReallocPlaneBounds(visplane_t *pl) +{ + pl->top_memory = static_cast(Z_Realloc(pl->top_memory, sizeof(UINT16) * (viewwidth + 2), PU_STATIC, NULL)); + pl->bottom_memory = static_cast(Z_Realloc(pl->bottom_memory, sizeof(UINT16) * (viewwidth + 2), PU_STATIC, NULL)); + pl->top = pl->top_memory + 1; + pl->bottom = pl->bottom_memory + 1; +} + +void R_AllocPlaneMemory(void) +{ + visplane_t *check; + + // Alloc visplane top/bottom bounds + for (unsigned i = 0; i < MAXVISPLANES; i++) + { + check = visplanes[i]; + + while (check) + { + R_ReallocPlaneBounds(check); + check = check->next; + } + } + + // Need to do it for "freed" visplanes too + check = freetail; + while (check) + { + R_ReallocPlaneBounds(check); + check = check->next; + } + + // Alloc ffloor clip tables + ffloor_f_clip = static_cast(Z_Realloc(ffloor_f_clip, sizeof(*ffloor_f_clip) * (viewwidth * MAXFFLOORS), PU_STATIC, NULL)); + ffloor_c_clip = static_cast(Z_Realloc(ffloor_c_clip, sizeof(*ffloor_c_clip) * (viewwidth * MAXFFLOORS), PU_STATIC, NULL)); + + for (unsigned i = 0; i < MAXFFLOORS; i++) + { + ffloor[i].f_clip = ffloor_f_clip + (i * viewwidth); + ffloor[i].c_clip = ffloor_c_clip + (i * viewwidth); + } + + yslopetab = static_cast(Z_Realloc(yslopetab, sizeof(*yslopetab) * (viewheight * 16), PU_STATIC, NULL)); + spanstart = static_cast(Z_Realloc(spanstart, sizeof(*spanstart) * viewheight, PU_STATIC, NULL)); +} + +// +// Water ripple effect!! +// Needs the height of the plane, and the vertical position of the span. +// Sets planeripple.xfrac and planeripple.yfrac, added to ds_xfrac and ds_yfrac, if the span is not tilted. +// +static fixed_t R_CalculateRippleOffset(drawspandata_t* ds, INT32 y) +{ + const fixed_t distance = FixedMul(ds->planeheight, yslope[y]); + const INT32 yay = (ds->planeripple.offset + (distance>>9)) & 8191; + return FixedDiv(FINESINE(yay), (1<<12) + (distance>>11)); +} + +static void R_CalculatePlaneRipple(drawspandata_t* ds, angle_t angle) +{ + angle >>= ANGLETOFINESHIFT; + angle = (angle + 2048) & 8191; // 90 degrees + ds->planeripple.xfrac = FixedMul(FINECOSINE(angle), ds->bgofs); + ds->planeripple.yfrac = FixedMul(FINESINE(angle), ds->bgofs); +} + +static void R_UpdatePlaneRipple(drawspandata_t* ds) +{ + ds->waterofs = (leveltime & 1)*16384; + ds->planeripple.offset = ((leveltime-1)*140) + ((rendertimefrac*140) / FRACUNIT); +} + +static bool R_CheckMapPlane(const char* funcname, INT32 y, INT32 x1, INT32 x2) +{ + if (x1 == x2) + return true; + + if (x1 < x2 && x1 >= 0 && x2 < viewwidth && y >= 0 && y < viewheight) + return true; + + CONS_Debug(DBG_RENDER, "%s: x1=%d, x2=%d at y=%d\n", funcname, x1, x2, y); + return false; +} + +// +// R_MapPlane +// +// Uses global vars: +// basexscale +// baseyscale +// centerx +// viewx +// viewy +// viewsin +// viewcos +// viewheight +static void R_MapPlane(drawspandata_t *ds, spandrawfunc_t *localspanfunc, INT32 y, INT32 x1, INT32 x2, boolean allow_parallel) +{ + angle_t angle, planecos, planesin; + fixed_t distance = 0, span; + size_t pindex; + + (void)allow_parallel; + + if (!R_CheckMapPlane(__func__, y, x1, x2)) + return; + + angle = (ds->currentplane->viewangle + ds->currentplane->plangle)>>ANGLETOFINESHIFT; + planecos = FINECOSINE(angle); + planesin = FINESINE(angle); + + // [RH] Notice that I dumped the caching scheme used by Doom. + // It did not offer any appreciable speedup. + distance = FixedMul(ds->planeheight, yslope[y]); + span = abs(centery - y); + + if (span) // don't divide by zero + { + ds->xstep = FixedMul(planesin, ds->planeheight) / span; + ds->ystep = FixedMul(planecos, ds->planeheight) / span; + } + else + { + ds->xstep = FixedMul(distance, basexscale); + ds->ystep = FixedMul(distance, baseyscale); + } + + // [RH] Instead of using the xtoviewangle array, I calculated the fractional values + // at the middle of the screen, then used the calculated ds_xstep and ds_ystep + // to step from those to the proper texture coordinate to start drawing at. + // That way, the texture coordinate is always calculated by its position + // on the screen and not by its position relative to the edge of the visplane. + ds->xfrac = ds->xoffs + FixedMul(planecos, distance) + (x1 - centerx) * ds->xstep; + ds->yfrac = ds->yoffs - FixedMul(planesin, distance) + (x1 - centerx) * ds->ystep; + + if (ds->planeripple.active) + { + ds->bgofs = R_CalculateRippleOffset(ds, y); + + R_CalculatePlaneRipple(ds, ds->currentplane->viewangle + ds->currentplane->plangle); + + ds->xfrac += ds->planeripple.xfrac; + ds->yfrac += ds->planeripple.yfrac; + ds->bgofs >>= FRACBITS; + + if ((y + ds->bgofs) >= viewheight) + ds->bgofs = viewheight-y-1; + if ((y + ds->bgofs) < 0) + ds->bgofs = -y; + } + + pindex = distance >> LIGHTZSHIFT; + if (pindex >= MAXLIGHTZ) + pindex = MAXLIGHTZ - 1; + + ds->colormap = ds->planezlight[pindex]; + + if (encoremap && !ds->currentplane->noencore) + ds->colormap += COLORMAP_REMAPOFFSET; + + if (ds->currentplane->extra_colormap) + ds->colormap = ds->currentplane->extra_colormap->colormap + (ds->colormap - colormaps); + + ds->y = y; + ds->x1 = x1; + ds->x2 = x2; + + localspanfunc(ds); +} + +static void R_MapTiltedPlane(drawspandata_t *ds, spandrawfunc_t *localspanfunc, INT32 y, INT32 x1, INT32 x2, boolean allow_parallel) +{ + (void)allow_parallel; + + if (!R_CheckMapPlane(__func__, y, x1, x2)) + return; + + // Water ripple effect + if (ds->planeripple.active) + { + ds->bgofs = R_CalculateRippleOffset(ds, y); + + R_SetTiltedSpan(ds, std::clamp(y, 0, viewheight)); + + R_CalculatePlaneRipple(ds, ds->currentplane->viewangle + ds->currentplane->plangle); + R_SetSlopePlaneVectors(ds, ds->currentplane, y, (ds->xoffs + ds->planeripple.xfrac), (ds->yoffs + ds->planeripple.yfrac)); + + ds->bgofs >>= FRACBITS; + + if ((y + ds->bgofs) >= viewheight) + ds->bgofs = viewheight-y-1; + if ((y + ds->bgofs) < 0) + ds->bgofs = -y; + } + + if (ds->currentplane->extra_colormap) + ds->colormap = ds->currentplane->extra_colormap->colormap; + else + ds->colormap = colormaps; + + if (encoremap && !ds->currentplane->noencore) + { + ds->colormap += COLORMAP_REMAPOFFSET; + } + + ds->y = y; + ds->x1 = x1; + ds->x2 = x2; + + localspanfunc(ds); +} + +void R_ClearFFloorClips(void) +{ + INT32 p; + + // opening / clipping determination + for (p = 0; p < MAXFFLOORS; p++) + { + visffloor_t *fffloor = &ffloor[p]; + std::fill(fffloor->f_clip, fffloor->f_clip + viewwidth, static_cast(viewheight)); + std::fill(fffloor->c_clip, fffloor->c_clip + viewwidth, static_cast(-1)); + } + + numffloors = 0; +} + +// +// R_ClearPlanes +// At begining of frame. +// +void R_ClearPlanes(void) +{ + INT32 i; + angle_t angle; + + // opening / clipping determination + std::fill(floorclip, floorclip + viewwidth, static_cast(viewheight)); + std::fill(ceilingclip, ceilingclip + viewwidth, static_cast(-1)); + std::fill(frontscale, frontscale + viewwidth, INT32_MAX); + + R_ClearFFloorClips(); + + for (i = 0; i < MAXVISPLANES; i++) + for (*freehead = visplanes[i], visplanes[i] = NULL; + freehead && *freehead ;) + { + freehead = &(*freehead)->next; + } + + lastopening = openings; + + // left to right mapping + angle = (viewangle-ANGLE_90)>>ANGLETOFINESHIFT; + + // scale will be unit scale at SCREENWIDTH/2 distance + basexscale = FixedDiv (FINECOSINE(angle), centerxfrac); + baseyscale = -FixedDiv (FINESINE(angle), centerxfrac); +} + +static visplane_t *new_visplane(unsigned hash) +{ + visplane_t *check = freetail; + + if (!check) + { + check = static_cast(calloc(1, sizeof (*check))); + if (check == NULL) + I_Error("new_visplane: Out of memory"); + check->top_memory = static_cast(Z_Malloc(sizeof(UINT16) * (viewwidth + 2), PU_STATIC, NULL)); + check->bottom_memory = static_cast(Z_Malloc(sizeof(UINT16) * (viewwidth + 2), PU_STATIC, NULL)); + check->top = check->top_memory + 1; + check->bottom = check->bottom_memory + 1; + } + else + { + freetail = freetail->next; + if (!freetail) + freehead = &freetail; + } + + check->next = visplanes[hash]; + visplanes[hash] = check; + + return check; +} + +// +// R_FindPlane: Seek a visplane having the identical values: +// Same height, same flattexture, same lightlevel. +// If not, allocates another of them. +// +visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, + fixed_t xoff, fixed_t yoff, angle_t plangle, extracolormap_t *planecolormap + , ffloor_t *pfloor + , polyobj_t *polyobj + , pslope_t *slope + , boolean noencore + , boolean reverseLight, const sector_t *lighting_sector) +{ + visplane_t *check; + unsigned hash; + + if (!slope) // Don't mess with this right now if a slope is involved + { + if (plangle != 0) + { + // Must use 64-bit math to avoid an overflow! + INT64 vx = xoff + viewx; + INT64 vy = yoff - viewy; + + // Add the view offset, rotated by the plane angle. + float ang = ANG2RAD(plangle); + float x = vx / (float)FRACUNIT; + float y = vy / (float)FRACUNIT; + + vx = (x * cos(ang) + y * sin(ang)) * FRACUNIT; + vy = (-x * sin(ang) + y * cos(ang)) * FRACUNIT; + + xoff = vx; + yoff = vy; + } + else + { + xoff += viewx; + yoff -= viewy; + } + } + + if (polyobj) + { + if (polyobj->angle != 0) + { + float ang = ANG2RAD(polyobj->angle); + float x = FixedToFloat(polyobj->centerPt.x); + float y = FixedToFloat(polyobj->centerPt.y); + xoff -= FloatToFixed(x * cos(ang) + y * sin(ang)); + yoff -= FloatToFixed(x * sin(ang) - y * cos(ang)); + } + else + { + xoff -= polyobj->centerPt.x; + yoff += polyobj->centerPt.y; + } + } + + // This appears to fix the Nimbus Ruins sky bug. + if (picnum == skyflatnum && pfloor) + { + height = 0; // all skies map together + lightlevel = 0; + } + else if (slope != NULL && P_ApplyLightOffset(lightlevel >> LIGHTSEGSHIFT, lighting_sector)) + { + if (reverseLight) + { + lightlevel -= slope->lightOffset * 8; + } + else + { + lightlevel += slope->lightOffset * 8; + } + } + + if (!pfloor) + { + hash = visplane_hash(picnum, lightlevel, height); + + for (check = visplanes[hash]; check; check = check->next) + { + if (polyobj != check->polyobj) + continue; + + if (height == check->height && picnum == check->picnum + && lightlevel == check->lightlevel + && xoff == check->xoffs && yoff == check->yoffs + && planecolormap == check->extra_colormap + && check->viewx == viewx && check->viewy == viewy && check->viewz == viewz + && check->viewangle == viewangle + && check->plangle == plangle + && check->slope == slope + && check->noencore == noencore) + { + return check; + } + } + } + else + { + hash = MAXVISPLANES - 1; + } + + check = new_visplane(hash); + + check->height = height; + check->picnum = picnum; + check->lightlevel = lightlevel; + check->minx = vid.width; + check->maxx = -1; + check->xoffs = xoff; + check->yoffs = yoff; + check->extra_colormap = planecolormap; + check->ffloor = pfloor; + check->viewx = viewx; + check->viewy = viewy; + check->viewz = viewz; + check->viewangle = viewangle; + check->plangle = plangle; + check->polyobj = polyobj; + check->slope = slope; + check->noencore = noencore; + check->cyan = levelflats[picnum].cyan; + + memset(check->top, 0xff, sizeof(*check->top) * viewwidth); + memset(check->bottom, 0x00, sizeof(*check->bottom) * viewwidth); + + return check; +} + +// +// R_CheckPlane: return same visplane or alloc a new one if needed +// +visplane_t *R_CheckPlane(visplane_t *pl, INT32 start, INT32 stop) +{ + INT32 intrl, intrh; + INT32 unionl, unionh; + INT32 x; + + if (start < pl->minx) + { + intrl = pl->minx; + unionl = start; + } + else + { + unionl = pl->minx; + intrl = start; + } + + if (stop > pl->maxx) + { + intrh = pl->maxx; + unionh = stop; + } + else + { + unionh = pl->maxx; + intrh = stop; + } + + // 0xff is not equal to -1 with shorts... + for (x = intrl; x <= intrh; x++) + if (pl->top[x] != 0xffff || pl->bottom[x] != 0x0000) + break; + + if (x > intrh) /* Can use existing plane; extend range */ + { + pl->minx = unionl; + pl->maxx = unionh; + } + else /* Cannot use existing plane; create a new one */ + { + visplane_t *new_pl; + + if (pl->ffloor) + { + new_pl = new_visplane(MAXVISPLANES - 1); + } + else + { + unsigned hash = visplane_hash(pl->picnum, pl->lightlevel, pl->height); + new_pl = new_visplane(hash); + } + + new_pl->height = pl->height; + new_pl->picnum = pl->picnum; + new_pl->lightlevel = pl->lightlevel; + new_pl->xoffs = pl->xoffs; + new_pl->yoffs = pl->yoffs; + new_pl->extra_colormap = pl->extra_colormap; + new_pl->ffloor = pl->ffloor; + new_pl->viewx = pl->viewx; + new_pl->viewy = pl->viewy; + new_pl->viewz = pl->viewz; + new_pl->viewangle = pl->viewangle; + new_pl->plangle = pl->plangle; + new_pl->polyobj = pl->polyobj; + new_pl->slope = pl->slope; + new_pl->noencore = pl->noencore; + new_pl->cyan = pl->cyan; + pl = new_pl; + pl->minx = start; + pl->maxx = stop; + memset(pl->top, 0xff, sizeof(*pl->top) * viewwidth); + memset(pl->bottom, 0x00, sizeof(*pl->bottom) * viewwidth); + } + return pl; +} + + +// +// R_ExpandPlane +// +// This function basically expands the visplane. +// The reason for this is that when creating 3D floor planes, there is no +// need to create new ones with R_CheckPlane, because 3D floor planes +// are created by subsector and there is no way a subsector can graphically +// overlap. +void R_ExpandPlane(visplane_t *pl, INT32 start, INT32 stop) +{ + // Don't expand polyobject planes here - we do that on our own. + if (pl->polyobj) + return; + + if (pl->minx > start) pl->minx = start; + if (pl->maxx < stop) pl->maxx = stop; +} + +// +// R_MakeSpans +// +static void R_MakeSpans(void (*mapfunc)(drawspandata_t* ds, void(*spanfunc)(drawspandata_t*), INT32, INT32, INT32, boolean), spandrawfunc_t* localspanfunc, drawspandata_t* ds, INT32 x, INT32 t1, INT32 b1, INT32 t2, INT32 b2, boolean allow_parallel) +{ + const INT32 vidheight = vid.height; + + // Alam: from r_splats's R_RenderFloorSplat + if (t1 >= vidheight) t1 = vidheight-1; + if (b1 >= vidheight) b1 = vidheight-1; + if (t2 >= vidheight) t2 = vidheight-1; + if (b2 >= vidheight) b2 = vidheight-1; + if (x-1 >= vid.width) x = vid.width; + + drawspandata_t dc_copy = *ds; + +#ifdef HAVE_THREADS + // We want to draw N spans per subtask to ensure the work is + // coarse enough to not be too slow due to task scheduling overhead. + // To safely do this, we need to copy part of spanstart to a local. + // This is essentially loop unrolling across threads. + constexpr const int kSpanTaskGranularity = 8; + while (t1 < t2 && t1 <= b1) + { + INT32 spanstartcopy[kSpanTaskGranularity] = {0}; + INT32 taskspans = 0; + for (int i = 0; i < kSpanTaskGranularity; i++) + { + if (!((t1 + i) < t2 && (t1 + i) <= b1)) + { + break; + } + spanstartcopy[i] = spanstart[t1 + i]; + taskspans += 1; + } + auto task = [=]() mutable -> void { + for (int i = 0; i < taskspans; i++) + { + mapfunc(&dc_copy, localspanfunc, t1 + i, spanstartcopy[i], x - 1, false); + } + }; + if (allow_parallel) + { + srb2::g_main_threadpool->schedule(std::move(task)); + } + else + { + (task)(); + } + t1 += taskspans; + } + while (b1 > b2 && b1 >= t1) + { + INT32 spanstartcopy[kSpanTaskGranularity] = {0}; + INT32 taskspans = 0; + for (int i = 0; i < kSpanTaskGranularity; i++) + { + if (!((b1 - i) > b2 && (b1 - i) >= t1)) + { + break; + } + spanstartcopy[i] = spanstart[b1 - i]; + taskspans += 1; + } + auto task = [=]() mutable -> void { + for (int i = 0; i < taskspans; i++) + { + mapfunc(&dc_copy, localspanfunc, b1 - i, spanstartcopy[i], x - 1, false); + } + }; + if (allow_parallel) + { + srb2::g_main_threadpool->schedule(std::move(task)); + } + else + { + (task)(); + } + b1 -= taskspans; + } +#else + (void)allow_parallel; + + while (t1 < t2 && t1 <= b1) + { + mapfunc(&dc_copy, localspanfunc, t1, spanstart[t1], x - 1, false); + t1++; + } + while (b1 > b2 && b1 >= t1) + { + mapfunc(&dc_copy, localspanfunc, b1, spanstart[b1], x - 1, false); + b1--; + } +#endif + + while (t2 < t1 && t2 <= b2) + spanstart[t2++] = x; + while (b2 > b1 && b2 >= t2) + spanstart[b2--] = x; +} + +void R_DrawPlanes(void) +{ + visplane_t *pl; + INT32 i; + drawspandata_t ds = {}; +#ifdef HAVE_THREADS + srb2::ThreadPool::Sema tp_sema; +#endif + + R_UpdatePlaneRipple(&ds); + +#ifdef HAVE_THREADS + srb2::g_main_threadpool->begin_sema(); +#endif + for (i = 0; i < MAXVISPLANES; i++, pl++) + { + for (pl = visplanes[i]; pl; pl = pl->next) + { + if (pl->ffloor != NULL || pl->polyobj != NULL) + continue; + + R_DrawSinglePlane(&ds, pl, cv_parallelsoftware.value); + } + } +#ifdef HAVE_THREADS + tp_sema = srb2::g_main_threadpool->end_sema(); + srb2::g_main_threadpool->notify_sema(tp_sema); + srb2::g_main_threadpool->wait_sema(tp_sema); +#endif +} + +static void R_DrawSkyPlane(visplane_t *pl, void(*colfunc2)(drawcolumndata_t*), boolean allow_parallel); + +void R_DrawSkyPlanes(void) +{ + visplane_t *pl; + INT32 i; + +#ifdef HAVE_THREADS + srb2::ThreadPool::Sema tp_sema; + srb2::g_main_threadpool->begin_sema(); +#endif + for (i = 0; i < MAXVISPLANES; i++, pl++) + { + for (pl = visplanes[i]; pl; pl = pl->next) + { + if (pl->picnum != skyflatnum || pl->ffloor || pl->polyobj) + continue; + + R_DrawSkyPlane(pl, colfunc, cv_parallelsoftware.value); + } + } +#ifdef HAVE_THREADS + tp_sema = srb2::g_main_threadpool->end_sema(); + srb2::g_main_threadpool->notify_sema(tp_sema); + srb2::g_main_threadpool->wait_sema(tp_sema); +#endif +} + +static void R_DrawSkyPlane(visplane_t *pl, void(*colfunc2)(drawcolumndata_t*), boolean allow_parallel) +{ + INT32 x; + + if (!(pl->minx <= pl->maxx)) + return; + + // If we're not supposed to draw the sky (e.g. for skyboxes), don't do anything! + // This probably utterly ruins sky rendering for FOFs and polyobjects, unfortunately + if (!newview->sky) + { + return; + } + + drawcolumndata_t dc = {}; + + // Reset column drawer function (note: couldn't we just call walldrawerfunc directly?) + // (that is, unless we'll need to switch drawers in future for some reason) + R_SetColumnFunc(BASEDRAWFUNC); + + // use correct aspect ratio scale + dc.iscale = skyscale; + + // Sky is always drawn full bright, + // i.e. colormaps[0] is used. + // Because of this hack, sky is not affected + // by INVUL inverse mapping. + dc.colormap = colormaps; + + if (encoremap) + dc.colormap += COLORMAP_REMAPOFFSET; + + dc.texturemid = skytexturemid; + dc.texheight = textureheight[skytexture] >>FRACBITS; + dc.sourcelength = dc.texheight; + + x = pl->minx; + + // Precache the texture so we don't corrupt the zoned heap off-main thread + if (!texturecache[texturetranslation[skytexture]]) + { + R_GenerateTexture(texturetranslation[skytexture]); + } + +#ifdef HAVE_THREADS + while (x <= pl->maxx) + { + // Tune concurrency granularity here to maximize throughput + // The cheaper colfunc is, the more coarse the task should be + constexpr const int kSkyPlaneMacroColumns = 8; + + auto thunk = [=]() mutable -> void { + for (int i = 0; i < kSkyPlaneMacroColumns && i + x <= pl->maxx; i++) + { + dc.yl = pl->top[x + i]; + dc.yh = pl->bottom[x + i]; + + if (dc.yl > dc.yh) + { + continue; + } + + INT32 angle = (pl->viewangle + xtoviewangle[x + i])>>ANGLETOSKYSHIFT; + angle -= (skytextureoffset >> FRACBITS); + + dc.iscale = FixedMul(skyscale, FINECOSINE(xtoviewangle[x + i]>>ANGLETOFINESHIFT)); + dc.x = x + i; + dc.source = + R_GetColumn(texturetranslation[skytexture], + -angle); // get negative of angle for each column to display sky correct way round! --Monster Iestyn 27/01/18 + + colfunc2(&dc); + } + }; + + if (allow_parallel) + { + srb2::g_main_threadpool->schedule(std::move(thunk)); + } + else + { + (thunk)(); + } + + x += kSkyPlaneMacroColumns; + } +#else + (void)allow_parallel; + + for (x = pl->minx; x <= pl->maxx; x++) + { + dc.yl = pl->top[x]; + dc.yh = pl->bottom[x]; + + if (dc.yl > dc.yh) + { + continue; + } + + INT32 angle = (pl->viewangle + xtoviewangle[x])>>ANGLETOSKYSHIFT; + angle -= (skytextureoffset >> FRACBITS); + + dc.iscale = FixedMul(skyscale, FINECOSINE(xtoviewangle[x]>>ANGLETOFINESHIFT)); + dc.x = x; + dc.source = + R_GetColumn(texturetranslation[skytexture], + -angle); // get negative of angle for each column to display sky correct way round! --Monster Iestyn 27/01/18 + + colfunc2(&dc); + } +#endif +} + +// Returns the height of the sloped plane at (x, y) as a 32.16 fixed_t +static INT64 R_GetSlopeZAt(const pslope_t *slope, fixed_t x, fixed_t y) +{ + INT64 x64 = ((INT64)x - (INT64)slope->o.x); + INT64 y64 = ((INT64)y - (INT64)slope->o.y); + + x64 = (x64 * (INT64)slope->d.x) / FRACUNIT; + y64 = (y64 * (INT64)slope->d.y) / FRACUNIT; + + return (INT64)slope->o.z + ((x64 + y64) * (INT64)slope->zdelta) / FRACUNIT; +} + +// Sets the texture origin vector of the sloped plane. +static void R_SetSlopePlaneOrigin(drawspandata_t *ds, pslope_t *slope, fixed_t xpos, fixed_t ypos, fixed_t zpos, fixed_t xoff, fixed_t yoff, fixed_t angle) +{ + floatv3_t *p = &ds->slope_origin; + + INT64 vx = (INT64)xpos + (INT64)xoff; + INT64 vy = (INT64)ypos - (INT64)yoff; + + float vxf = vx / (float)FRACUNIT; + float vyf = vy / (float)FRACUNIT; + float ang = ANG2RAD(ANGLE_270 - angle); + + // p is the texture origin in view space + // Don't add in the offsets at this stage, because doing so can result in + // errors if the flat is rotated. + p->x = vxf * cos(ang) - vyf * sin(ang); + p->z = vxf * sin(ang) + vyf * cos(ang); + p->y = (R_GetSlopeZAt(slope, -xoff, yoff) - zpos) / (float)FRACUNIT; +} + +// This function calculates all of the vectors necessary for drawing a sloped plane. +static void R_SetSlopePlane(drawspandata_t* ds, pslope_t *slope, fixed_t xpos, fixed_t ypos, fixed_t zpos, fixed_t xoff, fixed_t yoff, angle_t angle, angle_t plangle) +{ + // Potentially override other stuff for now cus we're mean. :< But draw a slope plane! + // I copied ZDoom's code and adapted it to SRB2... -Red + floatv3_t *m = &ds->slope_v, *n = &ds->slope_u; + fixed_t height, temp; + float ang; + + R_SetSlopePlaneOrigin(ds, slope, xpos, ypos, zpos, xoff, yoff, angle); + height = P_GetSlopeZAt(slope, xpos, ypos); + ds->zeroheight = FixedToFloat(height - zpos); + + // m is the v direction vector in view space + ang = ANG2RAD(ANGLE_180 - (angle + plangle)); + m->x = cos(ang); + m->z = sin(ang); + + // n is the u direction vector in view space + n->x = sin(ang); + n->z = -cos(ang); + + plangle >>= ANGLETOFINESHIFT; + temp = P_GetSlopeZAt(slope, xpos + FINESINE(plangle), ypos + FINECOSINE(plangle)); + m->y = FixedToFloat(temp - height); + temp = P_GetSlopeZAt(slope, xpos + FINECOSINE(plangle), ypos - FINESINE(plangle)); + n->y = FixedToFloat(temp - height); +} + +static void R_CalculateSlopeVectors(drawspandata_t* ds) +{ + float sfmult = 65536.f; + + // Eh. I tried making this stuff fixed-point and it exploded on me. Here's a macro for the only floating-point vector function I recall using. +#define CROSS(d, v1, v2) \ +d.x = (v1.y * v2.z) - (v1.z * v2.y);\ +d.y = (v1.z * v2.x) - (v1.x * v2.z);\ +d.z = (v1.x * v2.y) - (v1.y * v2.x) + CROSS(ds->sup, ds->slope_origin, ds->slope_v); + CROSS(ds->svp, ds->slope_origin, ds->slope_u); + CROSS(ds->szp, ds->slope_v, ds->slope_u); +#undef CROSS + + ds->sup.z *= focallengthf; + ds->svp.z *= focallengthf; + ds->szp.z *= focallengthf; + + // Premultiply the texture vectors with the scale factors + sfmult *= (1 << ds->nflatshiftup); + + ds->sup.x *= sfmult; + ds->sup.y *= sfmult; + ds->sup.z *= sfmult; + ds->svp.x *= sfmult; + ds->svp.y *= sfmult; + ds->svp.z *= sfmult; +} + +void R_SetTiltedSpan(drawspandata_t* ds, INT32 span) +{ + if (ds_su == NULL) + ds_su = static_cast(Z_Calloc(sizeof(*ds_su) * vid.height, PU_STATIC, NULL)); + if (ds_sv == NULL) + ds_sv = static_cast(Z_Calloc(sizeof(*ds_sv) * vid.height, PU_STATIC, NULL)); + if (ds_sz == NULL) + ds_sz = static_cast(Z_Calloc(sizeof(*ds_sz) * vid.height, PU_STATIC, NULL)); + + ds->sup = ds_su[span]; + ds->svp = ds_sv[span]; + ds->szp = ds_sz[span]; +} + +static void R_SetSlopePlaneVectors(drawspandata_t* ds, visplane_t *pl, INT32 y, fixed_t xoff, fixed_t yoff) +{ + R_SetTiltedSpan(ds, y); + R_SetSlopePlane(ds, pl->slope, pl->viewx, pl->viewy, pl->viewz, xoff, yoff, pl->viewangle, pl->plangle); + R_CalculateSlopeVectors(ds); +} + +static inline void R_AdjustSlopeCoordinates(drawspandata_t* ds, vector3_t *origin) +{ + const fixed_t modmask = ((1 << (32-ds->nflatshiftup)) - 1); + + const fixed_t ox = (origin->x & modmask); + const fixed_t oy = -(origin->y & modmask); + + ds->xoffs &= modmask; + ds->yoffs &= modmask; + + ds->xoffs -= (origin->x - ox); + ds->yoffs += (origin->y + oy); +} + +void R_DrawSinglePlane(drawspandata_t* ds, visplane_t *pl, boolean allow_parallel) +{ + INT32 light = 0; + INT32 x; + INT32 stop; + size_t size; + INT32 spanfunctype = BASEDRAWFUNC; + ffloor_t *rover; + void (*mapfunc)(drawspandata_t*, void(*)(drawspandata_t*), INT32, INT32, INT32, boolean) = R_MapPlane; + + if (!(pl->minx <= pl->maxx)) + return; + + R_UpdatePlaneRipple(ds); + + // sky flat + if (pl->picnum == skyflatnum) + { + // horrific + if (!newview->sky) + { + skyVisible = true; + } + + return; + } + + ds->planeripple.active = false; + R_SetSpanFunc(BASEDRAWFUNC); + + if (pl->polyobj && pl->polyobj->translucency != 0) + { + spanfunctype = SPANDRAWFUNC_TRANS; + + // Hacked up support for alpha value in software mode Tails 09-24-2002 (sidenote: ported to polys 10-15-2014, there was no time travel involved -Red) + if (pl->polyobj->translucency >= NUMTRANSMAPS) + return; // Don't even draw it + else if (pl->polyobj->translucency > 0) + ds->transmap = R_GetTranslucencyTable(pl->polyobj->translucency); + else // Opaque, but allow transparent flat pixels + spanfunctype = SPANDRAWFUNC_SPLAT; + +#ifdef SHITPLANESPARENCY + if (spanfunc == spanfuncs[SPANDRAWFUNC_SPLAT] || (pl->extra_colormap && pl->extra_colormap->fog)) +#else + if (!pl->extra_colormap || !(pl->extra_colormap->fog & 2)) +#endif + light = (pl->lightlevel >> LIGHTSEGSHIFT); + else + light = LIGHTLEVELS-1; + } + else + { + if (pl->ffloor) + { + // Don't draw planes that shouldn't be drawn. + for (rover = pl->ffloor->target->ffloors; rover; rover = rover->next) + { + if ((pl->ffloor->flags & FF_CUTEXTRA) && (rover->flags & FF_EXTRA)) + { + if (!(rover->flags & FF_EXTRA)) + continue; + + // The plane is from an extra 3D floor... Check the flags so + // there are no undesired cuts. + if (((pl->ffloor->flags & (FF_FOG|FF_SWIMMABLE)) == (rover->flags & (FF_FOG|FF_SWIMMABLE))) + && pl->height < *rover->topheight + && pl->height > *rover->bottomheight) + return; + } + } + + if (cv_softcyancut.value && pl->cyan && !(pl->ffloor->flags & FF_RIPPLE)) + spanfunctype = SPANDRAWFUNC_SPLAT; + + if (pl->ffloor->flags & FF_TRANSLUCENT) + { + spanfunctype = SPANDRAWFUNC_TRANS; + + // Hacked up support for alpha value in software mode Tails 09-24-2002 + // ...unhacked by toaster 04-01-2021, re-hacked a little by sphere 19-11-2021 + // and mercilessly shoved into saturn by chearii 02-02-2025 + { + INT32 trans = (10*((256+12) - pl->ffloor->alpha))/255; + + if (trans >= 10) + return; // Don't even draw it + + if (pl->ffloor->blend) // additive, (reverse) subtractive, modulative + ds->transmap = R_GetBlendTable(pl->ffloor->blend, trans); + else if (!(ds->transmap = R_GetTranslucencyTable(trans)) || trans == 0) + spanfunctype = SPANDRAWFUNC_SPLAT; // Opaque, but allow transparent flat pixels + } + +#ifdef SHITPLANESPARENCY + if (spanfunc == spanfuncs[SPANDRAWFUNC_SPLAT] || (pl->extra_colormap && pl->extra_colormap->fog)) +#else + if (!pl->extra_colormap || !(pl->extra_colormap->fog & 2)) +#endif + light = (pl->lightlevel >> LIGHTSEGSHIFT); + else + light = LIGHTLEVELS-1; + } + else if (pl->ffloor->flags & FF_FOG) + { + spanfunctype = SPANDRAWFUNC_FOG; + light = (pl->lightlevel >> LIGHTSEGSHIFT); + } + else light = (pl->lightlevel >> LIGHTSEGSHIFT); + + if (pl->ffloor->flags & FF_RIPPLE && cv_ripplewater.value) + { + INT32 top, bottom; + + ds->planeripple.active = true; + + if (spanfunctype == SPANDRAWFUNC_TRANS) + { + spanfunctype = SPANDRAWFUNC_WATER; + + // Copy the current scene, ugh + top = std::max(0, pl->high - 8); + bottom = std::min(viewheight, pl->low + 8); + + // Only copy the part of the screen we need + UINT8 i = R_GetViewNumber(); + INT32 scrx = 0; + INT32 scry = top; + INT32 offset; + + if (splitscreen == 1) + { + if (i & 1) + { + scry += viewheight; + } + } + else + { + if (i & 1) + { + scrx += viewwidth; + } + + if (i / 2) + { + scry += viewheight; + } + } + + offset = (scry*vid.width) + scrx; + + // No idea if this works + VID_BlitLinearScreen(renderscreen + offset, + vid.screens[1] + (top*vid.width), // intentionally not +offset + viewwidth, bottom-top, + vid.width, vid.width); + } + } + } + else light = (pl->lightlevel >> LIGHTSEGSHIFT); + } + + // Don't mess with angle on slopes! We'll handle this ourselves later + if (!pl->slope && viewangle != pl->viewangle+pl->plangle) + { + viewangle = pl->viewangle+pl->plangle; + } + + ds->currentplane = pl; + + ds->source = (UINT8 *)W_CacheLumpNum(levelflats[pl->picnum].lumpnum, PU_STATIC); // Stay here until Z_ChangeTag + size = W_LumpLength(levelflats[pl->picnum].lumpnum); + + switch (size) + { + case 4194304: // 2048x2048 lump + ds->nflatmask = 0x3FF800; + ds->nflatxshift = 21; + ds->nflatyshift = 10; + ds->nflatshiftup = 5; + break; + case 1048576: // 1024x1024 lump + ds->nflatmask = 0xFFC00; + ds->nflatxshift = 22; + ds->nflatyshift = 12; + ds->nflatshiftup = 6; + break; + case 262144:// 512x512 lump' + ds->nflatmask = 0x3FE00; + ds->nflatxshift = 23; + ds->nflatyshift = 14; + ds->nflatshiftup = 7; + break; + case 65536: // 256x256 lump + ds->nflatmask = 0xFF00; + ds->nflatxshift = 24; + ds->nflatyshift = 16; + ds->nflatshiftup = 8; + break; + case 16384: // 128x128 lump + ds->nflatmask = 0x3F80; + ds->nflatxshift = 25; + ds->nflatyshift = 18; + ds->nflatshiftup = 9; + break; + case 1024: // 32x32 lump + ds->nflatmask = 0x3E0; + ds->nflatxshift = 27; + ds->nflatyshift = 22; + ds->nflatshiftup = 11; + break; + default: // 64x64 lump + ds->nflatmask = 0xFC0; + ds->nflatxshift = 26; + ds->nflatyshift = 20; + ds->nflatshiftup = 10; + break; + } + + ds->xoffs = pl->xoffs; + ds->yoffs = pl->yoffs; + + if (light >= LIGHTLEVELS) + light = LIGHTLEVELS-1; + + if (light < 0) + light = 0; + + if (pl->slope) + { + mapfunc = R_MapTiltedPlane; + + if (!pl->plangle) + { + R_AdjustSlopeCoordinates(ds, &pl->slope->o); + } + + if (ds->planeripple.active) + { + ds->planeheight = abs(P_GetSlopeZAt(pl->slope, pl->viewx, pl->viewy) - pl->viewz); + + R_PlaneBounds(pl); + + for (x = pl->high; x < pl->low; x++) + { + ds->bgofs = R_CalculateRippleOffset(ds, x); + R_CalculatePlaneRipple(ds, pl->viewangle + pl->plangle); + R_SetSlopePlaneVectors(ds, pl, x, (ds->xoffs + ds->planeripple.xfrac), (ds->yoffs + ds->planeripple.yfrac)); + } + } + else + R_SetSlopePlaneVectors(ds, pl, 0, ds->xoffs, ds->yoffs); + + switch (spanfunctype) + { + case SPANDRAWFUNC_WATER: + spanfunctype = SPANDRAWFUNC_TILTEDWATER; + break; + case SPANDRAWFUNC_TRANS: + spanfunctype = SPANDRAWFUNC_TILTEDTRANS; + break; + case SPANDRAWFUNC_SPLAT: + spanfunctype = SPANDRAWFUNC_TILTEDSPLAT; + break; + case SPANDRAWFUNC_TRANSSPLAT: + spanfunctype = SPANDRAWFUNC_TILTEDTRANSSPLAT; + break; + case SPANDRAWFUNC_FOG: + spanfunctype = SPANDRAWFUNC_TILTEDFOG; + break; + default: + spanfunctype = SPANDRAWFUNC_TILTED; + break; + } + + ds->planezlight = scalelight[light]; + } + else + { + ds->planeheight = abs(pl->height - pl->viewz); + ds->planezlight = zlight[light]; + } + + R_SetSpanFunc(spanfunctype); + + // set the maximum value for unsigned + pl->top[pl->maxx+1] = 0xffff; + pl->top[pl->minx-1] = 0xffff; + pl->bottom[pl->maxx+1] = 0x0000; + pl->bottom[pl->minx-1] = 0x0000; + + stop = pl->maxx + 1; + + for (x = pl->minx; x <= stop; x++) + { + R_MakeSpans(mapfunc, spanfunc, ds, x, pl->top[x-1], pl->bottom[x-1], pl->top[x], pl->bottom[x], allow_parallel); + } + +/* +QUINCUNX anti-aliasing technique (sort of) + +Normally, Quincunx antialiasing staggers pixels +in a 5-die pattern like so: + +o o + o +o o + +To simulate this, we offset the plane by +FRACUNIT/4 in each direction, and draw +at 50% translucency. The result is +a 'smoothing' of the texture while +using the palette colors. +*/ +#ifdef QUINCUNX + if (spanfunc == spanfuncs[BASEDRAWFUNC]) + { + INT32 i; + + ds->transmap = R_GetTranslucencyTable(tr_trans50); + + R_SetSpanFunc(SPANDRAWFUNC_TRANS); + + for (i = 0; i < 4; i++) + { + ds->xoffs = pl->xoffs; + ds->yoffs = pl->yoffs; + + switch(i) + { + case 0: + ds->xoffs -= FRACUNIT/4; + ds->yoffs -= FRACUNIT/4; + break; + case 1: + ds->xoffs -= FRACUNIT/4; + ds->yoffs += FRACUNIT/4; + break; + case 2: + ds->xoffs += FRACUNIT/4; + ds->yoffs -= FRACUNIT/4; + break; + case 3: + ds->xoffs += FRACUNIT/4; + ds->yoffs += FRACUNIT/4; + break; + } + ds->planeheight = abs(pl->height - pl->viewz); + + if (light >= LIGHTLEVELS) + light = LIGHTLEVELS-1; + + if (light < 0) + light = 0; + + ds->planezlight = zlight[light]; + + // set the maximum value for unsigned + pl->top[pl->maxx+1] = 0xffff; + pl->top[pl->minx-1] = 0xffff; + pl->bottom[pl->maxx+1] = 0x0000; + pl->bottom[pl->minx-1] = 0x0000; + + stop = pl->maxx + 1; + + for (x = pl->minx; x <= stop; x++) + R_MakeSpans(x, pl->top[x-1], pl->bottom[x-1], + pl->top[x], pl->bottom[x]); + } + } +#endif + + Z_ChangeTag(ds->source, PU_CACHE); +} + +void R_PlaneBounds(visplane_t *plane) +{ + INT32 i; + INT32 hi, low; + + hi = plane->top[plane->minx]; + low = plane->bottom[plane->minx]; + + for (i = plane->minx + 1; i <= plane->maxx; i++) + { + if (plane->top[i] < hi) + hi = plane->top[i]; + if (plane->bottom[i] > low) + low = plane->bottom[i]; + } + plane->high = hi; + plane->low = low; +} diff --git a/src/r_plane.h b/src/r_plane.h index 5f0db2c7c..f330baa3d 100644 --- a/src/r_plane.h +++ b/src/r_plane.h @@ -14,6 +14,10 @@ #ifndef __R_PLANE__ #define __R_PLANE__ +#ifdef __cplusplus +extern "C" { +#endif + #include "screen.h" // needs MAXVIDWIDTH/MAXVIDHEIGHT #include "r_data.h" #include "p_polyobj.h" @@ -43,9 +47,8 @@ typedef struct visplane_s // colormaps per sector extracolormap_t *extra_colormap; - // leave pads for [minx-1]/[maxx+1] - UINT16 padtopstart, top[MAXVIDWIDTH], padtopend; - UINT16 padbottomstart, bottom[MAXVIDWIDTH], padbottomend; + UINT16 *top, *top_memory; + UINT16 *bottom, *bottom_memory; INT32 high, low; // R_PlaneBounds should set these. fixed_t xoffs, yoffs; // Scrolling flats. @@ -55,8 +58,11 @@ typedef struct visplane_s pslope_t *slope; boolean noencore; + boolean cyan; } visplane_t; +extern visplane_t *visplanes[MAXVISPLANES]; + extern visplane_t *floorplane; extern visplane_t *ceilingplane; @@ -64,25 +70,19 @@ extern visplane_t *ceilingplane; extern INT16 *lastopening, *openings; extern size_t maxopenings; -extern INT16 floorclip[MAXVIDWIDTH], ceilingclip[MAXVIDWIDTH]; -extern fixed_t frontscale[MAXVIDWIDTH], yslopetab[MAXVIDHEIGHT*16]; -extern fixed_t cachedheight[MAXVIDHEIGHT]; -extern fixed_t cacheddistance[MAXVIDHEIGHT]; -extern fixed_t cachedxstep[MAXVIDHEIGHT]; -extern fixed_t cachedystep[MAXVIDHEIGHT]; +extern INT16 *floorclip, *ceilingclip; +extern fixed_t *frontscale, *yslopetab; extern fixed_t basexscale, baseyscale; extern fixed_t *yslope; -extern lighttable_t **planezlight; -void R_InitPlanes(void); +void R_AllocPlaneMemory(void); void R_ClearPlanes(void); void R_ClearFFloorClips (void); -void R_MapPlane(INT32 y, INT32 x1, INT32 x2); -void R_MakeSpans(INT32 x, INT32 t1, INT32 b1, INT32 t2, INT32 b2); +void R_DrawSkyPlanes(void); void R_DrawPlanes(void); -void R_CalculateSlopeVectors(pslope_t *slope, fixed_t planeviewx, fixed_t planeviewy, fixed_t planeviewz, fixed_t planexscale, fixed_t planeyscale, fixed_t planexoffset, fixed_t planeyoffset, angle_t planeviewangle, angle_t planeangle, float fudge); + visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, fixed_t xoff, fixed_t yoff, angle_t plangle, extracolormap_t *planecolormap, ffloor_t *ffloor , polyobj_t *polyobj @@ -93,9 +93,6 @@ visplane_t *R_CheckPlane(visplane_t *pl, INT32 start, INT32 stop); void R_ExpandPlane(visplane_t *pl, INT32 start, INT32 stop); void R_PlaneBounds(visplane_t *plane); -// Draws a single visplane. -void R_DrawSinglePlane(visplane_t *pl); - typedef struct planemgr_s { visplane_t *plane; @@ -104,8 +101,8 @@ typedef struct planemgr_s fixed_t b_pos; // B for Back sector fixed_t f_frac, f_step; fixed_t b_frac, b_step; - INT16 f_clip[MAXVIDWIDTH]; - INT16 c_clip[MAXVIDWIDTH]; + INT16 *f_clip; + INT16 *c_clip; // For slope rendering; the height at the other end fixed_t f_pos_slope; @@ -119,4 +116,9 @@ typedef struct planemgr_s extern visffloor_t ffloor[MAXFFLOORS]; extern INT32 numffloors; + +#ifdef __cplusplus +} // extern "C" +#endif + #endif diff --git a/src/r_portal.c b/src/r_portal.c index afbcd46dd..432e3f50d 100644 --- a/src/r_portal.c +++ b/src/r_portal.c @@ -1,6 +1,6 @@ // SONIC ROBO BLAST 2 KART //----------------------------------------------------------------------------- -// Copyright (C) 2024 by Kart Krew. +// Copyright (C) 2025 by Kart Krew. // Copyright (C) 2020 by Sonic Team Junior. // Copyright (C) 2000 by DooM Legacy Team. // Copyright (C) 1996 by id Software, Inc. @@ -14,7 +14,9 @@ #include "r_portal.h" #include "r_plane.h" -#include "r_main.h" // viewheight, viewwidth +#include "r_main.h" +#include "doomstat.h" +#include "p_spec.h" // Skybox viewpoints #include "z_zone.h" #include "r_things.h" #include "r_sky.h" @@ -36,7 +38,6 @@ void Portal_InitList (void) portal_base = portal_cap = NULL; } - /** Store the clipping window for a portal in its given range. * * The window is copied from the current window at the time @@ -63,7 +64,6 @@ static void Portal_ClipRange (portal_t* portal) } } - /** Apply the clipping window from a portal. */ void Portal_ClipApply (const portal_t* portal) @@ -91,6 +91,7 @@ void Portal_ClipApply (const portal_t* portal) floorclip[i] = -1; ceilingclip[i] = (INT16)viewheight; } + for (i = end; i < vid.width; i++) { floorclip[i] = -1; @@ -119,11 +120,11 @@ static portal_t* Portal_Add (const INT16 x1, const INT16 x2) portal->next = NULL; // Store clipping values so they can be restored once the portal is rendered. - portal->ceilingclip = ceilingclipsave; - portal->floorclip = floorclipsave; - portal->frontscale = frontscalesave; - portal->start = x1; - portal->end = x2; + portal->ceilingclip = ceilingclipsave; + portal->floorclip = floorclipsave; + portal->frontscale = frontscalesave; + portal->start = x1; + portal->end = x2; // Increase recursion level. portal->pass = portalrender+1; @@ -166,6 +167,10 @@ void Portal_Add2Lines (const INT32 line1, const INT32 line2, const INT32 x1, con vertex_t dest_c, start_c; + portal->viewx = viewx; + portal->viewy = viewy; + portal->viewz = viewz; + // looking glass center start_c.x = (start->v1->x + start->v2->x) / 2; start_c.y = (start->v1->y + start->v2->y) / 2; @@ -174,13 +179,24 @@ void Portal_Add2Lines (const INT32 line1, const INT32 line2, const INT32 x1, con dest_c.x = (dest->v1->x + dest->v2->x) / 2; dest_c.y = (dest->v1->y + dest->v2->y) / 2; - disttopoint = R_PointToDist2(start_c.x, start_c.y, viewx, viewy); - angtopoint = R_PointToAngle2(start_c.x, start_c.y, viewx, viewy); - angtopoint += dangle; - - portal->viewx = dest_c.x + FixedMul(FINECOSINE(angtopoint>>ANGLETOFINESHIFT), disttopoint); - portal->viewy = dest_c.y + FixedMul(FINESINE(angtopoint>>ANGLETOFINESHIFT), disttopoint); portal->viewz = viewz + dest->frontsector->floorheight - start->frontsector->floorheight; + + if (dangle == 0) + { + // the entrance goes straight opposite the exit, so we just need to mess with the offset. + portal->viewx += dest_c.x - start_c.x; + portal->viewy += dest_c.y - start_c.y; + } + else + { + disttopoint = R_PointToDist2(start_c.x, start_c.y, viewx, viewy); + angtopoint = R_PointToAngle2(start_c.x, start_c.y, viewx, viewy); + angtopoint += dangle; + + portal->viewx = dest_c.x + FixedMul(FINECOSINE(angtopoint>>ANGLETOFINESHIFT), disttopoint); + portal->viewy = dest_c.y + FixedMul(FINESINE(angtopoint>>ANGLETOFINESHIFT), disttopoint); + } + portal->viewangle = viewangle + dangle; portal->clipline = line2; @@ -190,4 +206,151 @@ void Portal_Add2Lines (const INT32 line1, const INT32 line2, const INT32 x1, con g_portal = portal; // this tells R_StoreWallRange that curline is a portal seg } +/** Store the clipping window for a portal using a visplane. + * + * Since visplanes top/bottom windows work in an identical way, + * it can just be copied almost directly. + */ +static void Portal_ClipVisplane (const visplane_t* plane, portal_t* portal) +{ + INT16 start = portal->start; + INT16 end = portal->end; + INT32 i; + + for (i = 0; i < end - start; i++) + { + // Invalid column. + if (plane->top[i + start] == 65535) + { + portal->ceilingclip[i] = -1; + portal->floorclip[i] = -1; + continue; + } + portal->ceilingclip[i] = plane->top[i + start] - 1; + portal->floorclip[i] = plane->bottom[i + start] + 1; + portal->frontscale[i] = INT32_MAX; + } +} + +extern INT32 viewwidth; + +static boolean TrimVisplaneBounds (const visplane_t* plane, INT16* start, INT16* end) +{ + *start = plane->minx; + *end = plane->maxx + 1; + + // Visplanes have 1-px pads on their sides (extra columns). + // Trim them, else it may render out of bounds. + if (*end > viewwidth) + *end = viewwidth; + + if (!(*start < *end)) + return true; + + + /** Trims a visplane's horizontal gap to match its render area. + * + * Visplanes' minx/maxx may sometimes exceed the area they're + * covering. This merely adjusts the boundaries to the next + * valid area. + */ + + while (plane->bottom[*start] == 0 && plane->top[*start] == 65535 && *start < *end) + { + (*start)++; + } + + + while (plane->bottom[*end - 1] == 0 && plane->top[*start] == 65535 && *end > *start) + { + (*end)--; + } + + return false; +} + +/** Creates a skybox portal out of a visplane. + * + * Applies the necessary offsets and rotation to give + * a depth illusion to the skybox. + */ +void Portal_AddSkybox(const visplane_t* plane) +{ + INT16 start, end; + mapheader_t *mh; + portal_t* portal; + + if (TrimVisplaneBounds(plane, &start, &end)) + return; + + portal = Portal_Add(start, end); + + Portal_ClipVisplane(plane, portal); + + portal->viewx = skyboxmo[0]->x; + portal->viewy = skyboxmo[0]->y; + portal->viewz = skyboxmo[0]->z; + if (skyboxmo[0]->spawnpoint) + portal->viewz = ((fixed_t)skyboxmo[0]->spawnpoint->angle)<viewangle = viewangle + skyboxmo[0]->angle; + + mh = mapheaderinfo[gamemap-1]; + + // If a relative viewpoint exists, offset the viewpoint. + if (skyboxmo[1]) + { + fixed_t x = 0, y = 0; + angle_t ang = skyboxmo[0]->angle>>ANGLETOFINESHIFT; + + if (mh->skybox_scalex > 0) + x = (viewx - skyboxmo[1]->x) / mh->skybox_scalex; + else if (mh->skybox_scalex < 0) + x = (viewx - skyboxmo[1]->x) * -mh->skybox_scalex; + + if (mh->skybox_scaley > 0) + y = (viewy - skyboxmo[1]->y) / mh->skybox_scaley; + else if (mh->skybox_scaley < 0) + y = (viewy - skyboxmo[1]->y) * -mh->skybox_scaley; + + // Apply transform to account for the skybox viewport angle. + portal->viewx += FixedMul(x,FINECOSINE(ang)) - FixedMul(y, FINESINE(ang)); + portal->viewy += FixedMul(x, FINESINE(ang)) + FixedMul(y,FINECOSINE(ang)); + } + + if (mh->skybox_scalez > 0) + portal->viewz += viewz / mh->skybox_scalez; + else if (mh->skybox_scalez < 0) + portal->viewz += viewz * -mh->skybox_scalez; + + portal->clipline = -1; +} + +/** Creates portals for the currently existing sky visplanes. + * The visplanes are also removed and cleared from the list. + */ +void Portal_AddSkyboxPortals(void) +{ + visplane_t *pl; + INT32 i; + UINT16 count = 0; + + for (i = 0; i < MAXVISPLANES; i++, pl++) + { + for (pl = visplanes[i]; pl; pl = pl->next) + { + if (pl->picnum == skyflatnum) + { + Portal_AddSkybox(pl); + + pl->minx = 0; + pl->maxx = -1; + + count++; + } + } + } + + CONS_Debug(DBG_RENDER, "Skybox portals: %d\n", count); +} diff --git a/src/r_portal.h b/src/r_portal.h index c944f46d0..223dd83be 100644 --- a/src/r_portal.h +++ b/src/r_portal.h @@ -14,10 +14,14 @@ #ifndef __R_PORTAL__ #define __R_PORTAL__ +#ifdef __cplusplus +extern "C" { +#endif + #include "r_data.h" +#include "r_plane.h" // visplanes - -/** Portal structure. +/** Portal structure for the software renderer. */ typedef struct portal_s { @@ -54,4 +58,11 @@ void Portal_Add2Lines (const INT32 line1, const INT32 line2, const INT32 x1, con void Portal_ClipApply (const portal_t* portal); +void Portal_AddSkybox(const visplane_t* plane); +void Portal_AddSkyboxPortals(void); + +#ifdef __cplusplus +} // extern "C" +#endif + #endif diff --git a/src/r_segs.c b/src/r_segs.cpp similarity index 62% rename from src/r_segs.c rename to src/r_segs.cpp index f1954f0e7..452d1eb8e 100644 --- a/src/r_segs.c +++ b/src/r_segs.cpp @@ -17,6 +17,7 @@ #include "r_portal.h" #include "r_splats.h" +#include "r_fps.h" // newview #include "w_wad.h" #include "z_zone.h" @@ -26,6 +27,12 @@ #include "p_setup.h" #include "p_slopes.h" #include "console.h" // con_clipviewtop +#include "screen.h" + +#include "core/memory.h" + +#define HEIGHTBITS 12 +#define HEIGHTUNIT (1<topdelta != 0xff ;) - { - // calculate unclipped screen coordinates for post - topdelta = column->topdelta; - if (topdelta <= prevdelta) - topdelta += prevdelta; - prevdelta = topdelta; - topscreen = sprtopscreen + spryscale*topdelta; - bottomscreen = topscreen + spryscale*column->length; - - dc_yl = (topscreen+FRACUNIT-1)>>FRACBITS; - dc_yh = (bottomscreen-1)>>FRACBITS; - - if (dc_yh >= last_floorclip[dc_x]) - dc_yh = last_floorclip[dc_x] - 1; - if (dc_yl <= last_ceilingclip[dc_x]) - dc_yl = last_ceilingclip[dc_x] + 1; - if (dc_yl <= dc_yh && dl_yh < vid.height && yh > 0) - { - dc_source = (UINT8 *)column + 3; - dc_texturemid = basetexturemid - (topdelta<length + 4); - } - - dc_texturemid = basetexturemid; -} - -static void R_DrawWallSplats(void) -{ - wallsplat_t *splat; - seg_t *seg; - angle_t angle, angle1, angle2; - INT32 x1, x2; - size_t pindex; - column_t *col; - patch_t *patch; - fixed_t texturecolumn; - - splat = (wallsplat_t *)linedef->splats; - - I_Assert(splat != NULL); - - seg = ds_p->curline; - - // draw all splats from the line that touches the range of the seg - for (; splat; splat = splat->next) - { - angle1 = R_PointToAngle(splat->v1.x, splat->v1.y); - angle2 = R_PointToAngle(splat->v2.x, splat->v2.y); - angle1 = (angle1 - viewangle + ANGLE_90)>>ANGLETOFINESHIFT; - angle2 = (angle2 - viewangle + ANGLE_90)>>ANGLETOFINESHIFT; - // out of the viewangletox lut - /// \todo clip it to the screen - if (angle1 > FINEANGLES/2 || angle2 > FINEANGLES/2) - continue; - x1 = viewangletox[angle1]; - x2 = viewangletox[angle2]; - - if (x1 >= x2) - continue; // does not cross a pixel - - // splat is not in this seg range - if (x2 < ds_p->x1 || x1 > ds_p->x2) - continue; - - if (x1 < ds_p->x1) - x1 = ds_p->x1; - if (x2 > ds_p->x2) - x2 = ds_p->x2; - if (x2 <= x1) - continue; - - // calculate incremental stepping values for texture edges - rw_scalestep = ds_p->scalestep; - spryscale = ds_p->scale1 + (x1 - ds_p->x1)*rw_scalestep; - mfloorclip = floorclip; - mceilingclip = ceilingclip; - - patch = W_CachePatchNum(splat->patch, PU_SPRITE); - - dc_texturemid = splat->top + (patch->height<<(FRACBITS-1)) - viewz; - if (splat->yoffset) - dc_texturemid += *splat->yoffset; - - sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale); - - // set drawing mode - switch (splat->flags & SPLATDRAWMODE_MASK) - { - case SPLATDRAWMODE_OPAQUE: - colfunc = basecolfunc; - break; - case SPLATDRAWMODE_TRANS: - if (!cv_translucency.value) - colfunc = basecolfunc; - else - { - dc_transmap = R_GetTranslucencyTable(tr_trans50); - colfunc = fuzzcolfunc; - } - - break; - case SPLATDRAWMODE_SHADE: - colfunc = shadecolfunc; - break; - } - - dc_texheight = 0; - - // draw the columns - for (dc_x = x1; dc_x <= x2; dc_x++, spryscale += rw_scalestep) - { - pindex = FixedMul(spryscale, LIGHTRESOLUTIONFIX)>>LIGHTSCALESHIFT; - if (pindex >= MAXLIGHTSCALE) - pindex = MAXLIGHTSCALE - 1; - dc_colormap = walllights[pindex]; - if (encoremap && !(seg->linedef->flags & ML_TFERLINE)) - dc_colormap += COLORMAP_REMAPOFFSET; - - if (frontsector->extra_colormap) - dc_colormap = frontsector->extra_colormap->colormap + (dc_colormap - colormaps); - - sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale); - dc_iscale = 0xffffffffu / (unsigned)spryscale; - - // find column of patch, from perspective - angle = (rw_centerangle + xtoviewangle[dc_x])>>ANGLETOFINESHIFT; - texturecolumn = rw_offset2 - splat->offset - - FixedMul(FINETANGENT(angle), rw_distance); - - // FIXME! - texturecolumn >>= FRACBITS; - if (texturecolumn < 0 || texturecolumn >= patch->width) - continue; - - // draw the texture - col = (column_t *)((UINT8 *)patch->columns + (patch->columnofs[texturecolumn])); - R_DrawSplatColumn(col); - } - } // next splat - - colfunc = basecolfunc; -} - -#endif //WALLSPLATS - // ========================================================================== // R_RenderMaskedSegRange // ========================================================================== @@ -249,164 +91,126 @@ static void R_DrawWallSplats(void) // multi-patch textures. They are not normally needed as multi-patch // textures don't have holes in it. At least not for now. -static void R_Render2sidedMultiPatchColumn(column_t *column) +static void R_Render2sidedMultiPatchColumn(drawcolumndata_t* dc, column_t *column) { INT32 topscreen, bottomscreen; topscreen = sprtopscreen; // + spryscale*column->topdelta; topdelta is 0 for the wall bottomscreen = topscreen + spryscale * lengthcol; - dc_yl = (sprtopscreen+FRACUNIT-1)>>FRACBITS; - dc_yh = (bottomscreen-1)>>FRACBITS; + dc->yl = (sprtopscreen+FRACUNIT-1)>>FRACBITS; + dc->yh = (bottomscreen-1)>>FRACBITS; if (windowtop != INT32_MAX && windowbottom != INT32_MAX) { - dc_yl = ((windowtop + FRACUNIT)>>FRACBITS); - dc_yh = (windowbottom - 1)>>FRACBITS; + dc->yl = ((windowtop + FRACUNIT)>>FRACBITS); + dc->yh = (windowbottom - 1)>>FRACBITS; } - if (dc_yh >= mfloorclip[dc_x]) - dc_yh = mfloorclip[dc_x] - 1; - if (dc_yl <= mceilingclip[dc_x]) - dc_yl = mceilingclip[dc_x] + 1; + if (dc->yh >= mfloorclip[dc->x]) + dc->yh = mfloorclip[dc->x] - 1; + if (dc->yl <= mceilingclip[dc->x]) + dc->yl = mceilingclip[dc->x] + 1; - if (dc_yl >= vid.height || dc_yh < 0) + if (dc->yl >= vid.height || dc->yh < 0) return; - if (dc_yl <= dc_yh && dc_yh < vid.height && dc_yh > 0) + if (dc->yl <= dc->yh && dc->yh < vid.height && dc->yh > 0) { - dc_source = (UINT8 *)column + 3; - dc_sourcelength = lengthcol; + dc->source = (UINT8 *)column + 3; + dc->sourcelength = lengthcol; - if (colfunc == wallcolfunc) - twosmultipatchfunc(); - else if (colfunc == fuzzcolfunc) - twosmultipatchtransfunc(); - else - colfunc(); + // Drawn by R_DrawColumn. + drawcolumndata_t dc_copy = *dc; + coldrawfunc_t* colfunccopy = colfunc; + + // FIXME: do something better to look these up WITHOUT affecting global state... + if (R_CheckColumnFunc(BASEDRAWFUNC) == true) + { + colfunccopy = colfuncs[COLDRAWFUNC_TWOSMULTIPATCH]; + } + else if (R_CheckColumnFunc(COLDRAWFUNC_FUZZY) == true) + { + colfunccopy = colfuncs[COLDRAWFUNC_TWOSMULTIPATCHTRANS]; + } + + colfunccopy(const_cast(&dc_copy)); } } transnum_t R_GetLinedefTransTable(fixed_t alpha) { - return (20*(FRACUNIT - alpha - 1) + FRACUNIT) >> (FRACBITS+1); + return static_cast((20*(FRACUNIT - alpha - 1) + FRACUNIT) >> (FRACBITS+1)); } -void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) +static inline boolean R_OverflowTest(drawcolumndata_t* dc) +{ + INT64 overflow_test; + + overflow_test = (INT64)centeryfrac - (((INT64)dc->texturemid*spryscale)>>FRACBITS); + + if (overflow_test < 0) + overflow_test = -overflow_test; + + if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) + return true; + + return false; +} + +static void R_RenderMaskedSegLoop(drawcolumndata_t* dc, drawseg_t *drawseg, INT32 x1, INT32 x2, INT32 texnum, void (*colfunc_2s)(drawcolumndata_t*, column_t *)) { size_t pindex; column_t *col; - INT32 lightnum, texnum, i; + INT32 lightnum, i; fixed_t height, realbot; lightlist_t *light; r_lightlist_t *rlight; - void (*colfunc_2s)(column_t *); - line_t *ldef; sector_t *front, *back; INT32 times, repeats; - INT64 overflow_test; INT32 range; + line_t *ldef; - // Calculate light table. - // Use different light tables - // for horizontal / vertical / diagonal. Diagonal? - // OPTIMIZE: get rid of LIGHTSEGSHIFT globally - curline = ds->curline; - frontsector = curline->frontsector; - backsector = curline->backsector; - texnum = R_GetTextureNum(curline->sidedef->midtexture); - windowbottom = windowtop = sprbotscreen = INT32_MAX; - - // hack translucent linedef types (900-909 for transtables 1-9) ldef = curline->linedef; - if (!ldef->alpha) - return; - - if (ldef->blendmode) - { - if (ldef->alpha == NUMTRANSMAPS || ldef->blendmode == AST_MODULATE) - dc_transmap = R_GetBlendTable(ldef->blendmode, 0); - else - dc_transmap = R_GetBlendTable(ldef->blendmode, R_GetLinedefTransTable(ldef->alpha)); - colfunc = fuzzcolfunc; - } - else if (ldef->alpha > 0 && ldef->alpha < FRACUNIT) - { - dc_transmap = R_GetTranslucencyTable(R_GetLinedefTransTable(ldef->alpha)); - colfunc = fuzzcolfunc; - } - else if (ldef->special == 909) - { - colfunc = R_DrawFogColumn_8; - windowtop = frontsector->ceilingheight; - windowbottom = frontsector->floorheight; - } - else - { - colfunc = wallcolfunc; - } - - if (curline->polyseg && curline->polyseg->translucency > 0) - { - if (curline->polyseg->translucency >= NUMTRANSMAPS) - return; - - dc_transmap = R_GetTranslucencyTable(curline->polyseg->translucency); - colfunc = fuzzcolfunc; - } - - range = max(ds->x2-ds->x1, 1); - rw_scalestep = ds->scalestep; - spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep; - - // Texture must be cached before setting colfunc_2s, - // otherwise texture[texnum]->holes may be false when it shouldn't be - R_CheckTextureCache(texnum); - // handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures - // are not stored per-column with post info in SRB2 - if (textures[texnum]->holes) - colfunc_2s = R_DrawMaskedColumn; // render the usual 2sided single-patch packed texture - else - { - colfunc_2s = R_Render2sidedMultiPatchColumn; // render multipatch with no holes (no post_t info) - lengthcol = textures[texnum]->height; - } + range = std::max(drawseg->x2-drawseg->x1, 1); // Setup lighting based on the presence/lack-of 3D floors. - dc_numlights = 0; + dc->numlights = 0; + if (frontsector->numlights) { - dc_numlights = frontsector->numlights; - if (dc_numlights >= dc_maxlights) + dc->numlights = frontsector->numlights; + + if (dc->numlights > dc->maxlights) { - dc_maxlights = dc_numlights; - dc_lightlist = Z_Realloc(dc_lightlist, sizeof (*dc_lightlist) * dc_maxlights, PU_STATIC, NULL); + dc->maxlights = dc->numlights; + dc->lightlist = static_cast(Z_Frame_Alloc(sizeof (*dc->lightlist) * dc->maxlights)); } - for (i = 0; i < dc_numlights; i++) + for (i = 0; i < dc->numlights; i++) { fixed_t leftheight, rightheight; light = &frontsector->lightlist[i]; - rlight = &dc_lightlist[i]; + rlight = &dc->lightlist[i]; - leftheight = P_GetLightZAt(light, ds-> leftpos.x, ds-> leftpos.y); - rightheight = P_GetLightZAt(light, ds->rightpos.x, ds->rightpos.y); + leftheight = P_GetLightZAt(light, drawseg-> leftpos.x, drawseg-> leftpos.y); + rightheight = P_GetLightZAt(light, drawseg->rightpos.x, drawseg->rightpos.y); - leftheight -= viewz; + leftheight -= viewz; rightheight -= viewz; - rlight->height = (centeryfrac) - FixedMul(leftheight, ds->scale1); - rlight->heightstep = (centeryfrac) - FixedMul(rightheight, ds->scale2); - rlight->heightstep = (rlight->heightstep-rlight->height)/(range); - rlight->startheight = rlight->height; // keep starting value here to reset for each repeat - rlight->lightlevel = *light->lightlevel; + rlight->height = (centeryfrac) - FixedMul(leftheight, drawseg->scale1); + rlight->heightstep = (centeryfrac) - FixedMul(rightheight, drawseg->scale2); + rlight->heightstep = (rlight->heightstep-rlight->height)/(range); + rlight->startheight = rlight->height; // keep starting value here to reset for each repeat + rlight->lightlevel = *light->lightlevel; rlight->extra_colormap = light->extra_colormap; - rlight->flags = light->flags; + rlight->flags = static_cast(light->flags); if (rlight->flags & FF_FOG || (rlight->extra_colormap && rlight->extra_colormap->fog)) lightnum = (rlight->lightlevel >> LIGHTSEGSHIFT); - else if (colfunc == fuzzcolfunc) + else if (R_CheckColumnFunc(COLDRAWFUNC_FUZZY)) lightnum = LIGHTLEVELS - 1; else lightnum = (rlight->lightlevel >> LIGHTSEGSHIFT); @@ -421,17 +225,13 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) } else { - if (colfunc == fuzzcolfunc) - { - if (frontsector->extra_colormap && frontsector->extra_colormap->fog) - lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT); - else - lightnum = LIGHTLEVELS - 1; - } - else + if ((R_CheckColumnFunc(COLDRAWFUNC_FUZZY) == false) + || (frontsector->extra_colormap && frontsector->extra_colormap->fog)) lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT); + else + lightnum = LIGHTLEVELS - 1; - if (colfunc == R_DrawFogColumn_8 + if ((R_CheckColumnFunc(COLDRAWFUNC_FOG) == true) || (frontsector->extra_colormap && frontsector->extra_colormap->fog)) ; else if (P_ApplyLightOffset(lightnum, frontsector)) @@ -445,11 +245,6 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) walllights = scalelight[lightnum]; } - maskedtexturecol = ds->maskedtexturecol; - - mfloorclip = ds->sprbottomclip; - mceilingclip = ds->sprtopclip; - if (frontsector->heightsec != -1) front = §ors[frontsector->heightsec]; else @@ -460,8 +255,8 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) else back = backsector; - if (ds->curline->sidedef->repeatcnt) - repeats = 1 + ds->curline->sidedef->repeatcnt; + if (drawseg->curline->sidedef->repeatcnt) + repeats = 1 + drawseg->curline->sidedef->repeatcnt; else if (ldef->flags & ML_EFFECT5) { fixed_t high, low; @@ -487,76 +282,75 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) { if (times > 0) { - rw_scalestep = ds->scalestep; - spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep; - if (dc_numlights) + rw_scalestep = drawseg->scalestep; + spryscale = drawseg->scale1 + (x1 - drawseg->x1)*rw_scalestep; + if (dc->numlights) { // reset all lights to their starting heights - for (i = 0; i < dc_numlights; i++) + for (i = 0; i < dc->numlights; i++) { - rlight = &dc_lightlist[i]; + rlight = &dc->lightlist[i]; rlight->height = rlight->startheight; } } } - dc_texheight = textureheight[texnum]>>FRACBITS; + dc->texheight = textureheight[texnum]>>FRACBITS; // draw the columns - for (dc_x = x1; dc_x <= x2; dc_x++) + for (dc->x = x1; dc->x <= x2; dc->x++) { - dc_texturemid = ds->maskedtextureheight[dc_x]; + dc->texturemid = drawseg->maskedtextureheight[dc->x]; if (!!(curline->linedef->flags & ML_DONTPEGBOTTOM) ^ !!(curline->linedef->flags & ML_EFFECT3)) - dc_texturemid += (textureheight[texnum])*times + textureheight[texnum]; + dc->texturemid += (textureheight[texnum])*times + textureheight[texnum]; else - dc_texturemid -= (textureheight[texnum])*times; + dc->texturemid -= (textureheight[texnum])*times; + // calculate lighting - if (maskedtexturecol[dc_x] != INT16_MAX) + if (maskedtexturecol[dc->x] != INT16_MAX) { // Check for overflows first - overflow_test = (INT64)centeryfrac - (((INT64)dc_texturemid*spryscale)>>FRACBITS); - if (overflow_test < 0) overflow_test = -overflow_test; - if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) + if (R_OverflowTest(dc)) { // Eh, no, go away, don't waste our time - if (dc_numlights) + if (dc->numlights) { - for (i = 0; i < dc_numlights; i++) + for (i = 0; i < dc->numlights; i++) { - rlight = &dc_lightlist[i]; + rlight = &dc->lightlist[i]; rlight->height += rlight->heightstep; } } + spryscale += rw_scalestep; continue; } - if (dc_numlights) + if (dc->numlights) { lighttable_t **xwalllights; sprbotscreen = INT32_MAX; - sprtopscreen = windowtop = (centeryfrac - FixedMul(dc_texturemid, spryscale)); + sprtopscreen = windowtop = (centeryfrac - FixedMul(dc->texturemid, spryscale)); realbot = windowbottom = FixedMul(textureheight[texnum], spryscale) + sprtopscreen; - dc_iscale = 0xffffffffu / (unsigned)spryscale; + dc->iscale = 0xffffffffu / (unsigned)spryscale; // draw the texture - col = (column_t *)((UINT8 *)R_GetColumn(texnum, maskedtexturecol[dc_x]) - 3); + col = (column_t *)((UINT8 *)R_GetColumn(texnum, maskedtexturecol[dc->x]) - 3); - for (i = 0; i < dc_numlights; i++) + auto set_light_vars = [&](INT32 k) { - rlight = &dc_lightlist[i]; + rlight = &dc->lightlist[k]; - if ((rlight->flags & FF_NOSHADE)) - continue; + lightnum = rlight->lightnum; - if (rlight->lightnum < 0) + if (lightnum < 0) xwalllights = scalelight[0]; - else if (rlight->lightnum >= LIGHTLEVELS) + else if (lightnum >= LIGHTLEVELS) xwalllights = scalelight[LIGHTLEVELS-1]; else - xwalllights = scalelight[rlight->lightnum]; + xwalllights = scalelight[lightnum]; pindex = FixedMul(spryscale, LIGHTRESOLUTIONFIX)>>LIGHTSCALESHIFT; @@ -567,15 +361,33 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) rlight->rcolormap = rlight->extra_colormap->colormap + (xwalllights[pindex] - colormaps); else rlight->rcolormap = xwalllights[pindex]; + }; + + auto set_colormap_below_light = [&] + { + dc->colormap = rlight->rcolormap; + if (encoremap && !(ldef->flags & ML_TFERLINE)) + dc->colormap += COLORMAP_REMAPOFFSET; + }; + + // Use the base sector's light level above the first FOF. + // You can imagine it as the sky casting its light on top of the highest FOF. + set_light_vars(0); + set_colormap_below_light(); + + for (i = 0; i < dc->numlights; i++) + { + if ((dc->lightlist[i].flags & FF_NOSHADE)) + continue; + + set_light_vars(i); height = rlight->height; rlight->height += rlight->heightstep; if (height <= windowtop) { - dc_colormap = rlight->rcolormap; - if (encoremap && !(ldef->flags & ML_TFERLINE)) - dc_colormap += COLORMAP_REMAPOFFSET; + set_colormap_below_light(); continue; } @@ -583,24 +395,23 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) if (windowbottom >= realbot) { windowbottom = realbot; - colfunc_2s(col); - for (i++; i < dc_numlights; i++) + colfunc_2s(dc, col); + for (i++; i < dc->numlights; i++) { - rlight = &dc_lightlist[i]; + rlight = &dc->lightlist[i]; rlight->height += rlight->heightstep; } continue; } - colfunc_2s(col); + colfunc_2s(dc, col); + windowtop = windowbottom + 1; - dc_colormap = rlight->rcolormap; - if (encoremap && !(ldef->flags & ML_TFERLINE)) - dc_colormap += COLORMAP_REMAPOFFSET; + set_colormap_below_light(); } windowbottom = realbot; if (windowtop < windowbottom) - colfunc_2s(col); + colfunc_2s(dc, col); spryscale += rw_scalestep; continue; @@ -612,47 +423,170 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) if (pindex >= MAXLIGHTSCALE) pindex = MAXLIGHTSCALE - 1; - dc_colormap = walllights[pindex]; + dc->colormap = walllights[pindex]; if (encoremap && !(ldef->flags & ML_TFERLINE)) - dc_colormap += COLORMAP_REMAPOFFSET; + dc->colormap += COLORMAP_REMAPOFFSET; if (frontsector->extra_colormap) - dc_colormap = frontsector->extra_colormap->colormap + (dc_colormap - colormaps); + dc->colormap = frontsector->extra_colormap->colormap + (dc->colormap - colormaps); - sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale); - dc_iscale = 0xffffffffu / (unsigned)spryscale; + sprtopscreen = centeryfrac - FixedMul(dc->texturemid, spryscale); + dc->iscale = 0xffffffffu / (unsigned)spryscale; // draw the texture - col = (column_t *)((UINT8 *)R_GetColumn(texnum, maskedtexturecol[dc_x]) - 3); + col = (column_t *)((UINT8 *)R_GetColumn(texnum, maskedtexturecol[dc->x]) - 3); - colfunc_2s(col); + colfunc_2s(dc, col); } + spryscale += rw_scalestep; } } - colfunc = wallcolfunc; +} + +static boolean R_CheckBlendMode(drawcolumndata_t* dc, const line_t *ldef) +{ + if (!ldef->alpha) + return false; + + if (ldef->blendmode) + { + if (ldef->alpha == NUMTRANSMAPS || ldef->blendmode == AST_MODULATE) + dc->transmap = R_GetBlendTable(ldef->blendmode, 0); + else + dc->transmap = R_GetBlendTable(ldef->blendmode, R_GetLinedefTransTable(ldef->alpha)); + + R_SetColumnFunc(COLDRAWFUNC_FUZZY); + } + else if (ldef->alpha > 0 && ldef->alpha < FRACUNIT) + { + dc->transmap = R_GetTranslucencyTable(R_GetLinedefTransTable(ldef->alpha)); + R_SetColumnFunc(COLDRAWFUNC_FUZZY); + } + else if (ldef->special == 909) + { + windowtop = frontsector->ceilingheight; + windowbottom = frontsector->floorheight; + R_SetColumnFunc(COLDRAWFUNC_FOG); + } + else + { + R_SetColumnFunc(BASEDRAWFUNC); + } + + if (curline->polyseg && curline->polyseg->translucency > 0) + { + if (curline->polyseg->translucency >= NUMTRANSMAPS) + return false; + + dc->transmap = R_GetTranslucencyTable(curline->polyseg->translucency); + R_SetColumnFunc(COLDRAWFUNC_FUZZY); + } + + return true; +} + +void R_RenderMaskedSegRange(drawseg_t *drawseg, INT32 x1, INT32 x2) +{ + INT32 texnum; + line_t *ldef; + void (*colfunc_2s)(drawcolumndata_t* dc, column_t *); + drawcolumndata_t *dc = &g_dc; + + // Calculate light table. + // Use different light tables + // for horizontal / vertical / diagonal. Diagonal? + // OPTIMIZE: get rid of LIGHTSEGSHIFT globally + curline = drawseg->curline; + + frontsector = curline->frontsector; + backsector = curline->backsector; + texnum = R_GetTextureNum(curline->sidedef->midtexture); + windowbottom = windowtop = sprbotscreen = INT32_MAX; + + // hack translucent linedef types (900-909 for transtables 1-9) + ldef = curline->linedef; + + if (R_CheckBlendMode(dc, ldef) == false) + { + return; // does not render + } + + rw_scalestep = drawseg->scalestep; + spryscale = drawseg->scale1 + (x1 - drawseg->x1)*rw_scalestep; + + // Texture must be cached before setting colfunc_2s, + // otherwise texture[texnum]->holes may be false when it shouldn't be + R_CheckTextureCache(texnum); + + // handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures + // are not stored per-column with post info in SRB2 + if (textures[texnum]->holes) + colfunc_2s = R_DrawMaskedColumn; // render the usual 2sided single-patch packed texture + else + { + colfunc_2s = R_Render2sidedMultiPatchColumn; // render multipatch with no holes (no post_t info) + lengthcol = textures[texnum]->height; + } + + maskedtexturecol = drawseg->maskedtexturecol; + + mfloorclip = drawseg->sprbottomclip; + mceilingclip = drawseg->sprtopclip; + + R_RenderMaskedSegLoop(dc, drawseg, x1, x2, texnum, colfunc_2s); + + R_SetColumnFunc(BASEDRAWFUNC); +} + +template +static constexpr T saturating_add(T x, T y) noexcept +{ + INT64 z = static_cast(x) + static_cast(y); + if (z > static_cast(std::numeric_limits::max())) + { + z = static_cast(std::numeric_limits::max()); + } + else if (z < static_cast(std::numeric_limits::min())) + { + z = static_cast(std::numeric_limits::min()); + } + return static_cast(z); +} + +template +static constexpr T saturating_mul(T x, T y) noexcept +{ + INT64 z = static_cast(x) * static_cast(y); + if (z > static_cast(std::numeric_limits::max())) + { + z = static_cast(std::numeric_limits::max()); + } + else if (z < static_cast(std::numeric_limits::min())) + { + z = static_cast(std::numeric_limits::min()); + } + return static_cast(z); } // Loop through R_DrawMaskedColumn calls -static void R_DrawRepeatMaskedColumn(column_t *col) +static void R_DrawRepeatMaskedColumn(drawcolumndata_t* dc, column_t *col) { - INT64 z; while (sprtopscreen < sprbotscreen) { - R_DrawMaskedColumn(col); - z = sprtopscreen + (INT64)dc_texheight*spryscale; - if (z > (INT64)INT32_MAX) // prevent overflow - sprtopscreen = INT32_MAX; - else - sprtopscreen = z; + R_DrawMaskedColumn(dc, col); + sprtopscreen = saturating_add(sprtopscreen, saturating_mul(dc->texheight, spryscale)); } } // Returns true if a fake floor is translucent. static boolean R_IsFFloorTranslucent(visffloor_t *pfloor) { + if (cv_softcyancut.value && pfloor->plane->cyan) + return true; + if (pfloor->polyobj) - return (pfloor->polyobj->translucency > 0); + return true; // Polyobjects have no ffloors, and they're handled in the conditional above. if (pfloor->ffloor != NULL) @@ -664,7 +598,7 @@ static boolean R_IsFFloorTranslucent(visffloor_t *pfloor) // // R_RenderThickSideRange // Renders all the thick sides in the given range. -void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) +void R_RenderThickSideRange(drawseg_t *drawseg, INT32 x1, INT32 x2, ffloor_t *pfloor) { size_t pindex = 0; column_t * col; @@ -689,31 +623,35 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) INT32 oldx = -1; fixed_t left_top, left_bottom; // needed here for slope skewing pslope_t *skewslope = NULL; + boolean fog = false; + boolean fuzzy = false; - void (*colfunc_2s) (column_t *); + drawcolumndata_t *dc = &g_dc; + + void (*colfunc_2s) (drawcolumndata_t* dc, column_t *); // Calculate light table. // Use different light tables // for horizontal / vertical / diagonal. Diagonal? // OPTIMIZE: get rid of LIGHTSEGSHIFT globally - curline = ds->curline; + curline = drawseg->curline; backsector = pfloor->target; frontsector = curline->frontsector == pfloor->target ? curline->backsector : curline->frontsector; texnum = R_GetTextureNum(sides[pfloor->master->sidenum[0]].midtexture); - colfunc = wallcolfunc; + R_SetColumnFunc(BASEDRAWFUNC); if (pfloor->master->flags & ML_TFERLINE) { - size_t linenum = min((size_t)(curline->linedef-backsector->lines[0]), pfloor->master->frontsector->linecount); + size_t linenum = std::min((size_t)(curline->linedef-backsector->lines[0]), pfloor->master->frontsector->linecount); newline = pfloor->master->frontsector->lines[0] + linenum; texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture); } if (pfloor->flags & FF_TRANSLUCENT) { - boolean fuzzy = true; + fuzzy = true; // Hacked up support for alpha value in software mode Tails 09-24-2002 // ...unhacked by toaster 04-01-2021, re-hacked a little by sphere 19-11-2021 @@ -723,43 +661,55 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) if (trans >= 10) return; // Don't even draw it if (pfloor->blend) // additive, (reverse) subtractive, modulative - dc_transmap = R_GetBlendTable(pfloor->blend, trans); - else if (!(dc_transmap = R_GetTranslucencyTable(trans)) || trans == 0) + dc->transmap = R_GetBlendTable(pfloor->blend, trans); + else if (!(dc->transmap = R_GetTranslucencyTable(trans)) || trans == 0) fuzzy = false; // Opaque } - - if (fuzzy) - colfunc = fuzzcolfunc; } else if (pfloor->flags & FF_FOG) - colfunc = R_DrawFogColumn_8; + { + R_SetColumnFunc(COLDRAWFUNC_FOG); + fog = true; + } - range = max(ds->x2-ds->x1, 1); + range = std::max(drawseg->x2-drawseg->x1, 1); //SoM: Moved these up here so they are available for my lightlist calculations - rw_scalestep = ds->scalestep; - spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep; + rw_scalestep = drawseg->scalestep; + spryscale = drawseg->scale1 + (x1 - drawseg->x1)*rw_scalestep; - dc_numlights = 0; +#define CLAMPMAX INT32_MAX +#define CLAMPMIN (-INT32_MAX) // This is not INT32_MIN on purpose! INT32_MIN makes the drawers freak out. + auto overflow_clamp = [&](INT64 overflow_test) + { + return (overflow_test > (INT64)CLAMPMAX) ? CLAMPMAX : + (overflow_test > (INT64)CLAMPMIN) ? (fixed_t)overflow_test : + CLAMPMIN; + }; +#undef CLAMPMAX +#undef CLAMPMIN + + dc->numlights = 0; if (frontsector->numlights) { - dc_numlights = frontsector->numlights; - if (dc_numlights > dc_maxlights) + dc->numlights = frontsector->numlights; + + if (dc->numlights > dc->maxlights) { - dc_maxlights = dc_numlights; - dc_lightlist = Z_Realloc(dc_lightlist, sizeof (*dc_lightlist) * dc_maxlights, PU_STATIC, NULL); + dc->maxlights = dc->numlights; + dc->lightlist = static_cast(Z_Frame_Alloc(sizeof (*dc->lightlist) * dc->maxlights)); } - for (i = p = 0; i < dc_numlights; i++) + for (i = p = 0; i < dc->numlights; i++) { fixed_t leftheight, rightheight; fixed_t pfloorleft, pfloorright; INT64 overflow_test; light = &frontsector->lightlist[i]; - rlight = &dc_lightlist[p]; + rlight = &dc->lightlist[p]; #define SLOPEPARAMS(slope, end1, end2, normalheight) \ - end1 = P_GetZAt(slope, ds->leftpos.x, ds->leftpos.y, normalheight); \ - end2 = P_GetZAt(slope, ds->rightpos.x, ds->rightpos.y, normalheight); + end1 = P_GetZAt(slope, drawseg->leftpos.x, drawseg->leftpos.y, normalheight); \ + end2 = P_GetZAt(slope, drawseg->rightpos.x, drawseg->rightpos.y, normalheight); SLOPEPARAMS(light->slope, leftheight, rightheight, light->height) SLOPEPARAMS(*pfloor->b_slope, pfloorleft, pfloorright, *pfloor->bottomheight) @@ -769,31 +719,27 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) SLOPEPARAMS(*pfloor->t_slope, pfloorleft, pfloorright, *pfloor->topheight) - if (leftheight > pfloorleft && rightheight > pfloorright && i+1 < dc_numlights) + if (leftheight > pfloorleft && rightheight > pfloorright && i+1 < dc->numlights) { lightlist_t *nextlight = &frontsector->lightlist[i+1]; - if ((P_GetLightZAt(nextlight, ds->leftpos.x, ds->leftpos.y) > pfloorleft) - && (P_GetLightZAt(nextlight, ds->rightpos.x, ds->rightpos.y) > pfloorright)) + if ((P_GetLightZAt(nextlight, drawseg->leftpos.x, drawseg->leftpos.y) > pfloorleft) + && (P_GetLightZAt(nextlight, drawseg->rightpos.x, drawseg->rightpos.y) > pfloorright)) continue; } leftheight -= viewz; rightheight -= viewz; -#define CLAMPMAX INT32_MAX -#define CLAMPMIN (-INT32_MAX) // This is not INT32_MIN on purpose! INT32_MIN makes the drawers freak out. // Monster Iestyn (25/03/18): do not skip these lights if they fail overflow test, just clamp them instead so they behave. - overflow_test = (INT64)centeryfrac - (((INT64)leftheight*ds->scale1)>>FRACBITS); - if (overflow_test > (INT64)CLAMPMAX) rlight->height = CLAMPMAX; - else if (overflow_test > (INT64)CLAMPMIN) rlight->height = (fixed_t)overflow_test; - else rlight->height = CLAMPMIN; + overflow_test = (INT64)centeryfrac - (((INT64)leftheight*drawseg->scale1)>>FRACBITS); + rlight->height = overflow_clamp(overflow_test); + + overflow_test = (INT64)centeryfrac - (((INT64)rightheight*drawseg->scale2)>>FRACBITS); + rlight->heightstep = overflow_clamp(overflow_test); - overflow_test = (INT64)centeryfrac - (((INT64)rightheight*ds->scale2)>>FRACBITS); - if (overflow_test > (INT64)CLAMPMAX) rlight->heightstep = CLAMPMAX; - else if (overflow_test > (INT64)CLAMPMIN) rlight->heightstep = (fixed_t)overflow_test; - else rlight->heightstep = CLAMPMIN; rlight->heightstep = (rlight->heightstep-rlight->height)/(range); - rlight->flags = light->flags; + rlight->flags = static_cast(light->flags); + if (light->flags & FF_CUTLEVEL) { SLOPEPARAMS(*light->caster->b_slope, leftheight, rightheight, *light->caster->bottomheight) @@ -802,15 +748,12 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) rightheight -= viewz; // Monster Iestyn (25/03/18): do not skip these lights if they fail overflow test, just clamp them instead so they behave. - overflow_test = (INT64)centeryfrac - (((INT64)leftheight*ds->scale1)>>FRACBITS); - if (overflow_test > (INT64)CLAMPMAX) rlight->botheight = CLAMPMAX; - else if (overflow_test > (INT64)CLAMPMIN) rlight->botheight = (fixed_t)overflow_test; - else rlight->botheight = CLAMPMIN; + overflow_test = (INT64)centeryfrac - (((INT64)leftheight*drawseg->scale1)>>FRACBITS); + rlight->botheight = overflow_clamp(overflow_test); + + overflow_test = (INT64)centeryfrac - (((INT64)rightheight*drawseg->scale2)>>FRACBITS); + rlight->botheightstep = overflow_clamp(overflow_test); - overflow_test = (INT64)centeryfrac - (((INT64)rightheight*ds->scale2)>>FRACBITS); - if (overflow_test > (INT64)CLAMPMAX) rlight->botheightstep = CLAMPMAX; - else if (overflow_test > (INT64)CLAMPMIN) rlight->botheightstep = (fixed_t)overflow_test; - else rlight->botheightstep = CLAMPMIN; rlight->botheightstep = (rlight->botheightstep-rlight->botheight)/(range); } @@ -831,16 +774,16 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) p++; } - dc_numlights = p; + dc->numlights = p; } else { // Get correct light level! if ((frontsector->extra_colormap && frontsector->extra_colormap->fog)) lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT); - else if (pfloor->flags & FF_FOG) + else if (fog) lightnum = (pfloor->master->frontsector->lightlevel >> LIGHTSEGSHIFT); - else if (colfunc == fuzzcolfunc) + else if (fuzzy) lightnum = LIGHTLEVELS-1; else lightnum = R_FakeFlat(frontsector, &tempsec, &templight, &templight, false) @@ -859,15 +802,15 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) walllights = scalelight[lightnum]; } - maskedtexturecol = ds->thicksidecol; + maskedtexturecol = drawseg->thicksidecol; - mfloorclip = ds->sprbottomclip; - mceilingclip = ds->sprtopclip; - dc_texheight = textureheight[texnum]>>FRACBITS; + mfloorclip = drawseg->sprbottomclip; + mceilingclip = drawseg->sprtopclip; + dc->texheight = textureheight[texnum]>>FRACBITS; - // calculate both left ends - left_top = P_GetFFloorTopZAt (pfloor, ds->leftpos.x, ds->leftpos.y) - viewz; - left_bottom = P_GetFFloorBottomZAt(pfloor, ds->leftpos.x, ds->leftpos.y) - viewz; + // calculate both left endrawseg + left_top = P_GetFFloorTopZAt (pfloor, drawseg->leftpos.x, drawseg->leftpos.y) - viewz; + left_bottom = P_GetFFloorBottomZAt(pfloor, drawseg->leftpos.x, drawseg->leftpos.y) - viewz; skewslope = *pfloor->t_slope; // skew using top slope by default @@ -880,9 +823,9 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) slopeskew = true; if (slopeskew) - dc_texturemid = left_top; + dc->texturemid = left_top; else - dc_texturemid = *pfloor->topheight - viewz; + dc->texturemid = *pfloor->topheight - viewz; if (newline) { @@ -891,7 +834,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) { skewslope = *pfloor->b_slope; // skew using bottom slope if (slopeskew) - dc_texturemid = left_bottom; + dc->texturemid = left_bottom; else offsetvalue -= *pfloor->topheight - *pfloor->bottomheight; } @@ -903,29 +846,28 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) { skewslope = *pfloor->b_slope; // skew using bottom slope if (slopeskew) - dc_texturemid = left_bottom; + dc->texturemid = left_bottom; else offsetvalue -= *pfloor->topheight - *pfloor->bottomheight; } } - if (slopeskew) + if (slopeskew && skewslope) { angle_t lineangle = R_PointToAngle2(curline->v1->x, curline->v1->y, curline->v2->x, curline->v2->y); - - if (skewslope) - ffloortextureslide = FixedMul(skewslope->zdelta, FINECOSINE((lineangle-skewslope->xydirection)>>ANGLETOFINESHIFT)); + ffloortextureslide = FixedMul(skewslope->zdelta, FINECOSINE((lineangle-skewslope->xydirection)>>ANGLETOFINESHIFT)); } - dc_texturemid += offsetvalue; + dc->texturemid += offsetvalue; // Texture must be cached before setting colfunc_2s, // otherwise texture[texnum]->holes may be false when it shouldn't be R_CheckTextureCache(texnum); + //faB: handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures // are not stored per-column with post info anymore in Doom Legacy if (textures[texnum]->holes) - colfunc_2s = R_DrawRepeatMaskedColumn; //render the usual 2sided single-patch packed texture + colfunc_2s = R_DrawRepeatMaskedColumn; //render the usual 2sided single-patch packed texture else { colfunc_2s = R_Render2sidedMultiPatchColumn; //render multipatch with no holes (no post_t info) @@ -937,229 +879,260 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) fixed_t right_top, right_bottom; // calculate right ends now - right_top = P_GetFFloorTopZAt (pfloor, ds->rightpos.x, ds->rightpos.y) - viewz; - right_bottom = P_GetFFloorBottomZAt(pfloor, ds->rightpos.x, ds->rightpos.y) - viewz; + right_top = P_GetFFloorTopZAt (pfloor, drawseg->rightpos.x, drawseg->rightpos.y) - viewz; + right_bottom = P_GetFFloorBottomZAt(pfloor, drawseg->rightpos.x, drawseg->rightpos.y) - viewz; // using INT64 to avoid 32bit overflow - top_frac = (INT64)centeryfrac - (((INT64)left_top * ds->scale1) >> FRACBITS); - bottom_frac = (INT64)centeryfrac - (((INT64)left_bottom * ds->scale1) >> FRACBITS); - top_step = (INT64)centeryfrac - (((INT64)right_top * ds->scale2) >> FRACBITS); - bottom_step = (INT64)centeryfrac - (((INT64)right_bottom * ds->scale2) >> FRACBITS); + top_frac = (INT64)centeryfrac - (((INT64)left_top * drawseg->scale1) >> FRACBITS); + bottom_frac = (INT64)centeryfrac - (((INT64)left_bottom * drawseg->scale1) >> FRACBITS); + top_step = (INT64)centeryfrac - (((INT64)right_top * drawseg->scale2) >> FRACBITS); + bottom_step = (INT64)centeryfrac - (((INT64)right_bottom * drawseg->scale2) >> FRACBITS); top_step = (top_step-top_frac)/(range); bottom_step = (bottom_step-bottom_frac)/(range); - top_frac += top_step * (x1 - ds->x1); - bottom_frac += bottom_step * (x1 - ds->x1); + top_frac += top_step * (x1 - drawseg->x1); + bottom_frac += bottom_step * (x1 - drawseg->x1); } // draw the columns - for (dc_x = x1; dc_x <= x2; dc_x++) + for (dc->x = x1; dc->x <= x2; dc->x++) { - if (maskedtexturecol[dc_x] == INT16_MAX) + if (maskedtexturecol[dc->x] == INT16_MAX) continue; + // skew FOF walls + if (ffloortextureslide) { - if (ffloortextureslide) { // skew FOF walls - if (oldx != -1) - dc_texturemid += FixedMul(ffloortextureslide, (maskedtexturecol[oldx]-maskedtexturecol[dc_x])<texturemid += FixedMul(ffloortextureslide, (maskedtexturecol[oldx]-maskedtexturecol[dc->x])<x; + } - if (top_frac > (INT64)CLAMPMAX) sprtopscreen = windowtop = CLAMPMAX; - else if (top_frac > (INT64)CLAMPMIN) sprtopscreen = windowtop = (fixed_t)top_frac; - else sprtopscreen = windowtop = CLAMPMIN; - if (bottom_frac > (INT64)CLAMPMAX) sprbotscreen = windowbottom = CLAMPMAX; - else if (bottom_frac > (INT64)CLAMPMIN) sprbotscreen = windowbottom = (fixed_t)bottom_frac; - else sprbotscreen = windowbottom = CLAMPMIN; + // Calculate bounds + // clamp the values if necessary to avoid overflows and rendering glitches caused by them + sprtopscreen = windowtop = overflow_clamp(top_frac); + sprbotscreen = windowbottom = overflow_clamp(bottom_frac); - top_frac += top_step; - bottom_frac += bottom_step; + top_frac += top_step; + bottom_frac += bottom_step; - // SoM: If column is out of range, why bother with it?? - if (windowbottom < topbounds || windowtop > bottombounds) + // SoM: If column is out of range, why bother with it?? + if (windowbottom < topbounds || windowtop > bottombounds) + { + if (dc->numlights) { - if (dc_numlights) + for (i = 0; i < dc->numlights; i++) { - for (i = 0; i < dc_numlights; i++) - { - rlight = &dc_lightlist[i]; - rlight->height += rlight->heightstep; - if (rlight->flags & FF_CUTLEVEL) - rlight->botheight += rlight->botheightstep; - } + rlight = &dc->lightlist[i]; + rlight->height += rlight->heightstep; + if (rlight->flags & FF_CUTLEVEL) + rlight->botheight += rlight->botheightstep; } - spryscale += rw_scalestep; - continue; } - dc_iscale = 0xffffffffu / (unsigned)spryscale; + spryscale += rw_scalestep; + continue; + } - // Get data for the column - col = (column_t *)((UINT8 *)R_GetColumn(texnum,maskedtexturecol[dc_x]) - 3); + // Get data for the column + col = (column_t *)((UINT8 *)R_GetColumn(texnum, maskedtexturecol[dc->x]) - 3); - // SoM: New code does not rely on R_DrawColumnShadowed_8 which - // will (hopefully) put less strain on the stack. - if (dc_numlights) + if (!fog) + { + dc->iscale = 0xffffffffu / (unsigned)spryscale; + + if (fuzzy) + R_SetColumnFunc(COLDRAWFUNC_FUZZY); + else + R_SetColumnFunc(BASEDRAWFUNC); + } + + // SoM: New code does not rely on R_DrawColumnShadowed which + // will (hopefully) put less strain on the stack. + if (dc->numlights) + { + lighttable_t **xwalllights; + fixed_t height; + fixed_t bheight = 0; + INT32 solid = 0; + + auto set_light_vars = [&](INT32 k) { - lighttable_t **xwalllights; - fixed_t height; - fixed_t bheight = 0; - INT32 solid = 0; - INT32 lighteffect = 0; + rlight = &dc->lightlist[k]; - for (i = 0; i < dc_numlights; i++) + lightnum = rlight->lightnum; + + if (lightnum < 0) + xwalllights = scalelight[0]; + else if (lightnum >= LIGHTLEVELS) + xwalllights = scalelight[LIGHTLEVELS-1]; + else + xwalllights = scalelight[lightnum]; + + pindex = FixedMul(spryscale, LIGHTRESOLUTIONFIX)>>LIGHTSCALESHIFT; + + if (pindex >= MAXLIGHTSCALE) + pindex = MAXLIGHTSCALE-1; + + if (pfloor->flags & FF_FOG) { - // Check if the current light effects the colormap/lightlevel - rlight = &dc_lightlist[i]; - lighteffect = !(dc_lightlist[i].flags & FF_NOSHADE); + if (pfloor->master->frontsector->extra_colormap) + rlight->rcolormap = pfloor->master->frontsector->extra_colormap->colormap + (xwalllights[pindex] - colormaps); + else + rlight->rcolormap = xwalllights[pindex]; + } + else + { + if (rlight->extra_colormap) + rlight->rcolormap = rlight->extra_colormap->colormap + (xwalllights[pindex] - colormaps); + else + rlight->rcolormap = xwalllights[pindex]; + } + }; - if (lighteffect) + auto set_colormap_below_light = [&] + { + dc->colormap = rlight->rcolormap; + if (encoremap && !(curline->linedef->flags & ML_TFERLINE)) + dc->colormap += COLORMAP_REMAPOFFSET; + }; + + // Use the base sector's light level above the first FOF. + // You can imagine it as the sky casting its light on top of the highest FOF. + set_light_vars(0); + set_colormap_below_light(); + + for (i = 0; i < dc->numlights; i++) + { + // Check if the current light effects the colormap/lightlevel + rlight = &dc->lightlist[i]; + xwalllights = NULL; + + if (!(dc->lightlist[i].flags & FF_NOSHADE)) + set_light_vars(i); + + solid = 0; // don't carry over solid-cutting flag from the previous light + + // Check if the current light can cut the current 3D floor. + if (rlight->flags & FF_CUTSOLIDS && !(pfloor->flags & FF_EXTRA)) + { + solid = 1; + } + else if (rlight->flags & FF_CUTEXTRA && pfloor->flags & FF_EXTRA) + { + if (rlight->flags & FF_EXTRA) { - lightnum = rlight->lightnum; - - if (lightnum < 0) - xwalllights = scalelight[0]; - else if (lightnum >= LIGHTLEVELS) - xwalllights = scalelight[LIGHTLEVELS-1]; - else - xwalllights = scalelight[lightnum]; - - pindex = FixedMul(spryscale, LIGHTRESOLUTIONFIX)>>LIGHTSCALESHIFT; - - if (pindex >= MAXLIGHTSCALE) - pindex = MAXLIGHTSCALE-1; - - if (pfloor->flags & FF_FOG) - { - if (pfloor->master->frontsector->extra_colormap) - rlight->rcolormap = pfloor->master->frontsector->extra_colormap->colormap + (xwalllights[pindex] - colormaps); - else - rlight->rcolormap = xwalllights[pindex]; - } - else - { - if (rlight->extra_colormap) - rlight->rcolormap = rlight->extra_colormap->colormap + (xwalllights[pindex] - colormaps); - else - rlight->rcolormap = xwalllights[pindex]; - } - } - - solid = 0; // don't carry over solid-cutting flag from the previous light - - // Check if the current light can cut the current 3D floor. - if (rlight->flags & FF_CUTSOLIDS && !(pfloor->flags & FF_EXTRA)) - solid = 1; - else if (rlight->flags & FF_CUTEXTRA && pfloor->flags & FF_EXTRA) - { - if (rlight->flags & FF_EXTRA) - { - // The light is from an extra 3D floor... Check the flags so - // there are no undesired cuts. - if ((rlight->flags & (FF_FOG|FF_SWIMMABLE)) == (pfloor->flags & (FF_FOG|FF_SWIMMABLE))) - solid = 1; - } - else + // The light is from an extra 3D floor... Check the flags so + // there are no undesired cuts. + if ((rlight->flags & (FF_FOG|FF_SWIMMABLE)) == (pfloor->flags & (FF_FOG|FF_SWIMMABLE))) solid = 1; } else - solid = 0; - - height = rlight->height; - rlight->height += rlight->heightstep; - - if (solid) - { - bheight = rlight->botheight - (FRACUNIT >> 1); - rlight->botheight += rlight->botheightstep; - } - - if (height <= windowtop) - { - if (lighteffect) - { - dc_colormap = rlight->rcolormap; - if (encoremap && !(curline->linedef->flags & ML_TFERLINE)) - dc_colormap += COLORMAP_REMAPOFFSET; - } - if (solid && windowtop < bheight) - windowtop = bheight; - continue; - } - - windowbottom = height; - if (windowbottom >= sprbotscreen) - { - windowbottom = sprbotscreen; - // draw the texture - colfunc_2s (col); - for (i++; i < dc_numlights; i++) - { - rlight = &dc_lightlist[i]; - rlight->height += rlight->heightstep; - if (rlight->flags & FF_CUTLEVEL) - rlight->botheight += rlight->botheightstep; - } - continue; - } - // draw the texture - colfunc_2s (col); - if (solid) - windowtop = bheight; - else - windowtop = windowbottom + 1; - if (lighteffect) - { - dc_colormap = rlight->rcolormap; - if (encoremap && !(curline->linedef->flags & ML_TFERLINE)) - dc_colormap += COLORMAP_REMAPOFFSET; - } + solid = 1; } - windowbottom = sprbotscreen; - // draw the texture, if there is any space left - if (windowtop < windowbottom) - colfunc_2s (col); + else + solid = 0; - spryscale += rw_scalestep; - continue; + height = rlight->height; + rlight->height += rlight->heightstep; + + if (solid) + { + bheight = rlight->botheight - (FRACUNIT >> 1); + rlight->botheight += rlight->botheightstep; + } + + if (height <= windowtop) + { + if (xwalllights) + { + set_colormap_below_light(); + } + + if (solid && windowtop < bheight) + { + windowtop = bheight; + } + + continue; + } + + windowbottom = height; + if (windowbottom >= sprbotscreen) + { + windowbottom = sprbotscreen; + + // draw the texture + colfunc_2s (dc, col); + for (i++; i < dc->numlights; i++) + { + rlight = &dc->lightlist[i]; + rlight->height += rlight->heightstep; + + if (rlight->flags & FF_CUTLEVEL) + rlight->botheight += rlight->botheightstep; + } + + continue; + } + + // draw the texture + colfunc_2s (dc, col); + + if (solid) + windowtop = bheight; + else + windowtop = windowbottom + 1; + + if (xwalllights) + { + set_colormap_below_light(); + } } - // calculate lighting - pindex = FixedMul(spryscale, LIGHTRESOLUTIONFIX)>>LIGHTSCALESHIFT; + windowbottom = sprbotscreen; - if (pindex >= MAXLIGHTSCALE) - pindex = MAXLIGHTSCALE - 1; + // draw the texture, if there is any space left + if (windowtop < windowbottom) + { + colfunc_2s (dc, col); + } - dc_colormap = walllights[pindex]; - - if (encoremap && !(curline->linedef->flags & ML_TFERLINE)) - dc_colormap += COLORMAP_REMAPOFFSET; - - if (pfloor->flags & FF_FOG && pfloor->master->frontsector->extra_colormap) - dc_colormap = pfloor->master->frontsector->extra_colormap->colormap + (dc_colormap - colormaps); - else if (frontsector->extra_colormap) - dc_colormap = frontsector->extra_colormap->colormap + (dc_colormap - colormaps); - - // draw the texture - colfunc_2s (col); spryscale += rw_scalestep; + continue; } - } - colfunc = wallcolfunc; -#undef CLAMPMAX -#undef CLAMPMIN + // calculate lighting + pindex = FixedMul(spryscale, LIGHTRESOLUTIONFIX)>>LIGHTSCALESHIFT; + + if (pindex >= MAXLIGHTSCALE) + pindex = MAXLIGHTSCALE - 1; + + dc->colormap = walllights[pindex]; + + if (encoremap && !(curline->linedef->flags & ML_TFERLINE)) + dc->colormap += COLORMAP_REMAPOFFSET; + + if (pfloor->flags & FF_FOG && pfloor->master->frontsector->extra_colormap) + dc->colormap = pfloor->master->frontsector->extra_colormap->colormap + (dc->colormap - colormaps); + else if (frontsector->extra_colormap) + dc->colormap = frontsector->extra_colormap->colormap + (dc->colormap - colormaps); + + // draw the texture + colfunc_2s (dc, col); + spryscale += rw_scalestep; + } + + R_SetColumnFunc(BASEDRAWFUNC); } // R_FFloorCanClip // // Returns true if a fake floor can clip a column away. -static boolean R_FFloorCanClip(visffloor_t *pfloor) +static inline boolean R_FFloorCanClip(visffloor_t *pfloor) { - return (cv_ffloorclip.value && !R_IsFFloorTranslucent(pfloor) && !pfloor->polyobj); + return (cv_ffloorclip.value && !R_IsFFloorTranslucent(pfloor)); } // R_ExpandPlaneY @@ -1182,10 +1155,28 @@ static inline void R_ExpandPlaneY(visplane_t *pl, INT32 x, INT16 top, INT16 bott // textures. // CALLED: CORE LOOPING ROUTINE. // -#define HEIGHTBITS 12 -#define HEIGHTUNIT (1<yl = yl; + dc->yh = yh; + dc->texturemid = mid; + dc->source = R_GetColumn(texture, texturecolumn); + dc->texheight = textureheight[texture] >> FRACBITS; + dc->sourcelength = dc->texheight; + R_SetColumnFunc(colfunctype); + coldrawfunc_t* colfunccopy = colfunc; + drawcolumndata_t dc_copy = *dc; + if (remap) + { + dc_copy.colormap += COLORMAP_REMAPOFFSET; + } + colfunccopy(const_cast(&dc_copy)); +} + +static boolean didsolidcol; // True if at least one column was marked solid + +static void R_RenderSegLoop(drawcolumndata_t* dc) { angle_t angle; size_t pindex; @@ -1266,11 +1257,12 @@ static void R_RenderSegLoop (void) bottom_w = bottom; // Polyobject-specific hack to fix plane leaking -Red - if (ffloor[i].polyobj && top_w >= bottom_w) { - ffloor[i].plane->top[rw_x] = ffloor[i].plane->bottom[rw_x] = 0xFFFF; - } else - - if (top_w <= bottom_w) + if (ffloor[i].polyobj && top_w >= bottom_w) + { + ffloor[i].plane->top[rw_x] = 0xFFFF; + ffloor[i].plane->bottom[rw_x] = 0x0000; // fix for sky plane drawing crashes - Monster Iestyn 25/05/18 + } + else if (top_w <= bottom_w) { fftop = (INT16)top_w; ffbottom = (INT16)bottom_w; @@ -1284,6 +1276,7 @@ static void R_RenderSegLoop (void) { rw_floormarked = true; floorclip[rw_x] = fftop; + if (yh > fftop) yh = fftop; @@ -1310,11 +1303,12 @@ static void R_RenderSegLoop (void) bottom_w = bottom; // Polyobject-specific hack to fix plane leaking -Red - if (ffloor[i].polyobj && top_w >= bottom_w) { - ffloor[i].plane->top[rw_x] = ffloor[i].plane->bottom[rw_x] = 0xFFFF; - } else - - if (top_w <= bottom_w) + if (ffloor[i].polyobj && top_w >= bottom_w) + { + ffloor[i].plane->top[rw_x] = 0xFFFF; + ffloor[i].plane->bottom[rw_x] = 0x0000; // fix for sky plane drawing crashes - Monster Iestyn 25/05/18 + } + else if (top_w <= bottom_w) { fftop = (INT16)top_w; ffbottom = (INT16)bottom_w; @@ -1328,6 +1322,7 @@ static void R_RenderSegLoop (void) { rw_ceilingmarked = true; ceilingclip[rw_x] = ffbottom; + if (yl < ffbottom) yl = ffbottom; @@ -1351,7 +1346,8 @@ static void R_RenderSegLoop (void) // Mask 4095 to guarantee this index is within bounds texturecolumn = rw_offset-FixedMul(FINETANGENT(angle & 4095),rw_distance); - if (oldtexturecolumn != -1) { + if (oldtexturecolumn != -1) + { rw_bottomtexturemid += FixedMul(rw_bottomtextureslide, oldtexturecolumn-texturecolumn); rw_midtexturemid += FixedMul(rw_midtextureslide, oldtexturecolumn-texturecolumn); rw_toptexturemid += FixedMul(rw_toptextureslide, oldtexturecolumn-texturecolumn); @@ -1370,25 +1366,25 @@ static void R_RenderSegLoop (void) if (pindex >= MAXLIGHTSCALE) pindex = MAXLIGHTSCALE-1; - dc_colormap = walllights[pindex]; - if (encoremap && !(curline->linedef->flags & ML_TFERLINE)) - dc_colormap += COLORMAP_REMAPOFFSET; - dc_x = rw_x; - dc_iscale = 0xffffffffu / (unsigned)rw_scale; + dc->colormap = walllights[pindex]; + + dc->x = rw_x; + dc->iscale = 0xffffffffu / (unsigned)rw_scale; if (frontsector->extra_colormap) - dc_colormap = frontsector->extra_colormap->colormap + (dc_colormap - colormaps); + dc->colormap = frontsector->extra_colormap->colormap + (dc->colormap - colormaps); } - if (dc_numlights) + if (dc->numlights) { lighttable_t **xwalllights; - for (i = 0; i < dc_numlights; i++) + + for (i = 0; i < dc->numlights; i++) { INT32 lightnum; - lightnum = (dc_lightlist[i].lightlevel >> LIGHTSEGSHIFT); + lightnum = (dc->lightlist[i].lightlevel >> LIGHTSEGSHIFT); - if (dc_lightlist[i].extra_colormap) + if (dc->lightlist[i].extra_colormap) ; else if (P_ApplyLightOffset(lightnum, curline->frontsector)) lightnum += curline->lightOffset; @@ -1405,30 +1401,27 @@ static void R_RenderSegLoop (void) if (pindex >= MAXLIGHTSCALE) pindex = MAXLIGHTSCALE-1; - if (dc_lightlist[i].extra_colormap) - dc_lightlist[i].rcolormap = dc_lightlist[i].extra_colormap->colormap + (xwalllights[pindex] - colormaps); + if (dc->lightlist[i].extra_colormap) + dc->lightlist[i].rcolormap = dc->lightlist[i].extra_colormap->colormap + (xwalllights[pindex] - colormaps); else - dc_lightlist[i].rcolormap = xwalllights[pindex]; + dc->lightlist[i].rcolormap = xwalllights[pindex]; - colfunc = R_DrawColumnShadowed_8; + R_SetColumnFunc(COLDRAWFUNC_SHADOWED); } } frontscale[rw_x] = rw_scale; + const INT16 topclip = (yl >= 0) ? ((yl > viewheight) ? (INT16)viewheight : (INT16)((INT16)yl - 1)) : -1; + const INT16 bottomclip = (yh < viewheight) ? ((yh < -1) ? -1 : (INT16)((INT16)yh + 1)) : (INT16)viewheight; + // draw the wall tiers if (midtexture) { // single sided line if (yl <= yh && yh >= 0 && yl < viewheight) { - dc_yl = yl; - dc_yh = yh; - dc_texturemid = rw_midtexturemid; - dc_source = R_GetColumn(midtexture,texturecolumn); - dc_texheight = textureheight[midtexture]>>FRACBITS; - dc_sourcelength = dc_texheight; - colfunc(); + R_DrawWallColumn(dc, yl, yh, rw_midtexturemid, texturecolumn, midtexture, midremap); // dont draw anything more for this column, since // a midtexture blocks the view @@ -1441,16 +1434,13 @@ static void R_RenderSegLoop (void) { // note: don't use min/max macros, since casting from INT32 to INT16 is involved here if (markceiling && (!rw_ceilingmarked)) - ceilingclip[rw_x] = (yl >= 0) ? ((yl > viewheight) ? (INT16)viewheight : (INT16)((INT16)yl - 1)) : -1; + ceilingclip[rw_x] = topclip; if (markfloor && (!rw_floormarked)) - floorclip[rw_x] = (yh < viewheight) ? ((yh < -1) ? -1 : (INT16)((INT16)yh + 1)) : (INT16)viewheight; + floorclip[rw_x] = bottomclip; } } else { - INT16 topclip = (yl >= 0) ? ((yl > viewheight) ? (INT16)viewheight : (INT16)((INT16)yl - 1)) : -1; - INT16 bottomclip = (yh < viewheight) ? ((yh < -1) ? -1 : (INT16)((INT16)yh + 1)) : (INT16)viewheight; - // two sided line if (toptexture) { @@ -1470,13 +1460,7 @@ static void R_RenderSegLoop (void) } else if (mid >= 0) // safe to draw top texture { - dc_yl = yl; - dc_yh = mid; - dc_texturemid = rw_toptexturemid; - dc_source = R_GetColumn(toptexture,texturecolumn); - dc_texheight = textureheight[toptexture]>>FRACBITS; - dc_sourcelength = dc_texheight; - colfunc(); + R_DrawWallColumn(dc, yl, mid, rw_toptexturemid, texturecolumn, toptexture, topremap); ceilingclip[rw_x] = (INT16)mid; } else if (!rw_ceilingmarked) // entirely off top of screen @@ -1507,14 +1491,7 @@ static void R_RenderSegLoop (void) } else if (mid < viewheight) // safe to draw bottom texture { - dc_yl = mid; - dc_yh = yh; - dc_texturemid = rw_bottomtexturemid; - dc_source = R_GetColumn(bottomtexture, - texturecolumn); - dc_texheight = textureheight[bottomtexture]>>FRACBITS; - dc_sourcelength = dc_texheight; - colfunc(); + R_DrawWallColumn(dc, mid, yh, rw_bottomtexturemid, texturecolumn, bottomtexture, bottomremap); floorclip[rw_x] = (INT16)mid; } else if (!rw_floormarked) // entirely off bottom of screen @@ -1527,25 +1504,33 @@ static void R_RenderSegLoop (void) floorclip[rw_x] = bottomclip; } + if ((markceiling || markfloor) && (floorclip[rw_x] <= ceilingclip[rw_x] + 1)) + { + solidcol[rw_x] = 1; + didsolidcol = true; + } + if (maskedtexture || numthicksides) { // save texturecol for backdrawing of masked mid texture maskedtexturecol[rw_x] = (INT16)texturecolumn; - if (maskedtextureheight != NULL) { + if (maskedtextureheight != NULL) + { maskedtextureheight[rw_x] = (!!(curline->linedef->flags & ML_DONTPEGBOTTOM) ^ !!(curline->linedef->flags & ML_EFFECT3) ? - max(rw_midtexturemid, rw_midtextureback) : - min(rw_midtexturemid, rw_midtextureback)); + std::max(rw_midtexturemid, rw_midtextureback) : + std::min(rw_midtexturemid, rw_midtextureback)); } } - if (dc_numlights) + if (dc->numlights) { - for (i = 0; i < dc_numlights; i++) + for (i = 0; i < dc->numlights; i++) { - dc_lightlist[i].height += dc_lightlist[i].heightstep; - if (dc_lightlist[i].flags & FF_CUTSOLIDS) - dc_lightlist[i].botheight += dc_lightlist[i].botheightstep; + dc->lightlist[i].height += dc->lightlist[i].heightstep; + + if (dc->lightlist[i].flags & FF_CUTSOLIDS) + dc->lightlist[i].botheight += dc->lightlist[i].botheightstep; } } @@ -1570,8 +1555,74 @@ static void R_RenderSegLoop (void) topfrac += topstep; bottomfrac += bottomstep; } +} - //colfunc = wallcolfunc; +static void R_MarkSegBounds(void) +{ + INT32 yl, yh; + INT32 top, bottom; + INT16 topclip, bottomclip; + + for (; rw_x < rw_stopx; rw_x++) + { + // mark floor / ceiling areas + yl = (topfrac+HEIGHTUNIT-1)>>HEIGHTBITS; + + // no space above wall? + top = ceilingclip[rw_x]+1; + + // no space above wall? + if (yl < top) + yl = top; + + if (markceiling) + { + bottom = yl > floorclip[rw_x] ? floorclip[rw_x] : yl; + + if (top <= --bottom && ceilingplane) + { + R_ExpandPlaneY(ceilingplane, rw_x, top, bottom); + } + } + + yh = bottomfrac>>HEIGHTBITS; + + bottom = floorclip[rw_x]-1; + + if (yh > bottom) + yh = bottom; + + if (markfloor) + { + top = yh < ceilingclip[rw_x] ? ceilingclip[rw_x] : yh; + + if (++top <= bottom && floorplane) + { + R_ExpandPlaneY(floorplane, rw_x, top, bottom); + } + } + + frontscale[rw_x] = rw_scale; + + topclip = (yl >= 0) ? ((yl > viewheight) ? (INT16)viewheight : (INT16)((INT16)yl - 1)) : -1; + bottomclip = (yh < viewheight) ? ((yh < -1) ? -1 : (INT16)((INT16)yh + 1)) : (INT16)viewheight; + + if (markceiling) // no top wall + ceilingclip[rw_x] = topclip; + + if (markfloor) // no bottom wall + floorclip[rw_x] = bottomclip; + + if (floorclip[rw_x] <= ceilingclip[rw_x] + 1) + { + solidcol[rw_x] = 1; + didsolidcol = true; + } + + rw_scale += rw_scalestep; + topfrac += topstep; + bottomfrac += bottomstep; + } } // Uses precalculated seg->length @@ -1591,6 +1642,33 @@ static INT64 R_CalcSegDist(seg_t* seg, INT64 x2, INT64 y2) } } +static size_t maxdrawsegs = 0; + +static fixed_t *frontscaletable = NULL; +static fixed_t *maskedheighttable = NULL; + +void R_AllocSegMemory(void) +{ + if (!maxdrawsegs) + return; + + frontscaletable = static_cast(Z_Realloc(frontscaletable, sizeof(*frontscaletable) * (maxdrawsegs * viewwidth), PU_STATIC, NULL)); + maskedheighttable = static_cast(Z_Realloc(maskedheighttable, sizeof(*maskedheighttable) * (maxdrawsegs * viewwidth), PU_STATIC, NULL)); + + drawseg_t *lastseg = drawsegs + maxdrawsegs; + + fixed_t *frontscale_p = frontscaletable; + fixed_t *maskedheight_p = maskedheighttable; + + for (drawseg_t *ds = drawsegs; ds < lastseg; ds++) + { + ds->frontscale = frontscale_p; + ds->maskedtextureheight = maskedheight_p; + frontscale_p += viewwidth; + maskedheight_p += viewwidth; + } +} + // // R_StoreWallRange // A wall segment will be drawn @@ -1609,7 +1687,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) INT32 range; vertex_t segleft, segright; fixed_t ceilingfrontslide, floorfrontslide, ceilingbackslide, floorbackslide; - static size_t maxdrawsegs = 0; + drawcolumndata_t dc = {}; maskedtextureheight = NULL; //initialize segleft and segright @@ -1618,15 +1696,24 @@ void R_StoreWallRange(INT32 start, INT32 stop) if (ds_p == drawsegs+maxdrawsegs) { + size_t curpos = curdrawsegs - drawsegs; size_t pos = ds_p - drawsegs; size_t newmax = maxdrawsegs ? maxdrawsegs*2 : 128; + if (firstseg) firstseg = (drawseg_t *)(firstseg - drawsegs); - drawsegs = Z_Realloc(drawsegs, newmax*sizeof (*drawsegs), PU_STATIC, NULL); + + drawsegs = static_cast(Z_Realloc(drawsegs, newmax*sizeof (*drawsegs), PU_STATIC, NULL)); + ds_p = drawsegs + pos; + maxdrawsegs = newmax; + curdrawsegs = drawsegs + curpos; + if (firstseg) firstseg = drawsegs + (size_t)firstseg; + + R_AllocSegMemory(); } sidedef = curline->sidedef; @@ -1659,6 +1746,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) { size_t pos = lastopening - openings; size_t need = (rw_stopx - start)*4 + pos; + if (need > maxopenings) { drawseg_t *ds; //needed for fix from *cough* zdoom *cough* @@ -1668,7 +1756,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) do maxopenings = maxopenings ? maxopenings*2 : 16384; while (need > maxopenings); - openings = Z_Realloc(openings, maxopenings * sizeof (*openings), PU_STATIC, NULL); + openings = static_cast(Z_Realloc(openings, maxopenings * sizeof (*openings), PU_STATIC, NULL)); lastopening = openings + pos; if (oldopenings == NULL) @@ -1679,7 +1767,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) // were already stored in drawsegs. for (ds = drawsegs; ds < ds_p; ds++) { -#define ADJUST(p) if (ds->p + ds->x1 >= oldopenings && ds->p + ds->x1 <= oldlast) ds->p = ds->p - oldopenings + openings; +#define ADJUST(p) if (ds->p + ds->x1 >= oldopenings && ds->p + ds->x1 <= oldlast) ds->p = (ds->p - oldopenings) + openings; ADJUST(maskedtexturecol); ADJUST(sprtopclip); ADJUST(sprbottomclip); @@ -1727,57 +1815,38 @@ void R_StoreWallRange(INT32 start, INT32 stop) if (frontsector->hasslope || (backsector && backsector->hasslope)) // Commenting this out for FOFslop. -Red { angle_t temp; + double a1, b1, c1, a2, b2, c2, det; // 1 is the seg, 2 is the view angle vector... // left temp = xtoviewangle[start]+viewangle; -#define FIXED_TO_DOUBLE(x) (((double)(x)) / ((double)FRACUNIT)) -#define DOUBLE_TO_FIXED(x) (fixed_t)((x) * ((double)FRACUNIT)) + a1 = FixedToDouble(curline->v2->y-curline->v1->y); + b1 = FixedToDouble(curline->v1->x-curline->v2->x); + c1 = a1*FixedToDouble(curline->v1->x) + b1*FixedToDouble(curline->v1->y); - { - // Both lines can be written in slope-intercept form, so figure out line intersection - double a1, b1, c1, a2, b2, c2, det; // 1 is the seg, 2 is the view angle vector... - ///TODO: convert to fixed point + // Both lines can be written in slope-intercept form, so figure out line intersection - a1 = FIXED_TO_DOUBLE(curline->v2->y-curline->v1->y); - b1 = FIXED_TO_DOUBLE(curline->v1->x-curline->v2->x); - c1 = a1*FIXED_TO_DOUBLE(curline->v1->x) + b1*FIXED_TO_DOUBLE(curline->v1->y); + // left + a2 = -FixedToDouble(FINESINE(temp>>ANGLETOFINESHIFT)); + b2 = FixedToDouble(FINECOSINE(temp>>ANGLETOFINESHIFT)); + c2 = a2*FixedToDouble(viewx) + b2*FixedToDouble(viewy); - a2 = -FIXED_TO_DOUBLE(FINESINE(temp>>ANGLETOFINESHIFT)); - b2 = FIXED_TO_DOUBLE(FINECOSINE(temp>>ANGLETOFINESHIFT)); - c2 = a2*FIXED_TO_DOUBLE(viewx) + b2*FIXED_TO_DOUBLE(viewy); + det = a1*b2 - a2*b1; - det = a1*b2 - a2*b1; - - ds_p->leftpos.x = segleft.x = DOUBLE_TO_FIXED((b2*c1 - b1*c2)/det); - ds_p->leftpos.y = segleft.y = DOUBLE_TO_FIXED((a1*c2 - a2*c1)/det); - } + ds_p->leftpos.x = segleft.x = DoubleToFixed((b2*c1 - b1*c2)/det); + ds_p->leftpos.y = segleft.y = DoubleToFixed((a1*c2 - a2*c1)/det); // right temp = xtoviewangle[stop]+viewangle; - { - // Both lines can be written in slope-intercept form, so figure out line intersection - double a1, b1, c1, a2, b2, c2, det; // 1 is the seg, 2 is the view angle vector... - ///TODO: convert to fixed point + a2 = -FixedToDouble(FINESINE(temp>>ANGLETOFINESHIFT)); + b2 = FixedToDouble(FINECOSINE(temp>>ANGLETOFINESHIFT)); + c2 = a2*FixedToDouble(viewx) + b2*FixedToDouble(viewy); - a1 = FIXED_TO_DOUBLE(curline->v2->y-curline->v1->y); - b1 = FIXED_TO_DOUBLE(curline->v1->x-curline->v2->x); - c1 = a1*FIXED_TO_DOUBLE(curline->v1->x) + b1*FIXED_TO_DOUBLE(curline->v1->y); - - a2 = -FIXED_TO_DOUBLE(FINESINE(temp>>ANGLETOFINESHIFT)); - b2 = FIXED_TO_DOUBLE(FINECOSINE(temp>>ANGLETOFINESHIFT)); - c2 = a2*FIXED_TO_DOUBLE(viewx) + b2*FIXED_TO_DOUBLE(viewy); - - det = a1*b2 - a2*b1; - - ds_p->rightpos.x = segright.x = DOUBLE_TO_FIXED((b2*c1 - b1*c2)/det); - ds_p->rightpos.y = segright.y = DOUBLE_TO_FIXED((a1*c2 - a2*c1)/det); - } - -#undef FIXED_TO_DOUBLE -#undef DOUBLE_TO_FIXED + det = a1*b2 - a2*b1; + ds_p->rightpos.x = segright.x = DoubleToFixed((b2*c1 - b1*c2)/det); + ds_p->rightpos.y = segright.y = DoubleToFixed((a1*c2 - a2*c1)/det); } #define SLOPEPARAMS(slope, end1, end2, normalheight) \ @@ -1794,6 +1863,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) worldbottomslope -= viewz; midtexture = toptexture = bottomtexture = maskedtexture = 0; + midremap = topremap = bottomremap = false; ds_p->maskedtexturecol = NULL; ds_p->numthicksides = numthicksides = 0; ds_p->thicksidecol = NULL; @@ -1820,28 +1890,38 @@ void R_StoreWallRange(INT32 start, INT32 stop) rw_toptextureslide = rw_midtextureslide = rw_bottomtextureslide = 0; ceilingfrontslide = floorfrontslide = ceilingbackslide = floorbackslide = 0; - angle_t lineangle = R_PointToAngle2(curline->v1->x, curline->v1->y, curline->v2->x, curline->v2->y); + if (backsector || frontsector->f_slope || frontsector->c_slope) + { + angle_t lineangle = R_PointToAngle2(curline->v1->x, curline->v1->y, curline->v2->x, curline->v2->y); - if (frontsector->f_slope) - floorfrontslide = FixedMul(frontsector->f_slope->zdelta, FINECOSINE((lineangle-frontsector->f_slope->xydirection)>>ANGLETOFINESHIFT)); + if (frontsector->f_slope) + floorfrontslide = FixedMul(frontsector->f_slope->zdelta, FINECOSINE((lineangle-frontsector->f_slope->xydirection)>>ANGLETOFINESHIFT)); - if (frontsector->c_slope) - ceilingfrontslide = FixedMul(frontsector->c_slope->zdelta, FINECOSINE((lineangle-frontsector->c_slope->xydirection)>>ANGLETOFINESHIFT)); + if (frontsector->c_slope) + ceilingfrontslide = FixedMul(frontsector->c_slope->zdelta, FINECOSINE((lineangle-frontsector->c_slope->xydirection)>>ANGLETOFINESHIFT)); - if (backsector && backsector->f_slope) - floorbackslide = FixedMul(backsector->f_slope->zdelta, FINECOSINE((lineangle-backsector->f_slope->xydirection)>>ANGLETOFINESHIFT)); + if (backsector) + { + if (backsector->f_slope) + floorbackslide = FixedMul(backsector->f_slope->zdelta, FINECOSINE((lineangle-backsector->f_slope->xydirection)>>ANGLETOFINESHIFT)); - if (backsector && backsector->c_slope) - ceilingbackslide = FixedMul(backsector->c_slope->zdelta, FINECOSINE((lineangle-backsector->c_slope->xydirection)>>ANGLETOFINESHIFT)); + if (backsector->c_slope) + ceilingbackslide = FixedMul(backsector->c_slope->zdelta, FINECOSINE((lineangle-backsector->c_slope->xydirection)>>ANGLETOFINESHIFT)); + } + } if (!backsector) { fixed_t texheight; + // single sided line midtexture = R_GetTextureNum(sidedef->midtexture); + midremap = (encoremap && !(curline->linedef->flags & ML_TFERLINE)); texheight = textureheight[midtexture]; + // a single sided line is terminal, so it must mark ends markfloor = markceiling = true; + if (linedef->flags & ML_EFFECT2) { if (linedef->flags & ML_DONTPEGBOTTOM) @@ -1871,6 +1951,8 @@ void R_StoreWallRange(INT32 start, INT32 stop) else { // two sided line + boolean bothceilingssky = false; // turned on if both back and front ceilings are sky + SLOPEPARAMS(backsector->c_slope, worldhigh, worldhighslope, backsector->ceilingheight) SLOPEPARAMS(backsector->f_slope, worldlow, worldlowslope, backsector->floorheight) worldhigh -= viewz; @@ -1885,6 +1967,8 @@ void R_StoreWallRange(INT32 start, INT32 stop) { worldtopslope = worldhighslope = worldtop = worldhigh; + + bothceilingssky = true; } ds_p->sprtopclip = ds_p->sprbottomclip = NULL; @@ -1905,18 +1989,22 @@ void R_StoreWallRange(INT32 start, INT32 stop) // ds_p->sprbottomclip = negonearray; } - if (worldtopslope < worldhighslope || worldtop < worldhigh) + if (!bothceilingssky) { - ds_p->silhouette |= SIL_TOP; - if (P_GetSectorCeilingZAt(backsector, viewx, viewy) < viewz) + if (worldtopslope < worldhighslope || worldtop < worldhigh) + { + ds_p->silhouette |= SIL_TOP; + if (P_GetSectorCeilingZAt(backsector, viewx, viewy) < viewz) + ds_p->tsilheight = INT32_MIN; + else + ds_p->tsilheight = (frontsector->c_slope ? INT32_MIN : frontsector->ceilingheight); + } + else if (P_GetSectorCeilingZAt(backsector, viewx, viewy) < viewz) + { + ds_p->silhouette |= SIL_TOP; ds_p->tsilheight = INT32_MIN; - else - ds_p->tsilheight = (frontsector->c_slope ? INT32_MIN : frontsector->ceilingheight); - } - else if (P_GetSectorCeilingZAt(backsector, viewx, viewy) < viewz) - { - ds_p->silhouette |= SIL_TOP; - ds_p->tsilheight = INT32_MIN; + // ds_p->sprtopclip = screenheightarray; + } } if (viewsector != frontsector && viewsector != backsector) @@ -1941,18 +2029,18 @@ void R_StoreWallRange(INT32 start, INT32 stop) if (worldlow != worldbottom || worldlowslope != worldbottomslope || backsector->f_slope != frontsector->f_slope - || backsector->floorpic != frontsector->floorpic - || backsector->lightlevel != frontsector->lightlevel - //SoM: 3/22/2000: Check floor x and y offsets. - || backsector->floor_xoffs != frontsector->floor_xoffs - || backsector->floor_yoffs != frontsector->floor_yoffs - || backsector->floorpic_angle != frontsector->floorpic_angle - //SoM: 3/22/2000: Prevents bleeding. - || frontsector->heightsec != -1 - || backsector->floorlightsec != frontsector->floorlightsec - //SoM: 4/3/2000: Check for colormaps - || frontsector->extra_colormap != backsector->extra_colormap - || (frontsector->ffloors != backsector->ffloors && frontsector->tag != backsector->tag)) + || backsector->floorpic != frontsector->floorpic + || backsector->lightlevel != frontsector->lightlevel + //SoM: 3/22/2000: Check floor x and y offsets. + || backsector->floor_xoffs != frontsector->floor_xoffs + || backsector->floor_yoffs != frontsector->floor_yoffs + || backsector->floorpic_angle != frontsector->floorpic_angle + //SoM: 3/22/2000: Prevents bleeding. + || frontsector->heightsec != -1 + || backsector->floorlightsec != frontsector->floorlightsec + //SoM: 4/3/2000: Check for colormaps + || frontsector->extra_colormap != backsector->extra_colormap + || (frontsector->ffloors != backsector->ffloors && frontsector->tag != backsector->tag)) { markfloor = true; } @@ -1965,18 +2053,18 @@ void R_StoreWallRange(INT32 start, INT32 stop) if (worldhigh != worldtop || worldhighslope != worldtopslope || backsector->c_slope != frontsector->c_slope - || backsector->ceilingpic != frontsector->ceilingpic - || backsector->lightlevel != frontsector->lightlevel - //SoM: 3/22/2000: Check floor x and y offsets. - || backsector->ceiling_xoffs != frontsector->ceiling_xoffs - || backsector->ceiling_yoffs != frontsector->ceiling_yoffs - || backsector->ceilingpic_angle != frontsector->ceilingpic_angle - //SoM: 3/22/2000: Prevents bleeding. - || (frontsector->heightsec != -1 && frontsector->ceilingpic != skyflatnum) - || backsector->ceilinglightsec != frontsector->ceilinglightsec - //SoM: 4/3/2000: Check for colormaps - || frontsector->extra_colormap != backsector->extra_colormap - || (frontsector->ffloors != backsector->ffloors && frontsector->tag != backsector->tag)) + || backsector->ceilingpic != frontsector->ceilingpic + || backsector->lightlevel != frontsector->lightlevel + //SoM: 3/22/2000: Check floor x and y offsets. + || backsector->ceiling_xoffs != frontsector->ceiling_xoffs + || backsector->ceiling_yoffs != frontsector->ceiling_yoffs + || backsector->ceilingpic_angle != frontsector->ceilingpic_angle + //SoM: 3/22/2000: Prevents bleeding. + || (frontsector->heightsec != -1 && frontsector->ceilingpic != skyflatnum) + || backsector->ceilinglightsec != frontsector->ceilinglightsec + //SoM: 4/3/2000: Check for colormaps + || frontsector->extra_colormap != backsector->extra_colormap + || (frontsector->ffloors != backsector->ffloors && frontsector->tag != backsector->tag)) { markceiling = true; } @@ -1987,17 +2075,20 @@ void R_StoreWallRange(INT32 start, INT32 stop) } if (backsector->ceilingheight <= frontsector->floorheight || - backsector->floorheight >= frontsector->ceilingheight) + backsector->floorheight >= frontsector->ceilingheight) { // closed door markceiling = markfloor = true; } // check TOP TEXTURE - if (worldhigh < worldtop || worldhighslope < worldtopslope) + if (!bothceilingssky // never draw the top texture if on + && (worldhigh < worldtop || worldhighslope < worldtopslope)) { fixed_t texheight; // top texture + topremap = (encoremap && !(curline->linedef->flags & ML_TFERLINE)); + if ((linedef->flags & (ML_DONTPEGTOP) && (linedef->flags & ML_DONTPEGBOTTOM)) && linedef->sidenum[1] != 0xffff) { @@ -2034,11 +2125,13 @@ void R_StoreWallRange(INT32 start, INT32 stop) rw_toptextureslide = ceilingbackslide; } } + // check BOTTOM TEXTURE if (worldlow > worldbottom || worldlowslope > worldbottomslope) // Only if VISIBLE!!! { // bottom texture bottomtexture = R_GetTextureNum(sidedef->bottomtexture); + bottomremap = (encoremap && !(curline->linedef->flags & ML_TFERLINE)); if (!(linedef->flags & ML_EFFECT1)) // Ignore slopes for lower/upper textures unless flag is checked { @@ -2065,7 +2158,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) rw_bottomtexturemid += sidedef->rowoffset; // allocate space for masked texture tables - if (frontsector && backsector && frontsector->tag != backsector->tag && (backsector->ffloors || frontsector->ffloors)) + if (frontsector && backsector && (frontsector->tag != backsector->tag) && (backsector->ffloors || frontsector->ffloors)) { ffloor_t *rover; ffloor_t *r2; @@ -2080,10 +2173,18 @@ void R_StoreWallRange(INT32 start, INT32 stop) ds_p->thicksidecol = maskedtexturecol = lastopening - rw_x; lastopening += rw_stopx - rw_x; - lowcut = max(worldbottom, worldlow) + viewz; - highcut = min(worldtop, worldhigh) + viewz; - lowcutslope = max(worldbottomslope, worldlowslope) + viewz; - highcutslope = min(worldtopslope, worldhighslope) + viewz; + lowcut = std::max(worldbottom, worldlow) + viewz; + highcut = std::min(worldtop, worldhigh) + viewz; + lowcutslope = std::max(worldbottomslope, worldlowslope) + viewz; + highcutslope = std::min(worldtopslope, worldhighslope) + viewz; + + auto check_fof_offscreen = [&](INT32 bottom, INT32 bottomslope, INT32 top, INT32 topslope) + { + return ((P_GetFFloorTopZAt (rover, segleft .x, segleft .y) <= bottom + viewz + && P_GetFFloorTopZAt (rover, segright.x, segright.y) <= bottomslope + viewz) + || ( P_GetFFloorBottomZAt (rover, segleft .x, segleft .y) >= top + viewz + && P_GetFFloorBottomZAt (rover, segright.x, segright.y) >= topslope + viewz)); + }; if (frontsector->ffloors && backsector->ffloors) { @@ -2185,7 +2286,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) SLOPEPARAMS(*r2->t_slope, high2, highslope2, *r2->topheight) SLOPEPARAMS(*r2->b_slope, low2, lowslope2, *r2->bottomheight) - +#undef SLOPEPARAMS if ((high2 < lowcut || highslope2 < lowcutslope) || (low2 > highcut || lowslope2 > highcutslope)) continue; if ((high1 > high2 || highslope1 > highslope2) || (low1 < low2 || lowslope1 < lowslope2)) @@ -2206,14 +2307,12 @@ void R_StoreWallRange(INT32 start, INT32 stop) { if (!(rover->flags & FF_RENDERSIDES) || !(rover->flags & FF_EXISTS) || rover->flags & FF_INVERTSIDES) continue; + if (rover->norender == leveltime) continue; // Oy vey. - if ( ((P_GetFFloorTopZAt (rover, segleft .x, segleft .y)) <= worldbottom + viewz - && (P_GetFFloorTopZAt (rover, segright.x, segright.y)) <= worldbottomslope + viewz) - ||((P_GetFFloorBottomZAt(rover, segleft .x, segleft .y)) >= worldtop + viewz - && (P_GetFFloorBottomZAt(rover, segright.x, segright.y)) >= worldtopslope + viewz)) + if (check_fof_offscreen(worldbottom, worldbottomslope, worldtop, worldtopslope)) continue; ds_p->thicksides[i] = rover; @@ -2226,20 +2325,15 @@ void R_StoreWallRange(INT32 start, INT32 stop) { if (!(rover->flags & FF_RENDERSIDES) || !(rover->flags & FF_EXISTS) || !(rover->flags & FF_ALLSIDES)) continue; + if (rover->norender == leveltime) continue; // Oy vey. - if ( (P_GetFFloorTopZAt (rover, segleft .x, segleft .y) <= worldbottom + viewz - && P_GetFFloorTopZAt (rover, segright.x, segright.y) <= worldbottomslope + viewz) - ||(P_GetFFloorBottomZAt(rover, segleft .x, segleft .y) >= worldtop + viewz - && P_GetFFloorBottomZAt(rover, segright.x, segright.y) >= worldtopslope + viewz)) + if (check_fof_offscreen(worldbottom, worldbottomslope, worldtop, worldtopslope)) continue; - if ( (P_GetFFloorTopZAt (rover, segleft .x, segleft .y) <= worldlow + viewz - && P_GetFFloorTopZAt (rover, segright.x, segright.y) <= worldlowslope + viewz) - ||(P_GetFFloorBottomZAt(rover, segleft .x, segleft .y) >= worldhigh + viewz - && P_GetFFloorBottomZAt(rover, segright.x, segright.y) >= worldhighslope + viewz)) + if (check_fof_offscreen(worldlow, worldlowslope, worldhigh, worldhighslope)) continue; ds_p->thicksides[i] = rover; @@ -2268,9 +2362,9 @@ void R_StoreWallRange(INT32 start, INT32 stop) rw_midtextureslide = rw_midtexturebackslide = 0; if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) - rw_midtexturemid = rw_midtextureback = max(curline->frontsector->floorheight, curline->backsector->floorheight) - viewz; + rw_midtexturemid = rw_midtextureback = std::max(curline->frontsector->floorheight, curline->backsector->floorheight) - viewz; else - rw_midtexturemid = rw_midtextureback = min(curline->frontsector->ceilingheight, curline->backsector->ceilingheight) - viewz; + rw_midtexturemid = rw_midtextureback = std::min(curline->frontsector->ceilingheight, curline->backsector->ceilingheight) - viewz; } else { @@ -2280,9 +2374,9 @@ void R_StoreWallRange(INT32 start, INT32 stop) rw_midtextureslide = rw_midtexturebackslide = 0; if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) - rw_midtexturemid = rw_midtextureback = max(frontsector->floorheight, backsector->floorheight) - viewz; + rw_midtexturemid = rw_midtextureback = std::max(frontsector->floorheight, backsector->floorheight) - viewz; else - rw_midtexturemid = rw_midtextureback = min(frontsector->ceilingheight, backsector->ceilingheight) - viewz; + rw_midtexturemid = rw_midtextureback = std::min(frontsector->ceilingheight, backsector->ceilingheight) - viewz; } else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) @@ -2308,7 +2402,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) } // calculate rw_offset (only needed for textured lines) - segtextured = midtexture || toptexture || bottomtexture || maskedtexture || (numthicksides > 0); + segtextured = (midtexture || toptexture || bottomtexture || maskedtexture || (numthicksides > 0)); if (segtextured) { @@ -2390,10 +2484,53 @@ void R_StoreWallRange(INT32 start, INT32 stop) } else { - topstep = -FixedMul (rw_scalestep, worldtop); - topfrac = (centeryfrac>>4) - FixedMul (worldtop, rw_scale); + // for anyone that sees this + // dont. + // this is absolute shit-tier hacks + // but i just cant determine this in any sane way + // but this checks a shitton of things to make software handle skies better - bottomstep = -FixedMul (rw_scalestep,worldbottom); + auto set_topstep_normal = [&] + { + topstep = -FixedMul (rw_scalestep, worldtop); + topfrac = (centeryfrac>>4) - FixedMul (worldtop, rw_scale); + }; + + // untextured seg + if (!segtextured && !curline->polyseg) + { + const bool tophigh = (worldhigh <= worldtop && worldhighslope <= worldtopslope); + + // if we cant see the goddamn skyplane, well there wont be any skybox + // we could kill skyVisible instead, but i want to keep the performance improvemnts it yields + // so we do this absolute trash + if ((tophigh + && (frontsector->floorpic != skyflatnum && frontsector->ceilingpic != skyflatnum)) // try to guess if its a "window" + && ((!backsector) // single sided + || ((backsector && (worldhigh != worldtop || worldhighslope != worldtopslope)) + && (backsector->floorheight >= frontsector->ceilingheight || backsector->ceilingheight <= frontsector->floorheight)))) // check if there is a "thok" sector behind it + skyVisible = true; + + // this is an attempt to fix issues with textureless single sided lines drawing nothing where they should just draw sky instead + if (tophigh && !backsector && frontsector->ceilingpic == skyflatnum) + { + topstep = -FixedMul (rw_scalestep, worldbottom); + topfrac = (centeryfrac>>4) - FixedMul (worldbottom, rw_scale); + + // account for slopes to try and get rid of sharp edges from the black void + if (frontsector->f_slope || (backsector && backsector->f_slope)) + { + topstep = -FixedMul (rw_scalestep, worldbottomslope); + topfrac = (centeryfrac>>4) - FixedMul (worldbottomslope, rw_scale); + } + } + else + set_topstep_normal(); + } + else + set_topstep_normal(); + + bottomstep = -FixedMul (rw_scalestep, worldbottom); bottomfrac = (centeryfrac>>4) - FixedMul (worldbottom, rw_scale); if (frontsector->c_slope) @@ -2401,6 +2538,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) fixed_t topfracend = (centeryfrac>>4) - FixedMul (worldtopslope, ds_p->scale2); topstep = (topfracend-topfrac)/(range); } + if (frontsector->f_slope) { fixed_t bottomfracend = (centeryfrac>>4) - FixedMul (worldbottomslope, ds_p->scale2); @@ -2408,23 +2546,20 @@ void R_StoreWallRange(INT32 start, INT32 stop) } } - dc_numlights = 0; + dc.numlights = 0; if (frontsector->numlights) { - dc_numlights = frontsector->numlights; - if (dc_numlights >= dc_maxlights) - { - dc_maxlights = dc_numlights; - dc_lightlist = Z_Realloc(dc_lightlist, sizeof (*dc_lightlist) * dc_maxlights, PU_STATIC, NULL); - } + dc.numlights = frontsector->numlights; + dc.maxlights = dc.numlights; + dc.lightlist = static_cast(Z_Frame_Alloc(sizeof(*dc.lightlist) * dc.maxlights)); - for (i = p = 0; i < dc_numlights; i++) + for (i = p = 0; i < dc.numlights; i++) { fixed_t leftheight, rightheight; light = &frontsector->lightlist[i]; - rlight = &dc_lightlist[p]; + rlight = &dc.lightlist[p]; leftheight = P_GetLightZAt(light, segleft.x, segleft.y); rightheight = P_GetLightZAt(light, segright.x, segright.y); @@ -2444,14 +2579,14 @@ void R_StoreWallRange(INT32 start, INT32 stop) if (leftheight < worldbottom && rightheight < worldbottomslope) continue; - if (leftheight > worldtop && rightheight > worldtopslope && i+1 < dc_numlights && frontsector->lightlist[i+1].height > frontsector->ceilingheight) + if (leftheight > worldtop && rightheight > worldtopslope && i+1 < dc.numlights && frontsector->lightlist[i+1].height > frontsector->ceilingheight) continue; } rlight->height = (centeryfrac>>4) - FixedMul(leftheight, rw_scale); rlight->heightstep = (centeryfrac>>4) - FixedMul(rightheight, ds_p->scale2); rlight->heightstep = (rlight->heightstep-rlight->height)/(range); - rlight->flags = light->flags; + rlight->flags = static_cast(light->flags); if (light->caster && light->caster->flags & FF_CUTSOLIDS) { @@ -2479,7 +2614,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) p++; } - dc_numlights = p; + dc.numlights = p; } if (numffloors) @@ -2512,13 +2647,13 @@ void R_StoreWallRange(INT32 start, INT32 stop) if (toptexture) { - fixed_t topfracend = (centeryfrac>>4) - FixedMul (worldhighslope, ds_p->scale2); + fixed_t topfracend = (centeryfrac>>4) - FixedMul(worldhighslope, ds_p->scale2); pixhigh = (centeryfrac>>4) - FixedMul (worldhigh, rw_scale); pixhighstep = (topfracend-pixhigh)/(range); // If the lowest part of a ceiling stretching down covers the entire screen - if (min(pixhigh, topfracend)>>HEIGHTBITS >= viewheight-1) + if (std::min(pixhigh, topfracend)>>HEIGHTBITS >= viewheight-1) g_walloffscreen = true; } @@ -2530,7 +2665,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) pixlowstep = (bottomfracend-pixlow)/(range); // If the highest part of a floor stretching up covers the entire screen - if ((max(pixlow, bottomfracend)+HEIGHTUNIT-1)>>HEIGHTBITS <= 0) + if ((std::max(pixlow, bottomfracend)+HEIGHTUNIT-1)>>HEIGHTBITS <= 0) g_walloffscreen = true; } @@ -2540,12 +2675,25 @@ void R_StoreWallRange(INT32 start, INT32 stop) fixed_t planevistest; i = 0; + auto setup_back_fof = [&] + { + //ffloor[i].slope = *rover->b_slope; + ffloor[i].b_pos = roverleft; + ffloor[i].b_pos_slope = roverright; + ffloor[i].b_pos >>= 4; + ffloor[i].b_pos_slope >>= 4; + ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale); + ffloor[i].b_step = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos_slope, ds_p->scale2); + ffloor[i].b_step = (ffloor[i].b_step-ffloor[i].b_frac)/(range); + }; + if (backsector->ffloors) { for (rover = backsector->ffloors; rover && i < MAXFFLOORS; rover = rover->next) { if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERPLANES)) continue; + if (rover->norender == leveltime) continue; @@ -2558,18 +2706,11 @@ void R_StoreWallRange(INT32 start, INT32 stop) planevistest = P_GetFFloorBottomZAt(rover, viewx, viewy); if ((roverleft>>4 <= worldhigh || roverright>>4 <= worldhighslope) && - (roverleft>>4 >= worldlow || roverright>>4 >= worldlowslope) && - ((viewz < planevistest && !(rover->flags & FF_INVERTPLANES)) || - (viewz > planevistest && (rover->flags & FF_BOTHPLANES)))) + (roverleft>>4 >= worldlow || roverright>>4 >= worldlowslope) && + ((viewz < planevistest && !(rover->flags & FF_INVERTPLANES)) || + (viewz > planevistest && (rover->flags & FF_BOTHPLANES)))) { - //ffloor[i].slope = *rover->b_slope; - ffloor[i].b_pos = roverleft; - ffloor[i].b_pos_slope = roverright; - ffloor[i].b_pos >>= 4; - ffloor[i].b_pos_slope >>= 4; - ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale); - ffloor[i].b_step = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos_slope, ds_p->scale2); - ffloor[i].b_step = (ffloor[i].b_step-ffloor[i].b_frac)/(range); + setup_back_fof(); i++; } @@ -2581,18 +2722,11 @@ void R_StoreWallRange(INT32 start, INT32 stop) planevistest = P_GetFFloorTopZAt(rover, viewx, viewy); if ((roverleft>>4 <= worldhigh || roverright>>4 <= worldhighslope) && - (roverleft>>4 >= worldlow || roverright>>4 >= worldlowslope) && - ((viewz > planevistest && !(rover->flags & FF_INVERTPLANES)) || - (viewz < planevistest && (rover->flags & FF_BOTHPLANES)))) + (roverleft>>4 >= worldlow || roverright>>4 >= worldlowslope) && + ((viewz > planevistest && !(rover->flags & FF_INVERTPLANES)) || + (viewz < planevistest && (rover->flags & FF_BOTHPLANES)))) { - //ffloor[i].slope = *rover->t_slope; - ffloor[i].b_pos = roverleft; - ffloor[i].b_pos_slope = roverright; - ffloor[i].b_pos >>= 4; - ffloor[i].b_pos_slope >>= 4; - ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale); - ffloor[i].b_step = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos_slope, ds_p->scale2); - ffloor[i].b_step = (ffloor[i].b_step-ffloor[i].b_frac)/(range); + setup_back_fof(); i++; } } @@ -2615,18 +2749,11 @@ void R_StoreWallRange(INT32 start, INT32 stop) planevistest = P_GetFFloorBottomZAt(rover, viewx, viewy); if ((roverleft>>4 <= worldhigh || roverright>>4 <= worldhighslope) && - (roverleft>>4 >= worldlow || roverright>>4 >= worldlowslope) && - ((viewz < planevistest && !(rover->flags & FF_INVERTPLANES)) || - (viewz > planevistest && (rover->flags & FF_BOTHPLANES)))) + (roverleft>>4 >= worldlow || roverright>>4 >= worldlowslope) && + ((viewz < planevistest && !(rover->flags & FF_INVERTPLANES)) || + (viewz > planevistest && (rover->flags & FF_BOTHPLANES)))) { - //ffloor[i].slope = *rover->b_slope; - ffloor[i].b_pos = roverleft; - ffloor[i].b_pos_slope = roverright; - ffloor[i].b_pos >>= 4; - ffloor[i].b_pos_slope >>= 4; - ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale); - ffloor[i].b_step = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos_slope, ds_p->scale2); - ffloor[i].b_step = (ffloor[i].b_step-ffloor[i].b_frac)/(range); + setup_back_fof(); i++; } @@ -2638,18 +2765,11 @@ void R_StoreWallRange(INT32 start, INT32 stop) planevistest = P_GetFFloorTopZAt(rover, viewx, viewy); if ((roverleft>>4 <= worldhigh || roverright>>4 <= worldhighslope) && - (roverleft>>4 >= worldlow || roverright>>4 >= worldlowslope) && - ((viewz > planevistest && !(rover->flags & FF_INVERTPLANES)) || - (viewz < planevistest && (rover->flags & FF_BOTHPLANES)))) + (roverleft>>4 >= worldlow || roverright>>4 >= worldlowslope) && + ((viewz > planevistest && !(rover->flags & FF_INVERTPLANES)) || + (viewz < planevistest && (rover->flags & FF_BOTHPLANES)))) { - //ffloor[i].slope = *rover->t_slope; - ffloor[i].b_pos = roverleft; - ffloor[i].b_pos_slope = roverright; - ffloor[i].b_pos >>= 4; - ffloor[i].b_pos_slope >>= 4; - ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale); - ffloor[i].b_step = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos_slope, ds_p->scale2); - ffloor[i].b_step = (ffloor[i].b_step-ffloor[i].b_frac)/(range); + setup_back_fof(); i++; } } @@ -2657,6 +2777,21 @@ void R_StoreWallRange(INT32 start, INT32 stop) if (curline->polyseg && frontsector && (curline->polyseg->flags & POF_RENDERPLANES)) { + auto setup_back_polyobj = [&](fixed_t height) + { + if (ffloor[i].plane->minx > ds_p->x1) + ffloor[i].plane->minx = ds_p->x1; + + if (ffloor[i].plane->maxx < ds_p->x2) + ffloor[i].plane->maxx = ds_p->x2; + + ffloor[i].slope = NULL; + ffloor[i].b_pos = height; + ffloor[i].b_pos = (ffloor[i].b_pos - viewz) >> 4; + ffloor[i].b_step = FixedMul(-rw_scalestep, ffloor[i].b_pos); + ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale); + }; + while (i < numffloors && ffloor[i].polyobj != curline->polyseg) i++; @@ -2664,17 +2799,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) backsector->floorheight >= frontsector->floorheight && (viewz < backsector->floorheight)) { - if (ffloor[i].plane->minx > ds_p->x1) - ffloor[i].plane->minx = ds_p->x1; - - if (ffloor[i].plane->maxx < ds_p->x2) - ffloor[i].plane->maxx = ds_p->x2; - - ffloor[i].slope = NULL; - ffloor[i].b_pos = backsector->floorheight; - ffloor[i].b_pos = (ffloor[i].b_pos - viewz) >> 4; - ffloor[i].b_step = FixedMul(-rw_scalestep, ffloor[i].b_pos); - ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale); + setup_back_polyobj(backsector->floorheight); i++; } @@ -2682,17 +2807,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) backsector->ceilingheight <= frontsector->ceilingheight && (viewz > backsector->ceilingheight)) { - if (ffloor[i].plane->minx > ds_p->x1) - ffloor[i].plane->minx = ds_p->x1; - - if (ffloor[i].plane->maxx < ds_p->x2) - ffloor[i].plane->maxx = ds_p->x2; - - ffloor[i].slope = NULL; - ffloor[i].b_pos = backsector->ceilingheight; - ffloor[i].b_pos = (ffloor[i].b_pos - viewz) >> 4; - ffloor[i].b_step = FixedMul(-rw_scalestep, ffloor[i].b_pos); - ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale); + setup_back_polyobj(backsector->ceilingheight); i++; } } @@ -2767,32 +2882,52 @@ void R_StoreWallRange(INT32 start, INT32 stop) } - rw_silhouette = &(ds_p->silhouette); - rw_tsilheight = &(ds_p->tsilheight); - rw_bsilheight = &(ds_p->bsilheight); + didsolidcol = false; -#ifdef WALLSPLATS - if (linedef->splats && cv_splats.value) + if (!segtextured && !numffloors) { - // Isn't a bit wasteful to copy the ENTIRE array for every drawseg? - M_Memcpy(last_ceilingclip + ds_p->x1, ceilingclip + ds_p->x1, - sizeof (INT16) * (ds_p->x2 - ds_p->x1 + 1)); - M_Memcpy(last_floorclip + ds_p->x1, floorclip + ds_p->x1, - sizeof (INT16) * (ds_p->x2 - ds_p->x1 + 1)); - R_RenderSegLoop(); - R_DrawWallSplats(); + if (markfloor || markceiling) + R_MarkSegBounds(); + else + { + for (; rw_x < rw_stopx; rw_x++) + { + frontscale[rw_x] = rw_scale; + rw_scale += rw_scalestep; + } + } } else -#endif + { + rw_silhouette = &ds_p->silhouette; + rw_tsilheight = &ds_p->tsilheight; + rw_bsilheight = &ds_p->bsilheight; - R_RenderSegLoop(); - colfunc = wallcolfunc; + R_RenderSegLoop(&dc); + } + + R_SetColumnFunc(BASEDRAWFUNC); if (g_portal) // if curline is a portal, set portalrender for drawseg ds_p->portalpass = portalrender+1; else ds_p->portalpass = 0; + // cph - if a column was made solid by this wall, we _must_ save full clipping info + if (backsector && didsolidcol) + { + if (!(ds_p->silhouette & SIL_BOTTOM)) + { + ds_p->silhouette |= SIL_BOTTOM; + ds_p->bsilheight = backsector->f_slope ? INT32_MAX : backsector->floorheight; + } + if (!(ds_p->silhouette & SIL_TOP)) + { + ds_p->silhouette |= SIL_TOP; + ds_p->tsilheight = backsector->c_slope ? INT32_MIN : backsector->ceilingheight; + } + } + // save sprite clipping info if (((ds_p->silhouette & SIL_TOP) || maskedtexture) && !ds_p->sprtopclip) { @@ -2808,15 +2943,20 @@ void R_StoreWallRange(INT32 start, INT32 stop) lastopening += rw_stopx - start; } - if (maskedtexture && !(ds_p->silhouette & SIL_TOP)) + if (maskedtexture) { - ds_p->silhouette |= SIL_TOP; - ds_p->tsilheight = (sidedef->midtexture > 0 && sidedef->midtexture < numtextures) ? INT32_MIN: INT32_MAX; - } - if (maskedtexture && !(ds_p->silhouette & SIL_BOTTOM)) - { - ds_p->silhouette |= SIL_BOTTOM; - ds_p->bsilheight = (sidedef->midtexture > 0 && sidedef->midtexture < numtextures) ? INT32_MAX: INT32_MIN; + if (!(ds_p->silhouette & SIL_TOP)) + { + ds_p->silhouette |= SIL_TOP; + ds_p->tsilheight = (sidedef->midtexture > 0 && sidedef->midtexture < numtextures) ? INT32_MIN: INT32_MAX; + } + + if (!(ds_p->silhouette & SIL_BOTTOM)) + { + ds_p->silhouette |= SIL_BOTTOM; + ds_p->bsilheight = (sidedef->midtexture > 0 && sidedef->midtexture < numtextures) ? INT32_MAX: INT32_MIN; + } } + ds_p++; } diff --git a/src/r_segs.h b/src/r_segs.h index 006e81279..27dbbe54f 100644 --- a/src/r_segs.h +++ b/src/r_segs.h @@ -14,13 +14,24 @@ #ifndef __R_SEGS__ #define __R_SEGS__ +#ifdef __cplusplus +extern "C" { +#endif + #ifdef __GNUG__ #pragma interface #endif -transnum_t R_GetLinedefTransTable(fixed_t alpha); void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2); void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pffloor); void R_StoreWallRange(INT32 start, INT32 stop); +void R_AllocSegMemory(void); + +transnum_t R_GetLinedefTransTable(fixed_t alpha); + +#ifdef __cplusplus +} // extern "C" +#endif + #endif diff --git a/src/r_skins.c b/src/r_skins.c new file mode 100644 index 000000000..6bda9e263 --- /dev/null +++ b/src/r_skins.c @@ -0,0 +1,791 @@ +// SONIC ROBO BLAST 2 KART +//----------------------------------------------------------------------------- +// Copyright (C) 2025 by Vivian "toastergrl" Grannell. +// Copyright (C) 2025 by Kart Krew. +// Copyright (C) 2020 by Sonic Team Junior. +// Copyright (C) 2000 by DooM Legacy Team. +// Copyright (C) 1996 by id Software, Inc. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file r_skins.c +/// \brief Loading skins + +#include "dehacked.h" // get_number (for thok) +#include "doomdef.h" +#include "console.h" +#include "r_draw.h" +#include "r_things.h" +#include "r_skins.h" +#include "g_game.h" +#include "k_kart.h" // SRB2kart +#include "p_local.h" +#include "st_stuff.h" +#include "i_video.h" // rendermode +#include "w_wad.h" +#include "z_zone.h" + +#ifdef HWRENDER +#include "hardware/hw_md2.h" +#endif + +#include "qs22j.h" + +CV_PossibleValue_t Forceskin_cons_t[MAXSKINS+2]; + +INT32 numskins = 0; +INT32 numallskins = 0; +INT32 numlocalskins = 0; +skin_t skins[MAXSKINS]; +UINT8 skinstats[9][9][MAXSKINS]; +UINT8 skinstatscount[9][9] = { + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0} +}; +UINT8 skinsorted[MAXSKINS]; +skin_t localskins[MAXLOCALSKINS]; +skin_t allskins[MAXSKINS+MAXLOCALSKINS]; + +// FIXTHIS: don't work because it must be inistilised before the config load +//#define SKINVALUES +#ifdef SKINVALUES +CV_PossibleValue_t skin_cons_t[MAXSKINS+1]; +CV_PossibleValue_t localskin_cons_t[MAXLOCALSKINS+1]; +#endif + +static void Sk_SetDefaultValue(skin_t *skin, boolean local) +{ + INT32 i; + // + // set default skin values + // + memset(skin, 0, sizeof (skin_t)); + snprintf(skin->name, sizeof skin->name, "skin %u", K_GetMobjSkinNum(skin, local)); + skin->name[sizeof skin->name - 1] = '\0'; + skin->wadnum = INT16_MAX; + strcpy(skin->sprite, ""); + + skin->flags = 0; + + strcpy(skin->realname, "Someone"); + strcpy(skin->hudname, "???"); + strncpy(skin->facerank, "PLAYRANK", 9); + strncpy(skin->facewant, "PLAYWANT", 9); + strncpy(skin->facemmap, "PLAYMMAP", 9); + + skin->starttranscolor = 160; + skin->prefcolor = SKINCOLOR_GREEN; + + // SRB2kart + skin->kartspeed = 5; + skin->kartweight = 5; + // + + skin->highresscale = FRACUNIT>>1; + + for (i = 0; i < sfx_skinsoundslot0; i++) + if (S_sfx[i].skinsound != -1) + skin->soundsid[S_sfx[i].skinsound] = i; +} + +// +// Initialize the basic skins +// +void R_InitSkins(void) +{ + skin_t *skin; +#ifdef SKINVALUES + INT32 i; + + for (i = 0; i <= MAXSKINS; i++) + { + skin_cons_t[i].value = 0; + skin_cons_t[i].strvalue = NULL; + } + for (i = 0; i <= MAXLOCALSKINS; i++) + { + localskin_cons_t[i].value = 0; + localskin_cons_t[i].strvalue = NULL; + } +#endif + + // skin[0] = Sonic skin + skin = &skins[0]; + numskins = 1; + Sk_SetDefaultValue(skin, false); + memset(skinstats, 0, sizeof(skinstats)); + memset(skinsorted, 0, sizeof(skinsorted)); + + // Hardcoded S_SKIN customizations for Sonic. + strcpy(skin->name, DEFAULTSKIN); +#ifdef SKINVALUES + skin_cons_t[0].strvalue = skins[0].name; +#endif + skin->flags = 0; + strcpy(skin->realname, "Sonic"); + strcpy(skin->hudname, "SONIC"); + + strncpy(skin->facerank, "PLAYRANK", 9); + strncpy(skin->facewant, "PLAYWANT", 9); + strncpy(skin->facemmap, "PLAYMMAP", 9); + skin->wadnum = 0; // god what have you brought to this world + skin->prefcolor = SKINCOLOR_BLUE; + skin->localskin = false; + skin->localnum = 0; + + // SRB2kart + skin->kartspeed = 8; + skin->kartweight = 2; + // + + skin->spritedef.numframes = sprites[SPR_PLAY].numframes; + skin->spritedef.spriteframes = sprites[SPR_PLAY].spriteframes; + skin->sprinfo = spriteinfo[SPR_PLAY]; + ST_LoadFaceGraphics(skin->facerank, skin->facewant, skin->facemmap, 0); + + // Set values for Sonic skin + Forceskin_cons_t[1].value = 0; + Forceskin_cons_t[1].strvalue = skin->name; + + //MD2 for sonic doesn't want to load in Linux. +#ifdef HWRENDER + if (rendermode == render_opengl) + HWR_AddPlayerMD2(0, false); +#endif + + // lets set it + allskins[0] = skins[0]; + numallskins = 1; +} + +// returns true if the skin name is found (loaded from pwad) +// warning return -1 if not found +INT32 R_SkinAvailable(const char *name) +{ + INT32 i; + + for (i = 0; i < numskins; i++) + { + if (stricmp(skins[i].name,name) == 0) + return i; + } + return -1; +} + +// returns true if the skin name is found (loaded from pwad) +// warning return -1 if not found +INT32 R_AnySkinAvailable(const char *name) +{ + INT32 i; + + for (i = 0; i < numallskins; i++) + { + if (stricmp(allskins[i].name,name) == 0) + return i; + } + return -1; +} + +INT32 R_LocalSkinAvailable(const char *name, boolean local) +{ + INT32 i; + + if (local) + { + for (i = 0; i < numlocalskins; i++) + { + if (stricmp(localskins[i].name,name) == 0) + return i; + } + return -1; + } + else + return R_SkinAvailable(name); +} + +// network code calls this when a 'skin change' is received +boolean SetPlayerSkin(INT32 playernum, const char *skinname) +{ + INT32 i; + player_t *player = &players[playernum]; + + for (i = 0; i < numskins; i++) + { + // search in the skin list + if (stricmp(skins[i].name, skinname) == 0) + { + SetPlayerSkinByNum(playernum, i); + return true; + } + } + + if (P_IsLocalPlayer(player)) + CONS_Alert(CONS_WARNING, M_GetText("Skin '%s' not found.\n"), skinname); + else if(server || IsPlayerAdmin(consoleplayer)) + CONS_Alert(CONS_WARNING, M_GetText("Player %d (%s) skin '%s' not found\n"), playernum, player_names[playernum], skinname); + + SetPlayerSkinByNum(playernum, 0); + return false; +} + +void SetLocalPlayerSkin(INT32 playernum, const char *skinname, consvar_t *cvar) +{ + INT32 i; + player_t *player = &players[playernum]; + + if (stricmp(skinname, "none")) + { + for (i = 0; i < numlocalskins; i++) + { + // search in the localskin list + if (stricmp(localskins[i].name, skinname) == 0) + { + player->localskin = 1 + i; + player->skinlocal = true; + if (player->mo) + { + player->mo->localskin = &localskins[i]; + player->mo->skinlocal = true; + } + + goto setcvar; + } + } + + for (i = 0; i < numskins; i++) + { + // search in the skin list + if (stricmp(skins[i].name, skinname) == 0) + { + player->localskin = 1 + i; + player->skinlocal = false; + if (player->mo) + { + player->mo->localskin = &skins[i]; + player->mo->skinlocal = false; + } + + goto setcvar; + } + } + } + else + { + player->localskin = 0; + player->skinlocal = false; + if (player->mo) + { + player->mo->localskin = 0; + player->mo->skinlocal = false; + } + } + +setcvar: + if (cvar != NULL) + { + if (player->localskin > 0) + { + CV_StealthSet(&cv_fakelocalskin, K_GetSkinArray(player->skinlocal)[player->localskin-1].name); + CV_StealthSet(cvar, K_GetSkinArray(player->skinlocal)[player->localskin-1].name); + + } + else + { + CV_StealthSet(&cv_fakelocalskin, "none"); + CV_StealthSet(cvar, "none"); + } + } +} + +// Same as SetPlayerSkin, but uses the skin #. +// network code calls this when a 'skin change' is received +void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum) +{ + player_t *player = &players[playernum]; + skin_t *skin = &skins[skinnum]; + + if (skinnum >= 0 && skinnum < numskins) // Make sure it exists! + { + player->skin = skinnum; + if (player->mo) + player->mo->skin = skin; + + player->charflags = (UINT32)skin->flags; + + // SRB2kart + player->kartspeed = skin->kartspeed; + player->kartweight = skin->kartweight; + + if (player->mo) + P_SetScale(player->mo, player->mo->scale); + + demo_extradata[playernum] |= DXD_SKIN; + + return; + } + + if (P_IsLocalPlayer(player)) + CONS_Alert(CONS_WARNING, M_GetText("Skin %d not found\n"), skinnum); + else if(server || IsPlayerAdmin(consoleplayer)) + CONS_Alert(CONS_WARNING, "Player %d (%s) skin %d not found\n", playernum, player_names[playernum], skinnum); + + SetPlayerSkinByNum(playernum, 0); // not found put the sonic skin +} + +// +// Add skins from a pwad, each skin preceded by 'S_SKIN' marker +// + +// Does the same is in w_wad, but check only for +// the first 6 characters (this is so we can have S_SKIN1, S_SKIN2.. +// for wad editors that don't like multiple resources of the same name) +// +static UINT16 W_CheckForSkinMarkerInPwad(UINT16 wadid, UINT16 startlump) +{ + UINT16 i; + const char *S_SKIN = "S_SKIN"; + lumpinfo_t *lump_p; + + // scan forward, start at + if (startlump < wadfiles[wadid]->numlumps) + { + lump_p = wadfiles[wadid]->lumpinfo + startlump; + for (i = startlump; i < wadfiles[wadid]->numlumps; i++, lump_p++) + if (memcmp(lump_p->name,S_SKIN,6)==0) + return i; + } + return INT16_MAX; // not found +} + +//sort function for sorting skin names +static int skinSortFunc(const void *a, const void *b) //tbh i have no clue what the naming conventions for local functions are +{ + const skin_t *in1 = &skins[*(const UINT8 *)a]; + const skin_t *in2 = &skins[*(const UINT8 *)b]; + INT32 temp = 0; + const UINT8 val_a = *((const UINT8 *)a); + const UINT8 val_b = *((const UINT8 *)b); + + //return (strcmp(in1->realname, in2->realname) < 0) || (strcmp(in1->realname, in2->realname) ==); + + switch (cv_skinselectgridsort.value) + { + case SKINMENUSORT_REALNAME: + //CONS_Printf("Sorting by realname\n"); + // check name + if ((temp = strcmp(in1->realname, in2->realname))) + return temp; + // sort by internal name + return strcmp(in1->name, in2->name); + break; + + case SKINMENUSORT_NAME: + //CONS_Printf("Sorting by name\n"); + return strcmp(in1->name, in2->name); + break; + + case SKINMENUSORT_SPEED: + //CONS_Printf("Sorting by speed\n"); + // check speed + if (in1->kartspeed < in2->kartspeed) + return -1; + else if (in2->kartspeed < in1->kartspeed) + return 1; + // then check weight + if (in1->kartweight < in2->kartweight) + return -1; + else if (in2->kartweight < in1->kartweight) + return 1; + // then check name + if ((temp = strcmp(in1->realname, in2->realname))) + return temp; + // sort by internal name + return strcmp(in1->name, in2->name); + break; + + case SKINMENUSORT_WEIGHT: + //CONS_Printf("Sorting by weight\n"); + // check weight + if (in1->kartweight < in2->kartweight) + return -1; + else if (in2->kartweight < in1->kartweight) + return 1; + // then check speed + if (in1->kartspeed < in2->kartspeed) + return -1; + else if (in2->kartspeed < in1->kartspeed) + return 1; + // then check name + if ((temp = strcmp(in1->realname, in2->realname))) + return temp; + // sort by internal name + return strcmp(in1->name, in2->name); + break; + + case SKINMENUSORT_PREFCOLOR: + //CONS_Printf("Sorting by prefcolor\n"); + // check prefcolor + if (in1->prefcolor < in2->prefcolor) + return -1; + else if (in2->prefcolor < in1->prefcolor) + return 1; + // then check name + if ((temp = strcmp(in1->realname, in2->realname))) + return temp; + // sort by internal name + return strcmp(in1->name, in2->name); + break; + + case SKINMENUSORT_ID: + //CONS_Printf("Sorting by id\n"); + //how do i do by ID????? + //wait why dont i just convert the inputs to UINT32s + //please tell me im allowed to define variables in here since its a block + + if (val_a == val_b) + return 0; + else if (val_a < val_b) + return -1; + else + return 1; + + default: + return strcmp(in1->name, in2->name); + break; + } + //im scared this somehow will sometimes end up here so im gonna add this here just to be safe + return strcmp(in1->name, in2->name); +} + +void sortSkinGrid(void) +{ + //CONS_Printf("Sorting skin list (%d)...\n", cv_skinselectgridsort.value); + qs22j(skinsorted, numskins, sizeof(UINT8), skinSortFunc); +} + +// +// Find skin sprites, sounds & optional status bar face, & add them +// +void R_AddSkins(UINT16 wadnum, boolean local) +{ + UINT16 lump, lastlump = 0; + char *buf; + char *buf2; + char *stoken; + char *value; + size_t size; + skin_t *skin; + boolean hudname, realname; + +#define lnumskins (local ? numlocalskins : numskins) + + // + // search for all skin markers in pwad + // + + while ((lump = W_CheckForSkinMarkerInPwad(wadnum, lastlump)) != INT16_MAX) + { + // advance by default + lastlump = lump + 1; + + if (!local && numskins >= MAXSKINS) + { + CONS_Alert(CONS_WARNING, M_GetText("Unable to add skin, too many characters are loaded (%d maximum)\n"), MAXSKINS); + continue; // so we know how many skins couldn't be added + } + if (local && numlocalskins >= MAXLOCALSKINS) + { + CONS_Alert(CONS_WARNING, M_GetText("Unable to add localskin, too many localskins are loaded (%d maximum)\n"), MAXLOCALSKINS); + continue; // so we know how many skins couldn't be added + } + + buf = W_CacheLumpNumPwad(wadnum, lump, PU_CACHE); + size = W_LumpLengthPwad(wadnum, lump); + + // for strtok + buf2 = malloc(size+1); + if (!buf2) + I_Error("R_AddSkins: No more free memory\n"); + M_Memcpy(buf2,buf,size); + buf2[size] = '\0'; + + // set defaults + skin = &K_GetSkinArray(local)[lnumskins]; + Sk_SetDefaultValue(skin, local); + skin->wadnum = wadnum; + hudname = realname = false; + // parse + stoken = strtok (buf2, "\r\n= "); + while (stoken) + { + if ((stoken[0] == '/' && stoken[1] == '/') + || (stoken[0] == '#'))// skip comments + { + stoken = strtok(NULL, "\r\n"); // skip end of line + goto next_token; // find the real next token + } + + value = strtok(NULL, "\r\n= "); + + if (!value) + I_Error("R_AddSkins: syntax error in S_SKIN lump# %d(%s) in WAD %s\n", lump, W_CheckNameForNumPwad(wadnum,lump), wadfiles[wadnum]->filename); + + if (!stricmp(stoken, "name")) + { + // the skin name must uniquely identify a single skin + // I'm lazy so if name is already used I leave the 'skin x' + // default skin name set in Sk_SetDefaultValue + if (R_LocalSkinAvailable(value, local) == -1) + { + STRBUFCPY(skin->name, value); + strlwr(skin->name); + } + // I'm not lazy, so if the name is already used I make the name 'namex' + // using the default skin name's number set above + else + { + const size_t stringspace = + strlen(value) + sizeof lnumskins + 1; + char *value2 = Z_Malloc(stringspace, PU_STATIC, NULL); + snprintf(value2, stringspace, + "%s%d", value, lnumskins); + value2[stringspace - 1] = '\0'; + if (R_LocalSkinAvailable(value2, local) == -1) + { + STRBUFCPY(skin->name, + value2); + strlwr(skin->name); + } + Z_Free(value2); + } + + // copy to hudname and fullname as a default. + if (!realname) + { + STRBUFCPY(skin->realname, skin->name); + for (value = skin->realname; *value; value++) + if (*value == '_') *value = ' '; // turn _ into spaces. + } + if (!hudname) + { + STRBUFCPY(skin->hudname, skin->name); + strupr(skin->hudname); + for (value = skin->hudname; *value; value++) + if (*value == '_') *value = ' '; // turn _ into spaces. + } + } + else if (!stricmp(stoken, "realname")) + { // Display name (eg. "Knuckles") + realname = true; + STRBUFCPY(skin->realname, value); + for (value = skin->realname; *value; value++) + if (*value == '_') *value = ' '; // turn _ into spaces. + if (!hudname) + STRBUFCPY(skin->hudname, skin->realname); + } + else if (!stricmp(stoken, "hudname")) + { // Life icon name (eg. "K.T.E") + hudname = true; + STRBUFCPY(skin->hudname, value); + for (value = skin->hudname; *value; value++) + if (*value == '_') *value = ' '; // turn _ into spaces. + if (!realname) + STRBUFCPY(skin->realname, skin->hudname); + } + + else if (!stricmp(stoken, "sprite")) + { + strupr(value); + memcpy(skin->sprite, value, sizeof skin->sprite); + } + else if (!stricmp(stoken, "facerank")) + { + strupr(value); + memcpy(skin->facerank, value, sizeof(skin->facerank)-1); + skin->facerank[sizeof(skin->facerank)-1] = '\0'; + } + else if (!stricmp(stoken, "facewant")) + { + strupr(value); + memcpy(skin->facewant, value, sizeof(skin->facewant)-1); + skin->facewant[sizeof(skin->facewant)-1] = '\0'; + } + else if (!stricmp(stoken, "facemmap")) + { + strupr(value); + strncpy(skin->facemmap, value, sizeof(skin->facemmap)-1); + skin->facemmap[sizeof(skin->facemmap)-1] = '\0'; + } + +#define FULLPROCESS(field) else if (!stricmp(stoken, #field)) skin->field = get_number(value); + // character type identification + FULLPROCESS(flags) +#undef FULLPROCESS + +#define GETKARTSTAT(field) \ + else if (!stricmp(stoken, #field)) \ + { \ + skin->field = atoi(value); \ + if (skin->field < 1) skin->field = 1; \ + if (skin->field > 9) skin->field = 9; \ + } + GETKARTSTAT(kartspeed) + GETKARTSTAT(kartweight) +#undef GETKARTSTAT + + // custom translation table + else if (!stricmp(stoken, "startcolor")) + skin->starttranscolor = atoi(value); + + else if (!stricmp(stoken, "prefcolor")) + skin->prefcolor = K_GetKartColorByName(value); + else if (!stricmp(stoken, "highresscale")) + skin->highresscale = FLOAT_TO_FIXED(atof(value)); + else + { + INT32 found = false; + sfxenum_t i; + // copy name of sounds that are remapped + // for this skin + for (i = 0; i < sfx_skinsoundslot0; i++) + { + if (!S_sfx[i].name) + continue; + if (S_sfx[i].skinsound != -1 + && !stricmp(S_sfx[i].name, + stoken + 2)) + { + skin->soundsid[S_sfx[i].skinsound] = + S_AddSoundFx(value+2, S_sfx[i].singularity, S_sfx[i].pitch, true); + found = true; + } + } + if (!found) + CONS_Debug(DBG_SETUP, "R_AddSkins: Unknown keyword '%s' in S_SKIN lump# %d (WAD %s)\n", stoken, lump, wadfiles[wadnum]->filename); + } +next_token: + stoken = strtok(NULL, "\r\n= "); + } + free(buf2); + + lump++; // if no sprite defined use spirte just after this one + if (skin->sprite[0] == '\0') + { + const char *csprname = W_CheckNameForNumPwad(wadnum, lump); + + // skip to end of this skin's frames + lastlump = lump; + while (W_CheckNameForNumPwad(wadnum,lastlump) && memcmp(W_CheckNameForNumPwad(wadnum, lastlump),csprname,4)==0) + lastlump++; + // allocate (or replace) sprite frames, and set spritedef + R_AddSingleSpriteDef(csprname, &skin->spritedef, wadnum, lump, lastlump); + } + else + { + // search in the normal sprite tables + size_t name; + boolean found = false; + const char *sprname = skin->sprite; + for (name = 0;sprnames[name][0] != '\0';name++) + if (strncmp(sprnames[name], sprname, 4) == 0) + { + found = true; + skin->spritedef = sprites[name]; + } + + // not found so make a new one + // go through the entire current wad looking for our sprite + // don't just mass add anything beginning with our four letters. + // "HOODFACE" is not a sprite name. + if (!found) + { + UINT16 localllump = 0, lstart = UINT16_MAX, lend = UINT16_MAX; + const char *lname; + + while ((lname = W_CheckNameForNumPwad(wadnum,localllump))) + { + // If this is a valid sprite... + if (!memcmp(lname,sprname,4) && lname[4] && lname[5] && lname[5] >= '0' && lname[5] <= '8') + { + if (lstart == UINT16_MAX) + lstart = localllump; + // If already set do nothing + } + else + { + if (lstart != UINT16_MAX) + { + lend = localllump; + break; + } + // If not already set do nothing + } + ++localllump; + } + + R_AddSingleSpriteDef(sprname, &skin->spritedef, wadnum, lstart, lend); + } + + // I don't particularly care about skipping to the end of the used frames. + // We could be using frames from ANYWHERE in the current WAD file, including + // right before us, which is a terrible idea. + // So just let the function in the while loop take care of it for us. + } + + R_FlushTranslationColormapCache(); + + CONS_Printf(M_GetText("Added skin '%s'\n"), skin->name); +#ifdef SKINVALUES + (local ? localskin_cons_t : skin_cons_t)[lnumskins].value = lnumskins; + (local ? localskin_cons_t : skin_cons_t)[lnumskins].strvalue = skin->name; +#endif + + if (!local) + { + // Update the forceskin possiblevalues + Forceskin_cons_t[numskins+1].value = numskins; + Forceskin_cons_t[numskins+1].strvalue = skins[numskins].name; + skin->localskin = false; + skin->localnum = numskins; + ST_LoadFaceGraphics(skin->facerank, skin->facewant, skin->facemmap, numskins); + } + else + { + skin->localskin = true; + skin->localnum = numlocalskins; + ST_LoadLocalFaceGraphics(skin->facerank, skin->facewant, skin->facemmap, numlocalskins); + } + +#ifdef HWRENDER + if (rendermode == render_opengl) + HWR_AddPlayerMD2(lnumskins, local); +#endif + if (!local) + { + skinstats[skin->kartspeed-1][skin->kartweight-1][skinstatscount[skin->kartspeed-1][skin->kartweight-1]] = numskins; + CONS_Debug(DBG_SETUP, M_GetText("Added %d to %d, %d\n"), numskins, skin->kartweight, skin->kartweight); + skinstatscount[skin->kartspeed-1][skin->kartweight-1]++; + CONS_Debug(DBG_SETUP, M_GetText("Incremented %d, %d to %d\n"), skin->kartspeed, skin->kartweight, skinstatscount[skin->kartspeed - 1][skin->kartweight - 1]); + skinsorted[numskins] = numskins; + } + + allskins[numallskins] = K_GetSkinArray(local)[lnumskins]; + + local ? numlocalskins++ : numskins++; + numallskins++; + } + +#undef lnumskins + //sortSkinGrid(); + + return; +} diff --git a/src/r_skins.h b/src/r_skins.h new file mode 100644 index 000000000..cada396f4 --- /dev/null +++ b/src/r_skins.h @@ -0,0 +1,152 @@ +// SONIC ROBO BLAST 2 KART +//----------------------------------------------------------------------------- +// Copyright (C) 2025 by Vivian "toastergrl" Grannell. +// Copyright (C) 2025 by Kart Krew. +// Copyright (C) 2020 by Sonic Team Junior. +// Copyright (C) 2000 by DooM Legacy Team. +// Copyright (C) 1996 by id Software, Inc. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file r_skins.h +/// \brief Skins stuff + +#ifndef __R_SKINS__ +#define __R_SKINS__ +#ifdef __cplusplus +extern "C" { +#endif + +#include "d_player.h" +#include "sounds.h" +#include "r_patch.h" + +// "Left" and "Right" character symbols for additional rotation functionality +#define ROT_L ('L' - '0') +#define ROT_R ('R' - '0') + +#define SKINNAMESIZE 16 +// should be all lowercase!! S_SKIN processing does a strlwr +#define DEFAULTSKIN "sonic" +#define DEFAULTSKIN2 "tails" // secondary player +#define DEFAULTSKIN3 "knuckles" // third player +#define DEFAULTSKIN4 "eggman" // fourth player + +typedef struct +{ + char name[SKINNAMESIZE+1]; // INT16 descriptive name of the skin + spritedef_t spritedef; + spriteinfo_t sprinfo; + UINT16 wadnum; + char sprite[4]; // Sprite name, if seperated from S_SKIN. + skinflags_t flags; + + char realname[SKINNAMESIZE+1]; // Display name for level completion. + char hudname[SKINNAMESIZE+1]; // HUD name to display (officially exactly 5 characters long) + char facerank[9], facewant[9], facemmap[9]; // Arbitrarily named patch lumps + + // SRB2kart + UINT8 kartspeed; + UINT8 kartweight; + // + + // Definable color translation table + UINT8 starttranscolor; + UINT8 prefcolor; + fixed_t highresscale; // scale of highres, default is 0.5 + + // specific sounds per skin + sfxenum_t soundsid[NUMSKINSOUNDS]; // sound # in S_sfx table + + boolean localskin; + INT32 localnum; +} skin_t; + +extern CV_PossibleValue_t Forceskin_cons_t[]; + +extern INT32 numskins; +extern INT32 numlocalskins; +extern INT32 numallskins; +extern skin_t skins[MAXSKINS]; +extern UINT8 skinstats[9][9][MAXSKINS]; +extern UINT8 skinstatscount[9][9]; +extern UINT8 skinsorted[MAXSKINS]; + +extern skin_t localskins[MAXLOCALSKINS]; +extern skin_t allskins[MAXSKINS+MAXLOCALSKINS]; + +//faB: find sprites in wadfile, replace existing, add new ones +// (only sprites from namelist are added or replaced) +void R_AddSpriteDefs(UINT16 wadnum); + +void R_InitSkins(void); +void R_AddSkins(UINT16 wadnum, boolean local); + +INT32 R_SkinAvailable(const char *name); +INT32 R_AnySkinAvailable(const char *name); +INT32 R_LocalSkinAvailable(const char *name, boolean local); + +// had to move those here Zzz... +INT32 K_GetSkinNum(player_t *player); +INT32 K_GetMobjSkinNum(const skin_t *skin, boolean local); +skin_t *K_GetPlayerSkin(player_t *player); +skin_t *K_GetMobjSkin(const mobj_t *mobj); +patch_t *K_GetFacePrefix(player_t *player, INT32 skinnum); +skin_t *K_GetSkinArray(boolean local); + +void sortSkinGrid(void); + +boolean SetPlayerSkin(INT32 playernum,const char *skinname); +void SetPlayerSkinByNum(INT32 playernum,INT32 skinnum); // Tails 03-16-2002 +void SetLocalPlayerSkin(INT32 playernum,const char *skinname, consvar_t *cvar); + +char *GetPlayerFacePic(INT32 skinnum); + +// Functions to go from sprite character ID to frame number +// for 2.1 compatibility this still uses the old 'A' + frame code +// The use of symbols tends to be painful for wad editors though +// So the future version of this tries to avoid using symbols +// as much as possible while also defining all 64 slots in a sane manner +// 2.1: [[ ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ]] +// Future: [[ ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz!@ ]] +FUNCMATH FUNCINLINE static ATTRINLINE char R_Frame2Char(UINT8 frame) +{ +#if 1 // 2.1 compat + return 'A' + frame; +#else + if (frame < 26) return 'A' + frame; + if (frame < 36) return '0' + (frame - 26); + if (frame < 62) return 'a' + (frame - 36); + if (frame == 62) return '!'; + if (frame == 63) return '@'; + return '\xFF'; +#endif +} + +FUNCMATH FUNCINLINE static ATTRINLINE UINT8 R_Char2Frame(char cn) +{ +#if 1 // 2.1 compat + if (cn == '+') return '\\' - 'A'; // PK3 can't use backslash, so use + instead + return cn - 'A'; +#else + if (cn >= 'A' && cn <= 'Z') return cn - 'A'; + if (cn >= '0' && cn <= '9') return (cn - '0') + 26; + if (cn >= 'a' && cn <= 'z') return (cn - 'a') + 36; + if (cn == '!') return 62; + if (cn == '@') return 63; + return 255; +#endif +} + +FUNCMATH FUNCINLINE static ATTRINLINE boolean R_ValidSpriteAngle(UINT8 rotation) +{ + return ((rotation <= 8) || (rotation == ROT_L) || (rotation == ROT_R)); +} + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif //__R_SKINS__ diff --git a/src/r_sky.c b/src/r_sky.c index cb21092bb..8cbdd3a59 100644 --- a/src/r_sky.c +++ b/src/r_sky.c @@ -41,6 +41,10 @@ INT32 skytexture; */ INT32 skytexturemid; +/** \brief the x offset of the sky texture + */ +INT32 skytextureoffset; + /** \brief the scale of the sky */ fixed_t skyscale; @@ -50,6 +54,7 @@ fixed_t skyscale; INT32 levelskynum; INT32 globallevelskynum; + /** \brief The R_SetupSkyDraw function Called at loadlevel after skytexture is set, or when sky texture changes. @@ -61,12 +66,19 @@ INT32 globallevelskynum; */ void R_SetupSkyDraw(void) { - // the horizon line in a 256x128 sky texture - skytexturemid = (textures[skytexture]->height/2)<height / 2) << FRACBITS; + skytextureoffset = 0; - // get the right drawer, it was set by screen.c, depending on the - // current video mode bytes per pixel (quick fix) - wallcolfunc = walldrawerfunc; + if (textures[skytexture]->type == TEXTURETYPE_SINGLEPATCH) + { + // Sal: Allow for sky offsets + texpatch_t *const tex_patch = &textures[skytexture]->patches[0]; + patch_t *patch = W_CachePatchNumPwad(tex_patch->wad, tex_patch->lump, PU_CACHE); + + skytexturemid += (patch->topoffset << FRACBITS); + skytextureoffset += (patch->leftoffset << FRACBITS); + } R_SetSkyScale(); } @@ -79,5 +91,7 @@ void R_SetupSkyDraw(void) */ void R_SetSkyScale(void) { - skyscale = FixedDiv(fovtan, FixedDiv(vid.width*FRACUNIT, BASEVIDWIDTH*FRACUNIT)); + //skyscale = FixedDiv(fovtan, FixedDiv(vid.width*FRACUNIT, BASEVIDWIDTH*FRACUNIT)); + fixed_t difference = vid.fdupx-(vid.dupx<> VISSPRITECHUNKBITS] = {NULL}; + + // ========================================================================== // // Sprite loading routines: support sprites in pwad, dehacked sprite renaming, @@ -252,7 +264,7 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch // // Returns true if the sprite was succesfully added // -static boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 wadnum, UINT16 startlump, UINT16 endlump) +boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 wadnum, UINT16 startlump, UINT16 endlump) { UINT16 l; UINT8 frame; @@ -402,8 +414,7 @@ static boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, // allocate this sprite's frames if (!spritedef->spriteframes) - spritedef->spriteframes = - Z_Malloc(maxframe * sizeof (*spritedef->spriteframes), PU_STATIC, NULL); + spritedef->spriteframes = static_cast(Z_Malloc(maxframe * sizeof (*spritedef->spriteframes), PU_STATIC, NULL)); spritedef->numframes = maxframe; M_Memcpy(spritedef->spriteframes, sprtemp, maxframe*sizeof (spriteframe_t)); @@ -476,16 +487,6 @@ void R_AddSpriteDefs(UINT16 wadnum) CONS_Printf(M_GetText("%s added %d frames in %s sprites\n"), wadname, end-start, sizeu1(addsprites)); } - -// -// GAME FUNCTIONS -// -UINT32 visspritecount, numvisiblesprites; - -static UINT32 clippedvissprites; -static vissprite_t *visspritechunks[MAXVISSPRITES >> VISSPRITECHUNKBITS] = {NULL}; - - // // R_InitSprites // Called at program start. @@ -498,11 +499,6 @@ void R_InitSprites(void) float fa; #endif - for (i = 0; i < MAXVIDWIDTH; i++) - { - negonearray[i] = -1; - } - #ifdef ROTSPRITE for (angle = 1; angle < ROTANGLES; angle++) { @@ -522,7 +518,7 @@ void R_InitSprites(void) if (!numsprites) I_Error("R_AddSpriteDefs: no sprites in namelist\n"); - sprites = Z_Calloc(numsprites * sizeof (*sprites), PU_STATIC, NULL); + sprites = static_cast(Z_Calloc(numsprites * sizeof (*sprites), PU_STATIC, NULL)); // find sprites in each -file added pwad for (i = 0; i < numwadfiles; i++) @@ -550,6 +546,34 @@ void R_ClearSprites(void) visspritecount = numvisiblesprites = clippedvissprites = 0; } +static INT16 *vissprite_clipbot[MAXVISSPRITES >> VISSPRITECHUNKBITS]; +static INT16 *vissprite_cliptop[MAXVISSPRITES >> VISSPRITECHUNKBITS]; + +static void R_AllocVisSpriteChunkMemory(UINT32 chunk) +{ + vissprite_clipbot[chunk] = static_cast(Z_Realloc(vissprite_clipbot[chunk], sizeof(INT16) * (VISSPRITESPERCHUNK * viewwidth), PU_STATIC, NULL)); + vissprite_cliptop[chunk] = static_cast(Z_Realloc(vissprite_cliptop[chunk], sizeof(INT16) * (VISSPRITESPERCHUNK * viewwidth), PU_STATIC, NULL)); + + for (unsigned i = 0; i < VISSPRITESPERCHUNK; i++) + { + vissprite_t *sprite = visspritechunks[chunk] + i; + + sprite->clipbot = vissprite_clipbot[chunk] + (viewwidth * i); + sprite->cliptop = vissprite_cliptop[chunk] + (viewwidth * i); + } +} + +void R_AllocVisSpriteMemory(void) +{ + unsigned numchunks = MAXVISSPRITES >> VISSPRITECHUNKBITS; + + for (unsigned i = 0; i < numchunks; i++) + { + if (visspritechunks[i]) + R_AllocVisSpriteChunkMemory(i); + } +} + // // R_NewVisSprite // @@ -561,7 +585,10 @@ static vissprite_t *R_GetVisSprite(UINT32 num) // Allocate chunk if necessary if (!visspritechunks[chunk]) + { Z_Malloc(sizeof(vissprite_t) * VISSPRITESPERCHUNK, PU_LEVEL, &visspritechunks[chunk]); + R_AllocVisSpriteChunkMemory(chunk); + } return visspritechunks[chunk] + (num & VISSPRITEINDEXMASK); } @@ -586,16 +613,16 @@ INT16 *mceilingclip; fixed_t spryscale = 0, sprtopscreen = 0, sprbotscreen = 0; fixed_t windowtop = 0, windowbottom = 0; -void R_DrawMaskedColumn(column_t *column) +void R_DrawMaskedColumn(drawcolumndata_t* dc, column_t *column) { INT32 topscreen; INT32 bottomscreen; fixed_t basetexturemid; INT32 topdelta, prevdelta = 0; - basetexturemid = dc_texturemid; + basetexturemid = dc->texturemid; - for (; column->topdelta != 0xff ;) + while (column->topdelta != 0xff) { // calculate unclipped screen coordinates // for post @@ -606,61 +633,56 @@ void R_DrawMaskedColumn(column_t *column) topscreen = sprtopscreen + spryscale*topdelta; bottomscreen = topscreen + spryscale*column->length; - dc_yl = (topscreen+FRACUNIT-1)>>FRACBITS; - dc_yh = (bottomscreen-1)>>FRACBITS; + dc->yl = (topscreen+FRACUNIT-1)>>FRACBITS; + dc->yh = (bottomscreen-1)>>FRACBITS; if (windowtop != INT32_MAX && windowbottom != INT32_MAX) { if (windowtop > topscreen) - dc_yl = (windowtop + FRACUNIT - 1)>>FRACBITS; + dc->yl = (windowtop + FRACUNIT - 1)>>FRACBITS; if (windowbottom < bottomscreen) - dc_yh = (windowbottom - 1)>>FRACBITS; + dc->yh = (windowbottom - 1)>>FRACBITS; } - if (dc_yh >= mfloorclip[dc_x]) - dc_yh = mfloorclip[dc_x]-1; - if (dc_yl <= mceilingclip[dc_x]) - dc_yl = mceilingclip[dc_x]+1; + if (dc->yh >= mfloorclip[dc->x]) + dc->yh = mfloorclip[dc->x]-1; + if (dc->yl <= mceilingclip[dc->x]) + dc->yl = mceilingclip[dc->x]+1; - if (dc_yl < 0) - dc_yl = 0; - if (dc_yh >= vid.height) - dc_yh = vid.height - 1; + if (dc->yl < 0) + dc->yl = 0; + if (dc->yh >= vid.height) + dc->yh = vid.height - 1; - if (dc_yl <= dc_yh && dc_yh > 0 && column->length != 0) + if (dc->yl <= dc->yh && dc->yh > 0 && column->length != 0) { - dc_source = (UINT8 *)column + 3; - dc_sourcelength = column->length; - dc_texturemid = basetexturemid - (topdelta<source = (UINT8 *)column + 3; + dc->sourcelength = column->length; + dc->texturemid = basetexturemid - (topdelta<(&dc_copy)); } column = (column_t *)((UINT8 *)column + column->length + 4); } - dc_texturemid = basetexturemid; + dc->texturemid = basetexturemid; } INT32 lengthcol; // column->length : for flipped column function pointers and multi-patch on 2sided wall = texture->height -static void R_DrawFlippedMaskedColumn(column_t *column) +static void R_DrawFlippedMaskedColumn(drawcolumndata_t* dc, column_t *column) { INT32 topscreen; INT32 bottomscreen; - fixed_t basetexturemid = dc_texturemid; + fixed_t basetexturemid = dc->texturemid; INT32 topdelta, prevdelta = -1; UINT8 *d,*s; - for (; column->topdelta != 0xff ;) + while (column->topdelta != 0xff) { // calculate unclipped screen coordinates // for post @@ -672,48 +694,47 @@ static void R_DrawFlippedMaskedColumn(column_t *column) topscreen = sprtopscreen + spryscale*topdelta; bottomscreen = sprbotscreen == INT32_MAX ? topscreen + spryscale*column->length : sprbotscreen + spryscale*column->length; - dc_yl = (topscreen+FRACUNIT-1)>>FRACBITS; - dc_yh = (bottomscreen-1)>>FRACBITS; + dc->yl = (topscreen+FRACUNIT-1)>>FRACBITS; + dc->yh = (bottomscreen-1)>>FRACBITS; if (windowtop != INT32_MAX && windowbottom != INT32_MAX) { if (windowtop > topscreen) - dc_yl = (windowtop + FRACUNIT - 1)>>FRACBITS; + dc->yl = (windowtop + FRACUNIT - 1)>>FRACBITS; if (windowbottom < bottomscreen) - dc_yh = (windowbottom - 1)>>FRACBITS; + dc->yh = (windowbottom - 1)>>FRACBITS; } - if (dc_yh >= mfloorclip[dc_x]) - dc_yh = mfloorclip[dc_x]-1; - if (dc_yl <= mceilingclip[dc_x]) - dc_yl = mceilingclip[dc_x]+1; - if (dc_yl < 0) - dc_yl = 0; - if (dc_yh >= vid.height) // dc_yl must be < vid.height, so reduces number of checks in tight loop - dc_yh = vid.height - 1; + if (dc->yh >= mfloorclip[dc->x]) + dc->yh = mfloorclip[dc->x]-1; + if (dc->yl <= mceilingclip[dc->x]) + dc->yl = mceilingclip[dc->x]+1; + if (dc->yl < 0) + dc->yl = 0; + if (dc->yh >= vid.height) // dc->yl must be < vid.height, so reduces number of checks in tight loop + dc->yh = vid.height - 1; - if (dc_yl <= dc_yh && dc_yh > 0 && column->length != 0) + if (dc->yl <= dc->yh && dc->yh > 0 && column->length != 0) { - dc_source = ZZ_Alloc(column->length); - dc_sourcelength = column->length; + dc->source = static_cast(ZZ_Alloc(column->length)); + dc->sourcelength = column->length; - for (s = (UINT8 *)column+2+column->length, d = dc_source; d < dc_source+column->length; --s) + for (s = (UINT8 *)column+2+column->length, d = dc->source; d < dc->source+column->length; --s) *d++ = *s; - dc_texturemid = basetexturemid - (topdelta<texturemid = basetexturemid - (topdelta<(&dc_copy)); + + Z_Free(dc->source); } column = (column_t *)((UINT8 *)column + column->length + 4); } - dc_texturemid = basetexturemid; + dc->texturemid = basetexturemid; } // @@ -723,7 +744,7 @@ static void R_DrawFlippedMaskedColumn(column_t *column) static void R_DrawVisSprite(vissprite_t *vis) { column_t *column; - void (*localcolfunc)(column_t *); + void (*localcolfunc)(drawcolumndata_t*, column_t *); INT32 texturecolumn; INT32 pwidth; fixed_t frac; @@ -731,6 +752,7 @@ static void R_DrawVisSprite(vissprite_t *vis) fixed_t this_scale = vis->thingscale; INT32 x1, x2; INT64 overflow_test; + drawcolumndata_t dc = {}; if (!patch) return; @@ -756,76 +778,72 @@ static void R_DrawVisSprite(vissprite_t *vis) return; } - colfunc = basecolfunc; // hack: this isn't resetting properly somewhere. - dc_colormap = vis->colormap; + R_SetColumnFunc(BASEDRAWFUNC); // hack: this isn't resetting properly somewhere. + dc.colormap = vis->colormap; if ((vis->mobj->flags & MF_BOSS) && (vis->mobj->flags2 & MF2_FRET) && (leveltime & 1)) // Bosses "flash" { - // translate certain pixels to white - colfunc = transcolfunc; + R_SetColumnFunc(COLDRAWFUNC_TRANS); // translate certain pixels to white if (vis->mobj->type == MT_CYBRAKDEMON) - dc_translation = R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE); + dc.translation = R_GetTranslationColormap(TC_ALLWHITE, SKINCOLOR_NONE, GTC_CACHE); else if (vis->mobj->type == MT_METALSONIC_BATTLE) - dc_translation = R_GetTranslationColormap(TC_METALSONIC, 0, GTC_CACHE); + dc.translation = R_GetTranslationColormap(TC_METALSONIC, SKINCOLOR_NONE, GTC_CACHE); else - dc_translation = R_GetTranslationColormap(TC_BOSS, 0, GTC_CACHE); + dc.translation = R_GetTranslationColormap(TC_BOSS, SKINCOLOR_NONE, GTC_CACHE); } else if (vis->mobj->color && vis->transmap) // Color mapping { - colfunc = transtransfunc; - dc_transmap = vis->transmap; + R_SetColumnFunc(COLDRAWFUNC_TRANSTRANS); + dc.transmap = vis->transmap; if (vis->mobj->colorized) - dc_translation = R_GetTranslationColormap(TC_RAINBOW, vis->mobj->color, GTC_CACHE); + dc.translation = R_GetTranslationColormap(TC_RAINBOW, static_cast(vis->mobj->color), GTC_CACHE); else if (vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // MT_GHOST LOOKS LIKE A PLAYER SO USE THE PLAYER TRANSLATION TABLES. >_> - dc_translation = R_GetLocalTranslationColormap(vis->mobj->skin, vis->mobj->localskin, vis->mobj->color, GTC_CACHE, vis->mobj->skinlocal); + dc.translation = R_GetLocalTranslationColormap(static_cast(vis->mobj->skin), static_cast(vis->mobj->localskin), static_cast(vis->mobj->color), GTC_CACHE, vis->mobj->skinlocal); else // Use the defaults - dc_translation = R_GetTranslationColormap(TC_DEFAULT, vis->mobj->color, GTC_CACHE); + dc.translation = R_GetTranslationColormap(TC_DEFAULT, static_cast(vis->mobj->color), GTC_CACHE); } else if (vis->transmap) { - colfunc = fuzzcolfunc; - dc_transmap = vis->transmap; //Fab : 29-04-98: translucency table + R_SetColumnFunc(COLDRAWFUNC_FUZZY); + dc.transmap = vis->transmap; //Fab : 29-04-98: translucency table } else if (vis->mobj->color) { // translate green skin to another color - colfunc = transcolfunc; + R_SetColumnFunc(COLDRAWFUNC_TRANS); // New colormap stuff for skins Tails 06-07-2002 if (vis->mobj->colorized) - dc_translation = R_GetTranslationColormap(TC_RAINBOW, vis->mobj->color, GTC_CACHE); + dc.translation = R_GetTranslationColormap(TC_RAINBOW, static_cast(vis->mobj->color), GTC_CACHE); else if (vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // This thing is a player! - dc_translation = R_GetLocalTranslationColormap(vis->mobj->skin, vis->mobj->localskin, vis->mobj->color, GTC_CACHE, vis->mobj->skinlocal); + dc.translation = R_GetLocalTranslationColormap(static_cast(vis->mobj->skin), static_cast(vis->mobj->localskin), static_cast(vis->mobj->color), GTC_CACHE, vis->mobj->skinlocal); else // Use the defaults - dc_translation = R_GetTranslationColormap(TC_DEFAULT, vis->mobj->color, GTC_CACHE); + dc.translation = R_GetTranslationColormap(TC_DEFAULT, static_cast(vis->mobj->color), GTC_CACHE); } else if (vis->mobj->sprite == SPR_PLAY) // Looks like a player, but doesn't have a color? Get rid of green sonic syndrome. { - colfunc = transcolfunc; - dc_translation = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_BLUE, GTC_CACHE); + R_SetColumnFunc(COLDRAWFUNC_TRANS); + dc.translation = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_BLUE, GTC_CACHE); } if (vis->extra_colormap) { - if (!dc_colormap) - dc_colormap = vis->extra_colormap->colormap; + if (!dc.colormap) + dc.colormap = vis->extra_colormap->colormap; else - dc_colormap = &vis->extra_colormap->colormap[dc_colormap - colormaps]; + dc.colormap = &vis->extra_colormap->colormap[dc.colormap - colormaps]; } - if (!dc_colormap) - dc_colormap = colormaps; + if (!dc.colormap) + dc.colormap = colormaps; if (encoremap && !vis->mobj->color && !(vis->mobj->flags & MF_DONTENCOREMAP)) - dc_colormap += COLORMAP_REMAPOFFSET; + dc.colormap += COLORMAP_REMAPOFFSET; - dc_texturemid = vis->texturemid; - dc_texheight = patch->height; + dc.texturemid = vis->texturemid; + dc.texheight = patch->height; frac = vis->startfrac; windowtop = windowbottom = sprbotscreen = INT32_MAX; - if ((vis->mobj->skin || vis->mobj->localskin) && K_GetMobjSkin(vis->mobj)->flags & SF_HIRES) - this_scale = FixedMul(this_scale, K_GetMobjSkin(vis->mobj)->highresscale); - if (this_scale <= 0) this_scale = 1; @@ -838,15 +856,15 @@ static void R_DrawVisSprite(vissprite_t *vis) vis->xiscale = FixedDiv(vis->xiscale, this_scale); vis->isScaled = true; } - dc_texturemid = FixedDiv(dc_texturemid, this_scale); + dc.texturemid = FixedDiv(dc.texturemid, this_scale); } spryscale = vis->scale; if (!(vis->scalestep)) { - sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale); - dc_iscale = FixedDiv(FRACUNIT, vis->scale); + sprtopscreen = centeryfrac - FixedMul(dc.texturemid, spryscale); + dc.iscale = FixedDiv(FRACUNIT, vis->scale); } x1 = vis->x1; @@ -872,9 +890,9 @@ static void R_DrawVisSprite(vissprite_t *vis) fixed_t scalestep = FixedMul(vis->scalestep, vis->spriteyscale); // Papersprite drawing loop - for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, spryscale += scalestep) + for (dc.x = vis->x1; dc.x <= vis->x2; dc.x++, spryscale += scalestep) { - angle_t angle = ((vis->centerangle + xtoviewangle[dc_x]) >> ANGLETOFINESHIFT) & 0xFFF; + angle_t angle = ((vis->centerangle + xtoviewangle[dc.x]) >> ANGLETOFINESHIFT) & 0xFFF; texturecolumn = (vis->paperoffset - FixedMul(FINETANGENT(angle), vis->paperdistance)) / horzscale; if (texturecolumn < 0 || texturecolumn >= pwidth) @@ -883,28 +901,26 @@ static void R_DrawVisSprite(vissprite_t *vis) if (vis->xiscale < 0) // Flipped sprite texturecolumn = pwidth - 1 - texturecolumn; - sprtopscreen = (centeryfrac - FixedMul(dc_texturemid, spryscale)); - dc_iscale = (0xffffffffu / (unsigned)spryscale); + sprtopscreen = (centeryfrac - FixedMul(dc.texturemid, spryscale)); + dc.iscale = (0xffffffffu / (unsigned)spryscale); column = (column_t *)((UINT8 *)patch->columns + (patch->columnofs[texturecolumn])); - localcolfunc (column); + localcolfunc(&dc, column); } } else { // Non-paper drawing loop - for (dc_x = vis->x1; dc_x <= vis->x2 && (frac>>FRACBITS) < pwidth; dc_x++, frac += vis->xiscale) + for (dc.x = vis->x1; dc.x <= vis->x2; dc.x++, frac += vis->xiscale) { texturecolumn = CLAMP(frac >> FRACBITS, 0, pwidth - 1); column = (column_t *)((UINT8 *)patch->columns + (patch->columnofs[texturecolumn])); - - localcolfunc (column); + localcolfunc(&dc, column); } } - colfunc = basecolfunc; - dc_hires = 0; + R_SetColumnFunc(BASEDRAWFUNC); vis->x1 = x1; vis->x2 = x2; @@ -919,9 +935,11 @@ static void R_DrawPrecipitationVisSprite(vissprite_t *vis) patch_t *patch; fixed_t this_scale = vis->thingscale; INT64 overflow_test; + drawcolumndata_t dc = {}; //Fab : R_InitSprites now sets a wad lump number patch = vis->patch; + if (!patch) return; @@ -932,21 +950,21 @@ static void R_DrawPrecipitationVisSprite(vissprite_t *vis) if (vis->transmap) { - colfunc = fuzzcolfunc; - dc_transmap = vis->transmap; //Fab : 29-04-98: translucency table + R_SetColumnFunc(COLDRAWFUNC_FUZZY); + dc.transmap = vis->transmap; //Fab : 29-04-98: translucency table } - dc_colormap = colormaps; + dc.colormap = colormaps; if (encoremap) - dc_colormap += COLORMAP_REMAPOFFSET; + dc.colormap += COLORMAP_REMAPOFFSET; - dc_iscale = FixedDiv(FRACUNIT, vis->scale); - dc_texturemid = FixedDiv(vis->texturemid, this_scale); - dc_texheight = patch->height; + dc.iscale = FixedDiv(FRACUNIT, vis->scale); + dc.texturemid = FixedDiv(vis->texturemid, this_scale); + dc.texheight = patch->height; frac = vis->startfrac; spryscale = vis->scale; - sprtopscreen = centeryfrac - FixedMul(dc_texturemid,spryscale); + sprtopscreen = centeryfrac - FixedMul(dc.texturemid,spryscale); windowtop = windowbottom = sprbotscreen = INT32_MAX; if (vis->x1 < 0) @@ -955,7 +973,7 @@ static void R_DrawPrecipitationVisSprite(vissprite_t *vis) if (vis->x2 >= vid.width) vis->x2 = vid.width-1; - for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, frac += vis->xiscale) + for (dc.x = vis->x1; dc.x <= vis->x2; dc.x++, frac += vis->xiscale) { texturecolumn = frac>>FRACBITS; @@ -967,10 +985,10 @@ static void R_DrawPrecipitationVisSprite(vissprite_t *vis) column = (column_t *)((UINT8 *)patch->columns + (patch->columnofs[texturecolumn])); - R_DrawMaskedColumn(column); + R_DrawMaskedColumn(&dc, column); } - colfunc = basecolfunc; + R_SetColumnFunc(BASEDRAWFUNC); } // @@ -979,14 +997,9 @@ static void R_DrawPrecipitationVisSprite(vissprite_t *vis) // static void R_SplitSprite(vissprite_t *sprite) { - INT32 i, lightnum, lindex; - INT16 cutfrac; - sector_t *sector; - vissprite_t *newsprite; + sector_t *sector = sprite->sector; - sector = sprite->sector; - - for (i = 1; i < sector->numlights; i++) + for (INT32 i = 1; i < sector->numlights; i++) { fixed_t testheight; @@ -1000,7 +1013,7 @@ static void R_SplitSprite(vissprite_t *sprite) if (testheight <= sprite->gz) return; - cutfrac = (INT16)((centeryfrac - FixedMul(testheight - viewz, sprite->sortscale))>>FRACBITS); + INT16 cutfrac = (INT16)((centeryfrac - FixedMul(testheight - viewz, sprite->sortscale))>>FRACBITS); if (cutfrac < 0) continue; if (cutfrac > viewheight) @@ -1008,9 +1021,18 @@ static void R_SplitSprite(vissprite_t *sprite) // Found a split! Make a new sprite, copy the old sprite to it, and // adjust the heights. - newsprite = M_Memcpy(R_NewVisSprite(), sprite, sizeof (vissprite_t)); + vissprite_t *newsprite = R_NewVisSprite(); - sprite->cut |= SC_BOTTOM; + // Needs to keep the new sprite's clipping tables + INT16 *cliptop = newsprite->cliptop; + INT16 *clipbot = newsprite->clipbot; + + M_Memcpy(newsprite, sprite, sizeof (vissprite_t)); + + newsprite->cliptop = cliptop; + newsprite->clipbot = clipbot; + + sprite->cut = static_cast(sprite->cut | SC_BOTTOM); sprite->gz = testheight; newsprite->gzt = sprite->gz; @@ -1028,10 +1050,11 @@ static void R_SplitSprite(vissprite_t *sprite) newsprite->szt -= 8; - newsprite->cut |= SC_TOP; + sprite->cut = static_cast(sprite->cut | SC_TOP); + if (!(sector->lightlist[i].caster->flags & FF_NOSHADE)) { - lightnum = (*sector->lightlist[i].lightlevel >> LIGHTSEGSHIFT); + INT32 lightnum = (*sector->lightlist[i].lightlevel >> LIGHTSEGSHIFT); if (lightnum < 0) spritelights = scalelight[0]; @@ -1045,7 +1068,7 @@ static void R_SplitSprite(vissprite_t *sprite) if (!((newsprite->cut & SC_FULLBRIGHT) && (!newsprite->extra_colormap || !(newsprite->extra_colormap->fog & 1)))) { - lindex = FixedMul(sprite->xscale, LIGHTRESOLUTIONFIX)>>(LIGHTSCALESHIFT); + INT32 lindex = FixedMul(sprite->xscale, LIGHTRESOLUTIONFIX)>>(LIGHTSCALESHIFT); // Mitigate against negative xscale and arithmetic overflow lindex = CLAMP(lindex, 0, MAXLIGHTSCALE - 1); @@ -1124,7 +1147,7 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope) fixed_t R_GetSpriteDirectionalLighting(angle_t angle) { // Copied from P_UpdateSegLightOffset - const UINT8 contrast = min(max(0, maplighting.contrast - maplighting.backlight), UINT8_MAX); + const UINT8 contrast = std::min(std::max(0, maplighting.contrast - maplighting.backlight), UINT8_MAX); const fixed_t contrastFixed = ((fixed_t)contrast) * FRACUNIT; fixed_t light = FRACUNIT; @@ -1141,6 +1164,8 @@ fixed_t R_GetSpriteDirectionalLighting(angle_t angle) return extralight; } +#define std_R_QuickCamDist(x, y) std::max(abs(((x)>>FRACBITS) - (viewx>>FRACBITS)), abs(((y)>>FRACBITS) - (viewy>>FRACBITS))) + // // R_ProjectSprite // Generates a vissprite for a thing @@ -1178,8 +1203,6 @@ static void R_ProjectSprite(mobj_t *thing) fixed_t offset, offset2; fixed_t paperoffset = 0, paperdistance = 0; angle_t centerangle = 0; - INT32 lightnum; - //SoM: 3/17/2000 fixed_t gz, gzt; INT32 heightsec, phs; @@ -1200,7 +1223,7 @@ static void R_ProjectSprite(mobj_t *thing) angle_t sliptiderollangle = 0; #endif - if (P_MobjWasRemoved(thing) || thing->subsector == NULL) + if (!thing || thing->subsector == NULL) return; mobj_t *oldthing = thing; @@ -1211,10 +1234,10 @@ static void R_ProjectSprite(mobj_t *thing) const boolean papersprite = (thing->frame & FF_PAPERSPRITE); if (cv_maxinterpdist.value) - dist = R_QuickCamDist(thing->x, thing->y); + dist = std_R_QuickCamDist(thing->x, thing->y); // uncapped/interpolation - interpmobjstate_t interp = {0}; + interpmobjstate_t interp = {}; // do interpolation if (R_UsingFrameInterpolation() && !paused && (!cv_maxinterpdist.value || dist < cv_maxinterpdist.value)) @@ -1244,7 +1267,7 @@ static void R_ProjectSprite(mobj_t *thing) tx = FixedMul(tr_x, viewsin) - FixedMul(tr_y, viewcos); // sideways distance // too far off the side? - if (!papersprite && abs(tx) > tz<<2) // papersprite clipping is handled later + if (!papersprite && abs(tx) > (INT64)FixedMul(tz, fovtan)<<2) // papersprite clipping is handled later return; // aspect ratio stuff @@ -1470,7 +1493,7 @@ static void R_ProjectSprite(mobj_t *thing) tx2 = FixedMul(tr_x, viewsin) - FixedMul(tr_y, viewcos); - if (max(tz, tz2) < FixedMul(MINZ, this_scale)) // non-papersprite clipping is handled earlier + if (std::max(tz, tz2) < FixedMul(MINZ, this_scale)) // non-papersprite clipping is handled earlier return; // Needs partially clipped @@ -1487,7 +1510,7 @@ static void R_ProjectSprite(mobj_t *thing) tz2 = FixedMul(MINZ, this_scale); } - if (tx2 < -(FixedMul(tz2, fovtan)<<2) || tx > FixedMul(tz, fovtan)<<2) // too far off the side? + if ((tx2 / 4) < -(FixedMul(tz2, fovtan)) || (tx / 4) > FixedMul(tz, fovtan)) // too far off the side? return; yscale = FixedDiv(projectiony, tz); @@ -1513,7 +1536,7 @@ static void R_ProjectSprite(mobj_t *thing) range++; // fencepost problem - if (range > 32767) + if (range > INT16_MAX) { // If the range happens to be too large for fixed_t, // abort the draw to avoid xscale becoming negative due to arithmetic overflow. @@ -1537,14 +1560,14 @@ static void R_ProjectSprite(mobj_t *thing) scalestep = 0; yscale = sortscale; tx += offset; - x1 = (centerxfrac + FixedMul(tx,xscale))>>FRACBITS; + x1 = centerx + (FixedMul(tx,xscale) / FRACUNIT); // off the right side? if (x1 > viewwidth) return; tx += offset2; - x2 = ((centerxfrac + FixedMul(tx,xscale))>>FRACBITS); x2--; + x2 = (centerx + (FixedMul(tx,xscale) / FRACUNIT)) - 1; // off the left side if (x2 < 0) @@ -1561,13 +1584,13 @@ static void R_ProjectSprite(mobj_t *thing) return; } + // Determine the blendmode and translucency value INT32 blendmode; if (oldthing->frame & FF_BLENDMASK) blendmode = ((oldthing->frame & FF_BLENDMASK) >> FF_BLENDSHIFT) + 1; else blendmode = oldthing->blendmode; - // Determine the translucency value. if (oldthing->flags2 & MF2_SHADOW || thing->flags2 & MF2_SHADOW) // actually only the player should use this (temporary invisibility) trans = tr_trans80; // because now the translucency is set through FF_TRANSMASK else if (oldthing->frame & FF_TRANSMASK) @@ -1603,16 +1626,18 @@ static void R_ProjectSprite(mobj_t *thing) if (oldthing->frame & FF_ABSOLUTELIGHTLEVEL) { const UINT8 n = R_ThingLightLevel(oldthing); - // n = uint8 aka 0 - 255, so the shift will always be 0 - LIGHTLEVELS - 1 lights_array = scalelight[n >> LIGHTSEGSHIFT]; } else { + INT32 lightnum; + if (thing->subsector->sector->numlights) { light = thing->subsector->sector->numlights - 1; + // R_GetPlaneLight won't work on sloped lights! for (lightnum = 1; lightnum < thing->subsector->sector->numlights; lightnum++) { fixed_t h = P_GetLightZAt(&thing->subsector->sector->lightlist[lightnum], interp.x, interp.y); @@ -1633,7 +1658,7 @@ static void R_ProjectSprite(mobj_t *thing) lightnum = (lightnum + R_ThingLightLevel(thing)) >> LIGHTSEGSHIFT; - if (maplighting.directional == true && P_SectorUsesDirectionalLighting(thing->subsector->sector)) + if (maplighting.directional && P_SectorUsesDirectionalLighting(thing->subsector->sector)) { fixed_t extralight = R_GetSpriteDirectionalLighting(papersprite ? interp.angle + (ang >= ANGLE_180 ? -ANGLE_90 : ANGLE_90) @@ -1648,7 +1673,7 @@ static void R_ProjectSprite(mobj_t *thing) } // Less change in contrast in dark sectors - extralight = FixedMul(extralight, min(max(0, lightnum), LIGHTLEVELS - 1) * FRACUNIT / (LIGHTLEVELS - 1)); + extralight = FixedMul(extralight, std::min(std::max(0, lightnum), LIGHTLEVELS - 1) * FRACUNIT / (LIGHTLEVELS - 1)); if (papersprite) { @@ -1660,7 +1685,7 @@ static void R_ProjectSprite(mobj_t *thing) fixed_t n = FixedDiv(FixedMul(xscale, LIGHTRESOLUTIONFIX), ((MAXLIGHTSCALE-1) << LIGHTSCALESHIFT)); // Less change in contrast at further distances, to counteract DOOM diminished light - extralight = FixedMul(extralight, min(n, FRACUNIT)); + extralight = FixedMul(extralight, std::min(n, FRACUNIT)); // Contrast is stronger for normal sprites, stronger than wall lighting is at the same distance lightnum += FixedFloor((extralight / 4) + (FRACUNIT / 2)) / FRACUNIT; @@ -1676,23 +1701,20 @@ static void R_ProjectSprite(mobj_t *thing) } heightsec = thing->subsector->sector->heightsec; - if (viewplayer->mo && viewplayer->mo->subsector) + if (viewplayer && viewplayer->mo && viewplayer->mo->subsector) phs = viewplayer->mo->subsector->sector->heightsec; else phs = -1; if (heightsec != -1 && phs != -1) // only clip things which are in special sectors { - fixed_t top = gzt; - fixed_t bottom = interp.z; - if (viewz < sectors[phs].floorheight ? - bottom >= sectors[heightsec].floorheight : - top < sectors[heightsec].floorheight) + interp.z >= sectors[heightsec].floorheight : + gzt < sectors[heightsec].floorheight) return; if (viewz > sectors[phs].ceilingheight ? - top < sectors[heightsec].ceilingheight && viewz >= sectors[heightsec].ceilingheight : - bottom >= sectors[heightsec].ceilingheight) + gzt < sectors[heightsec].ceilingheight && viewz >= sectors[heightsec].ceilingheight : + interp.z >= sectors[heightsec].ceilingheight) return; } @@ -1765,11 +1787,11 @@ static void R_ProjectSprite(mobj_t *thing) vis->transmap = NULL; if (R_ThingIsFullBright(oldthing) || oldthing->flags2 & MF2_SHADOW || thing->flags2 & MF2_SHADOW) - vis->cut |= SC_FULLBRIGHT; + vis->cut = static_cast(vis->cut | SC_FULLBRIGHT); else if (R_ThingIsSemiBright(oldthing)) - vis->cut |= SC_SEMIBRIGHT; + vis->cut = static_cast(vis->cut | SC_SEMIBRIGHT); else if (R_ThingIsFullDark(oldthing)) - vis->cut |= SC_FULLDARK; + vis->cut = static_cast(vis->cut | SC_FULLDARK); // // determine the colormap (lightlevel & special effects) @@ -1804,7 +1826,7 @@ static void R_ProjectSprite(mobj_t *thing) vis->patch = rotsprite; else #endif - vis->patch = W_CachePatchNum(sprframe->lumppat[rot], PU_SPRITE); + vis->patch = static_cast(W_CachePatchNum(sprframe->lumppat[rot], PU_SPRITE)); vis->precip = false; @@ -1846,10 +1868,10 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) return; if (cv_maxinterpdist.value) - dist = R_QuickCamDist(thing->x, thing->y); + dist = std_R_QuickCamDist(thing->x, thing->y); // uncapped/interpolation - interpmobjstate_t interp = {0}; + interpmobjstate_t interp = {}; // okay... this is a hack, but weather isn't networked, so it should be ok if (!P_PrecipThinker(thing)) @@ -1892,7 +1914,6 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) // aspect ratio stuff : xscale = FixedDiv(projection, tz); - yscale = FixedDiv(projectiony, tz); // decide which patch to use for sprite relative to player #ifdef RANGECHECK @@ -1954,6 +1975,9 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) return; } + // aspect ratio stuff : + yscale = FixedDiv(projectiony, tz); + // store information in a vissprite vis = R_NewVisSprite(); vis->scale = FixedMul(yscale, this_scale); @@ -1989,7 +2013,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) //Fab: lumppat is the lump number of the patch to use, this is different // than lumpid for sprites-in-pwad : the graphics are patched - vis->patch = W_CachePatchNum(sprframe->lumppat[0], PU_SPRITE); + vis->patch = static_cast(W_CachePatchNum(sprframe->lumppat[0], PU_SPRITE)); // specific translucency if ((thing->blendmode != AST_COPY) && cv_translucency.value) @@ -2108,9 +2132,7 @@ void R_AddPrecipitationSprites(void) // // R_SortVisSprites // -static vissprite_t vsprsortedhead; - -void R_SortVisSprites(void) +static void R_SortVisSprites(vissprite_t* vsprsortedhead, UINT32 start, UINT32 end) { UINT32 i; vissprite_t *ds, *dsprev, *dsnext, *dsfirst; @@ -2119,20 +2141,18 @@ void R_SortVisSprites(void) fixed_t bestscale; INT32 bestdispoffset; - if (!visspritecount) - return; - unsorted.next = unsorted.prev = &unsorted; - dsfirst = R_GetVisSprite(0); + dsfirst = R_GetVisSprite(start); // The first's prev and last's next will be set to // nonsense, but are fixed in a moment - for (i = 0, dsnext = dsfirst, ds = NULL; i < visspritecount; i++) + for (i = start, dsnext = dsfirst, ds = NULL; i < end; i++) { dsprev = ds; ds = dsnext; - if (i < visspritecount - 1) dsnext = R_GetVisSprite(i + 1); + if (i < end - 1) + dsnext = R_GetVisSprite(i + 1); ds->next = dsnext; ds->prev = dsprev; @@ -2146,8 +2166,8 @@ void R_SortVisSprites(void) unsorted.prev = ds; // pull the vissprites out by scale - vsprsortedhead.next = vsprsortedhead.prev = &vsprsortedhead; - for (i = 0; i < visspritecount; i++) + vsprsortedhead->next = vsprsortedhead->prev = vsprsortedhead; + for (i = start; i < end; i++) { bestscale = bestdispoffset = INT32_MAX; for (ds = unsorted.next; ds != &unsorted; ds = ds->next) @@ -2177,10 +2197,10 @@ void R_SortVisSprites(void) { best->next->prev = best->prev; best->prev->next = best->next; - best->next = &vsprsortedhead; - best->prev = vsprsortedhead.prev; - vsprsortedhead.prev->next = best; - vsprsortedhead.prev = best; + best->next = vsprsortedhead; + best->prev = vsprsortedhead->prev; + vsprsortedhead->prev->next = best; + vsprsortedhead->prev = best; } } } @@ -2191,28 +2211,29 @@ void R_SortVisSprites(void) static drawnode_t *R_CreateDrawNode(drawnode_t *link); static drawnode_t nodebankhead; -static drawnode_t nodehead; -static void R_CreateDrawNodes(void) +static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean tempskip) { drawnode_t *entry; drawseg_t *ds; INT32 i, p, best, x1, x2; fixed_t bestdelta, delta; vissprite_t *rover; + static vissprite_t vsprsortedhead; drawnode_t *r2; visplane_t *plane; INT32 sintersect; fixed_t scale = 0; + const INT32 vidheight = vid.height; // Add the 3D floors, thicksides, and masked textures... - for (ds = ds_p; ds-- > drawsegs ;) + for (ds = drawsegs + mask->drawsegs[1]; ds-- > drawsegs + mask->drawsegs[0];) { if (ds->numthicksides) { for (i = 0; i < ds->numthicksides; i++) { - entry = R_CreateDrawNode(&nodehead); + entry = R_CreateDrawNode(head); entry->thickseg = ds; entry->ffloor = ds->thicksides[i]; } @@ -2223,12 +2244,12 @@ static void R_CreateDrawNodes(void) plane = ds->curline->polyseg->visplane; R_PlaneBounds(plane); - if (plane->low < 0 || plane->high > vid.height || plane->high > plane->low) + if (plane->low < 0 || plane->high > vidheight || plane->high > plane->low) ; else { // Put it in! - entry = R_CreateDrawNode(&nodehead); + entry = R_CreateDrawNode(head); entry->plane = plane; entry->seg = ds; } @@ -2236,7 +2257,7 @@ static void R_CreateDrawNodes(void) } if (ds->maskedtexturecol) { - entry = R_CreateDrawNode(&nodehead); + entry = R_CreateDrawNode(head); entry->seg = ds; } if (ds->numffloorplanes) @@ -2253,7 +2274,7 @@ static void R_CreateDrawNodes(void) plane = ds->ffloorplanes[p]; R_PlaneBounds(plane); - if (plane->low < 0 || plane->high > vid.height || plane->high > plane->low || plane->polyobj) + if (plane->low < 0 || plane->high > vidheight || plane->high > plane->low || plane->polyobj) { ds->ffloorplanes[p] = NULL; continue; @@ -2268,7 +2289,7 @@ static void R_CreateDrawNodes(void) } if (best != -1) { - entry = R_CreateDrawNode(&nodehead); + entry = R_CreateDrawNode(head); entry->plane = ds->ffloorplanes[best]; entry->seg = ds; ds->ffloorplanes[best] = NULL; @@ -2279,6 +2300,9 @@ static void R_CreateDrawNodes(void) } } + if (tempskip) + return; + // find all the remaining polyobject planes and add them on the end of the list // probably this is a terrible idea if we wanted them to be sorted properly // but it works getting them in for now @@ -2290,31 +2314,32 @@ static void R_CreateDrawNodes(void) plane = PolyObjects[i].visplane; R_PlaneBounds(plane); - if (plane->low < 0 || plane->high > vid.height || plane->high > plane->low) + if (plane->low < 0 || plane->high > vidheight || plane->high > plane->low) { PolyObjects[i].visplane = NULL; continue; } - entry = R_CreateDrawNode(&nodehead); + entry = R_CreateDrawNode(head); entry->plane = plane; // note: no seg is set, for what should be obvious reasons PolyObjects[i].visplane = NULL; } - if (visspritecount == 0) + // No vissprites in this mask? + if (mask->vissprites[1] - mask->vissprites[0] == 0) return; - R_SortVisSprites(); + R_SortVisSprites(&vsprsortedhead, mask->vissprites[0], mask->vissprites[1]); for (rover = vsprsortedhead.prev; rover != &vsprsortedhead; rover = rover->prev) { - if (rover->szt > vid.height || rover->sz < 0) + if (rover->szt > vidheight || rover->sz < 0) continue; sintersect = (rover->x1 + rover->x2) / 2; - for (r2 = nodehead.next; r2 != &nodehead; r2 = r2->next) + for (r2 = head->next; r2 != head; r2 = r2->next) { if (r2->plane) { @@ -2326,21 +2351,17 @@ static void R_CreateDrawNodes(void) // Effective height may be different for each comparison in the case of slopes planeobjectz = P_GetZAt(r2->plane->slope, rover->gx, rover->gy, r2->plane->height); - planecameraz = P_GetZAt(r2->plane->slope, viewx, viewy, r2->plane->height); + planecameraz = P_GetZAt(r2->plane->slope, viewx, viewy, r2->plane->height); - if (rover->mobjflags & MF_NOCLIPHEIGHT) + // bird: if any part of the sprite peeks in front the plane + if (planecameraz < viewz) { - //Objects with NOCLIPHEIGHT can appear halfway in. - if (planecameraz < viewz && rover->pz+(rover->thingheight/2) >= planeobjectz) - continue; - if (planecameraz > viewz && rover->pzt-(rover->thingheight/2) <= planeobjectz) + if (rover->gzt >= planeobjectz) continue; } - else + else if (planecameraz > viewz) { - if (planecameraz < viewz && rover->pz >= planeobjectz) - continue; - if (planecameraz > viewz && rover->pzt <= planeobjectz) + if (rover->gz <= planeobjectz) continue; } @@ -2374,7 +2395,7 @@ static void R_CreateDrawNodes(void) } else if (r2->thickseg) { - fixed_t topplaneobjectz, topplanecameraz, botplaneobjectz, botplanecameraz; + //fixed_t topplaneobjectz, topplanecameraz, botplaneobjectz, botplanecameraz; if (rover->x1 > r2->thickseg->x2 || rover->x2 < r2->thickseg->x1) continue; @@ -2387,6 +2408,11 @@ static void R_CreateDrawNodes(void) if (scale <= rover->sortscale) continue; + // bird: Always sort sprites behind segs. This helps the plane + // sorting above too. Basically if the sprite gets sorted behind + // the seg here, it will be behind the plane too, since planes + // are added after segs in the list. +#if 0 topplaneobjectz = P_GetFFloorTopZAt (r2->ffloor, rover->gx, rover->gy); topplanecameraz = P_GetFFloorTopZAt (r2->ffloor, viewx, viewy); botplaneobjectz = P_GetFFloorBottomZAt(r2->ffloor, rover->gx, rover->gy); @@ -2395,6 +2421,7 @@ static void R_CreateDrawNodes(void) if ((topplanecameraz > viewz && botplanecameraz < viewz) || (topplanecameraz < viewz && rover->gzt < topplaneobjectz) || (botplanecameraz > viewz && rover->gz > botplaneobjectz)) +#endif { entry = R_CreateDrawNode(NULL); (entry->prev = r2->prev)->next = entry; @@ -2440,9 +2467,9 @@ static void R_CreateDrawNodes(void) } } } - if (r2 == &nodehead) + if (r2 == head) { - entry = R_CreateDrawNode(&nodehead); + entry = R_CreateDrawNode(head); entry->sprite = rover; } } @@ -2454,7 +2481,7 @@ static drawnode_t *R_CreateDrawNode(drawnode_t *link) if (node == &nodebankhead) { - node = malloc(sizeof (*node)); + node = static_cast(malloc(sizeof (*node))); if (!node) I_Error("No more free memory to CreateDrawNode"); } @@ -2486,25 +2513,24 @@ static void R_DoneWithNode(drawnode_t *node) (node->prev = &nodebankhead)->next = node; } -static void R_ClearDrawNodes(void) +static void R_ClearDrawNodes(drawnode_t* head) { drawnode_t *rover; drawnode_t *next; - for (rover = nodehead.next; rover != &nodehead ;) + for (rover = head->next; rover != head;) { next = rover->next; R_DoneWithNode(rover); rover = next; } - nodehead.next = nodehead.prev = &nodehead; + head->next = head->prev = head; } void R_InitDrawNodes(void) { nodebankhead.next = nodebankhead.prev = &nodebankhead; - nodehead.next = nodehead.prev = &nodehead; } // @@ -2543,7 +2569,7 @@ static boolean R_CheckSpriteVisible(vissprite_t *spr, INT32 x1, INT32 x2) scalestep = FixedMul(scalestep, spr->spriteyscale); if (spr->thingscale != FRACUNIT) - texturemid = FixedDiv(spr->texturemid, max(spr->thingscale, 1)); + texturemid = FixedDiv(spr->texturemid, std::max(spr->thingscale, 1)); else texturemid = spr->texturemid; } @@ -2568,7 +2594,7 @@ static boolean R_CheckSpriteVisible(vissprite_t *spr, INT32 x1, INT32 x2) // R_ClipVisSprite // Clips vissprites without drawing, so that portals can work. -Red -static void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2) +static void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, portal_t* portal) { drawseg_t *ds; INT32 x; @@ -2598,8 +2624,10 @@ static void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2) while (++curr <= last) { + __builtin_prefetch(curr + 1, 0, 3); + // determine if the drawseg obscures the sprite - if (curr->x1 > spr->x2 || curr->x2 < spr->x1) + if (curr->x1 > x2 || curr->x2 < x1) { // does not cover sprite continue; @@ -2607,33 +2635,33 @@ static void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2) ds = curr->user; - if (ds->portalpass > 0 && ds->portalpass <= portalrender) - continue; // is a portal - - r1 = ds->x1 < spr->x1 ? spr->x1 : ds->x1; - r2 = ds->x2 > spr->x2 ? spr->x2 : ds->x2; - - if (ds->scale1 > ds->scale2) + if (ds->portalpass != 66) // unused? { - lowscale = ds->scale2; - scale = ds->scale1; - } - else - { - lowscale = ds->scale1; - scale = ds->scale2; + if (ds->portalpass > 0 && ds->portalpass <= portalrender) + continue; // is a portal + + if (ds->scale1 > ds->scale2) + { + lowscale = ds->scale2; + scale = ds->scale1; + } + else + { + lowscale = ds->scale1; + scale = ds->scale2; + } + + if (scale < spr->sortscale || + (lowscale < spr->sortscale && + !R_PointOnSegSide(spr->gx, spr->gy, ds->curline))) + { + // seg is behind sprite + continue; + } } - if (scale < spr->sortscale || - (lowscale < spr->sortscale && - !R_PointOnSegSide (spr->gx, spr->gy, ds->curline))) - { - // masked mid texture? - /*if (ds->maskedtexturecol) - R_RenderMaskedSegRange (ds, r1, r2);*/ - // seg is behind sprite - continue; - } + r1 = ds->x1 < x1 ? x1 : ds->x1; + r2 = ds->x2 > x2 ? x2 : ds->x2; // clip this piece of the sprite silhouette = ds->silhouette; @@ -2675,20 +2703,21 @@ static void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2) if (spr->heightsec != -1) // only things in specially marked sectors { fixed_t mh, h; - INT32 phs = viewplayer->mo->subsector->sector->heightsec; + const INT32 phs = viewplayer->mo->subsector->sector->heightsec; + if ((mh = sectors[spr->heightsec].floorheight) > spr->gz && (h = centeryfrac - FixedMul(mh -= viewz, spr->sortscale)) >= 0 && (h >>= FRACBITS) < viewheight) { if (mh <= 0 || (phs != -1 && viewz > sectors[phs].floorheight)) { // clip bottom - for (x = spr->x1; x <= spr->x2; x++) + for (x = x1; x <= x2; x++) if (spr->clipbot[x] == -2 || h < spr->clipbot[x]) spr->clipbot[x] = (INT16)h; } else // clip top { - for (x = spr->x1; x <= spr->x2; x++) + for (x = x1; x <= x2; x++) if (spr->cliptop[x] == -2 || h > spr->cliptop[x]) spr->cliptop[x] = (INT16)h; } @@ -2700,21 +2729,22 @@ static void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2) { if (phs != -1 && viewz >= sectors[phs].ceilingheight) { // clip bottom - for (x = spr->x1; x <= spr->x2; x++) + for (x = x1; x <= x2; x++) if (spr->clipbot[x] == -2 || h < spr->clipbot[x]) spr->clipbot[x] = (INT16)h; } else // clip top { - for (x = spr->x1; x <= spr->x2; x++) + for (x = x1; x <= x2; x++) if (spr->cliptop[x] == -2 || h > spr->cliptop[x]) spr->cliptop[x] = (INT16)h; } } } + if (spr->cut & SC_TOP && spr->cut & SC_BOTTOM) { - for (x = spr->x1; x <= spr->x2; x++) + for (x = x1; x <= x2; x++) { if (spr->cliptop[x] == -2 || spr->szt > spr->cliptop[x]) spr->cliptop[x] = spr->szt; @@ -2725,7 +2755,7 @@ static void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2) } else if (spr->cut & SC_TOP) { - for (x = spr->x1; x <= spr->x2; x++) + for (x = x1; x <= x2; x++) { if (spr->cliptop[x] == -2 || spr->szt > spr->cliptop[x]) spr->cliptop[x] = spr->szt; @@ -2733,7 +2763,7 @@ static void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2) } else if (spr->cut & SC_BOTTOM) { - for (x = spr->x1; x <= spr->x2; x++) + for (x = x1; x <= x2; x++) { if (spr->clipbot[x] == -2 || spr->sz < spr->clipbot[x]) spr->clipbot[x] = spr->sz; @@ -2743,7 +2773,7 @@ static void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2) // all clipping has been performed, so store the values - what, did you think we were drawing them NOW? // check for unclipped columns - for (x = spr->x1; x <= spr->x2; x++) + for (x = x1; x <= x2; x++) { if (spr->clipbot[x] == -2) spr->clipbot[x] = (INT16)viewheight; @@ -2757,13 +2787,37 @@ static void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2) if (cv_spriteclip.value) { if (!R_CheckSpriteVisible(spr, x1, x2)) - spr->cut |= SC_NOTVISIBLE; + spr->cut = static_cast(spr->cut | SC_NOTVISIBLE); + } + + if (portal) + { + INT32 start_index = std::max(portal->start, x1); + INT32 end_index = std::min(portal->start + portal->end - portal->start, x2); + + for (x = x1; x < start_index; x++) + { + spr->clipbot[x] = -1; + spr->cliptop[x] = -1; + } + for (x = start_index; x <= end_index; x++) + { + if (spr->clipbot[x] > portal->floorclip[x - portal->start]) + spr->clipbot[x] = portal->floorclip[x - portal->start]; + if (spr->cliptop[x] < portal->ceilingclip[x - portal->start]) + spr->cliptop[x] = portal->ceilingclip[x - portal->start]; + } + for (x = end_index + 1; x <= x2; x++) + { + spr->clipbot[x] = -1; + spr->cliptop[x] = -1; + } } } -void R_ClipSprites(void) +void R_ClipSprites(drawseg_t* dsstart, portal_t* portal) { - const size_t maxdrawsegs = ds_p - drawsegs; + const size_t maxdrawsegs = ds_p - dsstart; const INT32 cx = viewwidth / 2; drawseg_t* ds; INT32 i; @@ -2788,15 +2842,15 @@ void R_ClipSprites(void) for (i = 0; i < DS_RANGES_COUNT; i++) { - drawsegs_xranges[i].items = Z_Realloc( + drawsegs_xranges[i].items = static_cast(Z_Realloc( drawsegs_xranges[i].items, drawsegs_xrange_size * sizeof(drawsegs_xranges[i].items[0]), PU_STATIC, NULL - ); + )); } } - for (ds = ds_p; ds-- > drawsegs;) + for (ds = ds_p; ds-- > dsstart;) { if (ds->silhouette || ds->maskedtexturecol) { @@ -2830,7 +2884,7 @@ void R_ClipSprites(void) if (cv_spriteclip.value && (spr->szt > vid.height || spr->sz < 0)) { - spr->cut |= SC_NOTVISIBLE; + spr->cut = static_cast(spr->cut | SC_NOTVISIBLE); continue; } @@ -2850,7 +2904,7 @@ void R_ClipSprites(void) drawsegs_xrange_count = drawsegs_xranges[0].count; } - R_ClipVisSprite(spr, spr->x1, spr->x2); + R_ClipVisSprite(spr, spr->x1, spr->x2, portal); if ((spr->cut & SC_NOTVISIBLE) == 0) numvisiblesprites++; @@ -2906,26 +2960,26 @@ boolean R_ThingIsFullDark(mobj_t *thing) // // R_DrawMasked // -void R_DrawMasked(void) +static void R_DrawMaskedList(drawnode_t* head) { drawnode_t *r2; drawnode_t *next; - R_CreateDrawNodes(); - - for (r2 = nodehead.next; r2 != &nodehead; r2 = r2->next) + for (r2 = head->next; r2 != head; r2 = r2->next) { if (r2->plane) { + drawspandata_t ds = {}; next = r2->prev; - R_DrawSinglePlane(r2->plane); + // Force disable multithreading since it is usually slower because of waiting for each plane to render + R_DrawSinglePlane(&ds, r2->plane, false); R_DoneWithNode(r2); r2 = next; } else if (r2->seg && r2->seg->maskedtexturecol != NULL) { next = r2->prev; - R_RenderMaskedSegRange(r2->seg, r2->seg->x1, r2->seg->x2); + R_RenderMaskedSegRange( r2->seg, r2->seg->x1, r2->seg->x2); r2->seg->maskedtexturecol = NULL; R_DoneWithNode(r2); r2 = next; @@ -2942,775 +2996,50 @@ void R_DrawMasked(void) next = r2->prev; // Tails 08-18-2002 - if (r2->sprite->precip == true) + if (r2->sprite->precip) + { R_DrawPrecipitationSprite(r2->sprite); + } else + { R_DrawSprite(r2->sprite); + } R_DoneWithNode(r2); r2 = next; } } - R_ClearDrawNodes(); } -// ========================================================================== -// -// SKINS CODE -// -// ========================================================================== - -INT32 numskins = 0; -INT32 numallskins = 0; -INT32 numlocalskins = 0; -skin_t skins[MAXSKINS]; -UINT8 skinstats[9][9][MAXSKINS]; -UINT8 skinstatscount[9][9] = { - {0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0} -}; -UINT8 skinsorted[MAXSKINS]; -skin_t localskins[MAXLOCALSKINS]; -skin_t allskins[MAXSKINS+MAXLOCALSKINS]; - -// FIXTHIS: don't work because it must be inistilised before the config load -//#define SKINVALUES -#ifdef SKINVALUES -CV_PossibleValue_t skin_cons_t[MAXSKINS+1]; -CV_PossibleValue_t localskin_cons_t[MAXLOCALSKINS+1]; -#endif - -static void Sk_SetDefaultValue(skin_t *skin, boolean local) +void R_DrawMasked(maskcount_t* masks, INT32 nummasks) { INT32 i; - // - // set default skin values - // - memset(skin, 0, sizeof (skin_t)); - snprintf(skin->name, sizeof skin->name, "skin %u", K_GetMobjSkinNum(skin, local)); - skin->name[sizeof skin->name - 1] = '\0'; - skin->wadnum = INT16_MAX; - strcpy(skin->sprite, ""); + drawnode_t *heads; /**< Drawnode lists; as many as number of views/portals. */ - skin->flags = 0; + heads = static_cast(calloc(nummasks, sizeof(drawnode_t))); - strcpy(skin->realname, "Someone"); - strcpy(skin->hudname, "???"); - strncpy(skin->facerank, "PLAYRANK", 9); - strncpy(skin->facewant, "PLAYWANT", 9); - strncpy(skin->facemmap, "PLAYMMAP", 9); + for (i = 0; i < nummasks; i++) + { + heads[i].next = heads[i].prev = &heads[i]; - skin->starttranscolor = 160; - skin->prefcolor = SKINCOLOR_GREEN; + viewx = masks[i].viewx; + viewy = masks[i].viewy; + viewz = masks[i].viewz; + viewsector = masks[i].viewsector; - // SRB2kart - skin->kartspeed = 5; - skin->kartweight = 5; - // + R_CreateDrawNodes(&masks[i], &heads[i], false); + } - skin->highresscale = FRACUNIT>>1; + for (; nummasks > 0; nummasks--) + { + viewx = masks[nummasks - 1].viewx; + viewy = masks[nummasks - 1].viewy; + viewz = masks[nummasks - 1].viewz; + viewsector = masks[nummasks - 1].viewsector; - for (i = 0; i < sfx_skinsoundslot0; i++) - if (S_sfx[i].skinsound != -1) - skin->soundsid[S_sfx[i].skinsound] = i; -} - -// -// Initialize the basic skins -// -void R_InitSkins(void) -{ - skin_t *skin; -#ifdef SKINVALUES - INT32 i; - - for (i = 0; i <= MAXSKINS; i++) - { - skin_cons_t[i].value = 0; - skin_cons_t[i].strvalue = NULL; - } - for (i = 0; i <= MAXLOCALSKINS; i++) - { - localskin_cons_t[i].value = 0; - localskin_cons_t[i].strvalue = NULL; - } -#endif - - // skin[0] = Sonic skin - skin = &skins[0]; - numskins = 1; - Sk_SetDefaultValue(skin, false); - memset(skinstats, 0, sizeof(skinstats)); - memset(skinsorted, 0, sizeof(skinsorted)); - - // Hardcoded S_SKIN customizations for Sonic. - strcpy(skin->name, DEFAULTSKIN); -#ifdef SKINVALUES - skin_cons_t[0].strvalue = skins[0].name; -#endif - skin->flags = 0; - strcpy(skin->realname, "Sonic"); - strcpy(skin->hudname, "SONIC"); - - strncpy(skin->facerank, "PLAYRANK", 9); - strncpy(skin->facewant, "PLAYWANT", 9); - strncpy(skin->facemmap, "PLAYMMAP", 9); - skin->wadnum = 0; // god what have you brought to this world - skin->prefcolor = SKINCOLOR_BLUE; - skin->localskin = false; - skin->localnum = 0; - - // SRB2kart - skin->kartspeed = 8; - skin->kartweight = 2; - // - - skin->spritedef.numframes = sprites[SPR_PLAY].numframes; - skin->spritedef.spriteframes = sprites[SPR_PLAY].spriteframes; - skin->sprinfo = spriteinfo[SPR_PLAY]; - ST_LoadFaceGraphics(skin->facerank, skin->facewant, skin->facemmap, 0); - - // Set values for Sonic skin - Forceskin_cons_t[1].value = 0; - Forceskin_cons_t[1].strvalue = skin->name; - - //MD2 for sonic doesn't want to load in Linux. -#ifdef HWRENDER - if (rendermode == render_opengl) - HWR_AddPlayerMD2(0, false); -#endif - - // lets set it - allskins[0] = skins[0]; - numallskins = 1; -} - -// returns true if the skin name is found (loaded from pwad) -// warning return -1 if not found -INT32 R_SkinAvailable(const char *name) -{ - INT32 i; - - for (i = 0; i < numskins; i++) - { - if (stricmp(skins[i].name,name) == 0) - return i; - } - return -1; -} - -// returns true if the skin name is found (loaded from pwad) -// warning return -1 if not found -INT32 R_AnySkinAvailable(const char *name) -{ - INT32 i; - - for (i = 0; i < numallskins; i++) - { - if (stricmp(allskins[i].name,name) == 0) - return i; - } - return -1; -} - -INT32 R_LocalSkinAvailable(const char *name, boolean local) -{ - INT32 i; - - if (local) - { - for (i = 0; i < numlocalskins; i++) - { - if (stricmp(localskins[i].name,name) == 0) - return i; - } - return -1; - } - else - return R_SkinAvailable(name); -} - -// network code calls this when a 'skin change' is received -boolean SetPlayerSkin(INT32 playernum, const char *skinname) -{ - INT32 i; - player_t *player = &players[playernum]; - - for (i = 0; i < numskins; i++) - { - // search in the skin list - if (stricmp(skins[i].name, skinname) == 0) - { - SetPlayerSkinByNum(playernum, i); - return true; - } + R_DrawMaskedList(&heads[nummasks - 1]); + R_ClearDrawNodes(&heads[nummasks - 1]); } - - if (P_IsLocalPlayer(player)) - CONS_Alert(CONS_WARNING, M_GetText("Skin '%s' not found.\n"), skinname); - else if(server || IsPlayerAdmin(consoleplayer)) - CONS_Alert(CONS_WARNING, M_GetText("Player %d (%s) skin '%s' not found\n"), playernum, player_names[playernum], skinname); - - SetPlayerSkinByNum(playernum, 0); - return false; -} - -void SetLocalPlayerSkin(INT32 playernum, const char *skinname, consvar_t *cvar) -{ - INT32 i; - player_t *player = &players[playernum]; - - if (stricmp(skinname, "none")) - { - for (i = 0; i < numlocalskins; i++) - { - // search in the localskin list - if (stricmp(localskins[i].name, skinname) == 0) - { - player->localskin = 1 + i; - player->skinlocal = true; - if (player->mo) - { - player->mo->localskin = &localskins[i]; - player->mo->skinlocal = true; - } - - goto setcvar; - } - } - - for (i = 0; i < numskins; i++) - { - // search in the skin list - if (stricmp(skins[i].name, skinname) == 0) - { - player->localskin = 1 + i; - player->skinlocal = false; - if (player->mo) - { - player->mo->localskin = &skins[i]; - player->mo->skinlocal = false; - } - - goto setcvar; - } - } - } - else - { - player->localskin = 0; - player->skinlocal = false; - if (player->mo) - { - player->mo->localskin = 0; - player->mo->skinlocal = false; - } - } - -setcvar: - if (cvar != NULL) - { - if (player->localskin > 0) - { - CV_StealthSet(&cv_fakelocalskin, K_GetSkinArray(player->skinlocal)[player->localskin-1].name); - CV_StealthSet(cvar, K_GetSkinArray(player->skinlocal)[player->localskin-1].name); - - } - else - { - CV_StealthSet(&cv_fakelocalskin, "none"); - CV_StealthSet(cvar, "none"); - } - } -} - -// Same as SetPlayerSkin, but uses the skin #. -// network code calls this when a 'skin change' is received -void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum) -{ - player_t *player = &players[playernum]; - skin_t *skin = &skins[skinnum]; - - if (skinnum >= 0 && skinnum < numskins) // Make sure it exists! - { - player->skin = skinnum; - if (player->mo) - player->mo->skin = skin; - - player->charflags = (UINT32)skin->flags; - - // SRB2kart - player->kartspeed = skin->kartspeed; - player->kartweight = skin->kartweight; - - if (player->mo) - P_SetScale(player->mo, player->mo->scale); - - demo_extradata[playernum] |= DXD_SKIN; - - return; - } - - if (P_IsLocalPlayer(player)) - CONS_Alert(CONS_WARNING, M_GetText("Skin %d not found\n"), skinnum); - else if(server || IsPlayerAdmin(consoleplayer)) - CONS_Alert(CONS_WARNING, "Player %d (%s) skin %d not found\n", playernum, player_names[playernum], skinnum); - - SetPlayerSkinByNum(playernum, 0); // not found put the sonic skin -} - -// -// Add skins from a pwad, each skin preceded by 'S_SKIN' marker -// - -// Does the same is in w_wad, but check only for -// the first 6 characters (this is so we can have S_SKIN1, S_SKIN2.. -// for wad editors that don't like multiple resources of the same name) -// -static UINT16 W_CheckForSkinMarkerInPwad(UINT16 wadid, UINT16 startlump) -{ - UINT16 i; - const char *S_SKIN = "S_SKIN"; - lumpinfo_t *lump_p; - - // scan forward, start at - if (startlump < wadfiles[wadid]->numlumps) - { - lump_p = wadfiles[wadid]->lumpinfo + startlump; - for (i = startlump; i < wadfiles[wadid]->numlumps; i++, lump_p++) - if (memcmp(lump_p->name,S_SKIN,6)==0) - return i; - } - return INT16_MAX; // not found -} - -//sort function for sorting skin names -static int skinSortFunc(const void *a, const void *b) //tbh i have no clue what the naming conventions for local functions are -{ - const skin_t *in1 = &skins[*(const UINT8 *)a]; - const skin_t *in2 = &skins[*(const UINT8 *)b]; - INT32 temp = 0; - const UINT8 val_a = *((const UINT8 *)a); - const UINT8 val_b = *((const UINT8 *)b); - - //return (strcmp(in1->realname, in2->realname) < 0) || (strcmp(in1->realname, in2->realname) ==); - - switch (cv_skinselectgridsort.value) - { - case SKINMENUSORT_REALNAME: - //CONS_Printf("Sorting by realname\n"); - // check name - if ((temp = strcmp(in1->realname, in2->realname))) - return temp; - // sort by internal name - return strcmp(in1->name, in2->name); - break; - - case SKINMENUSORT_NAME: - //CONS_Printf("Sorting by name\n"); - return strcmp(in1->name, in2->name); - break; - - case SKINMENUSORT_SPEED: - //CONS_Printf("Sorting by speed\n"); - // check speed - if (in1->kartspeed < in2->kartspeed) - return -1; - else if (in2->kartspeed < in1->kartspeed) - return 1; - // then check weight - if (in1->kartweight < in2->kartweight) - return -1; - else if (in2->kartweight < in1->kartweight) - return 1; - // then check name - if ((temp = strcmp(in1->realname, in2->realname))) - return temp; - // sort by internal name - return strcmp(in1->name, in2->name); - break; - - case SKINMENUSORT_WEIGHT: - //CONS_Printf("Sorting by weight\n"); - // check weight - if (in1->kartweight < in2->kartweight) - return -1; - else if (in2->kartweight < in1->kartweight) - return 1; - // then check speed - if (in1->kartspeed < in2->kartspeed) - return -1; - else if (in2->kartspeed < in1->kartspeed) - return 1; - // then check name - if ((temp = strcmp(in1->realname, in2->realname))) - return temp; - // sort by internal name - return strcmp(in1->name, in2->name); - break; - - case SKINMENUSORT_PREFCOLOR: - //CONS_Printf("Sorting by prefcolor\n"); - // check prefcolor - if (in1->prefcolor < in2->prefcolor) - return -1; - else if (in2->prefcolor < in1->prefcolor) - return 1; - // then check name - if ((temp = strcmp(in1->realname, in2->realname))) - return temp; - // sort by internal name - return strcmp(in1->name, in2->name); - break; - - case SKINMENUSORT_ID: - //CONS_Printf("Sorting by id\n"); - //how do i do by ID????? - //wait why dont i just convert the inputs to UINT32s - //please tell me im allowed to define variables in here since its a block - - if (val_a == val_b) - return 0; - else if (val_a < val_b) - return -1; - else - return 1; - - default: - return strcmp(in1->name, in2->name); - break; - } - //im scared this somehow will sometimes end up here so im gonna add this here just to be safe - return strcmp(in1->name, in2->name); -} - -void sortSkinGrid(void) -{ - //CONS_Printf("Sorting skin list (%d)...\n", cv_skinselectgridsort.value); - qs22j(skinsorted, numskins, sizeof(UINT8), skinSortFunc); -} - -// -// Find skin sprites, sounds & optional status bar face, & add them -// -void R_AddSkins(UINT16 wadnum, boolean local) -{ - UINT16 lump, lastlump = 0; - char *buf; - char *buf2; - char *stoken; - char *value; - size_t size; - skin_t *skin; - boolean hudname, realname; - -#define lnumskins (local ? numlocalskins : numskins) - - // - // search for all skin markers in pwad - // - - while ((lump = W_CheckForSkinMarkerInPwad(wadnum, lastlump)) != INT16_MAX) - { - // advance by default - lastlump = lump + 1; - - if (!local && numskins >= MAXSKINS) - { - CONS_Alert(CONS_WARNING, M_GetText("Unable to add skin, too many characters are loaded (%d maximum)\n"), MAXSKINS); - continue; // so we know how many skins couldn't be added - } - if (local && numlocalskins >= MAXLOCALSKINS) - { - CONS_Alert(CONS_WARNING, M_GetText("Unable to add localskin, too many localskins are loaded (%d maximum)\n"), MAXLOCALSKINS); - continue; // so we know how many skins couldn't be added - } - - buf = W_CacheLumpNumPwad(wadnum, lump, PU_CACHE); - size = W_LumpLengthPwad(wadnum, lump); - - // for strtok - buf2 = malloc(size+1); - if (!buf2) - I_Error("R_AddSkins: No more free memory\n"); - M_Memcpy(buf2,buf,size); - buf2[size] = '\0'; - - // set defaults - skin = &K_GetSkinArray(local)[lnumskins]; - Sk_SetDefaultValue(skin, local); - skin->wadnum = wadnum; - hudname = realname = false; - // parse - stoken = strtok (buf2, "\r\n= "); - while (stoken) - { - if ((stoken[0] == '/' && stoken[1] == '/') - || (stoken[0] == '#'))// skip comments - { - stoken = strtok(NULL, "\r\n"); // skip end of line - goto next_token; // find the real next token - } - - value = strtok(NULL, "\r\n= "); - - if (!value) - I_Error("R_AddSkins: syntax error in S_SKIN lump# %d(%s) in WAD %s\n", lump, W_CheckNameForNumPwad(wadnum,lump), wadfiles[wadnum]->filename); - - if (!stricmp(stoken, "name")) - { - // the skin name must uniquely identify a single skin - // I'm lazy so if name is already used I leave the 'skin x' - // default skin name set in Sk_SetDefaultValue - if (R_LocalSkinAvailable(value, local) == -1) - { - STRBUFCPY(skin->name, value); - strlwr(skin->name); - } - // I'm not lazy, so if the name is already used I make the name 'namex' - // using the default skin name's number set above - else - { - const size_t stringspace = - strlen(value) + sizeof lnumskins + 1; - char *value2 = Z_Malloc(stringspace, PU_STATIC, NULL); - snprintf(value2, stringspace, - "%s%d", value, lnumskins); - value2[stringspace - 1] = '\0'; - if (R_LocalSkinAvailable(value2, local) == -1) - { - STRBUFCPY(skin->name, - value2); - strlwr(skin->name); - } - Z_Free(value2); - } - - // copy to hudname and fullname as a default. - if (!realname) - { - STRBUFCPY(skin->realname, skin->name); - for (value = skin->realname; *value; value++) - if (*value == '_') *value = ' '; // turn _ into spaces. - } - if (!hudname) - { - STRBUFCPY(skin->hudname, skin->name); - strupr(skin->hudname); - for (value = skin->hudname; *value; value++) - if (*value == '_') *value = ' '; // turn _ into spaces. - } - } - else if (!stricmp(stoken, "realname")) - { // Display name (eg. "Knuckles") - realname = true; - STRBUFCPY(skin->realname, value); - for (value = skin->realname; *value; value++) - if (*value == '_') *value = ' '; // turn _ into spaces. - if (!hudname) - STRBUFCPY(skin->hudname, skin->realname); - } - else if (!stricmp(stoken, "hudname")) - { // Life icon name (eg. "K.T.E") - hudname = true; - STRBUFCPY(skin->hudname, value); - for (value = skin->hudname; *value; value++) - if (*value == '_') *value = ' '; // turn _ into spaces. - if (!realname) - STRBUFCPY(skin->realname, skin->hudname); - } - - else if (!stricmp(stoken, "sprite")) - { - strupr(value); - memcpy(skin->sprite, value, sizeof skin->sprite); - } - else if (!stricmp(stoken, "facerank")) - { - strupr(value); - memcpy(skin->facerank, value, sizeof(skin->facerank)-1); - skin->facerank[sizeof(skin->facerank)-1] = '\0'; - } - else if (!stricmp(stoken, "facewant")) - { - strupr(value); - memcpy(skin->facewant, value, sizeof(skin->facewant)-1); - skin->facewant[sizeof(skin->facewant)-1] = '\0'; - } - else if (!stricmp(stoken, "facemmap")) - { - strupr(value); - strncpy(skin->facemmap, value, sizeof(skin->facemmap)-1); - skin->facemmap[sizeof(skin->facemmap)-1] = '\0'; - } - -#define FULLPROCESS(field) else if (!stricmp(stoken, #field)) skin->field = get_number(value); - // character type identification - FULLPROCESS(flags) -#undef FULLPROCESS - -#define GETKARTSTAT(field) \ - else if (!stricmp(stoken, #field)) \ - { \ - skin->field = atoi(value); \ - if (skin->field < 1) skin->field = 1; \ - if (skin->field > 9) skin->field = 9; \ - } - GETKARTSTAT(kartspeed) - GETKARTSTAT(kartweight) -#undef GETKARTSTAT - - // custom translation table - else if (!stricmp(stoken, "startcolor")) - skin->starttranscolor = atoi(value); - - else if (!stricmp(stoken, "prefcolor")) - skin->prefcolor = K_GetKartColorByName(value); - else if (!stricmp(stoken, "highresscale")) - skin->highresscale = FLOAT_TO_FIXED(atof(value)); - else - { - INT32 found = false; - sfxenum_t i; - // copy name of sounds that are remapped - // for this skin - for (i = 0; i < sfx_skinsoundslot0; i++) - { - if (!S_sfx[i].name) - continue; - if (S_sfx[i].skinsound != -1 - && !stricmp(S_sfx[i].name, - stoken + 2)) - { - skin->soundsid[S_sfx[i].skinsound] = - S_AddSoundFx(value+2, S_sfx[i].singularity, S_sfx[i].pitch, true); - found = true; - } - } - if (!found) - CONS_Debug(DBG_SETUP, "R_AddSkins: Unknown keyword '%s' in S_SKIN lump# %d (WAD %s)\n", stoken, lump, wadfiles[wadnum]->filename); - } -next_token: - stoken = strtok(NULL, "\r\n= "); - } - free(buf2); - - lump++; // if no sprite defined use spirte just after this one - if (skin->sprite[0] == '\0') - { - const char *csprname = W_CheckNameForNumPwad(wadnum, lump); - - // skip to end of this skin's frames - lastlump = lump; - while (W_CheckNameForNumPwad(wadnum,lastlump) && memcmp(W_CheckNameForNumPwad(wadnum, lastlump),csprname,4)==0) - lastlump++; - // allocate (or replace) sprite frames, and set spritedef - R_AddSingleSpriteDef(csprname, &skin->spritedef, wadnum, lump, lastlump); - } - else - { - // search in the normal sprite tables - size_t name; - boolean found = false; - const char *sprname = skin->sprite; - for (name = 0;sprnames[name][0] != '\0';name++) - if (strncmp(sprnames[name], sprname, 4) == 0) - { - found = true; - skin->spritedef = sprites[name]; - } - - // not found so make a new one - // go through the entire current wad looking for our sprite - // don't just mass add anything beginning with our four letters. - // "HOODFACE" is not a sprite name. - if (!found) - { - UINT16 localllump = 0, lstart = UINT16_MAX, lend = UINT16_MAX; - const char *lname; - - while ((lname = W_CheckNameForNumPwad(wadnum,localllump))) - { - // If this is a valid sprite... - if (!memcmp(lname,sprname,4) && lname[4] && lname[5] && lname[5] >= '0' && lname[5] <= '8') - { - if (lstart == UINT16_MAX) - lstart = localllump; - // If already set do nothing - } - else - { - if (lstart != UINT16_MAX) - { - lend = localllump; - break; - } - // If not already set do nothing - } - ++localllump; - } - - R_AddSingleSpriteDef(sprname, &skin->spritedef, wadnum, lstart, lend); - } - - // I don't particularly care about skipping to the end of the used frames. - // We could be using frames from ANYWHERE in the current WAD file, including - // right before us, which is a terrible idea. - // So just let the function in the while loop take care of it for us. - } - - R_FlushTranslationColormapCache(); - - CONS_Printf(M_GetText("Added skin '%s'\n"), skin->name); -#ifdef SKINVALUES - (local ? localskin_cons_t : skin_cons_t)[lnumskins].value = lnumskins; - (local ? localskin_cons_t : skin_cons_t)[lnumskins].strvalue = skin->name; -#endif - - if (!local) - { - // Update the forceskin possiblevalues - Forceskin_cons_t[numskins+1].value = numskins; - Forceskin_cons_t[numskins+1].strvalue = skins[numskins].name; - skin->localskin = false; - skin->localnum = numskins; - ST_LoadFaceGraphics(skin->facerank, skin->facewant, skin->facemmap, numskins); - } - else - { - skin->localskin = true; - skin->localnum = numlocalskins; - ST_LoadLocalFaceGraphics(skin->facerank, skin->facewant, skin->facemmap, numlocalskins); - } - -#ifdef HWRENDER - if (rendermode == render_opengl) - HWR_AddPlayerMD2(lnumskins, local); -#endif - if (!local) - { - skinstats[skin->kartspeed-1][skin->kartweight-1][skinstatscount[skin->kartspeed-1][skin->kartweight-1]] = numskins; - CONS_Debug(DBG_SETUP, M_GetText("Added %d to %d, %d\n"), numskins, skin->kartweight, skin->kartweight); - skinstatscount[skin->kartspeed-1][skin->kartweight-1]++; - CONS_Debug(DBG_SETUP, M_GetText("Incremented %d, %d to %d\n"), skin->kartspeed, skin->kartweight, skinstatscount[skin->kartspeed - 1][skin->kartweight - 1]); - skinsorted[numskins] = numskins; - } - - allskins[numallskins] = K_GetSkinArray(local)[lnumskins]; - - local ? numlocalskins++ : numskins++; - numallskins++; - } - -#undef lnumskins - //sortSkinGrid(); - return; + free(heads); } diff --git a/src/r_things.h b/src/r_things.h index fe4f532b6..45f1fc30e 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -1,4 +1,4 @@ -// SONIC ROBO BLAST 2 +// SONIC ROBO BLAST 2 KART //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. @@ -14,13 +14,12 @@ #ifndef __R_THINGS__ #define __R_THINGS__ -#include "sounds.h" -#include "r_plane.h" -#include "r_patch.h" +#ifdef __cplusplus +extern "C" { +#endif -// "Left" and "Right" character symbols for additional rotation functionality -#define ROT_L ('L' - '0') -#define ROT_R ('R' - '0') +#include "r_plane.h" +#include "r_portal.h" // number of sprite lumps for spritewidth,offset,topoffset lookup tables // Fab: this is a hack : should allocate the lookup tables per sprite @@ -44,8 +43,8 @@ // Constant arrays used for psprite clipping // and initializing clipping. -extern INT16 negonearray[MAXVIDWIDTH]; -extern INT16 screenheightarray[MAXVIDWIDTH]; +extern INT16 *negonearray; +extern INT16 *screenheightarray; // vars for R_DrawMaskedColumn extern INT16 *mfloorclip; @@ -62,76 +61,33 @@ fixed_t R_GetSpriteDirectionalLighting(angle_t angle); fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope); -void R_DrawMaskedColumn(column_t *column); -void R_SortVisSprites(void); - -//faB: find sprites in wadfile, replace existing, add new ones -// (only sprites from namelist are added or replaced) -void R_AddSpriteDefs(UINT16 wadnum); - //SoM: 6/5/2000: Light sprites correctly! +boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 wadnum, UINT16 startlump, UINT16 endlump); void R_AddSprites(sector_t *sec, INT32 lightlevel); void R_AddPrecipitationSprites(void); void R_InitSprites(void); void R_ClearSprites(void); -void R_DrawMasked(void); - -boolean R_ThingVisible (mobj_t *thing); -boolean R_ThingWithinDist (mobj_t *thing, INT32 limit_dist); - -boolean R_ThingIsFullBright (mobj_t *thing); -boolean R_ThingIsSemiBright (mobj_t *thing); -boolean R_ThingIsFullDark (mobj_t *thing); - -// ----------- -// SKINS STUFF -// ----------- -#define SKINNAMESIZE 16 -// should be all lowercase!! S_SKIN processing does a strlwr -#define DEFAULTSKIN "sonic" -#define DEFAULTSKIN2 "tails" // secondary player -#define DEFAULTSKIN3 "knuckles" // third player -#define DEFAULTSKIN4 "eggman" // fourth player +/** Used to count the amount of masked elements + * per portal to later group them in separate + * drawnode lists. + */ typedef struct { - char name[SKINNAMESIZE+1]; // INT16 descriptive name of the skin - spritedef_t spritedef; - spriteinfo_t sprinfo; - UINT16 wadnum; - char sprite[4]; // Sprite name, if seperated from S_SKIN. - skinflags_t flags; + size_t drawsegs[2]; + size_t vissprites[2]; + fixed_t viewx, viewy, viewz; /**< View z stored at the time of the BSP traversal for the view/portal. Masked sorting/drawing needs it. */ + sector_t* viewsector; +} maskcount_t; - char realname[SKINNAMESIZE+1]; // Display name for level completion. - char hudname[SKINNAMESIZE+1]; // HUD name to display (officially exactly 5 characters long) - char facerank[9], facewant[9], facemmap[9]; // Arbitrarily named patch lumps +void R_DrawMasked(maskcount_t* masks, INT32 nummasks); - // SRB2kart - UINT8 kartspeed; - UINT8 kartweight; - // +boolean R_ThingVisible(mobj_t *thing); +boolean R_ThingWithinDist(mobj_t *thing, INT32 limit_dist); - // Definable color translation table - UINT8 starttranscolor; - UINT8 prefcolor; - fixed_t highresscale; // scale of highres, default is 0.5 - - // specific sounds per skin - sfxenum_t soundsid[NUMSKINSOUNDS]; // sound # in S_sfx table - - boolean localskin; - INT32 localnum; -} skin_t; - -extern CV_PossibleValue_t Forceskin_cons_t[]; - -// had to move those here Zzz... -INT32 K_GetSkinNum(player_t *player); -INT32 K_GetMobjSkinNum(const skin_t *skin, boolean local); -skin_t *K_GetPlayerSkin(player_t *player); -skin_t *K_GetMobjSkin(const mobj_t *mobj); -patch_t *K_GetFacePrefix(player_t *player, INT32 skinnum); -skin_t *K_GetSkinArray(boolean local); +boolean R_ThingIsFullBright(mobj_t *thing); +boolean R_ThingIsSemiBright(mobj_t *thing); +boolean R_ThingIsFullDark(mobj_t *thing); // ----------- // NOT SKINS STUFF ! @@ -201,7 +157,7 @@ typedef struct vissprite_s fixed_t spritexscale, spriteyscale; fixed_t spritexoffset, spriteyoffset; - INT16 clipbot[MAXVIDWIDTH], cliptop[MAXVIDWIDTH]; + INT16 *clipbot, *cliptop; boolean precip; boolean vflip; // Flip vertically @@ -211,10 +167,14 @@ typedef struct vissprite_s extern UINT32 visspritecount, numvisiblesprites; -void R_ClipSprites(void); +void R_ClipSprites(drawseg_t* dsstart, portal_t* portal); + +void R_AllocVisSpriteMemory(void); UINT8 *R_GetSpriteTranslation(vissprite_t *vis); +void R_InitDrawNodes(void); + // ---------- // DRAW NODES // ---------- @@ -233,69 +193,8 @@ typedef struct drawnode_s struct drawnode_s *prev; } drawnode_t; -extern INT32 numskins; -extern INT32 numlocalskins; -extern INT32 numallskins; -extern skin_t skins[MAXSKINS]; -extern UINT8 skinstats[9][9][MAXSKINS]; -extern UINT8 skinstatscount[9][9]; -extern UINT8 skinsorted[MAXSKINS]; - -void sortSkinGrid(void); -extern skin_t localskins[MAXLOCALSKINS]; -extern skin_t allskins[MAXSKINS+MAXLOCALSKINS]; - -boolean SetPlayerSkin(INT32 playernum,const char *skinname); -void SetPlayerSkinByNum(INT32 playernum,INT32 skinnum); // Tails 03-16-2002 -void SetLocalPlayerSkin(INT32 playernum,const char *skinname, consvar_t *cvar); -INT32 R_SkinAvailable(const char *name); -INT32 R_AnySkinAvailable(const char *name); -INT32 R_LocalSkinAvailable(const char *name, boolean local); -void R_AddSkins(UINT16 wadnum, boolean local); - -void R_InitDrawNodes(void); - -char *GetPlayerFacePic(INT32 skinnum); - -// Functions to go from sprite character ID to frame number -// for 2.1 compatibility this still uses the old 'A' + frame code -// The use of symbols tends to be painful for wad editors though -// So the future version of this tries to avoid using symbols -// as much as possible while also defining all 64 slots in a sane manner -// 2.1: [[ ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ]] -// Future: [[ ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz!@ ]] -FUNCMATH FUNCINLINE static ATTRINLINE char R_Frame2Char(UINT8 frame) -{ -#if 1 // 2.1 compat - return 'A' + frame; -#else - if (frame < 26) return 'A' + frame; - if (frame < 36) return '0' + (frame - 26); - if (frame < 62) return 'a' + (frame - 36); - if (frame == 62) return '!'; - if (frame == 63) return '@'; - return '\xFF'; +#ifdef __cplusplus +} // extern "C" #endif -} - -FUNCMATH FUNCINLINE static ATTRINLINE UINT8 R_Char2Frame(char cn) -{ -#if 1 // 2.1 compat - if (cn == '+') return '\\' - 'A'; // PK3 can't use backslash, so use + instead - return cn - 'A'; -#else - if (cn >= 'A' && cn <= 'Z') return cn - 'A'; - if (cn >= '0' && cn <= '9') return (cn - '0') + 26; - if (cn >= 'a' && cn <= 'z') return (cn - 'a') + 36; - if (cn == '!') return 62; - if (cn == '@') return 63; - return 255; -#endif -} - -FUNCMATH FUNCINLINE static ATTRINLINE boolean R_ValidSpriteAngle(UINT8 rotation) -{ - return ((rotation <= 8) || (rotation == ROT_L) || (rotation == ROT_R)); -} #endif //__R_THINGS__ diff --git a/src/screen.c b/src/screen.c index e41b5360f..67ef0f1dd 100644 --- a/src/screen.c +++ b/src/screen.c @@ -33,23 +33,6 @@ // SRB2Kart #include "r_fps.h" // R_GetFramerateCap -// -------------------------------------------- -// assembly or c drawer routines for 8bpp/16bpp -// -------------------------------------------- -void (*wallcolfunc)(void); // new wall column drawer to draw posts >128 high -void (*colfunc)(void); // standard column, up to 128 high posts - -void (*basecolfunc)(void); -void (*fuzzcolfunc)(void); // standard fuzzy effect column drawer -void (*transcolfunc)(void); // translation column drawer -void (*shadecolfunc)(void); // smokie test.. -void (*spanfunc)(void); // span drawer, use a 64x64 tile -void (*splatfunc)(void); // span drawer w/ transparency -void (*basespanfunc)(void); // default span func for color mode -void (*transtransfunc)(void); // translucent translated column drawer -void (*twosmultipatchfunc)(void); // for cols with transparent pixels -void (*twosmultipatchtransfunc)(void); // for cols with transparent pixels AND translucency - // ------------------ // global video state // ------------------ @@ -65,6 +48,8 @@ consvar_t cv_renderview = {"renderview", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, consvar_t cv_vhseffect = {"vhspause", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_shittyscreen = {"televisionsignal", "Okay", CV_NOSHOWHELP, shittyscreen_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_parallelsoftware = {"parallelsoftware", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; + static CV_PossibleValue_t votescale_cons_t[] = {{0, "Vanilla"}, {1, "Adaptive"}, {2, "VerticalFill"}, {3, "HorizontalFill"}, {0, NULL}}; consvar_t cv_votebgscaling = {"votebgscaling", "Adaptive", CV_SAVE, votescale_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -89,13 +74,41 @@ consvar_t cv_accuratefps = {"fpssampling", "1", CV_SAVE, accuratefps_cons_t, NUL // SCREEN VARIABLES // ========================================================================= -INT32 scr_bpp; // current video mode bytes per pixel UINT8 *scr_borderpatch; // flat used to fill the reduced view borders set at ST_Init() // ========================================================================= -// Short and Tall sky drawer, for the current color mode -void (*walldrawerfunc)(void); +static void SCR_SetDrawFuncs(void) +{ + // + // setup the right draw routines + // + + spanfuncs[BASEDRAWFUNC] = R_DrawSpan; + spanfuncs[SPANDRAWFUNC_TRANS] = R_DrawTranslucentSpan; + spanfuncs[SPANDRAWFUNC_TILTED] = R_DrawSpan_Tilted; + spanfuncs[SPANDRAWFUNC_TILTEDTRANS] = R_DrawTranslucentSpan_Tilted; + spanfuncs[SPANDRAWFUNC_SPLAT] = R_DrawSplat; + spanfuncs[SPANDRAWFUNC_TRANSSPLAT] = R_DrawTranslucentSplat; + spanfuncs[SPANDRAWFUNC_TILTEDSPLAT] = R_DrawSplat_Tilted; + spanfuncs[SPANDRAWFUNC_TILTEDTRANSSPLAT] = R_DrawTranslucentSpan_Tilted; + spanfuncs[SPANDRAWFUNC_WATER] = R_DrawTranslucentWaterSpan; + spanfuncs[SPANDRAWFUNC_TILTEDWATER] = R_DrawTranslucentWaterSpan_Tilted; + spanfuncs[SPANDRAWFUNC_FOG] = R_DrawFogSpan; + spanfuncs[SPANDRAWFUNC_TILTEDFOG] = R_DrawFogSpan_Tilted; + + colfuncs[BASEDRAWFUNC] = R_DrawColumn; + colfuncs[COLDRAWFUNC_FUZZY] = R_DrawTranslucentColumn; + colfuncs[COLDRAWFUNC_TRANS] = R_DrawTranslatedColumn; + colfuncs[COLDRAWFUNC_SHADOWED] = R_DrawColumnShadowed; + colfuncs[COLDRAWFUNC_TRANSTRANS] = R_DrawTranslatedTranslucentColumn; + colfuncs[COLDRAWFUNC_TWOSMULTIPATCH] = R_Draw2sMultiPatchColumn; + colfuncs[COLDRAWFUNC_TWOSMULTIPATCHTRANS] = R_Draw2sMultiPatchTranslucentColumn; + colfuncs[COLDRAWFUNC_FOG] = R_DrawFogColumn; + + R_SetColumnFunc(BASEDRAWFUNC); + R_SetSpanFunc(BASEDRAWFUNC); +} void SCR_SetMode(void) { @@ -109,22 +122,47 @@ void SCR_SetMode(void) V_SetPalette(0); - spanfunc = basespanfunc = R_DrawSpan_8; - splatfunc = R_DrawSplat_8; - transcolfunc = R_DrawTranslatedColumn_8; - transtransfunc = R_DrawTranslatedTranslucentColumn_8; - - colfunc = basecolfunc = R_DrawColumn_8; - shadecolfunc = R_DrawShadeColumn_8; - fuzzcolfunc = R_DrawTranslucentColumn_8; - walldrawerfunc = R_DrawWallColumn_8; - twosmultipatchfunc = R_Draw2sMultiPatchColumn_8; - twosmultipatchtransfunc = R_Draw2sMultiPatchTranslucentColumn_8; + SCR_SetDrawFuncs(); // set the apprpriate drawer for the sky (tall or INT16) setmodeneeded = 0; } +void R_SetColumnFunc(size_t id) +{ + I_Assert(id < COLDRAWFUNC_MAX); + + colfunctype = id; + colfunc = colfuncs[id]; +} + +void R_SetSpanFunc(size_t id) +{ + I_Assert(id < SPANDRAWFUNC_MAX); + spanfunc = spanfuncs[id]; +} + +boolean R_CheckColumnFunc(size_t id) +{ + size_t i; + + if (colfunc == NULL) + { + // Shouldn't happen. + return false; + } + + for (i = 0; i < COLDRAWFUNC_MAX; i++) + { + if (colfunc == colfuncs[id]) + { + return true; + } + } + + return false; +} + // do some initial settings for the game loading screen // void SCR_Startup(void) @@ -148,19 +186,9 @@ void SCR_Startup(void) vid.meddupx = (UINT8)(vid.dupx >> 1) + 1; vid.meddupy = (UINT8)(vid.dupy >> 1) + 1; -#ifdef HWRENDER - vid.fmeddupx = vid.meddupx*FRACUNIT; - vid.fmeddupy = vid.meddupy*FRACUNIT; -#endif vid.smalldupx = (UINT8)(vid.dupx / 3) + 1; vid.smalldupy = (UINT8)(vid.dupy / 3) + 1; -#ifdef HWRENDER - vid.fsmalldupx = vid.smalldupx*FRACUNIT; - vid.fsmalldupy = vid.smalldupy*FRACUNIT; -#endif - - vid.baseratio = FRACUNIT; V_Init(); CV_RegisterVar(&cv_highreshudscale); @@ -205,9 +233,6 @@ void SCR_Recalc(void) if (dedicated) return; - // bytes per pixel quick access - scr_bpp = vid.bpp; - // scale 1,2,3 times in x and y the patches for the menus and overlays... // calculated once and for all, used by routines in v_video.c vid.dupx = vid.width / BASEVIDWIDTH; @@ -226,22 +251,11 @@ void SCR_Recalc(void) vid.fdupx = vid.fdupy = (vid.fdupx < vid.fdupy ? vid.fdupx : vid.fdupy); - //vid.baseratio = FixedDiv(vid.height << FRACBITS, BASEVIDHEIGHT << FRACBITS); - vid.baseratio = FRACUNIT; - vid.meddupx = (UINT8)(vid.dupx >> 1) + 1; vid.meddupy = (UINT8)(vid.dupy >> 1) + 1; -#ifdef HWRENDER - vid.fmeddupx = vid.meddupx*FRACUNIT; - vid.fmeddupy = vid.meddupy*FRACUNIT; -#endif vid.smalldupx = (UINT8)(vid.dupx / 3) + 1; vid.smalldupy = (UINT8)(vid.dupy / 3) + 1; -#ifdef HWRENDER - vid.fsmalldupx = vid.smalldupx*FRACUNIT; - vid.fsmalldupy = vid.smalldupy*FRACUNIT; -#endif // toggle off (then back on) the automap because some screensize-dependent values will // be calculated next time the automap is activated. diff --git a/src/screen.h b/src/screen.h index 224897def..c0a2799c1 100644 --- a/src/screen.h +++ b/src/screen.h @@ -39,113 +39,56 @@ // we try to re-allocate a minimum of buffers for stability of the memory, // so all the small-enough tables based on screen size, are allocated once // and for all at the maximum size. -#define MAXVIDWIDTH 5120 // don't set this too high because actually -#define MAXVIDHEIGHT 2880 // lots of tables are allocated with the MAX size. +#define MAXVIDWIDTH 8192 // don't set this too high because actually +#define MAXVIDHEIGHT 8192 // lots of tables are allocated with the MAX size. #define BASEVIDWIDTH 320 // NEVER CHANGE THIS! This is the original #define BASEVIDHEIGHT 200 // resolution of the graphics. -// max res for png capture; just here to prevent some crashes on very high resolutions; tho you should never go this high cause ogl allocs certain things with MAXVIDWIDTH and MAXVIDHEIGHT too Zzz... -#define MAXPNGWIDTH 7680 -#define MAXPNGHEIGHT 4320 - // global video state typedef struct viddef_s { INT32 modenum; // vidmode num indexes videomodes list + // Each screen is [vid.width*vid.height]; + UINT8 *screens[5]; + // screens[0] = main display window + // screens[1] = back screen, alternative blitting + // screens[2] = screenshot buffer, gif movie buffer + // screens[3] = fade screen start + // screens[4] = fade screen end, postimage tempoarary buffer + UINT8 *buffer; // invisible screens buffer size_t rowbytes; // bytes per scanline of the VIDEO mode INT32 width; // PIXELS per scanline INT32 height; - union { // don't need numpages for OpenGL, so we can use it for fullscreen/windowed mode - INT32 numpages; // always 1, page flipping todo - INT32 windowed; // windowed or fullscren mode? - } u; - INT32 recalc; // if true, recalc vid-based stuff - UINT8 *direct; // linear frame buffer, or vga base mem. + boolean recalc; // if true, recalc vid-based stuff INT32 dupx, dupy; // scale 1, 2, 3 value for menus & overlays INT32/*fixed_t*/ fdupx, fdupy; // same as dupx, dupy, but exact value when aspect ratio isn't 320/200 - INT32 bpp; // BYTES per pixel: 1 = 256color, 2 = highcolor - INT32 baseratio; // Used to get the correct value for lighting walls - - // for Win32 version - DNWH WndParent; // handle of the application's window UINT8 smalldupx, smalldupy; // factor for a little bit of scaling UINT8 meddupx, meddupy; // factor for moderate, but not full, scaling #ifdef HWRENDER - INT32/*fixed_t*/ fsmalldupx, fsmalldupy; - INT32/*fixed_t*/ fmeddupx, fmeddupy; INT32 glstate; #endif } viddef_t; -#define VIDWIDTH vid.width -#define VIDHEIGHT vid.height enum { - VID_GL_LIBRARY_LOADED = 1, + VID_GL_LIBRARY_LOADED = 1, VID_GL_LIBRARY_ERROR = -1, }; -// internal additional info for vesa modes only -typedef struct -{ - INT32 vesamode; // vesa mode number plus LINEAR_MODE bit - void *plinearmem; // linear address of start of frame buffer -} vesa_extra_t; - -// a video modes from the video modes list, -// note: video mode 0 is always standard VGA320x200. -typedef struct vmode_s -{ - struct vmode_s *pnext; - char *name; - UINT32 width, height; - UINT32 rowbytes; // bytes per scanline - UINT32 bytesperpixel; // 1 for 256c, 2 for highcolor - INT32 windowed; // if true this is a windowed mode - INT32 numpages; - vesa_extra_t *pextradata; // vesa mode extra data -#ifdef _WIN32 - INT32 (WINAPI *setmode)(viddef_t *lvid, struct vmode_s *pcurrentmode); -#else - INT32 (*setmode)(viddef_t *lvid, struct vmode_s *pcurrentmode); -#endif - INT32 misc; // misc for display driver (r_opengl.dll etc) -} vmode_t; - -#define NUMSPECIALMODES 4 -extern vmode_t specialmodes[NUMSPECIALMODES]; - -// --------------------------------------------- -// color mode dependent drawer function pointers -// --------------------------------------------- - -extern void (*wallcolfunc)(void); -extern void (*colfunc)(void); -extern void (*basecolfunc)(void); -extern void (*fuzzcolfunc)(void); -extern void (*transcolfunc)(void); -extern void (*shadecolfunc)(void); -extern void (*spanfunc)(void); -extern void (*basespanfunc)(void); -extern void (*splatfunc)(void); -extern void (*transtransfunc)(void); -extern void (*twosmultipatchfunc)(void); -extern void (*twosmultipatchtransfunc)(void); - // ---------------- // screen variables // ---------------- extern viddef_t vid; extern INT32 setmodeneeded; // mode number to set if needed, or 0 -extern double averageFPS; -extern INT32 scr_bpp; extern UINT8 *scr_borderpatch; // patch used to fill the view borders extern consvar_t cv_scr_width, cv_scr_height, cv_renderview, cv_fullscreen, cv_vhseffect, cv_shittyscreen; +extern consvar_t cv_parallelsoftware; + extern consvar_t cv_highreshudscale; // wait for page flipping to end or not extern consvar_t cv_vidwait; @@ -155,8 +98,9 @@ extern consvar_t cv_alwaysgrabmouse; extern consvar_t cv_votebgscaling; -// quick fix for tall/short skies, depending on bytesperpixel -extern void (*walldrawerfunc)(void); +void R_SetColumnFunc(size_t id); +void R_SetSpanFunc(size_t id); +boolean R_CheckColumnFunc(size_t id); // Change video mode, only at the start of a refresh. void SCR_SetMode(void); diff --git a/src/sdl/endtxt.h b/src/sdl/endtxt.h index 41f8e51ad..5691312b4 100644 --- a/src/sdl/endtxt.h +++ b/src/sdl/endtxt.h @@ -19,6 +19,14 @@ #ifndef __ENDTXT__ #define __ENDTXT__ +#ifdef __cplusplus +extern "C" { +#endif + void ShowEndTxt (void); +#ifdef __cplusplus +} // extern "C" +#endif + #endif diff --git a/src/sdl/i_system.c b/src/sdl/i_system.cpp similarity index 95% rename from src/sdl/i_system.c rename to src/sdl/i_system.cpp index 5b3d85421..2d8ae4e70 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.cpp @@ -192,6 +192,8 @@ static char returnWadPath[256]; #include "../r_main.h" // Frame interpolation/uncapped #include "../r_fps.h" +#include "../s_sound.h" + #ifdef MAC_ALERT #include "macosx/mac_alert.h" #endif @@ -204,6 +206,11 @@ static char returnWadPath[256]; #include "../byteptr.h" #endif +#ifdef HAVE_THREADS +#include "../core/thread_pool.h" +static std::thread::id g_main_thread_id; +#endif + INT32 numcontrollers = 0; #ifdef HAVE_LIBBACKTRACE @@ -211,11 +218,13 @@ INT32 numcontrollers = 0; // TODO - move this to some header file instead extern struct backtrace_state *bt_state; +typedef enum { + BTCRASH_SIGNAL, + BTCRASH_ERRORMSG, +} bt_crash_type_t; + typedef struct bt_crash_reason_s { - enum { - BTCRASH_SIGNAL, - BTCRASH_ERRORMSG, - } type; + bt_crash_type_t type; union { INT32 signal; @@ -496,6 +505,16 @@ static void I_ReportSignal(int num, int coredumped) #ifndef NEWSIGNALHANDLER FUNCNORETURN static ATTRNORETURN void signal_handler(INT32 num) { +#ifdef HAVE_THREADS + if (g_main_thread_id != std::this_thread::get_id()) + { + // Do not attempt any sort of recovery if this signal triggers off the main thread + signal(num, SIG_DFL); + raise(num); + exit(-2); + } +#endif + g_in_exiting_signal_handler = true; D_QuitNetGame(); // Fix server freezes @@ -514,6 +533,16 @@ FUNCNORETURN static ATTRNORETURN void signal_handler(INT32 num) FUNCNORETURN static ATTRNORETURN void quit_handler(int num) { +#ifdef HAVE_THREADS + if (g_main_thread_id != std::this_thread::get_id()) + { + // Do not attempt any sort of recovery if this signal triggers off the main thread + signal(num, SIG_DFL); + raise(num); + exit(-2); + } +#endif + signal(num, SIG_DFL); //default signal action raise(num); I_Quit(); @@ -609,8 +638,8 @@ static void I_StartupConsole(void) signal(SIGTTIN, SIG_IGN); signal(SIGTTOU, SIG_IGN); - consolevent = !M_CheckParm("-noconsole"); - framebuffer = M_CheckParm("-framebuffer"); + consolevent = static_cast(!M_CheckParm("-noconsole")); + framebuffer = static_cast( M_CheckParm("-framebuffer")); if (framebuffer) consolevent = SDL_FALSE; @@ -650,8 +679,9 @@ static void I_StartupConsole(void) void I_GetConsoleEvents(void) { // we use this when sending back commands - event_t ev = {0,0,0,0}; + event_t ev = {}; char key = 0; + struct pollfd pfd = { .fd = STDIN_FILENO, @@ -857,6 +887,10 @@ static inline void I_ShutdownConsole(void){} // static void I_RegisterSignals (void) { +#ifdef HAVE_THREADS + g_main_thread_id = std::this_thread::get_id(); +#endif + #ifdef SIGINT signal(SIGINT , quit_handler); #endif @@ -914,7 +948,7 @@ void I_OutputMsg(const char *fmt, ...) if (len == 0) return; - txt = malloc(len+1); + txt = static_cast(malloc(len+1)); va_start(argptr,fmt); vsprintf(txt, fmt, argptr); va_end(argptr); @@ -981,7 +1015,7 @@ void I_OutputMsg(const char *fmt, ...) return; } - ReadConsoleOutputCharacter(co, oldLines, oldLength, coordNextWrite, &bytesWritten); + ReadConsoleOutputCharacter(co, (LPSTR)oldLines, oldLength, coordNextWrite, &bytesWritten); // Move to where we what to print - which is where we would've been, // had console input not been in the way, @@ -1204,7 +1238,7 @@ void I_ShutdownJoystick(UINT8 index) void I_GetJoystickEvents(UINT8 index) { - static event_t event = {0,0,0,0}; + static event_t event = {}; INT32 i = 0; UINT64 joyhats = 0; @@ -1527,7 +1561,7 @@ void I_SetGamepadIndicatorColor(INT32 playernum, UINT8 red, UINT8 green, UINT8 b #define DEG2RAD (0.017453292519943295769236907684883l) // TAU/360 or PI/180 #define MUMBLEUNIT (64.0f) // FRACUNITS in a Meter -static struct { +static struct mumble_s { #ifdef WINMUMBLE UINT32 uiVersion; DWORD uiTick; @@ -1557,10 +1591,12 @@ static void I_SetupMumble(void) { #ifdef WINMUMBLE HANDLE hMap = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE, L"MumbleLink"); + if (!hMap) return; - mumble = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(*mumble)); + mumble = static_cast(MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(*mumble))); + if (!mumble) CloseHandle(hMap); #elif defined (HAVE_SHM) @@ -1570,10 +1606,11 @@ static void I_SetupMumble(void) snprintf(memname, 256, "/MumbleLink.%d", getuid()); shmfd = shm_open(memname, O_RDWR, S_IRUSR | S_IWUSR); - if(shmfd < 0) + if (shmfd < 0) return; - mumble = mmap(NULL, sizeof(*mumble), PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0); + mumble = static_cast(mmap(NULL, sizeof(*mumble), PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0)); + if (mumble == MAP_FAILED) mumble = NULL; #endif @@ -1588,8 +1625,9 @@ void I_UpdateMumble(const mobj_t *mobj, const listener_t listener) if (!mumble) return; - if(mumble->uiVersion != 2) { - wcsncpy(mumble->name, L"SRB2Kart "VERSIONSTRINGW, 256); + if (mumble->uiVersion != 2) + { + wcsncpy(mumble->name, L"SRB2Kart " VERSIONSTRINGW, 256); wcsncpy(mumble->description, L"Sonic Robo Blast 2 Kart with integrated Mumble Link support.", 2048); mumble->uiVersion = 2; } @@ -1608,11 +1646,12 @@ void I_UpdateMumble(const mobj_t *mobj, const listener_t listener) { UINT8 *p = mumble->context; WRITEMEM(p, server_context, 8); - WRITEINT16(p, gamemap); + WRITEINT16_2(p, gamemap); mumble->context_len = (UINT32)(p - mumble->context); } - if (mobj) { + if (mobj) + { mumble->fAvatarPosition[0] = FIXED_TO_FLOAT(mobj->x) / MUMBLEUNIT; mumble->fAvatarPosition[1] = FIXED_TO_FLOAT(mobj->z) / MUMBLEUNIT; mumble->fAvatarPosition[2] = FIXED_TO_FLOAT(mobj->y) / MUMBLEUNIT; @@ -1767,8 +1806,8 @@ void I_SleepDuration(precise_t duration) #if defined(__linux__) || defined(__FreeBSD__) || defined(__HAIKU__) UINT64 precision = I_GetPrecisePrecision(); struct timespec ts = { - .tv_sec = duration / precision, - .tv_nsec = duration * 1000000000 / precision % 1000000000, + .tv_sec = static_cast<__time_t>(duration / precision), + .tv_nsec = static_cast<__syscall_slong_t>(duration * 1000000000 / precision % 1000000000), }; int status; do status = clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, &ts); @@ -1903,6 +1942,8 @@ INT32 I_StartupSystem(void) #ifdef HAVE_THREADS I_start_threads(); I_AddExitFunc(I_stop_threads); + I_ThreadPoolInit(); + I_AddExitFunc(I_ThreadPoolShutdown); #endif I_RegisterSignals(); I_OutputMsg("Compiled for SDL version: %d.%d.%d\n", @@ -1993,6 +2034,14 @@ void I_Error(const char *error, ...) va_list argptr; char buffer[8192]; +#ifdef HAVE_THREADS + if (std::this_thread::get_id() != g_main_thread_id) + { + // Do not attempt a graceful shutdown. Errors off the main thread are unresolvable. + exit(-2); + } +#endif + // recursive error detecting if (shutdowning) { @@ -2026,7 +2075,7 @@ void I_Error(const char *error, ...) // which should fail gracefully if it can't put a message box up // on the target system SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, - "SRB2Kart "VERSIONSTRING" Recursive Error", + "SRB2Kart " VERSIONSTRING " Recursive Error", buffer, NULL); W_Shutdown(); @@ -2075,7 +2124,7 @@ void I_Error(const char *error, ...) // which should fail gracefully if it can't put a message box up // on the target system SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, - "SRB2Kart "VERSIONSTRING" Error", + "SRB2Kart " VERSIONSTRING " Error", buffer, NULL); // Note that SDL_ShowSimpleMessageBox does *not* require SDL to be // initialized at the time, so calling it after SDL_Quit() is @@ -2113,7 +2162,6 @@ void I_AddExitFunc(void (*func)()) } } - // // Removes a function from the list that need to be called by // I_SystemShutdown(). @@ -2376,7 +2424,7 @@ const char *I_ClipboardPaste(void) */ static boolean isWadPathOk(const char *path) { - char *wad3path = malloc(256); + char *wad3path = static_cast(malloc(256)); if (!wad3path) return false; @@ -2502,43 +2550,43 @@ static const char *locateWad(void) // examine default dirs #ifdef DEFAULTWADLOCATION1 - I_OutputMsg(","DEFAULTWADLOCATION1); + I_OutputMsg("," DEFAULTWADLOCATION1); strcpy(returnWadPath, DEFAULTWADLOCATION1); if (isWadPathOk(returnWadPath)) return returnWadPath; #endif #ifdef DEFAULTWADLOCATION2 - I_OutputMsg(","DEFAULTWADLOCATION2); + I_OutputMsg("," DEFAULTWADLOCATION2); strcpy(returnWadPath, DEFAULTWADLOCATION2); if (isWadPathOk(returnWadPath)) return returnWadPath; #endif #ifdef DEFAULTWADLOCATION3 - I_OutputMsg(","DEFAULTWADLOCATION3); + I_OutputMsg("," DEFAULTWADLOCATION3); strcpy(returnWadPath, DEFAULTWADLOCATION3); if (isWadPathOk(returnWadPath)) return returnWadPath; #endif #ifdef DEFAULTWADLOCATION4 - I_OutputMsg(","DEFAULTWADLOCATION4); + I_OutputMsg("," DEFAULTWADLOCATION4); strcpy(returnWadPath, DEFAULTWADLOCATION4); if (isWadPathOk(returnWadPath)) return returnWadPath; #endif #ifdef DEFAULTWADLOCATION5 - I_OutputMsg(","DEFAULTWADLOCATION5); + I_OutputMsg("," DEFAULTWADLOCATION5); strcpy(returnWadPath, DEFAULTWADLOCATION5); if (isWadPathOk(returnWadPath)) return returnWadPath; #endif #ifdef DEFAULTWADLOCATION6 - I_OutputMsg(","DEFAULTWADLOCATION6); + I_OutputMsg("," DEFAULTWADLOCATION6); strcpy(returnWadPath, DEFAULTWADLOCATION6); if (isWadPathOk(returnWadPath)) return returnWadPath; #endif #ifdef DEFAULTWADLOCATION7 - I_OutputMsg(","DEFAULTWADLOCATION7); + I_OutputMsg("," DEFAULTWADLOCATION7); strcpy(returnWadPath, DEFAULTWADLOCATION7); if (isWadPathOk(returnWadPath)) return returnWadPath; @@ -2548,7 +2596,7 @@ static const char *locateWad(void) I_OutputMsg(",HOME/" DEFAULTDIR); if ((envstr = I_GetEnv("HOME")) != NULL) { - char *tmp = malloc(strlen(envstr) + sizeof(PATHSEP) + sizeof(DEFAULTDIR)); + char *tmp = static_cast(malloc(strlen(envstr) + sizeof(PATHSEP) + sizeof(DEFAULTDIR))); strcpy(tmp, envstr); strcat(tmp, PATHSEP); strcat(tmp, DEFAULTDIR); @@ -2560,21 +2608,21 @@ static const char *locateWad(void) #endif #ifdef DEFAULTSEARCHPATH1 // find in /usr/local - I_OutputMsg(", in:"DEFAULTSEARCHPATH1); + I_OutputMsg(", in:" DEFAULTSEARCHPATH1); WadPath = searchWad(DEFAULTSEARCHPATH1); if (WadPath) return WadPath; #endif #ifdef DEFAULTSEARCHPATH2 // find in /usr/games - I_OutputMsg(", in:"DEFAULTSEARCHPATH2); + I_OutputMsg(", in:" DEFAULTSEARCHPATH2); WadPath = searchWad(DEFAULTSEARCHPATH2); if (WadPath) return WadPath; #endif #ifdef DEFAULTSEARCHPATH3 // find in ??? - I_OutputMsg(", in:"DEFAULTSEARCHPATH3); + I_OutputMsg(", in:" DEFAULTSEARCHPATH3); WadPath = searchWad(DEFAULTSEARCHPATH3); if (WadPath) return WadPath; @@ -2618,17 +2666,22 @@ const char *I_LocateWad(void) static long get_entry(const char* name, const char* buf) { long val; - char* hit = strstr(buf, name); - if (hit == NULL) { + const char* hit = strstr(buf, name); + + if (hit == NULL) + { return -1; } errno = 0; val = strtol(hit + strlen(name), NULL, 10); - if (errno != 0) { + + if (errno != 0) + { CONS_Alert(CONS_ERROR, M_GetText("get_entry: strtol() failed: %s\n"), strerror(errno)); return -1; } + return val; } #endif diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index faf4c67f7..26a6d84db 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -1497,7 +1497,7 @@ void I_FinishUpdate(void) ST_AskToJoinEnvelope(); #endif - if (rendermode == render_soft && screens[0]) + if (rendermode == render_soft && vid.screens[0]) { if (!bufSurface) //Double-Check { @@ -1547,9 +1547,7 @@ void I_ReadScreen(UINT8 *scr) if (rendermode != render_soft) I_Error ("I_ReadScreen: called while in non-software mode"); else - VID_BlitLinearScreen(screens[0], scr, - vid.width*vid.bpp, vid.height, - vid.rowbytes, vid.rowbytes); + VID_BlitLinearScreen(vid.screens[0], scr, vid.width, vid.height, vid.rowbytes, vid.rowbytes); } // @@ -1753,8 +1751,7 @@ INT32 VID_SetMode(INT32 modeNum) { SDLdoUngrabMouse(); - vid.recalc = 1; - vid.bpp = 1; + vid.recalc = true; if (modeNum >= 0 && modeNum < MAXWINMODES) { @@ -1944,16 +1941,9 @@ static void Impl_VideoSetupSDLBuffer(void) bufSurface = NULL; } // Set up the SDL palletized buffer (copied to vidbuffer before being rendered to texture) - if (vid.bpp == 1) - { - bufSurface = SDL_CreateRGBSurfaceFrom(screens[0],vid.width,vid.height,8, - (int)vid.rowbytes,0x00000000,0x00000000,0x00000000,0x00000000); // 256 mode - } - else if (vid.bpp == 2) // Fury -- don't think this is used at all anymore - { - bufSurface = SDL_CreateRGBSurfaceFrom(screens[0],vid.width,vid.height,15, - (int)vid.rowbytes,0x00007C00,0x000003E0,0x0000001F,0x00000000); // 555 mode - } + bufSurface = SDL_CreateRGBSurfaceFrom(vid.screens[0], vid.width, vid.height, 8, + (int)vid.rowbytes, 0x00000000, 0x00000000, 0x00000000, 0x00000000); // 256 mode + if (bufSurface) { SDL_SetPaletteColors(bufSurface->format->palette, localPalette, 0, 256); @@ -1969,11 +1959,13 @@ static void Impl_VideoSetupBuffer(void) // Set up game's software render buffer //if (rendermode == render_soft) { - vid.rowbytes = vid.width * vid.bpp; - vid.direct = NULL; + vid.rowbytes = vid.width; + if (vid.buffer) free(vid.buffer); + vid.buffer = calloc(vid.rowbytes*vid.height, NUMSCREENS); + if (!vid.buffer) { I_Error("%s", M_GetText("Not enough memory for video buffer\n")); @@ -2184,9 +2176,6 @@ void I_StartupGraphics(void) vid.width = BASEVIDWIDTH; // Default size for startup vid.height = BASEVIDHEIGHT; // BitsPerPixel is the SDL interface's vid.recalc = true; // Set up the console stufff - vid.direct = NULL; // Maybe direct access? - vid.bpp = 1; // This is the game engine's Bpp - vid.WndParent = NULL; //For the window? #ifdef HAVE_TTF I_ShutdownTTF(); diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c index 9035e8241..9dbfdde15 100644 --- a/src/sdl/mixer_sound.c +++ b/src/sdl/mixer_sound.c @@ -276,7 +276,7 @@ void I_UpdateSound(void) // sorry. more asm needed. static Mix_Chunk *ds2chunk(void *stream) { - UINT16 ver,freq; + UINT16 ver, freq; UINT32 samples, i, newsamples; UINT8 *sound; diff --git a/src/sdl/sdlmain.h b/src/sdl/sdlmain.h index b0def402d..0c5bfaeff 100644 --- a/src/sdl/sdlmain.h +++ b/src/sdl/sdlmain.h @@ -19,6 +19,10 @@ #ifndef __sdlmain__ #define __sdlmain__ +#ifdef __cplusplus +extern "C" { +#endif + extern SDL_bool consolevent; extern SDL_bool framebuffer; @@ -84,4 +88,8 @@ void SDLforceUngrabMouse(void); // Needed for some WIN32 functions extern SDL_Window *window; +#ifdef __cplusplus +} // extern "C" +#endif + #endif diff --git a/src/st_stuff.c b/src/st_stuff.c index 4f5401aae..7e4dd8840 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -167,48 +167,50 @@ boolean ST_SameTeam(player_t *a, player_t *b) static boolean st_stopped = true; -void ST_Ticker(void) -{ - if (st_stopped) - return; -} - // 0 is default, any others are special palettes. INT32 st_palette = 0; -void ST_doPaletteStuff(void) +void ST_ResetPaletteStuff(void) { - INT32 palette; + st_palette = 0; + V_SetPalette(0); +} - if (stplyr && stplyr->flashcount) - palette = stplyr->flashpal; - else - palette = 0; +static void ST_doPaletteStuff(void) +{ + INT32 palette = 0; #ifdef HWRENDER if (rendermode == render_opengl && !HWR_PalRenderFlashpal()) - palette = 0; // Don't set the palette to a flashpal in OpenGL's truecolor mode + return; #endif - palette = min(max(palette, 0), 13); + if (stplyr && stplyr->flashcount) + palette = CLAMP(stplyr->flashpal, 0, 13); if (palette != st_palette) { st_palette = palette; -#ifdef HWRENDER - if (rendermode == render_soft || (rendermode == render_opengl && HWR_PalRenderFlashpal())) -#else - if (rendermode != render_none) -#endif + if (!splitscreen) { - //V_SetPaletteLump(GetPalette()); // Reset the palette -- is this needed? - if (!splitscreen) - V_SetPalette(palette); + V_SetPalette(palette); } } } +void ST_Ticker(void) +{ + if (st_stopped) + return; + + // Do red-/gold-shifts from damage/items + //25/08/99: Hurdler: palette changes is done for all players, + // not only player1! That's why this part + // of code is moved somewhere else. + ST_doPaletteStuff(); +} + void ST_UnloadGraphics(void) { Patch_FreeTag(PU_HUDGFX); @@ -306,9 +308,7 @@ static inline void ST_Stop(void) void ST_Start(void) { - if (!st_stopped) - ST_Stop(); - + ST_Stop(); ST_InitData(); if (!dedicated) @@ -757,15 +757,6 @@ void ST_Drawer(void) if (vid.recalc) st_palette = -1; - // Do red-/gold-shifts from damage/items -#ifdef HWRENDER - //25/08/99: Hurdler: palette changes is done for all players, - // not only player1! That's why this part - // of code is moved somewhere else. - if (rendermode == render_soft || (rendermode == render_opengl && HWR_PalRenderFlashpal())) -#endif - if (rendermode != render_none) ST_doPaletteStuff(); - if (st_overlay) { if (renderisnewtic) diff --git a/src/st_stuff.h b/src/st_stuff.h index 54d2483ee..d0ed92b1a 100644 --- a/src/st_stuff.h +++ b/src/st_stuff.h @@ -28,6 +28,8 @@ extern tic_t directortoggletimer; // Called by main loop. void ST_Ticker(void); +void ST_ResetPaletteStuff(void); + // Called when naming a replay. void ST_DrawDemoTitleEntry(void); @@ -56,8 +58,6 @@ void ST_LoadFaceGraphics(char *rankstr, char *wantstr, char *mmapstr, INT32 play void ST_LoadLocalFaceGraphics(char *rankstr, char *wantstr, char *mmapstr, INT32 playernum); void ST_ReloadSkinFaceGraphics(void); -void ST_doPaletteStuff(void); - // return if player a is in the same team as player b boolean ST_SameTeam(player_t *a, player_t *b); diff --git a/src/tables.h b/src/tables.h index 4856c90ea..2f492bebb 100644 --- a/src/tables.h +++ b/src/tables.h @@ -14,6 +14,10 @@ #ifndef __TABLES__ #define __TABLES__ +#ifdef __cplusplus +extern "C" { +#endif + #ifdef LINUX #include #endif @@ -134,4 +138,8 @@ void FM_Rotate(matrix_t *dest, angle_t angle, fixed_t x, fixed_t y, fixed_t z); #define FSIN(n) FINESINE(ANGLETOFINE(n)) #define FCOS(n) FINECOSINE(ANGLETOFINE(n)) +#ifdef __cplusplus +} // extern "C" +#endif + #endif diff --git a/src/v_video.c b/src/v_video.c index 7df5cacea..247272dcb 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -35,14 +35,6 @@ #include "hardware/r_opengl/r_opengl.h" #endif -// Each screen is [vid.width*vid.height]; -UINT8 *screens[5]; -// screens[0] = main display window -// screens[1] = back screen, alternative blitting -// screens[2] = screenshot buffer, gif movie buffer -// screens[3] = fade screen start -// screens[4] = fade screen end, postimage tempoarary buffer - static CV_PossibleValue_t fps_cons_t[] = {{0, "No"}, {1, "Normal"}, {2, "Compact"}, {3, "Old"}, {4, "Old Compact"}, {0, NULL}}; consvar_t cv_ticrate = {"showfps", "No", CV_SAVE, fps_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -644,29 +636,17 @@ UINT8 hudtrans = 0; static const UINT8 *v_colormap = NULL; static const UINT8 *v_translevel = NULL; -FUNCINLINE static ATTRINLINE UINT8 standardpdraw(const UINT8 *dest, const UINT8 *source, fixed_t ofs) -{ - (void)dest; return source[ofs>>FRACBITS]; -} -FUNCINLINE static ATTRINLINE UINT8 mappedpdraw(const UINT8 *dest, const UINT8 *source, fixed_t ofs) -{ - (void)dest; return *(v_colormap + source[ofs>>FRACBITS]); -} -FUNCINLINE static ATTRINLINE UINT8 translucentpdraw(const UINT8 *dest, const UINT8 *source, fixed_t ofs) -{ - return *(v_translevel + ((source[ofs>>FRACBITS]<<8)&0xff00) + (*dest&0xff)); -} -FUNCINLINE static ATTRINLINE UINT8 transmappedpdraw(const UINT8 *dest, const UINT8 *source, fixed_t ofs) -{ - return *(v_translevel + (((*(v_colormap + source[ofs>>FRACBITS]))<<8)&0xff00) + (*dest&0xff)); -} +#define STANDARDDRAW 1 +#define MAPPEDDRAW 2 +#define TRANSLUCENTDRAW 3 +#define TRANSMAPPEDDRAW 4 // Draws a patch scaled to arbitrary size. void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 scrn, patch_t *patch, const UINT8 *colormap, INT32 bflags) { - UINT8 (*patchdrawfunc)(const UINT8*, const UINT8*, fixed_t); - UINT32 alphalevel = ((scrn & V_ALPHAMASK) >> V_ALPHASHIFT); - UINT32 blendmode = ((bflags & V_BLENDMASK) >> V_BLENDSHIFT); + UINT8 patchdrawtype; + UINT32 alphalevel; + UINT32 blendmode; fixed_t col, ofs, colfrac, rowfrac, fdup, vdup; INT32 dupx, dupy; @@ -676,10 +656,7 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca fixed_t pwidth; // patch width fixed_t offx = 0; // x offset - if (rendermode == render_none) - return; - - if (!patch) + if (rendermode == render_none || !patch) return; #ifdef HWRENDER @@ -691,17 +668,26 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca } #endif - patchdrawfunc = standardpdraw; + alphalevel = ((scrn & V_ALPHAMASK) >> V_ALPHASHIFT); + blendmode = ((bflags & V_BLENDMASK) >> V_BLENDSHIFT); + + patchdrawtype = STANDARDDRAW; v_translevel = NULL; if (alphalevel || blendmode) { - if (alphalevel == 13) - alphalevel = hudminusalpha[hudtrans]; - else if (alphalevel == 14) - alphalevel = 10 - hudtrans; - else if (alphalevel == 15) - alphalevel = hudplusalpha[hudtrans]; + switch (alphalevel) + { + case 13: + alphalevel = hudminusalpha[hudtrans]; + break; + case 14: + alphalevel = (10 - hudtrans); + break; + case 15: + alphalevel = hudplusalpha[hudtrans]; + break; + } if (alphalevel >= 10) return; // invis @@ -709,7 +695,7 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca if (alphalevel || blendmode) { v_translevel = R_GetBlendTable(blendmode+1, alphalevel); - patchdrawfunc = translucentpdraw; + patchdrawtype = TRANSLUCENTDRAW; } } @@ -718,7 +704,7 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca if (colormap) { v_colormap = colormap; - patchdrawfunc = (v_translevel) ? transmappedpdraw : mappedpdraw; + patchdrawtype = (v_translevel) ? TRANSMAPPEDDRAW : MAPPEDDRAW; } dupx = vid.dupx; @@ -786,7 +772,7 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca if (scrn & V_HORZSCREEN) x += (BASEVIDWIDTH/2)<>FRACBITS) < patch->width; col += colfrac, ++offx, desttop++) { INT32 topdelta, prevdelta = -1; @@ -866,37 +854,111 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca { if (x+pwidth-offx < 0) // don't draw off the left of the screen (WRAP PREVENTION) break; - if (x+pwidth-offx >= vid.width) // don't draw off the right of the screen (WRAP PREVENTION) + if (x+pwidth-offx >= stride) // don't draw off the right of the screen (WRAP PREVENTION) continue; } else { if (x+offx < 0) // don't draw off the left of the screen (WRAP PREVENTION) continue; - if (x+offx >= vid.width) // don't draw off the right of the screen (WRAP PREVENTION) + if (x+offx >= stride) // don't draw off the right of the screen (WRAP PREVENTION) break; } column = (const column_t *)((const UINT8 *)(patch->columns) + (patch->columnofs[col>>FRACBITS])); - while (column->topdelta != 0xff) + switch (patchdrawtype) { - topdelta = column->topdelta; - if (topdelta <= prevdelta) - topdelta += prevdelta; - prevdelta = topdelta; - source = (const UINT8 *)(column) + 3; - dest = desttop; - if (scrn & V_FLIP) - dest = deststart + (destend - desttop); - dest += FixedInt(FixedMul(topdelta<topdelta != 0xff) + { + topdelta = column->topdelta; + if (topdelta <= prevdelta) + topdelta += prevdelta; + prevdelta = topdelta; + source = (const UINT8 *)(column) + 3; + dest = desttop; + if (scrn & V_FLIP) + dest = deststart + (destend - desttop); + dest += FixedInt(FixedMul(topdelta<>FRACBITS) < column->length; ofs += rowfrac) - { - if (dest >= screens[scrn&V_PARAMMASK]) // don't draw off the top of the screen (CRASH PREVENTION) - *dest = patchdrawfunc(dest, source, ofs); - dest += vid.width; - } - column = (const column_t *)((const UINT8 *)column + column->length + 4); + for (ofs = 0; dest < deststop && (ofs>>FRACBITS) < column->length; ofs += rowfrac) + { + if (dest >= vid.screens[scrn&V_PARAMMASK]) // don't draw off the top of the screen (CRASH PREVENTION) + *dest = source[ofs>>FRACBITS]; + dest += stride; + } + column = (const column_t *)((const UINT8 *)column + column->length + 4); + } + break; + + case MAPPEDDRAW: + while (column->topdelta != 0xff) + { + topdelta = column->topdelta; + if (topdelta <= prevdelta) + topdelta += prevdelta; + prevdelta = topdelta; + source = (const UINT8 *)(column) + 3; + dest = desttop; + if (scrn & V_FLIP) + dest = deststart + (destend - desttop); + dest += FixedInt(FixedMul(topdelta<>FRACBITS) < column->length; ofs += rowfrac) + { + if (dest >= vid.screens[scrn&V_PARAMMASK]) // don't draw off the top of the screen (CRASH PREVENTION) + *dest = *(v_colormap + source[ofs>>FRACBITS]); + dest += stride; + } + column = (const column_t *)((const UINT8 *)column + column->length + 4); + } + break; + + case TRANSLUCENTDRAW: + while (column->topdelta != 0xff) + { + topdelta = column->topdelta; + if (topdelta <= prevdelta) + topdelta += prevdelta; + prevdelta = topdelta; + source = (const UINT8 *)(column) + 3; + dest = desttop; + if (scrn & V_FLIP) + dest = deststart + (destend - desttop); + dest += FixedInt(FixedMul(topdelta<>FRACBITS) < column->length; ofs += rowfrac) + { + if (dest >= vid.screens[scrn&V_PARAMMASK]) // don't draw off the top of the screen (CRASH PREVENTION) + *dest = *(v_translevel + ((source[ofs>>FRACBITS]<<8)&0xff00) + (*dest&0xff)); + dest += stride; + } + column = (const column_t *)((const UINT8 *)column + column->length + 4); + } + break; + + case TRANSMAPPEDDRAW: + while (column->topdelta != 0xff) + { + topdelta = column->topdelta; + if (topdelta <= prevdelta) + topdelta += prevdelta; + prevdelta = topdelta; + source = (const UINT8 *)(column) + 3; + dest = desttop; + if (scrn & V_FLIP) + dest = deststart + (destend - desttop); + dest += FixedInt(FixedMul(topdelta<>FRACBITS) < column->length; ofs += rowfrac) + { + if (dest >= vid.screens[scrn&V_PARAMMASK]) // don't draw off the top of the screen (CRASH PREVENTION) + *dest = *(v_translevel + (((*(v_colormap + source[ofs>>FRACBITS]))<<8)&0xff00) + (*dest&0xff)); + dest += stride; + } + column = (const column_t *)((const UINT8 *)column + column->length + 4); + } + break; } } } @@ -904,9 +966,8 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca // Draws a patch cropped and scaled to arbitrary size. void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t *patch, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h) { - UINT8 (*patchdrawfunc)(const UINT8*, const UINT8*, fixed_t); + UINT8 patchdrawtype; UINT32 alphalevel = 0; - // boolean flip = false; fixed_t col, ofs, colfrac, rowfrac, fdup; INT32 dupx, dupy; @@ -914,10 +975,7 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ UINT8 *desttop, *dest; const UINT8 *source, *deststop; - if (rendermode == render_none) - return; - - if (!patch) + if (rendermode == render_none || !patch) return; #ifdef HWRENDER @@ -928,17 +986,23 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ } #endif - patchdrawfunc = standardpdraw; + patchdrawtype = STANDARDDRAW; v_translevel = NULL; if ((alphalevel = ((scrn & V_ALPHAMASK) >> V_ALPHASHIFT))) { - if (alphalevel == 13) - alphalevel = hudminusalpha[hudtrans]; - else if (alphalevel == 14) - alphalevel = 10 - hudtrans; - else if (alphalevel == 15) - alphalevel = hudplusalpha[hudtrans]; + switch (alphalevel) + { + case 13: + alphalevel = hudminusalpha[hudtrans]; + break; + case 14: + alphalevel = (10 - hudtrans); + break; + case 15: + alphalevel = hudplusalpha[hudtrans]; + break; + } if (alphalevel >= 10) return; // invis @@ -946,7 +1010,7 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ if (alphalevel) { v_translevel = transtables + ((alphalevel-1)<topoffset<leftoffset<>FRACBITS) < patch->width && ((col>>FRACBITS) - sx) < w; col += colfrac, ++x, desttop++) { INT32 topdelta, prevdelta = -1; + if (x < 0) // don't draw off the left of the screen (WRAP PREVENTION) continue; - if (x >= vid.width) // don't draw off the right of the screen (WRAP PREVENTION) + + if (x >= stride) // don't draw off the right of the screen (WRAP PREVENTION) break; + column = (const column_t *)((const UINT8 *)(patch->columns) + (patch->columnofs[col>>FRACBITS])); - while (column->topdelta != 0xff) + switch (patchdrawtype) { - topdelta = column->topdelta; - if (topdelta <= prevdelta) - topdelta += prevdelta; - prevdelta = topdelta; - source = (const UINT8 *)(column) + 3; - dest = desttop; - if (topdelta-sy > 0) - { - dest += FixedInt(FixedMul((topdelta-sy)<topdelta != 0xff) + { + topdelta = column->topdelta; + if (topdelta <= prevdelta) + topdelta += prevdelta; + prevdelta = topdelta; + source = (const UINT8 *)(column) + 3; + dest = desttop; + if (topdelta-sy > 0) + { + dest += FixedInt(FixedMul((topdelta-sy)<>FRACBITS) < column->length && (((ofs>>FRACBITS) - sy) + topdelta) < h; ofs += rowfrac) - { - if (dest >= screens[scrn&V_PARAMMASK]) // don't draw off the top of the screen (CRASH PREVENTION) - *dest = patchdrawfunc(dest, source, ofs); - dest += vid.width; - } - column = (const column_t *)((const UINT8 *)column + column->length + 4); + for (; dest < deststop && (ofs>>FRACBITS) < column->length && (((ofs>>FRACBITS) - sy) + topdelta) < h; ofs += rowfrac) + { + if (dest >= vid.screens[scrn&V_PARAMMASK]) // don't draw off the top of the screen (CRASH PREVENTION) + *dest = source[ofs>>FRACBITS]; + dest += stride; + } + column = (const column_t *)((const UINT8 *)column + column->length + 4); + } + break; + + case TRANSLUCENTDRAW: + while (column->topdelta != 0xff) + { + topdelta = column->topdelta; + if (topdelta <= prevdelta) + topdelta += prevdelta; + prevdelta = topdelta; + source = (const UINT8 *)(column) + 3; + dest = desttop; + if (topdelta-sy > 0) + { + dest += FixedInt(FixedMul((topdelta-sy)<>FRACBITS) < column->length && (((ofs>>FRACBITS) - sy) + topdelta) < h; ofs += rowfrac) + { + if (dest >= vid.screens[scrn&V_PARAMMASK]) // don't draw off the top of the screen (CRASH PREVENTION) + *dest = *(v_translevel + ((source[ofs>>FRACBITS]<<8)&0xff00) + (*dest&0xff)); + dest += stride; + } + column = (const column_t *)((const UINT8 *)column + column->length + 4); + } + break; } } } @@ -1076,8 +1177,8 @@ void V_DrawBlock(INT32 x, INT32 y, INT32 scrn, INT32 width, INT32 height, const I_Error("Bad V_DrawBlock"); #endif - dest = screens[scrn] + y*vid.width + x; - deststop = screens[scrn] + vid.rowbytes * vid.height; + dest = vid.screens[scrn] + y*vid.width + x; + deststop = vid.screens[scrn] + vid.rowbytes * vid.height; while (height--) { @@ -1117,7 +1218,7 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) if (x == 0 && y == 0 && w == BASEVIDWIDTH && h == BASEVIDHEIGHT) { // Clear the entire screen, from dest to deststop. Yes, this really works. - memset(screens[0], (c&255), vid.width * vid.height * vid.bpp); + memset(vid.screens[0], (c&255), vid.width * vid.height); return; } @@ -1144,6 +1245,7 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) else if (!(c & V_SNAPTOTOP)) y += (vid.height - (BASEVIDHEIGHT * dupy)) / 2; } + if (c & V_SPLITSCREEN) y += (BASEVIDHEIGHT * dupy)/2; if (c & V_HORZSCREEN) @@ -1172,17 +1274,23 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) if (y + h > vid.height) h = vid.height-y; - dest = screens[0] + y*vid.width + x; - deststop = screens[0] + vid.rowbytes * vid.height; + dest = vid.screens[0] + y*vid.width + x; + deststop = vid.screens[0] + vid.rowbytes * vid.height; if (alphalevel) { - if (alphalevel == 13) - alphalevel = hudminusalpha[hudtrans]; - else if (alphalevel == 14) - alphalevel = 10 - hudtrans; - else if (alphalevel == 15) - alphalevel = hudplusalpha[hudtrans]; + switch (alphalevel) + { + case 13: + alphalevel = hudminusalpha[hudtrans]; + break; + case 14: + alphalevel = (10 - hudtrans); + break; + case 15: + alphalevel = hudplusalpha[hudtrans]; + break; + } if (alphalevel >= 10) return; // invis @@ -1202,7 +1310,7 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) else { for (;(--h >= 0) && dest < deststop; dest += vid.width) - memset(dest, c, w * vid.bpp); + memset(dest, c, w); } } @@ -1259,7 +1367,7 @@ void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) if (rendermode == render_opengl) { UINT32 hwcolor = V_GetHWConsBackColor(); - HWR_DrawConsoleFill(x, y, w, h, hwcolor, c); // we still use the regular color stuff but only for flags. actual draw color is "hwcolor" for this. + HWR_DrawConsoleFill(x, y, w, h, hwcolor, c); // we still use the regular color stuff but only for flags. actual draw color is "hwcolor" for this. return; } #endif @@ -1270,7 +1378,7 @@ void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) if (x == 0 && y == 0 && w == BASEVIDWIDTH && h == BASEVIDHEIGHT) { // Clear the entire screen, from dest to deststop. Yes, this really works. - memset(screens[0], (UINT8)(c&255), vid.width * vid.height * vid.bpp); + memset(vid.screens[0], (UINT8)(c&255), vid.width * vid.height); return; } @@ -1317,16 +1425,22 @@ void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) if (y + h > vid.height) h = vid.height-y; - dest = screens[0] + y*vid.width + x; + dest = vid.screens[0] + y*vid.width + x; if ((alphalevel = ((c & V_ALPHAMASK) >> V_ALPHASHIFT))) { - if (alphalevel == 13) - alphalevel = hudminusalpha[hudtrans]; - else if (alphalevel == 14) - alphalevel = 10 - hudtrans; - else if (alphalevel == 15) - alphalevel = hudplusalpha[hudtrans]; + switch (alphalevel) + { + case 13: + alphalevel = hudminusalpha[hudtrans]; + break; + case 14: + alphalevel = (10 - hudtrans); + break; + case 15: + alphalevel = hudplusalpha[hudtrans]; + break; + } if (alphalevel >= 10) return; // invis @@ -1334,13 +1448,18 @@ void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) c &= 255; - if (!alphalevel) { - for (v = 0; v < h; v++, dest += vid.width) { - for (u = 0; u < w; u++) { + if (!alphalevel) + { + for (v = 0; v < h; v++, dest += vid.width) + { + for (u = 0; u < w; u++) + { dest[u] = consolebgmap[dest[u]]; } } - } else { // mpc 12-04-2018 + } + else + { // mpc 12-04-2018 const UINT8 *fadetable = ((UINT8 *)transtables + ((alphalevel-1)<y) ? y : x w = clip(w,vid.width); @@ -1440,14 +1559,14 @@ void V_DrawDiag(INT32 x, INT32 y, INT32 wh, INT32 c) if (h > w) h = w; - dest = screens[0] + y*vid.width + x; - deststop = screens[0] + vid.rowbytes * vid.height; + dest = vid.screens[0] + y*vid.width + x; + deststop = vid.screens[0] + vid.rowbytes * vid.height; c &= 255; for (;(--h >= 0) && dest < deststop; dest += vid.width) { - memset(dest, c, w * vid.bpp); + memset(dest, c, w); if (wait) wait--; else @@ -1512,8 +1631,8 @@ void V_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatnum) dupx = dupy = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy); - dest = screens[0] + y*dupy*vid.width + x*dupx; - deststop = screens[0] + vid.rowbytes * vid.height; + dest = vid.screens[0] + y*dupy*vid.width + x*dupx; + deststop = vid.screens[0] + vid.rowbytes * vid.height; // from V_DrawScaledPatch if (vid.width != BASEVIDWIDTH * dupx) @@ -1614,7 +1733,7 @@ void V_DrawVhsEffect(boolean rewind) { static fixed_t upbary = 100*FRACUNIT, downbary = 150*FRACUNIT; - UINT8 *buf = screens[0], *tmp = screens[4]; + UINT8 *buf = vid.screens[0], *tmp = vid.screens[4]; UINT16 y; UINT32 x, pos = 0; @@ -1670,7 +1789,7 @@ void V_DrawVhsEffect(boolean rewind) if (y == 0 && offs < 0) offs = 0; else if (y >= vid.height-2 && offs > 0) offs = 0; - for (x = pos+vid.rowbytes*2; pos < x; pos++) + for (x = min(pos+vid.rowbytes*2, vid.rowbytes*vid.height); pos < x; pos++) { tmp[pos] = thismapstart[buf[pos+offs]]; #ifdef HQ_VHS @@ -1707,8 +1826,8 @@ void V_DrawFadeScreen(UINT16 color, UINT8 strength) : ((color & 0xFF00) // Color is not palette index? ? ((UINT8 *)colormaps + strength*256) // Do COLORMAP fade. : ((UINT8 *)transtables + ((9-strength)<postimg & POSTIMG_WATER) { @@ -3482,7 +3601,7 @@ void V_DoPostProcessor(INT32 view, INT32 param) /* Unoptimized version - for (x = 0; x < vid.width*vid.bpp; x++) + for (x = 0; x < vid.width; x++) { newpix = (x + sine); @@ -3579,7 +3698,7 @@ void V_DoPostProcessor(INT32 view, INT32 param) INT32 y, x, x2; for (y = yoffset; y < yoffset+viewheight; y++) - for (x = xoffset, x2 = xoffset+((viewwidth*vid.bpp)-1); x < xoffset+(viewwidth*vid.bpp); x++, x2--) + for (x = xoffset, x2 = xoffset+(viewwidth-1); x < xoffset+viewwidth; x++, x2--) tmpscr[y*vid.width + x2] = srcscr[y*vid.width + x]; UINT8 *tmp = tmpscr; @@ -3599,8 +3718,8 @@ void V_DoPostProcessor(INT32 view, INT32 param) srcscr = tmp; } - VID_BlitLinearScreen(srcscr+vid.width*vid.bpp*yoffset+xoffset, tmpscr+vid.width*vid.bpp*yoffset+xoffset, - viewwidth*vid.bpp, viewheight, vid.width*vid.bpp, vid.width); + VID_BlitLinearScreen(srcscr+vid.width*yoffset+xoffset, tmpscr+vid.width*yoffset+xoffset, + viewwidth, viewheight, vid.width, vid.width); #endif } @@ -3660,18 +3779,15 @@ void V_Init(void) const INT32 screensize = vid.rowbytes * vid.height; for (i = 0; i < NUMSCREENS; i++) - screens[i] = NULL; + vid.screens[i] = NULL; // start address of NUMSCREENS * width*height vidbuffers if (base) { for (i = 0; i < NUMSCREENS; i++) - screens[i] = base + i*screensize; + vid.screens[i] = base + i*screensize; } - if (vid.direct) - screens[0] = vid.direct; - #ifdef DEBUG CONS_Debug(DBG_RENDER, "V_Init done:\n"); for (i = 0; i < NUMSCREENS; i++) diff --git a/src/v_video.h b/src/v_video.h index 3a8cf7396..d5a4adf5e 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -14,6 +14,10 @@ #ifndef __V_VIDEO__ #define __V_VIDEO__ +#ifdef __cplusplus +extern "C" { +#endif + #include "doomdef.h" #include "doomtype.h" #include "r_defs.h" @@ -23,11 +27,6 @@ // VIDEO // -// Screen 0 is the screen updated by I_Update screen. -// Screen 1 is an extra buffer. - -extern UINT8 *screens[5]; - extern consvar_t cv_ticrate, cv_accuratefps, cv_allcaps, cv_constextsize, cv_menucaps, cv_globalgamma, cv_globalsaturation, cv_rhue, cv_yhue, cv_ghue, cv_chue, cv_bhue, cv_mhue, @@ -290,4 +289,8 @@ void V_DrawHorizontallyScaledFullScreenPatch(patch_t *patch); void VID_BlitLinearScreen(const UINT8 *srcptr, UINT8 *destptr, INT32 width, INT32 height, size_t srcrowbytes, size_t destrowbytes); +#ifdef __cplusplus +} // extern "C" +#endif + #endif diff --git a/src/w_wad.h b/src/w_wad.h index 12ad8cea7..9b1035fa2 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -14,6 +14,10 @@ #ifndef __W_WAD__ #define __W_WAD__ +#ifdef __cplusplus +extern "C" { +#endif + #ifdef HWRENDER #include "hardware/hw_data.h" #endif @@ -233,4 +237,8 @@ int W_VerifyNMUSlumps(const char *filename); int W_CheckPostLoadList(const char *filename); +#ifdef __cplusplus +} // extern "C" +#endif + #endif // __W_WAD__ diff --git a/src/y_inter.c b/src/y_inter.c index 3c0a77ac1..e89224aa0 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -512,7 +512,7 @@ void Y_IntermissionDrawer(void) else { if (rendermode == render_soft) - VID_BlitLinearScreen(screens[1], screens[0], vid.width*vid.bpp, vid.height, vid.width*vid.bpp, vid.rowbytes); + VID_BlitLinearScreen(vid.screens[1], vid.screens[0], vid.width, vid.height, vid.width, vid.rowbytes); #ifdef HWRENDER else if (rendermode == render_opengl) HWR_DrawIntermissionBG(); diff --git a/src/z_zone.h b/src/z_zone.h index 41ea1d669..ab908bfec 100644 --- a/src/z_zone.h +++ b/src/z_zone.h @@ -14,6 +14,10 @@ #ifndef __Z_ZONE__ #define __Z_ZONE__ +#ifdef __cplusplus +extern "C" { +#endif + #include #include "doomdef.h" #include "doomtype.h" @@ -153,4 +157,8 @@ size_t Z_TagsUsage(INT32 lowtag, INT32 hightag); // char *Z_StrDup(const char *in); +#ifdef __cplusplus +} // extern "C" +#endif + #endif