155 lines
3.6 KiB
C++
155 lines
3.6 KiB
C++
#pragma once
|
|
#include <common.hpp>
|
|
#include <type_traits>
|
|
#include <cassert>
|
|
#include <portable_endian_bswap.h>
|
|
#include <fstream>
|
|
|
|
namespace natsukashii::util {
|
|
enum MessageType : u8 {
|
|
INFO, WARN, ERROR
|
|
};
|
|
|
|
template <MessageType messageType = INFO, typename ...Args>
|
|
constexpr void print(const std::string& fmt, Args... args) {
|
|
if constexpr(messageType == ERROR) {
|
|
fmt::print(fmt::emphasis::bold | fg(fmt::color::red), fmt, args...);
|
|
exit(-1);
|
|
} else if constexpr(messageType == WARN) {
|
|
fmt::print(fg(fmt::color::yellow), fmt, args...);
|
|
} else if constexpr(messageType == INFO) {
|
|
fmt::print(fmt, args...);
|
|
}
|
|
}
|
|
|
|
template <typename ...Args>
|
|
constexpr void panic(const std::string& fmt, Args... args) {
|
|
print<ERROR>(fmt, args...);
|
|
}
|
|
|
|
template <typename ...Args>
|
|
constexpr void warn(const std::string& fmt, Args... args) {
|
|
print<WARN>(fmt, args...);
|
|
}
|
|
|
|
template <typename ...Args>
|
|
constexpr void info(const std::string& fmt, Args... args) {
|
|
print(fmt, args...);
|
|
}
|
|
|
|
template <typename T, bool HToBE = false>
|
|
auto GetSwapFunc(T num) -> T {
|
|
if constexpr(sizeof(T) == 2) {
|
|
if constexpr(HToBE) {
|
|
return htobe16(num);
|
|
}
|
|
return be16toh(num);
|
|
} else if constexpr(sizeof(T) == 4) {
|
|
if constexpr(HToBE) {
|
|
return htobe32(num);
|
|
}
|
|
return be32toh(num);
|
|
} else if constexpr(sizeof(T) == 8) {
|
|
if constexpr(HToBE) {
|
|
return htobe64(num);
|
|
}
|
|
return be64toh(num);
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
inline T ReadAccess(u8* data, u32 index) {
|
|
static_assert(sizeof(T) != 2 || sizeof(T) != 4 || sizeof(T) != 8);
|
|
T result = 0;
|
|
memcpy(&result, &data[index], sizeof(T));
|
|
return GetSwapFunc<T>(result);
|
|
}
|
|
|
|
template <typename T>
|
|
inline void WriteAccess(u8* data, u32 index, T val) {
|
|
static_assert(sizeof(T) != 2 || sizeof(T) != 4 || sizeof(T) != 8);
|
|
T temp = GetSwapFunc<T, true>(val);
|
|
memcpy(&data[index], &temp, sizeof(T));
|
|
}
|
|
|
|
#define Z64 0x80371240
|
|
#define N64 0x40123780
|
|
#define V64 0x37804012
|
|
|
|
inline void SwapN64Rom(size_t size, u8* data) {
|
|
u32 endianness;
|
|
memcpy(&endianness, data, 4);
|
|
endianness = be32toh(endianness);
|
|
switch(endianness) {
|
|
case V64:
|
|
for(int i = 0; i < size; i += 2) {
|
|
u16 original = *(u16*)&data[i];
|
|
*(u16*)&data[i] = bswap_16(original);
|
|
}
|
|
break;
|
|
case N64:
|
|
for(int i = 0; i < size; i += 4) {
|
|
u32 original = *(u32*)&data[i];
|
|
*(u32*)&data[i] = bswap_32(original);
|
|
}
|
|
break;
|
|
case Z64: break;
|
|
default:
|
|
panic("Unrecognized rom format! Make sure this is a valid Nintendo 64 ROM dump!\n");
|
|
}
|
|
}
|
|
|
|
template <size_t size, typename T = u8>
|
|
struct CircularBuffer {
|
|
CircularBuffer() : head(0) {
|
|
memset(raw, 0, size * sizeof(T));
|
|
}
|
|
|
|
void PushValue(T val) {
|
|
raw[head & mask] = val;
|
|
head &= mask;
|
|
head++;
|
|
}
|
|
|
|
T PopValue() {
|
|
head--;
|
|
head &= mask;
|
|
return raw[head & mask];
|
|
}
|
|
size_t GetHead() { return head; }
|
|
private:
|
|
T raw[size];
|
|
size_t head;
|
|
static constexpr size_t mask = size - 1;
|
|
};
|
|
|
|
inline size_t NextPow2(size_t num) {
|
|
// Taken from "Bit Twiddling Hacks" by Sean Anderson:
|
|
// https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
|
|
--num;
|
|
num |= num >> 1;
|
|
num |= num >> 2;
|
|
num |= num >> 4;
|
|
num |= num >> 8;
|
|
num |= num >> 16;
|
|
return num + 1;
|
|
}
|
|
|
|
inline void ReadFileBinary(const std::string& path, void* buf) {
|
|
std::ifstream file("external/vert.spv", std::ios::binary);
|
|
file.unsetf(std::ios::skipws);
|
|
if(!file.is_open()) {
|
|
util::panic("Could not load file!\n");
|
|
}
|
|
file.seekg(std::ios::end);
|
|
auto size = file.tellg();
|
|
file.seekg(std::ios::beg);
|
|
if(buf)
|
|
free(buf);
|
|
|
|
buf = calloc(size, 1);
|
|
file.read((char*)buf, size);
|
|
file.close();
|
|
}
|
|
}
|