#ifndef SDLUTIL_H #define SDLUTIL_H #ifndef __EMSCRIPTEN__ #include #endif #include #include #include #include struct AtomicFlag { AtomicFlag() { clear(); } void set() { #ifdef __EMSCRIPTEN__ atom = true; #else SDL_AtomicSet(&atom, 1); #endif } void clear() { #ifdef __EMSCRIPTEN__ atom = false; #else SDL_AtomicSet(&atom, 0); #endif } operator bool() const { #ifdef __EMSCRIPTEN__ return atom; #else return SDL_AtomicGet(&atom); #endif } private: #ifdef __EMSCRIPTEN__ bool atom = false; #else mutable SDL_atomic_t atom; #endif }; template int __sdlThreadFun(void *obj) { (static_cast(obj)->*func)(); return 0; } template SDL_Thread *createSDLThread(C *obj, const std::string &name = std::string()) { return SDL_CreateThread((__sdlThreadFun), 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 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