Give the software renderer some love! #186

Merged
alufolie91 merged 147 commits from softwarecrap into Saturn-Next 2025-07-01 15:21:48 +02:00
112 changed files with 7694 additions and 6324 deletions

No files matched your search

+7 -19
View File
@@ -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)))
-2
View File
@@ -4,8 +4,6 @@ sources+=$(call List,dedicated/Sourcefile)
opts+=-DDEDICATED
libs+=-lpthread
ifdef MINGW
libs+=-mconsole
endif
+1 -1
View File
@@ -10,8 +10,8 @@
makedir:=$(makedir)/SDL
sources+=$(call List,sdl/Sourcefile)
opts+=-DDIRECTFULLSCREEN -DHAVE_SDL
sources+=$(call List,sdl/Sourcefile)
NOUPNP=1
+3
View File
@@ -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
+5 -4
View File
@@ -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
+1 -1
View File
@@ -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];
}
//
-1
View File
@@ -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;
}
+2
View File
@@ -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)
+8
View File
@@ -13,6 +13,10 @@
#ifndef __COMMAND_H__
#define __COMMAND_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#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__
-7
View File
@@ -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"));
+1
View File
@@ -0,0 +1 @@
target_sourcefile(cpp)
+2
View File
@@ -0,0 +1,2 @@
memory.cpp
thread_pool.cpp
+71
View File
@@ -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 <array>
#include <new>
#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();
}
+32
View File
@@ -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 <stddef.h>
#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__
+192
View File
@@ -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 <array>
#include <atomic>
#include <cstddef>
#include <memory>
#include <optional>
//#include <tracy/tracy/Tracy.hpp>
#include "../cxxutil.hpp"
namespace srb2
{
template <typename T>
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<T[]>(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<T[]> _buff;
};
alignas(64) std::atomic<int64_t> bottom_;
alignas(64) std::atomic<int64_t> top_;
alignas(64) std::atomic<RingBuff*> buffer_;
std::vector<std::unique_ptr<RingBuff>> 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<size_t>(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<T> 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<T> 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__
+255
View File
@@ -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 <array>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <initializer_list>
#include <iterator>
#include <stdexcept>
#include <type_traits>
#include "../cxxutil.hpp"
namespace srb2
{
template <typename T, size_t Limit>
class StaticVec;
template <typename T, size_t Limit>
class StaticVec
{
std::array<T, Limit> 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<T>)
{
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<T> list) noexcept(std::is_nothrow_move_assignable_v<T>)
{
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<T>)
{
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<T, Limit>::iterator;
using const_iterator = typename std::array<T, Limit>::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<iterator> rbegin() noexcept { return std::reverse_iterator(this->end()); }
constexpr std::reverse_iterator<const_iterator> crbegin() const noexcept { return std::reverse_iterator(this->cend()); }
constexpr std::reverse_iterator<iterator> rend() noexcept { return std::reverse_iterator(this->begin()); }
constexpr std::reverse_iterator<const_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 <typename T, size_t L1, size_t L2>
bool operator==(const srb2::StaticVec<T, L1>& lhs, const srb2::StaticVec<T, L2>& 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 <typename T, size_t L1, size_t L2>
bool operator!=(const srb2::StaticVec<T, L1>& lhs, const srb2::StaticVec<T, L2>& rhs)
{
return !(lhs == rhs);
}
template <typename T, size_t Limit>
struct std::hash<srb2::StaticVec<T, Limit>>
{
size_t operator()(const srb2::StaticVec<T, Limit>& 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<T>(*itr);
}
return ret;
}
};
#endif // __SRB2_CORE_STATIC_VEC_HPP__
+346
View File
@@ -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 <algorithm>
#include <condition_variable>
#include <exception>
#include <mutex>
#include <string>
#include <system_error>
//#include <fmt/format.h>
//#include <tracy/tracy/Tracy.hpp>
#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<std::atomic<bool>> pool_alive,
std::shared_ptr<std::mutex> worker_ready_mutex,
std::shared_ptr<std::condition_variable> worker_ready_condvar,
std::shared_ptr<ThreadPool::Queue> my_wq,
std::vector<std::shared_ptr<ThreadPool::Queue>> 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<ThreadPool::Task> 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<std::mutex> 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<std::atomic<bool>>(true);
for (size_t i = 0; i < threads; i++)
{
std::shared_ptr<Queue> wsq = std::make_shared<Queue>(2048);
work_queues_.push_back(wsq);
std::shared_ptr<std::mutex> mutex = std::make_shared<std::mutex>();
worker_ready_mutexes_.push_back(std::move(mutex));
std::shared_ptr<std::condition_variable> condvar = std::make_shared<std::condition_variable>();
worker_ready_condvars_.push_back(std::move(condvar));
}
for (size_t i = 0; i < threads; i++)
{
std::shared_ptr<Queue> my_queue = work_queues_[i];
std::vector<std::shared_ptr<Queue>> 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<Task> 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<Task> 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<ThreadPool> srb2::g_main_threadpool;
void I_ThreadPoolInit(void)
{
SRB2_ASSERT(g_main_threadpool == nullptr);
size_t thread_count = std::min(static_cast<unsigned int>(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<ThreadPool>();
}
else
{
g_main_threadpool = std::make_unique<ThreadPool>(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();
}
+163
View File
@@ -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 <stddef.h>
#ifdef __cplusplus
#include <condition_variable>
#include <cstddef>
#include <functional>
#include <memory>
#include <mutex>
#include <thread>
#include <utility>
#include <vector>
#include "spmc_queue.hpp"
namespace srb2
{
class ThreadPool
{
public:
struct Task
{
void (*thunk)(void*);
void (*deleter)(void*);
std::shared_ptr<std::atomic<uint32_t>> pseudosema;
std::array<std::byte, 512 - sizeof(void(*)(void*)) * 2 - sizeof(std::shared_ptr<std::atomic<uint32_t>>)> raw;
};
using Queue = SpMcQueue<Task>;
class Sema
{
std::shared_ptr<std::atomic<uint32_t>> pseudosema_;
explicit Sema(std::shared_ptr<std::atomic<uint32_t>> sema) : pseudosema_(sema) {}
friend class ThreadPool;
public:
Sema() = default;
};
private:
std::shared_ptr<std::atomic<bool>> pool_alive_;
std::vector<std::shared_ptr<std::mutex>> worker_ready_mutexes_;
std::vector<std::shared_ptr<std::condition_variable>> worker_ready_condvars_;
std::vector<std::shared_ptr<Queue>> work_queues_;
std::vector<std::thread> threads_;
size_t next_queue_index_ = 0;
std::shared_ptr<std::atomic<uint32_t>> 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 <typename T> 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<ThreadPool> g_main_threadpool;
template <typename F>
void callable_caller(F* f)
{
(*f)();
}
template <typename F>
void callable_destroyer(F* f)
{
f->~F();
}
template <typename T>
void ThreadPool::schedule(T&& thunk)
{
static_assert(sizeof(T) <= sizeof(std::declval<Task>().raw));
if (immediate_mode_)
{
(thunk)();
return;
}
if (sema_begun_)
{
if (cur_sema_ == nullptr)
{
cur_sema_ = std::make_shared<std::atomic<uint32_t>>(0);
}
cur_sema_->fetch_add(1, std::memory_order_relaxed);
}
size_t qi = next_queue_index_;
{
std::shared_ptr<Queue> q = work_queues_[qi];
Task task;
task.thunk = reinterpret_cast<void(*)(void*)>(callable_caller<T>);
task.deleter = reinterpret_cast<void(*)(void*)>(callable_destroyer<T>);
task.pseudosema = cur_sema_;
new (reinterpret_cast<T*>(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__
+152
View File
@@ -0,0 +1,152 @@
#ifndef __SRB2_CXXUTIL_HPP__
#define __SRB2_CXXUTIL_HPP__
#include <cstdlib>
#include <type_traits>
#include <utility>
#include "doomdef.h"
namespace srb2 {
template <class F>
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 <class F>
Finally<std::decay_t<F>> finally(F&& f) noexcept {
return Finally {std::forward<F>(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 <unsigned int Level, class Handler, class Expr>
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 <unsigned int Level, class, class Expr>
std::enable_if_t<(Level > SRB2_ASSERTION_LEVEL), void>
do_assert(const Expr&, const SourceLocation&, const char* = "") noexcept {
}
template <typename T>
class NotNull final {
T ptr_;
public:
static_assert(std::is_convertible_v<decltype(std::declval<T>() != 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<T> from any compatible pointer U, for example with polymorphic classes.
template <typename U, typename = std::enable_if_t<std::is_convertible_v<U, T>>>
constexpr NotNull(U&& rhs) : ptr_(std::forward<U>(rhs)) {
SRB2_ASSERT(ptr_ != nullptr);
}
/// @brief Wrap the pointer type T, asserting that the pointer is not null.
template <typename = std::enable_if_t<!std::is_same_v<std::nullptr_t, T>>>
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 <typename U, typename = std::enable_if_t<std::is_convertible_v<U, T>>>
constexpr NotNull(const NotNull<U>& 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<T> with nullptr regardless of T.
NotNull(std::nullptr_t) = delete;
NotNull& operator=(std::nullptr_t) = delete;
};
template <class T>
NotNull(T) -> NotNull<T>;
} // namespace srb2
#endif // __SRB2_CXXUTIL_HPP__
+9
View File
@@ -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
+39 -13
View File
@@ -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;
+8
View File
@@ -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__
+8 -2
View File
@@ -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
+2 -5
View File
@@ -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);
+13
View File
@@ -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
+8
View File
@@ -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 *
+8
View File
@@ -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__
+18
View File
@@ -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__
+1 -1
View File
@@ -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;
+23 -16
View File
@@ -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 <stdbool.h>
// 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__
+3 -3
View File
@@ -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
+8
View File
@@ -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__
+8
View File
@@ -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
+2 -3
View File
@@ -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;
+4 -4
View File
@@ -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;
}
+11 -29
View File
@@ -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)<<FRACBITS, (y)<<FRACBITS, FRACUNIT, FRACUNIT, V_NOSCALESTART, NULL, 0);
}
}
// check for new console commands.
NetUpdate();
// Clear view, set viewport (glViewport), set perspective...
HWR_ClearView();
ST_doPaletteStuff();
// Draw the sky background.
HWR_DrawSkyBackground();
if (skybox)
@@ -5745,6 +5726,7 @@ void HWR_LoadLevel(boolean reloadinggamestate)
static void HWR_TogglePaletteRendering(void)
{
V_ResetPaletteCVars(); // dont carry over changed palettes
ST_ResetPaletteStuff();
// which state should we go to?
if (HWR_ShouldUsePaletteRendering())
+8
View File
@@ -34,6 +34,10 @@
#define GLENCORE
#ifdef __cplusplus
extern "C" {
#endif
// Startup & Shutdown the hardware mode renderer
void HWR_Startup(void);
void HWR_Shutdown(void);
@@ -228,4 +232,8 @@ FUNCINLINE static ATTRINLINE boolean HWR_PalRenderFlashpal(void)
return (cv_glflashpal.value && HWR_ShouldUsePaletteRendering());
}
#ifdef __cplusplus
}// extern "C"
#endif
#endif
+8
View File
@@ -15,6 +15,10 @@
#ifndef _HW_MD2_H_
#define _HW_MD2_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "hw_glob.h"
#include "hw_model.h"
@@ -46,4 +50,8 @@ void HWR_DrawMD2(gl_vissprite_t *spr);
void HWR_AddPlayerMD2(INT32 skin, boolean local);
void HWR_AddSpriteMD2(size_t spritenum);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // _HW_MD2_H_
+2 -2
View File
@@ -66,6 +66,7 @@ void HWR_FreePortalList(gl_portallist_t freelist)
// free memory from portal list allocated by calls to Add2Lines
gl_portal_t *gl_portal_temp = freelist.base;
while (gl_portal_temp)
{
gl_portal_t *nextportal = gl_portal_temp->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
{
+8
View File
@@ -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__
+8
View File
@@ -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
+8
View File
@@ -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
+8
View File
@@ -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
+8
View File
@@ -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*/
+8
View File
@@ -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
+8
View File
@@ -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__
+1
View File
@@ -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"
+1
View File
@@ -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"
+1
View File
@@ -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"
+1
View File
@@ -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"
+2 -1
View File
@@ -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;
}
}
+4 -4
View File
@@ -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
+8
View File
@@ -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__
+14
View File
@@ -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))
+9
View File
@@ -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__
+13 -4
View File
@@ -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
+8
View File
@@ -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
+1
View File
@@ -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"
+1
View File
@@ -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"
+9
View File
@@ -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
+1
View File
@@ -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"
+30 -3
View File
@@ -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
+9
View File
@@ -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
+9
View File
@@ -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
+123 -189
View File
@@ -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<UINT8*>(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 <ClipType Type>
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<UINT8*>(memchr(solidcol+first, 0, last-first));
if (!p)
return; // All solid
first = p - solidcol;
}
else
{
p = static_cast<UINT8*>(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<ClipType::kPass>(x1, x2);
if (g_walloffscreen)
R_ClipPassWallSegment(x1, x2 - 1, true);
R_ClipWallSegment<ClipType::kSolidDontRender>(x1, x2);
return;
clipsolid:
g_walloffscreen = false;
R_ClipSolidWallSegment(x1, x2 - 1);
R_ClipWallSegment<ClipType::kSolid>(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<polyobj_t**>(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<lightlist_t*>(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;
+12
View File
@@ -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
+7 -3
View File
@@ -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);
+20
View File
@@ -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
+33 -5
View File
@@ -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;
+89 -200
View File
@@ -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 <algorithm>
#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<UINT8*>(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<UINT8*>(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<UINT8**>(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<UINT8*>(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<INT16*>(Z_Realloc(negonearray, sizeof(*negonearray) * viewwidth, PU_STATIC, NULL));
screenheightarray = static_cast<INT16*>(Z_Realloc(screenheightarray, sizeof(*screenheightarray) * viewwidth, PU_STATIC, NULL));
floorclip = static_cast<INT16*>(Z_Realloc(floorclip, sizeof(*floorclip) * viewwidth, PU_STATIC, NULL));
ceilingclip = static_cast<INT16*>(Z_Realloc(ceilingclip, sizeof(*ceilingclip) * viewwidth, PU_STATIC, NULL));
frontscale = static_cast<fixed_t*>(Z_Realloc(frontscale, sizeof(*frontscale) * viewwidth, PU_STATIC, NULL));
xtoviewangle = static_cast<angle_t*>(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"
+155 -74
View File
@@ -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__
-1814
View File
File diff suppressed because it is too large. Load diff
+356
View File
@@ -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<DrawColumnType Type>
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<DrawColumnType Type>
static constexpr UINT8 R_GetColumnTranslucent(drawcolumndata_t* dc, UINT8 * restrict dest, UINT8 col, const UINT8 * restrict colormap)
{
col = R_GetColumnTranslated<Type>(dc, col, colormap);
if constexpr (Type & DrawColumnType::DC_TRANSMAP)
{
return *(dc->transmap + (col << 8) + (*dest));
}
else
{
return col;
}
}
template<DrawColumnType Type>
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<Type>(dc, dest, col, colormap);
}
/** \brief The R_DrawColumn function
Experiment to make software go faster. Taken from the Boom source
*/
template<DrawColumnType Type>
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<DrawColumnType>(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<NewType>(&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<NewType>(&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<Type>(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<Type>(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<Type>(dc, dest, (frac>>FRACBITS) & heightmask, source, colormap);
dest += stride;
frac += fracstep;
*dest = R_DrawColumnPixel<Type>(dc, dest, (frac>>FRACBITS) & heightmask, source, colormap);
dest += stride;
frac += fracstep;
}
if (count & 1)
{
*dest = R_DrawColumnPixel<Type>(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<Type>(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<DrawColumnType>(flags); \
R_DrawColumnTemplate<opt>(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--);
}
+446
View File
@@ -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 <windows.h>
#define local_for_thread static __thread
#else
#include <threads.h>
#define local_for_thread thread_local static
#endif
#else
#define local_for_thread static
#endif
// ==========================================================================
// SPANS
// ==========================================================================
#define SPANSIZE 16
#define INVSPAN 0.0625f
// <Callum> 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<DrawSpanType Type>
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<DrawSpanType Type>
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<Type>(ds, dsrc, colormap, col);
}
/** \brief The R_DrawSpan_8 function
Draws the actual span.
*/
template<DrawSpanType Type>
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<Type>(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<Type>(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<DrawSpanType Type>
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<INT32*>(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<Type>(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<Type>(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<Type>(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<Type>(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<DrawSpanType>(flags); \
template<opt>(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<INT32*>(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);
}
+3 -3
View File
@@ -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;
+8
View File
@@ -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
+8
View File
@@ -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__
+245 -236
View File
@@ -13,6 +13,8 @@
/// utility functions (BSP, geometry, trigonometry).
/// See tables.c, too.
#include <algorithm>
#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<INT32*>(realloc(viewmorph.scrmap, vid.width*vid.height * sizeof(INT32)));
viewmorph.ceilingclip = static_cast<INT16*>(realloc(viewmorph.ceilingclip, vid.width * sizeof(INT16)));
viewmorph.floorclip = static_cast<INT16*>(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<<FRACBITS;
centeryfrac = centery<<FRACBITS;
R_SetFov(cv_fov.value);
R_InitViewBuffer(scaledviewwidth, viewheight);
R_SetupViewBuffers();
// why did we calc all the software crap?
#ifdef HWRENDER
@@ -942,7 +934,10 @@ void R_ExecuteSetViewSize(void)
// thing clipping
for (i = 0; i < viewwidth; i++)
{
negonearray[i] = -1;
screenheightarray[i] = (INT16)viewheight;
}
if (ds_su)
Z_Free(ds_su);
@@ -952,7 +947,6 @@ void R_ExecuteSetViewSize(void)
Z_Free(ds_sz);
ds_su = ds_sv = ds_sz = NULL;
ds_sup = ds_svp = ds_szp = NULL;
memset(scalelight, 0xFF, sizeof(scalelight));
@@ -980,33 +974,52 @@ void R_ExecuteSetViewSize(void)
fixed_t R_GetPlayerFov(player_t *player)
{
fixed_t fov = cv_fov.value + player->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)<<FRACBITS;
dy = FixedMul(abs(dy), fovtan);
yslopetab[i] = FixedDiv(centerx*FRACUNIT, dy);
}
projection = projectiony = FixedDiv(centerxfrac, fovtan);
}
static void R_InitViewMapping(void)
{
R_InitTextureMapping();
if (rendermode == render_soft)
{
// 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)<<FRACBITS;
dy = FixedMul(abs(dy), fovtan);
yslopetab[i] = FixedDiv(centerx*FRACUNIT, dy);
}
}
// setup sky scaling
R_SetSkyScale();
}
static void R_SetupViewBuffers(void)
{
R_CalcFov(cv_fov.value);
R_InitViewBuffer(viewwidth, viewheight);
R_InitViewMapping();
}
static void R_SetFov(fixed_t playerfov)
{
R_CalcFov(playerfov);
R_InitViewMapping();
}
//
// R_Init
@@ -1022,9 +1035,6 @@ void R_Init(void)
R_InitViewBorder();
R_SetViewSize(); // setsizeneeded is set true
//I_OutputMsg("\nR_InitPlanes");
R_InitPlanes();
// this is now done by SCR_Recalc() at the first mode set
//I_OutputMsg("\nR_InitLightTables");
R_InitLightTables();
@@ -1085,17 +1095,87 @@ static void R_SetupAimingFrame(player_t *player, camera_t *thiscam)
}
}
static void R_SetupSkyScale(player_t *player, camera_t *thiscam, mapheader_t *mh)
{
if (!mh->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_e>(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)<<FRACBITS;
newview->z = (viewmobj->spawnpoint) ? (((fixed_t)viewmobj->spawnpoint->angle)<<FRACBITS) : 0;
#define SETUPSKYVIEW(viewmo, zscale)\
if (skyboxmo[1])\
{\
fixed_t x = 0, y = 0;\
if (mh->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_e>(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<maskcount_t*>(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<maskcount_t*>(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++)
{
+11 -1
View File
@@ -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
+1
View File
@@ -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"
+8
View File
@@ -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__
-1204
View File
File diff suppressed because it is too large. Load diff
+1408
View File
File diff suppressed because it is too large. Load diff
+21 -19
View File
@@ -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
+178 -15
View File
@@ -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)<<FRACBITS;
portal->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);
}
+13 -2
View File
@@ -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
File diff suppressed because it is too large. Load diff
+12 -1
View File
@@ -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
+791
View File
@@ -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 <startlump>
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;
}
+152
View File
@@ -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__
+20 -6
View File
@@ -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)<<FRACBITS;
// the horizon line in the sky texture
skytexturemid = (textures[skytexture]->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<<FRACBITS);
skyscale = FixedDiv(fovtan, vid.fdupx+difference);
}
+9 -1
View File
@@ -14,6 +14,10 @@
#ifndef __R_SKY__
#define __R_SKY__
#ifdef __cplusplus
extern "C" {
#endif
#include "m_fixed.h"
#ifdef __GNUG__
@@ -26,7 +30,7 @@
/// \brief The sky map is 256*128*4 maps.
#define ANGLETOSKYSHIFT 22
extern INT32 skytexture, skytexturemid;
extern INT32 skytexture, skytexturemid, skytextureoffset;
extern fixed_t skyscale;
extern INT32 skyflatnum;
@@ -38,4 +42,8 @@ void R_SetupSkyDraw(void);
void R_SetSkyScale(void);
#ifdef __cplusplus
} // extern "C"
#endif
#endif
+10 -1
View File
@@ -33,7 +33,16 @@ struct rastery_s
fixed_t tx1, ty1;
fixed_t tx2, ty2; // start/end points in texture at this line
};
static struct rastery_s rastertab[MAXVIDHEIGHT];
static struct rastery_s *rastertab;
static boolean *cliptable;
void R_AllocFloorSpriteTables(void)
{
//cliptable = Z_Realloc(cliptable, sizeof(*cliptable) * (viewwidth + 1), PU_STATIC, NULL);
rastertab = Z_Realloc(rastertab, sizeof(*rastertab) * viewheight, PU_STATIC, NULL);
}
static void prepare_rastertab(void);
#endif
+2
View File
@@ -75,4 +75,6 @@ void R_ClearVisibleFloorSplats(void);
void R_AddVisibleFloorSplats(subsector_t *subsec);
void R_DrawVisibleFloorSplats(void);
void R_AllocFloorSpriteTables(void);
#endif /*__R_SPLATS_H__*/
+1 -1
View File
@@ -104,7 +104,7 @@ extern angle_t clipangle;
extern angle_t doubleclipangle;
extern INT32 viewangletox[FINEANGLES/2];
extern angle_t xtoviewangle[MAXVIDWIDTH+1];
extern angle_t *xtoviewangle;
extern fixed_t rw_distance;
extern angle_t rw_normalangle;
File diff suppressed because it is too large. Load diff
+32 -133
View File
@@ -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__
+69 -55
View File
@@ -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.
+17 -73
View File
@@ -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);
+8
View File
@@ -19,6 +19,14 @@
#ifndef __ENDTXT__
#define __ENDTXT__
#ifdef __cplusplus
extern "C" {
#endif
void ShowEndTxt (void);
#ifdef __cplusplus
} // extern "C"
#endif
#endif
Loaded 100 of 112 files, more files were not shown because too many files have changed in this diff. Show more