Initial engine repository

This commit is contained in:
2026-06-08 19:58:35 +08:00
commit 7a925c3736
137 changed files with 162421 additions and 0 deletions
@@ -0,0 +1,395 @@
#pragma once
#include <type_traits>
#include <iterator>
#include <stdexcept>
#include <cassert>
namespace frostbite2D {
template <typename _PtrTy>
class IntrusiveListValue;
template <typename _PtrTy>
class IntrusiveList {
public:
using value_type = typename std::pointer_traits<_PtrTy>::pointer;
using pointer = value_type*;
using reference = value_type&;
IntrusiveList()
: first_(nullptr)
, last_(nullptr) {
}
~IntrusiveList() {
Clear();
}
const value_type& GetFirst() const {
return first_;
}
value_type& GetFirst() {
return first_;
}
const value_type& GetLast() const {
return last_;
}
value_type& GetLast() {
return last_;
}
inline bool IsEmpty() const {
return first_ == nullptr;
}
void PushBack(reference child) {
if (child->GetPrev()) {
child->GetPrev()->GetNext() = child->GetNext();
}
if (child->GetNext()) {
child->GetNext()->GetPrev() = child->GetPrev();
}
child->GetPrev() = last_;
child->GetNext() = nullptr;
if (first_) {
last_->GetNext() = child;
} else {
first_ = child;
}
last_ = child;
}
void PushFront(reference child) {
if (child->GetPrev()) {
child->GetPrev()->GetNext() = child->GetNext();
}
if (child->GetNext()) {
child->GetNext()->GetPrev() = child->GetPrev();
}
child->GetPrev() = nullptr;
child->GetNext() = first_;
if (first_) {
first_->GetPrev() = child;
} else {
last_ = child;
}
first_ = child;
}
void InsertBefore(reference child, reference before) {
if (child->GetPrev()) {
child->GetPrev()->GetNext() = child->GetNext();
}
if (child->GetNext()) {
child->GetNext()->GetPrev() = child->GetPrev();
}
if (before->GetPrev()) {
before->GetPrev()->GetNext() = child;
} else {
first_ = child;
}
child->GetPrev() = before->GetPrev();
child->GetNext() = before;
before->GetPrev() = child;
}
void InsertAfter(reference child, reference after) {
if (child->GetPrev()) {
child->GetPrev()->GetNext() = child->GetNext();
}
if (child->GetNext()) {
child->GetNext()->GetPrev() = child->GetPrev();
}
if (after->GetNext()) {
after->GetNext()->GetPrev() = child;
} else {
last_ = child;
}
child->GetNext() = after->GetNext();
child->GetPrev() = after;
after->GetNext() = child;
}
void Remove(reference child) {
if (child->GetNext()) {
child->GetNext()->GetPrev() = child->GetPrev();
} else {
last_ = child->GetPrev();
}
if (child->GetPrev()) {
child->GetPrev()->GetNext() = child->GetNext();
} else {
first_ = child->GetNext();
}
child->GetPrev() = nullptr;
child->GetNext() = nullptr;
}
void Clear() {
value_type p = first_;
while (p) {
value_type tmp = p;
p = p->GetNext();
if (tmp) {
tmp->GetNext() = nullptr;
tmp->GetPrev() = nullptr;
}
}
first_ = nullptr;
last_ = nullptr;
}
bool CheckValid() {
if (!first_) {
return true;
}
int pos = 0;
value_type p = first_;
value_type tmp = p;
do {
tmp = p;
p = p->GetNext();
++pos;
if (p) {
if (p->GetPrev() != tmp) {
return false;
}
} else {
if (tmp != last_) {
return false;
}
}
} while (p);
return true;
}
public:
template <typename _IterPtrTy>
struct Iterator {
using iterator_category = std::bidirectional_iterator_tag;
using value_type = _IterPtrTy;
using pointer = _IterPtrTy*;
using reference = _IterPtrTy&;
using difference_type = ptrdiff_t;
inline Iterator(value_type ptr = nullptr, bool is_end = false)
: base_(ptr)
, is_end_(is_end) {
}
inline reference operator*() const {
assert(base_ && !is_end_);
return const_cast<reference>(base_);
}
inline pointer operator->() const {
return std::pointer_traits<pointer>::pointer_to(**this);
}
inline Iterator& operator++() {
assert(base_ && !is_end_);
value_type next = base_->GetNext();
if (next) {
base_ = next;
} else {
is_end_ = true;
}
return (*this);
}
inline Iterator operator++(int) {
Iterator old = (*this);
++(*this);
return old;
}
inline Iterator& operator--() {
assert(base_);
if (is_end_) {
is_end_ = false;
} else {
base_ = base_->GetPrev();
}
return (*this);
}
inline Iterator operator--(int) {
Iterator old = (*this);
--(*this);
return old;
}
inline bool operator==(const Iterator& other) const {
return base_ == other.base_ && is_end_ == other.is_end_;
}
inline bool operator!=(const Iterator& other) const {
return !(*this == other);
}
inline operator bool() const {
return base_ != nullptr && !is_end_;
}
private:
bool is_end_;
typename std::remove_const<value_type>::type base_;
};
public:
using iterator = Iterator<value_type>;
using const_iterator = Iterator<const value_type>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
inline iterator begin() {
return iterator(first_, first_ == nullptr);
}
inline const_iterator begin() const {
return const_iterator(first_, first_ == nullptr);
}
inline const_iterator cbegin() const {
return begin();
}
inline iterator end() {
return iterator(last_, true);
}
inline const_iterator end() const {
return const_iterator(last_, true);
}
inline const_iterator cend() const {
return end();
}
inline reverse_iterator rbegin() {
return reverse_iterator(end());
}
inline const_reverse_iterator rbegin() const {
return const_reverse_iterator(end());
}
inline const_reverse_iterator crbegin() const {
return rbegin();
}
inline reverse_iterator rend() {
return reverse_iterator(begin());
}
inline const_reverse_iterator rend() const {
return const_reverse_iterator(begin());
}
inline const_reverse_iterator crend() const {
return rend();
}
inline value_type& front() {
if (IsEmpty()) {
throw std::out_of_range("front() called on empty list");
}
return first_;
}
inline const value_type& front() const {
if (IsEmpty()) {
throw std::out_of_range("front() called on empty list");
}
return first_;
}
inline value_type& back() {
if (IsEmpty()) {
throw std::out_of_range("back() called on empty list");
}
return last_;
}
inline const value_type& back() const {
if (IsEmpty()) {
throw std::out_of_range("back() called on empty list");
}
return last_;
}
private:
value_type first_;
value_type last_;
template <typename T>
friend class IntrusiveListValue;
};
template <typename _PtrTy>
class IntrusiveListValue {
public:
using value_type = typename std::pointer_traits<_PtrTy>::pointer;
using reference = value_type&;
using pointer = value_type*;
IntrusiveListValue()
: prev_(nullptr)
, next_(nullptr) {
}
IntrusiveListValue(value_type rhs)
: prev_(nullptr)
, next_(nullptr) {
if (rhs) {
prev_ = rhs->GetPrev();
next_ = rhs->GetNext();
}
}
const value_type& GetPrev() const {
return prev_;
}
value_type& GetPrev() {
return prev_;
}
const value_type& GetNext() const {
return next_;
}
value_type& GetNext() {
return next_;
}
private:
value_type prev_;
value_type next_;
template <typename T>
friend class IntrusiveList;
};
}
@@ -0,0 +1,152 @@
#pragma once
#include <SDL2/SDL.h>
#include <fstream>
#include <mutex>
#include <string>
namespace frostbite2D {
class StartupTrace {
public:
static constexpr bool enabled() {
#ifndef NDEBUG
return true;
#else
return false;
#endif
}
static void reset(const char* label = nullptr) {
if (!enabled()) {
return;
}
Uint64 now = SDL_GetPerformanceCounter();
std::string line;
{
std::lock_guard<std::mutex> lock(mutex());
startCounter() = now;
if (label && label[0] != '\0') {
line = std::string("[Startup] reset: ") + label;
clearLogFileUnlocked();
writeLineUnlocked(line);
} else {
clearLogFileUnlocked();
}
}
if (!line.empty()) {
SDL_Log("%s", line.c_str());
}
}
static double totalElapsedMs() {
if (!enabled()) {
return 0.0;
}
Uint64 start = 0;
{
std::lock_guard<std::mutex> lock(mutex());
start = startCounter();
}
if (start == 0) {
return 0.0;
}
Uint64 now = SDL_GetPerformanceCounter();
Uint64 frequency = SDL_GetPerformanceFrequency();
if (frequency == 0) {
return 0.0;
}
return static_cast<double>(now - start) * 1000.0 /
static_cast<double>(frequency);
}
static void mark(const char* label) {
if (!enabled()) {
return;
}
char buffer[256] = {};
SDL_snprintf(buffer, sizeof(buffer),
"[Startup] %s reached at %.2f ms (thread=%u)",
label ? label : "<unnamed>", totalElapsedMs(), SDL_ThreadID());
logLine(buffer);
SDL_Log("%s", buffer);
}
static void logLine(const std::string& line) {
if (!enabled()) {
return;
}
std::lock_guard<std::mutex> lock(mutex());
writeLineUnlocked(line);
}
private:
static Uint64& startCounter() {
static Uint64 counter = 0;
return counter;
}
static std::mutex& mutex() {
static std::mutex value;
return value;
}
static const char* logFilePath() {
return "startup_trace.log";
}
static void clearLogFileUnlocked() {
std::ofstream stream(logFilePath(), std::ios::trunc);
}
static void writeLineUnlocked(const std::string& line) {
std::ofstream stream(logFilePath(), std::ios::app);
if (!stream) {
return;
}
stream << line << '\n';
}
};
class ScopedStartupTrace {
public:
explicit ScopedStartupTrace(const char* label)
: label_(label ? label : "<unnamed>"),
startCounter_(SDL_GetPerformanceCounter()) {}
~ScopedStartupTrace() {
if (!StartupTrace::enabled()) {
return;
}
Uint64 now = SDL_GetPerformanceCounter();
Uint64 frequency = SDL_GetPerformanceFrequency();
double elapsedMs = 0.0;
if (frequency != 0) {
elapsedMs = static_cast<double>(now - startCounter_) * 1000.0 /
static_cast<double>(frequency);
}
char buffer[256] = {};
SDL_snprintf(buffer, sizeof(buffer),
"[Startup] %s took %.2f ms (total %.2f ms, thread=%u)",
label_, elapsedMs, StartupTrace::totalElapsedMs(),
SDL_ThreadID());
StartupTrace::logLine(buffer);
SDL_Log("%s", buffer);
}
private:
const char* label_;
Uint64 startCounter_ = 0;
};
} // namespace frostbite2D