RenderD7 is now LibRenderD7

This commit is contained in:
2022-07-24 00:55:18 +02:00
parent 3c7c12ef39
commit 6af08275e9
37 changed files with 553 additions and 98 deletions

20
source/Clock.cpp Normal file
View File

@ -0,0 +1,20 @@
#include <renderd7/Clock.hpp>
namespace rnd7 {
////////////////////////////////////////////////////////////
Time Clock::getElapsedTime() const {
return getCurrentTime() - m_startTime;
}
////////////////////////////////////////////////////////////
Time Clock::restart() {
Time now = getCurrentTime();
Time elapsed = now - m_startTime;
m_startTime = now;
return elapsed;
}
}

200
source/Time.cpp Normal file
View File

@ -0,0 +1,200 @@
#include <renderd7/Time.hpp>
namespace rnd7 {
////////////////////////////////////////////////////////////
const Time Time::Zero_;
////////////////////////////////////////////////////////////
Time::Time() :
m_microseconds(0) {
}
////////////////////////////////////////////////////////////
float Time::asSeconds() const {
return m_microseconds / 1000000.f;
}
////////////////////////////////////////////////////////////
int Time::asMilliseconds() const {
return static_cast<int>(m_microseconds / 1000);
}
////////////////////////////////////////////////////////////
long Time::asMicroseconds() const {
return m_microseconds;
}
////////////////////////////////////////////////////////////
Time::Time(long microseconds) :
m_microseconds(microseconds) {
}
////////////////////////////////////////////////////////////
Time seconds(float amount) {
return Time(static_cast<long>(amount * 1000000));
}
////////////////////////////////////////////////////////////
Time milliseconds(int amount) {
return Time(static_cast<long>(amount) * 1000);
}
////////////////////////////////////////////////////////////
Time microseconds(long amount) {
return Time(amount);
}
////////////////////////////////////////////////////////////
bool operator==(Time left, Time right) {
return left.asMicroseconds() == right.asMicroseconds();
}
////////////////////////////////////////////////////////////
bool operator!=(Time left, Time right) {
return left.asMicroseconds() != right.asMicroseconds();
}
////////////////////////////////////////////////////////////
bool operator<(Time left, Time right) {
return left.asMicroseconds() < right.asMicroseconds();
}
////////////////////////////////////////////////////////////
bool operator>(Time left, Time right) {
return left.asMicroseconds() > right.asMicroseconds();
}
////////////////////////////////////////////////////////////
bool operator<=(Time left, Time right) {
return left.asMicroseconds() <= right.asMicroseconds();
}
////////////////////////////////////////////////////////////
bool operator>=(Time left, Time right) {
return left.asMicroseconds() >= right.asMicroseconds();
}
////////////////////////////////////////////////////////////
Time operator-(Time right) {
return microseconds(-right.asMicroseconds());
}
////////////////////////////////////////////////////////////
Time operator+(Time left, Time right) {
return microseconds(left.asMicroseconds() + right.asMicroseconds());
}
////////////////////////////////////////////////////////////
Time &operator+=(Time &left, Time right) {
return left = left + right;
}
////////////////////////////////////////////////////////////
Time operator-(Time left, Time right) {
return microseconds(left.asMicroseconds() - right.asMicroseconds());
}
////////////////////////////////////////////////////////////
Time &operator-=(Time &left, Time right) {
return left = left - right;
}
////////////////////////////////////////////////////////////
Time operator*(Time left, float right) {
return seconds(left.asSeconds() * right);
}
////////////////////////////////////////////////////////////
Time operator*(Time left, long right) {
return microseconds(left.asMicroseconds() * right);
}
////////////////////////////////////////////////////////////
Time operator*(float left, Time right) {
return right * left;
}
////////////////////////////////////////////////////////////
Time operator*(long left, Time right) {
return right * left;
}
////////////////////////////////////////////////////////////
Time &operator*=(Time &left, float right) {
return left = left * right;
}
////////////////////////////////////////////////////////////
Time &operator*=(Time &left, long right) {
return left = left * right;
}
////////////////////////////////////////////////////////////
Time operator/(Time left, float right) {
return seconds(left.asSeconds() / right);
}
////////////////////////////////////////////////////////////
Time operator/(Time left, long right) {
return microseconds(left.asMicroseconds() / right);
}
////////////////////////////////////////////////////////////
Time &operator/=(Time &left, float right) {
return left = left / right;
}
////////////////////////////////////////////////////////////
Time &operator/=(Time &left, long right) {
return left = left / right;
}
////////////////////////////////////////////////////////////
float operator/(Time left, Time right) {
return left.asSeconds() / right.asSeconds();
}
////////////////////////////////////////////////////////////
Time operator%(Time left, Time right) {
return microseconds(left.asMicroseconds() % right.asMicroseconds());
}
////////////////////////////////////////////////////////////
Time &operator%=(Time &left, Time right) {
return left = left % right;
}
}

