mkxp-freebird/src/sdl-util.h

162 lines
2.6 KiB
C++

#ifndef SDLUTIL_H
#define SDLUTIL_H
#include <SDL_atomic.h>
#include <SDL_thread.h>
#include <SDL_rwops.h>
#include <string>
#include <iostream>
struct AtomicFlag
{
AtomicFlag()
{
clear();
}
void set()
{
SDL_AtomicSet(&atom, 1);
}
void clear()
{
SDL_AtomicSet(&atom, 0);
}
operator bool() const
{
return SDL_AtomicGet(&atom);
}
private:
mutable SDL_atomic_t atom;
};
template<class C, void (C::*func)()>
int __sdlThreadFun(void *obj)
{
(static_cast<C*>(obj)->*func)();
return 0;
}
template<class C, void (C::*func)()>
SDL_Thread *createSDLThread(C *obj, const std::string &name = std::string())
{
return SDL_CreateThread(__sdlThreadFun<C, func>, name.c_str(), obj);
}
/* On Android, SDL_RWFromFile always opens files from inside
* the apk asset folder even when a file with same name exists
* on the physical filesystem. This wrapper attempts to open a
* real file first before falling back to the assets folder */
static inline
SDL_RWops *RWFromFile(const char *filename,
const char *mode)
{
FILE *f = fopen(filename, mode);
if (!f)
return SDL_RWFromFile(filename, mode);
return SDL_RWFromFP(f, SDL_TRUE);
}
inline bool readFileSDL(const char *path,
std::string &out)
{
SDL_RWops *f = RWFromFile(path, "rb");
if (!f)
return false;
long size = SDL_RWsize(f);
size_t back = out.size();
out.resize(back+size);
size_t read = SDL_RWread(f, &out[back], 1, size);
SDL_RWclose(f);
if (read != (size_t) size)
out.resize(back+read);
return true;
}
template<size_t bufSize = 248, size_t pbSize = 8>
class SDLRWBuf : public std::streambuf
{
public:
SDLRWBuf(SDL_RWops *ops)
: ops(ops)
{
char *end = buf + bufSize + pbSize;
setg(end, end, end);
}
private:
int_type underflow()
{
if (!ops)
return traits_type::eof();
if (gptr() < egptr())
return traits_type::to_int_type(*gptr());
char *base = buf;
char *start = base;
if (eback() == base)
{
memmove(base, egptr() - pbSize, pbSize);
start += pbSize;
}
size_t n = SDL_RWread(ops, start, 1, bufSize - (start - base));
if (n == 0)
return traits_type::eof();
setg(base, start, start + n);
return underflow();
}
SDL_RWops *ops;
char buf[bufSize+pbSize];
};
class SDLRWStream
{
public:
SDLRWStream(const char *filename,
const char *mode)
: ops(RWFromFile(filename, mode)),
buf(ops),
s(&buf)
{}
~SDLRWStream()
{
if (ops)
SDL_RWclose(ops);
}
operator bool() const
{
return ops != 0;
}
std::istream &stream()
{
return s;
}
private:
SDL_RWops *ops;
SDLRWBuf<> buf;
std::istream s;
};
#endif // SDLUTIL_H