106
source/bmpconverter.cpp Normal file
View File

@ -0,0 +1,106 @@
#include <renderd7/bmpconverter.hpp>
namespace BitmapConverter{
//returns 0 if all went ok, non-0 if error
//output image is always given in RGBA (with alpha channel), even if it's a BMP without alpha channel
unsigned decodeBMP(std::vector<unsigned char>& image, unsigned& w, unsigned& h, const std::vector<unsigned char>& bmp) {
static const unsigned MINHEADER = 54; //minimum BMP header size
if(bmp.size() < MINHEADER) return -1;
if(bmp[0] != 'B' || bmp[1] != 'M') return 1; //It's not a BMP file if it doesn't start with marker 'BM'
unsigned pixeloffset = bmp[10] + 256 * bmp[11]; //where the pixel data starts
//read width and height from BMP header
w = bmp[18] + bmp[19] * 256;
h = bmp[22] + bmp[23] * 256;
//read number of channels from BMP header
if(bmp[28] != 24 && bmp[28] != 32) return 2; //only 24-bit and 32-bit BMPs are supported.
unsigned numChannels = bmp[28] / 8;
//The amount of scanline bytes is width of image times channels, with extra bytes added if needed
//to make it a multiple of 4 bytes.
unsigned scanlineBytes = w * numChannels;
if(scanlineBytes % 4 != 0) scanlineBytes = (scanlineBytes / 4) * 4 + 4;
unsigned dataSize = scanlineBytes * h;
if(bmp.size() < dataSize + pixeloffset) return 3; //BMP file too small to contain all pixels
image.resize(w * h * 4);
/*
There are 3 differences between BMP and the raw image buffer for LodePNG:
-it's upside down
-it's in BGR instead of RGB format (or BRGA instead of RGBA)
-each scanline has padding bytes to make it a multiple of 4 if needed
The 2D for loop below does all these 3 conversions at once.
*/
for(unsigned y = 0; y < h; y++)
for(unsigned x = 0; x < w; x++) {
//pixel start byte position in the BMP
unsigned bmpos = pixeloffset + (h - y - 1) * scanlineBytes + numChannels * x;
//pixel start byte position in the new raw image
unsigned newpos = 4 * y * w + 4 * x;
if(numChannels == 3) {
image[newpos + 0] = bmp[bmpos + 2]; //R
image[newpos + 1] = bmp[bmpos + 1]; //G
image[newpos + 2] = bmp[bmpos + 0]; //B
image[newpos + 3] = 255; //A
} else {
image[newpos + 0] = bmp[bmpos + 2]; //R
image[newpos + 1] = bmp[bmpos + 1]; //G
image[newpos + 2] = bmp[bmpos + 0]; //B
image[newpos + 3] = bmp[bmpos + 3]; //A
}
}
return 0;
}
std::vector<unsigned char> ConvertFile(std::string filename) {
std::vector<unsigned char> bmp;
lodepng::load_file(bmp, filename);
std::vector<unsigned char> image;
unsigned w, h;
unsigned error = BitmapConverter::decodeBMP(image, w, h, bmp);
if(error) {
std::cout << "BMP decoding error " << error << std::endl;
}
std::vector<unsigned char> png;
error = lodepng::encode(png, image, w, h);
if(error) {
std::cout << "PNG encoding error " << error << ": " << lodepng_error_text(error) << std::endl;
}
return png;
}
std::vector<unsigned char> ConvertData(std::vector<unsigned char> data) {
std::vector<unsigned char> image;
unsigned w, h;
unsigned error = BitmapConverter::decodeBMP(image, w, h, data);
if(error) {
std::cout << "BMP decoding error " << error << std::endl;
}
std::vector<unsigned char> png;
error = lodepng::encode(png, image, w, h);
if(error) {
std::cout << "PNG encoding error " << error << ": " << lodepng_error_text(error) << std::endl;
}
return png;
}
}

98
source/lang.cpp Normal file
View File

@ -0,0 +1,98 @@
#include <renderd7/lang.hpp>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <3ds.h>
static nlohmann::json appJson;
std::string RenderD7::Lang::getSys()
{
u8 language = 1;
CFGU_GetSystemLanguage(&language);
switch(language) {
case 0:
return "jp"; // Japanese
break;
case 1:
return "en"; // English
break;
case 2:
return "fr"; // French
break;
case 3:
return "de"; // German
break;
case 4:
return "it"; // Italian
break;
case 5:
return "es"; // Spanish
break;
case 6:
return "zh-CN"; // Chinese (Simplified)
break;
// case 7:
// return "ko"; // Korean
// break;
// case 8:
// return "nl"; // Dutch
// break;
case 9:
return "pt"; // Portuguese
break;
case 10:
return "ru"; // Russian
break;
case 11:
return "zh-TW"; // Chinese (Traditional)
break;
default:
return "en"; // Fall back to English if missing
break;
}
}
std::string RenderD7::Lang::get(const std::string &key) {
if (!appJson.contains(key)) return key;
return appJson.at(key).get_ref<const std::string&>();
}
void RenderD7::Lang::load(const std::string &lang) {
FILE *values;
if (access(("romfs:/lang/" + lang + "/app.json").c_str(), F_OK) == 0) {
values = fopen(("romfs:/lang/" + lang + "/app.json").c_str(), "rt");
if (values) {
appJson = nlohmann::json::parse(values, nullptr, false);
fclose(values);
}
if (appJson.is_discarded())
appJson = { };
return;
} else {
values = fopen("romfs:/lang/en/app.json", "rt");
if (values) {
appJson = nlohmann::json::parse(values, nullptr, false);
fclose(values);
}
if (appJson.is_discarded())
appJson = { };
return;
}
}

60
source/log.cpp Normal file
View File

@ -0,0 +1,60 @@
#include <renderd7/log.hpp>
#include <memory>
std::string Log::format(const std::string& fmt_str, ...)
{
va_list ap;
char* fp = NULL;
va_start(ap, fmt_str);
vasprintf(&fp, fmt_str.c_str(), ap);
va_end(ap);
std::unique_ptr<char, decltype(free)*> formatted(fp, free);
return std::string(formatted.get());
}
std::string Log::logDate(void)
{
time_t unixTime;
struct tm timeStruct;
time(&unixTime);
localtime_r(&unixTime, &timeStruct);
return format("%04i-%02i-%02i_%02i-%02i-%02i", timeStruct.tm_year + 1900, timeStruct.tm_mon + 1, timeStruct.tm_mday,
timeStruct.tm_hour, timeStruct.tm_min, timeStruct.tm_sec);
}
Log::Log()
{
}
void Log::Init(const char *filename)
{
std::string name = "sdmc:/" + Log::logDate() + filename + ".txt";
this->filename = name.c_str();
if ((access(name.c_str(), F_OK) == 0))
{
}
else
{
FILE* logfile = fopen((name.c_str()), "w");
fclose(logfile);
}
}
void Log::Write(std::string debug_text)
{
std::ofstream logFile;
logFile.open((this->filename), std::ofstream::app);
std::string writeDebug = "[";
writeDebug += logDate();
writeDebug += "] ";
writeDebug += debug_text.c_str();
logFile << writeDebug << std::endl;
logFile.close();
}
Log::~Log()
{
}

1730
source/renderd7.cpp Normal file

File diff suppressed because it is too large Load Diff

130
source/sound.cpp Normal file
View File

@ -0,0 +1,130 @@
#include <renderd7/sound.hpp>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
extern bool isndspinit;
using std::string;
// Reference: http://yannesposito.com/Scratch/en/blog/2010-10-14-Fun-with-wav/
typedef struct _WavHeader {
char magic[4]; // "RIFF"
u32 totallength; // Total file length, minus 8.
char wavefmt[8]; // Should be "WAVEfmt "
u32 format; // 16 for PCM format
u16 pcm; // 1 for PCM format
u16 channels; // Channels
u32 frequency; // Sampling frequency
u32 bytes_per_second;
u16 bytes_by_capture;
u16 bits_per_sample;
char data[4]; // "data"
u32 bytes_in_data;
} WavHeader;
static_assert(sizeof(WavHeader) == 44, "WavHeader size is not 44 bytes.");
sound::sound(const string& path, int channel, bool toloop) {
if (isndspinit){
ndspSetOutputMode(NDSP_OUTPUT_STEREO);
ndspSetOutputCount(2); // Num of buffers
// Reading wav file
FILE* fp = fopen(path.c_str(), "rb");
if (!fp) {
printf("Could not open the WAV file: %s\n", path.c_str());
return;
}
WavHeader wavHeader;
size_t read = fread(&wavHeader, 1, sizeof(wavHeader), fp);
if (read != sizeof(wavHeader)) {
// Short read.
printf("WAV file header is too short: %s\n", path.c_str());
fclose(fp);
return;
}
// Verify the header.
static const char RIFF_magic[4] = {'R','I','F','F'};
if (memcmp(wavHeader.magic, RIFF_magic, sizeof(wavHeader.magic)) != 0) {
// Incorrect magic number.
printf("Wrong file format.\n");
fclose(fp);
return;
}
if (wavHeader.totallength == 0 ||
(wavHeader.channels != 1 && wavHeader.channels != 2) ||
(wavHeader.bits_per_sample != 8 && wavHeader.bits_per_sample != 16)) {
// Unsupported WAV file.
printf("Corrupted wav file.\n");
fclose(fp);
return;
}
// Get the file size.
fseek(fp, 0, SEEK_END);
dataSize = ftell(fp) - sizeof(wavHeader);
// Allocating and reading samples
data = static_cast<u8*>(linearAlloc(dataSize));
fseek(fp, 44, SEEK_SET);
fread(data, 1, dataSize, fp);
fclose(fp);
dataSize /= 2; // FIXME: 16-bit or stereo?
// Find the right format
u16 ndspFormat;
if (wavHeader.bits_per_sample == 8) {
ndspFormat = (wavHeader.channels == 1) ?
NDSP_FORMAT_MONO_PCM8 :
NDSP_FORMAT_STEREO_PCM8;
} else {
ndspFormat = (wavHeader.channels == 1) ?
NDSP_FORMAT_MONO_PCM16 :
NDSP_FORMAT_STEREO_PCM16;
}
ndspChnReset(channel);
ndspChnSetInterp(channel, NDSP_INTERP_NONE);
ndspChnSetRate(channel, float(wavHeader.frequency));
ndspChnSetFormat(channel, ndspFormat);
// Create and play a wav buffer
memset(&waveBuf, 0, sizeof(waveBuf));
waveBuf.data_vaddr = reinterpret_cast<u32*>(data);
waveBuf.nsamples = dataSize / (wavHeader.bits_per_sample >> 3);
waveBuf.looping = toloop;
waveBuf.status = NDSP_WBUF_FREE;
chnl = channel;}
}
sound::~sound() {
if (isndspinit){
waveBuf.data_vaddr = 0;
waveBuf.nsamples = 0;
waveBuf.looping = false;
waveBuf.status = 0;
ndspChnWaveBufClear(chnl);
if (data) {
linearFree(data);
}}
}
void sound::play() {
if (isndspinit){
if (!data) return;
DSP_FlushDataCache(data, dataSize);
ndspChnWaveBufAdd(chnl, &waveBuf);}
}
void sound::stop() {
if (isndspinit){
if (!data) return;
ndspChnWaveBufClear(chnl);}
}

81
source/thread.cpp Normal file
View File

@ -0,0 +1,81 @@
#include <renderd7/thread.hpp>
namespace RenderD7 {
void Threads::Exit()
{
}
Thread::Thread() :
m_started(false),
m_running(false) { /* do nothing */ }
Thread::Thread(std::function<void(RenderD7::Parameter)> t_function, RenderD7::Parameter t_parameter, bool t_autostart, bool t_detached, unsigned long long int t_stackSize) :
m_started(false),
m_running(false) {
initialize(t_function, t_parameter, t_autostart, t_detached, t_stackSize);
}
Thread::~Thread() {
join();
if (m_started) threadFree(m_thread);
}
void Thread::initialize(std::function<void(RenderD7::Parameter)> t_function, RenderD7::Parameter t_parameter, bool t_autostart, bool t_detached, unsigned long long int t_stackSize) {
m_stackSize = t_stackSize;
m_data.m_parameter = t_parameter;
m_data.m_function = t_function;
m_data.m_running = &m_running;
if (t_autostart) {
start(t_detached);
}
}
void Thread::setStackSize(unsigned long long int t_stackSize) {
m_stackSize = t_stackSize;
}
void Thread::start(bool t_detached) {
if (!m_running) {
m_started = true;
m_running = true;
s32 prio;
svcGetThreadPriority(&prio, CUR_THREAD_HANDLE);
m_thread = threadCreate(threadFunction, &m_data, m_stackSize, prio + 1, -2, t_detached);
}
}
void Thread::kill() {
threadDetach(m_thread);
m_running = false;
m_started = false;
}
void Thread::join(long long unsigned int t_timeout) {
if (m_running) {
threadJoin(m_thread, t_timeout);
threadFree(m_thread);
m_running = false;
m_started = false;
}
}
bool Thread::isRunning() {
return m_running;
}
void Thread::sleep() {
svcSleepThread(0);
}
void Thread::sleep(int t_milliseconds) {
svcSleepThread(1000000 * t_milliseconds);
}
// private methods
void Thread::threadFunction(void* arg) {
RenderD7::Thread::ThreadData data = *static_cast<RenderD7::Thread::ThreadData*>(arg);
data.m_function(data.m_parameter);
*data.m_running = false;
}
}