Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
97 KB
Referenced Files
None
Subscribers
None
diff --git a/util/file-system.cpp b/util/file-system.cpp
index ef3e07d8..66f6ecb4 100644
--- a/util/file-system.cpp
+++ b/util/file-system.cpp
@@ -1,689 +1,690 @@
#ifdef USE_ALLEGRO
#include <allegro.h>
/* FIXME: replace with <winalleg.h> */
#ifdef _WIN32
#define BITMAP dummyBITMAP
#include <windows.h>
#undef BITMAP
#endif
#endif
#include <algorithm>
#include "funcs.h"
#include "file-system.h"
#include "thread.h"
#include "system.h"
#include "globals.h"
#include <dirent.h>
#include <sstream>
#include <exception>
#include <string>
#include <fstream>
#include <ostream>
#ifndef USE_ALLEGRO
/* some sfl symbols conflict with allegro */
#include "sfl/sfl.h"
#include "sfl/sfldir.h"
#endif
#ifdef _WIN32
#define _WIN32_IE 0x400
#include <shlobj.h>
#endif
using namespace std;
/* some filesystem access can only be done by one thread at a time. specifically, sfl
* has its own allocator that is meant to be used in a single-threaded manner.
* rather than try to add locks to sfl we just wrap all sfl calls with a lock.
*
* initialize() must be called to initialize this lock
*/
-Util::Thread::Lock lock;
+// Util::Thread::Lock lock;
-namespace Filesystem{
+namespace Storage{
+
+/* remove extra path separators (/) */
+string sanitize(string path){
+ size_t double_slash = path.find("//");
+ while (double_slash != string::npos){
+ path.erase(double_slash, 1);
+ double_slash = path.find("//");
+ }
+ return path;
+}
+
+static int invert(int c){
+ if (c == '\\'){
+ return '/';
+ }
+ return c;
+}
+
+std::string invertSlashes(string str){
+ transform(str.begin(), str.end(), str.begin(), invert);
+ return str;
+}
Exception::Exception(const std::string & where, int line, const std::string & file):
Exc::Base(where, line),
reason(file){
}
Exception::Exception(const std::string & where, int line, const Exc::Base & nested, const std::string & file):
Exc::Base(where, line, nested),
reason(file){
}
Exception::Exception(const Exception & copy):
Exc::Base(copy),
reason(copy.reason){
}
Exception::~Exception() throw (){
}
const std::string Exception::getReason() const {
return reason;
}
NotFound::NotFound(const std::string & where, int line, const std::string & file):
Exception(where, line, file + string(" was not found")){
}
NotFound::NotFound(const std::string & where, int line, const Exc::Base & nested, const std::string & file):
Exception(where, line, nested, file + string(" was not found")){
}
NotFound::NotFound(const NotFound & copy):
Exception(copy){
}
NotFound::~NotFound() throw (){
}
IllegalPath::IllegalPath(const std::string & where, int line, const std::string & file):
Exception(where, line, file){
}
IllegalPath::IllegalPath(const std::string & where, int line, const Exc::Base & nested, const std::string & file):
Exception(where, line, nested, file){
}
IllegalPath::IllegalPath(const IllegalPath & copy):
Exception(copy){
}
IllegalPath::~IllegalPath() throw(){
}
-#ifdef _WIN32
-AbsolutePath userDirectory(){
- ostringstream str;
- char path[MAX_PATH];
- SHGetSpecialFolderPathA(0, path, CSIDL_APPDATA, false);
- str << path << "/paintown/";
- return AbsolutePath(str.str());
-}
-
-AbsolutePath configFile(){
- ostringstream str;
- char path[MAX_PATH];
- SHGetSpecialFolderPathA(0, path, CSIDL_APPDATA, false);
- str << path << "/paintown_configuration.txt";
- return AbsolutePath(str.str());
-}
-#else
-AbsolutePath configFile(){
- ostringstream str;
- /* what if HOME isn't set? */
- str << getenv("HOME") << "/.paintownrc";
- return AbsolutePath(str.str());
+System::System(){
}
-AbsolutePath userDirectory(){
- ostringstream str;
- /* what if HOME isn't set? */
- str << getenv("HOME") << "/.paintown/";
- return AbsolutePath(str.str());
+System::~System(){
}
-#endif
-
-static AbsolutePath lookup(const RelativePath path){
- /* first try the main data directory */
- AbsolutePath final = Util::getDataPath2().join(path);
- if (System::readable(final.path())){
- return final;
- }
- /* then try the user directory, like ~/.paintown */
- final = userDirectory().join(path);
- if (System::readable(final.path())){
- return final;
- }
- /* then just look in the cwd */
- if (System::readable(path.path())){
- return AbsolutePath(path.path());
+
+System & instance(){
+ if (self != NULL){
+ return *self;
}
-
- ostringstream out;
- out << "Cannot find " << path.path() << ". I looked in '" << Util::getDataPath2().join(path).path() << "', '" << userDirectory().join(path).path() << "', and '" << path.path() << "'";
-
- throw NotFound(__FILE__, __LINE__, out.str());
+ self = new Filesystem(Util::getDataPath2());
+ return *self;
}
+Util::ReferenceCount<System> self;
-AbsolutePath lookupInsensitive(const AbsolutePath & directory, const RelativePath & path){
- if (path.path() == ""){
- throw NotFound(__FILE__, __LINE__, "Given empty path to lookup");
- }
- if (path.path() == "."){
- return directory;
- }
- if (path.path() == ".."){
- return directory.getDirectory();
- }
- if (path.isFile()){
- vector<AbsolutePath> all = getFiles(directory, "*", true);
- for (vector<AbsolutePath>::iterator it = all.begin(); it != all.end(); it++){
- AbsolutePath & check = *it;
- if (InsensitivePath(check.getFilename()) == path){
- return check;
- }
- }
-
- ostringstream out;
- out << "Cannot find " << path.path() << " in " << directory.path();
- throw NotFound(__FILE__, __LINE__, out.str());
- } else {
- return lookupInsensitive(lookupInsensitive(directory, path.firstDirectory()), path.removeFirstDirectory());
- }
+const string & Path::path() const {
+ return mypath;
}
-static vector<AbsolutePath> findDirectoriesIn(const AbsolutePath & path){
- vector<AbsolutePath> dirs;
- DIR * dir = opendir(path.path().c_str());
- if (dir == NULL){
- return dirs;
- }
-
- struct dirent * entry = readdir(dir);
- while (entry != NULL){
- if (string(entry->d_name) != "." && string(entry->d_name) != ".."){
- string total = path.path() + "/" + entry->d_name;
- if (System::isDirectory(total)){
- dirs.push_back(AbsolutePath(total));
- }
- }
- entry = readdir(dir);
- }
-
- closedir(dir);
-
- return dirs;
+bool Path::isEmpty() const {
+ return mypath.empty();
}
-
-vector<AbsolutePath> findDirectories(const RelativePath & path){
- typedef vector<AbsolutePath> Paths;
- Paths dirs;
-
- Paths main_dirs = findDirectoriesIn(Util::getDataPath2().join(path));
- Paths user_dirs = findDirectoriesIn(userDirectory().join(path));
- Paths here_dirs = findDirectoriesIn(Filesystem::AbsolutePath(path.path()));
-
- dirs.insert(dirs.end(), main_dirs.begin(), main_dirs.end());
- dirs.insert(dirs.end(), user_dirs.begin(), user_dirs.end());
- dirs.insert(dirs.end(), here_dirs.begin(), here_dirs.end());
-
- return dirs;
+
+Path::~Path(){
}
-/* a/b/c/ -> a/b/c */
-static string removeTrailingSlash(string str){
- while (str.size() > 0 && str[str.size() - 1] == '/'){
- str = str.erase(str.size() - 1);
- }
- return str;
+Path::Path(){
}
-
-vector<AbsolutePath> getFiles(const AbsolutePath & dataPath, const string & find, bool caseInsensitive){
-#ifdef USE_ALLEGRO
- struct al_ffblk info;
- vector<AbsolutePath> files;
-
- if ( al_findfirst( (dataPath.path() + "/" + find).c_str(), &info, FA_ALL ) != 0 ){
- return files;
- }
- files.push_back(AbsolutePath(dataPath.path() + "/" + string(info.name)));
- while ( al_findnext( &info ) == 0 ){
- files.push_back(AbsolutePath(dataPath.path() + "/" + string(info.name)));
- }
- al_findclose( &info );
- return files;
-#else
- Util::Thread::acquireLock(&lock);
- vector<AbsolutePath> files;
- DIRST sflEntry;
- // bool ok = open_dir(&sflEntry, removeTrailingSlash(dataPath.path()).c_str());
- bool ok = open_dir(&sflEntry, dataPath.path().c_str());
- while (ok){
- if (file_matches(sflEntry.file_name, find.c_str())){
- files.push_back(AbsolutePath(dataPath.path() + "/" + string(sflEntry.file_name)));
- }
- ok = read_dir(&sflEntry);
- }
- close_dir(&sflEntry);
- // Global::debug(0) << "Warning: Filesystem::getFiles() is not implemented yet for SDL" << endl;
- Util::Thread::releaseLock(&lock);
- return files;
-#endif
+Path::Path(const std::string & path):
+mypath(sanitize(invertSlashes(path))){
}
-template <class X>
-static void append(vector<X> & destination, const vector<X> & source){
- /*
- for (typename vector<X>::const_iterator it = source.begin(); it != source.end(); it++){
- destination.push_back(*it);
- }
- */
- copy(source.begin(), source.end(), back_insert_iterator<vector<X> >(destination));
-}
-
-void initialize(){
- Util::Thread::initializeLock(&lock);
-}
-
-static vector<AbsolutePath> getAllDirectories(const AbsolutePath & path){
- vector<AbsolutePath> all = findDirectoriesIn(path);
- vector<AbsolutePath> final;
- append(final, all);
- for (vector<AbsolutePath>::iterator it = all.begin(); it != all.end(); it++){
- vector<AbsolutePath> more = getAllDirectories(*it);
- append(final, more);
- }
- return final;
+Path::Path(const Path & path):
+mypath(sanitize(invertSlashes(path.path()))){
}
-vector<AbsolutePath> getFilesRecursive(const AbsolutePath & dataPath, const string & find, bool caseInsensitive){
- vector<AbsolutePath> directories = getAllDirectories(dataPath);
- directories.push_back(dataPath);
- vector<AbsolutePath> files;
- for (vector<AbsolutePath>::iterator it = directories.begin(); it != directories.end(); it++){
- vector<AbsolutePath> found = getFiles(*it, find, caseInsensitive);
- append(files, found);
- }
- return files;
+RelativePath::RelativePath(){
}
-/* remove extra path separators (/) */
-string sanitize(string path){
- size_t double_slash = path.find("//");
- while (double_slash != string::npos){
- path.erase(double_slash, 1);
- double_slash = path.find("//");
+RelativePath::RelativePath(const std::string & path):
+Path(path){
+ if (! path.empty() && path[0] == '/'){
+ ostringstream out;
+ out << "Relative path '" << path << "' cannot start with a /. Only absolute paths can start with /";
+ throw IllegalPath(__FILE__, __LINE__, out.str());
}
- return path;
}
-/*
-std::string find(const std::string path){
- if (path.length() == 0){
- throw NotFound("No path given");
- }
- if (path[0] == '/'){
- string str(path);
- str.erase(0, 1);
- string out = lookup(str);
- if (System::isDirectory(out)){
- return sanitize(out + "/");
+/* a/b/c/d -> b/c/d */
+std::string stripFirstDir(const std::string & str){
+ if (str.find("/") != std::string::npos || str.find( "\\") != std::string::npos){
+ std::string temp = str;
+ size_t rem = temp.find("/");
+ if (rem != std::string::npos){
+ return str.substr(rem+1,str.size());
}
- return sanitize(out);
- }
- string out = lookup(path);
- if (System::isDirectory(out)){
- return sanitize(out + "/");
- }
- return sanitize(out);
-}
-*/
-
-AbsolutePath find(const RelativePath & path){
- if (path.isEmpty()){
- throw NotFound(__FILE__, __LINE__, "No path given");
- }
-
- AbsolutePath out = lookup(path);
- if (System::isDirectory(out.path())){
- return AbsolutePath(out.path() + "/");
- }
- return AbsolutePath(out.path());
-}
-
-AbsolutePath findInsensitive(const RelativePath & path){
- try{
- /* try sensitive lookup first */
- return lookup(path);
- } catch (const NotFound & fail){
- }
- /* get the base directory */
- AbsolutePath directory = lookup(path.getDirectory());
- return lookupInsensitive(directory, path.getFilename());
-}
-
-bool exists(const RelativePath & path){
- try{
- AbsolutePath absolute = find(path);
- return true;
- } catch (const NotFound & found){
- return false;
- }
-}
-
-bool exists(const AbsolutePath & path){
- return System::readable(path.path());
-}
-
-RelativePath cleanse(const AbsolutePath & path){
- string str = path.path();
- if (str.find(Util::getDataPath2().path()) == 0){
- str.erase(0, Util::getDataPath2().path().length());
- } else if (str.find(userDirectory().path()) == 0){
- str.erase(0, userDirectory().path().length());
- }
- return RelativePath(str);
-}
-
-static string joinPath(const vector<string> & paths){
- ostringstream out;
- bool first = true;
- for (vector<string>::const_iterator it = paths.begin(); it != paths.end(); it++){
- if (!first){
- out << '/';
+ rem = temp.find("\\");
+ if( rem != std::string::npos ){
+ return str.substr(rem+1,str.size());
}
- out << *it;
- first = false;
}
- return out.str();
+ return str;
}
static vector<string> splitPath(string path){
vector<string> all;
if (path.size() > 0 && path[0] == '/'){
all.push_back("/");
}
size_t found = path.find('/');
while (found != string::npos){
if (found > 0){
all.push_back(path.substr(0, found));
}
path.erase(0, found + 1);
found = path.find('/');
}
if (path.size() != 0){
all.push_back(path);
}
return all;
}
+static string joinPath(const vector<string> & paths){
+ ostringstream out;
+ bool first = true;
+ for (vector<string>::const_iterator it = paths.begin(); it != paths.end(); it++){
+ if (!first){
+ out << '/';
+ }
+ out << *it;
+ first = false;
+ }
+ return out.str();
+}
+
/* a/b/c/d -> a/b/c
* a/b/c/d/ -> a/b/c
*/
static string dirname(string path){
vector<string> paths = splitPath(path);
if (paths.size() > 1){
paths.pop_back();
return joinPath(paths);
} else if (paths.size() == 1){
if (paths[0] == "/"){
return "/";
}
return ".";
} else {
return ".";
}
/*
while (path.size() > 0 && path[path.size() - 1] == '/'){
path.erase(path.size() - 1);
}
if (path.find("/") != string::npos ||
path.find("\\") != string::npos){
size_t rem = path.find_last_of("/");
if (rem != string::npos){
return path.substr(0, rem + 1);
}
rem = path.find_last_of("\\");
if (rem != string::npos){
- return path.substr(0, rem + 1);
- }
- }
-
- return "";
- */
-}
-
-/* a/b/c/d -> b/c/d */
-std::string stripFirstDir(const std::string & str){
- if (str.find("/") != std::string::npos || str.find( "\\") != std::string::npos){
- std::string temp = str;
- size_t rem = temp.find("/");
- if (rem != std::string::npos){
- return str.substr(rem+1,str.size());
- }
- rem = temp.find("\\");
- if( rem != std::string::npos ){
- return str.substr(rem+1,str.size());
- }
- }
- return str;
-}
-
-/* a/b/c/d -> d */
-std::string stripDir(const std::string & str){
- if (str.find("/") != std::string::npos || str.find( "\\") != std::string::npos){
- std::string temp = str;
- size_t rem = temp.find_last_of( "/" );
- if (rem != std::string::npos){
- return str.substr(rem+1,str.size());
- }
- rem = temp.find_last_of( "\\" );
- if( rem != std::string::npos ){
- return str.substr(rem+1,str.size());
- }
- }
- return str;
-}
-
-std::string removeExtension(const std::string & str){
- if (str.find(".") != std::string::npos){
- return str.substr(0, str.find_last_of("."));
- }
- return str;
-}
-
-const string & Path::path() const {
- return mypath;
-}
-
-bool Path::isEmpty() const {
- return mypath.empty();
-}
-
-Path::~Path(){
-}
-
-Path::Path(){
-}
-
-static int invert(int c){
- if (c == '\\'){
- return '/';
- }
- return c;
-}
-
-std::string invertSlashes(string str){
- transform(str.begin(), str.end(), str.begin(), invert);
- return str;
-
- /*
- string tempStr = str;
- if (tempStr.find('\\') != string::npos){
- for (int i = tempStr.size()-1; i>-1; --i){
- if (tempStr[i] == '\\'){
- tempStr[i] = '/';
- }
- }
- }
-
- return tempStr;
- */
-}
-
-Path::Path(const std::string & path):
-mypath(sanitize(invertSlashes(path))){
-}
-
-Path::Path(const Path & path):
-mypath(sanitize(invertSlashes(path.path()))){
-}
-
-RelativePath::RelativePath(){
-}
-
-RelativePath::RelativePath(const std::string & path):
-Path(path){
- if (! path.empty() && path[0] == '/'){
- ostringstream out;
- out << "Relative path '" << path << "' cannot start with a /. Only absolute paths can start with /";
- throw IllegalPath(__FILE__, __LINE__, out.str());
+ return path.substr(0, rem + 1);
+ }
}
+
+ return "";
+ */
}
RelativePath::RelativePath(const RelativePath & path):
Path(path){
}
RelativePath RelativePath::removeFirstDirectory() const {
return RelativePath(stripFirstDir(path()));
}
bool RelativePath::isFile() const {
vector<string> paths = splitPath(path());
return paths.size() == 1;
}
RelativePath RelativePath::firstDirectory() const {
vector<string> paths = splitPath(path());
if (paths.size() > 1){
return RelativePath(paths[0]);
}
return RelativePath();
}
RelativePath RelativePath::getDirectory() const {
return RelativePath(dirname(path()));
}
RelativePath RelativePath::getFilename() const {
return RelativePath(stripDir(path()));
}
bool RelativePath::operator<(const RelativePath & path) const {
return this->path() < path.path();
}
bool RelativePath::operator==(const RelativePath & path) const {
return this->path() == path.path();
}
RelativePath RelativePath::join(const RelativePath & him) const {
return RelativePath(path() + "/" + him.path());
}
RelativePath & RelativePath::operator=(const RelativePath & copy){
setPath(copy.path());
return *this;
}
AbsolutePath::AbsolutePath(){
}
AbsolutePath::AbsolutePath(const std::string & path):
Path(path){
}
AbsolutePath::AbsolutePath(const AbsolutePath & path):
Path(path){
}
AbsolutePath & AbsolutePath::operator=(const AbsolutePath & copy){
setPath(copy.path());
return *this;
}
bool AbsolutePath::operator==(const AbsolutePath & path) const {
return this->path() == path.path();
}
bool AbsolutePath::operator<(const AbsolutePath & path) const {
return this->path() < path.path();
}
AbsolutePath AbsolutePath::getDirectory() const {
return AbsolutePath(dirname(path()));
}
AbsolutePath AbsolutePath::getFilename() const {
return AbsolutePath(stripDir(path()));
}
AbsolutePath AbsolutePath::join(const RelativePath & path) const {
return AbsolutePath(this->path() + "/" + path.path());
}
InsensitivePath::InsensitivePath(const Path & what):
Path(what){
}
bool InsensitivePath::operator==(const Path & path) const {
return Util::upperCaseAll(this->path()) == Util::upperCaseAll(path.path());
}
+std::string removeExtension(const std::string & str){
+ if (str.find(".") != std::string::npos){
+ return str.substr(0, str.find_last_of("."));
+ }
+ return str;
+}
+
/* will read upto 'length' bytes unless a null byte is seen first */
string EndianReader::readStringX(int length){
ostringstream out;
uint8_t letter = readByte1();
while (letter != 0 && length > 0){
out << letter;
letter = readByte1();
length -= 1;
}
return out.str();
}
/* unconditionally reads 'length' bytes */
std::string EndianReader::readString2(int length){
ostringstream out;
vector<uint8_t> bytes = readBytes(length);
for (vector<uint8_t>::iterator it = bytes.begin(); it != bytes.end(); it++){
char byte = *it;
if (byte == 0){
break;
}
out << *it;
}
return out.str();
}
void EndianReader::seekEnd(streamoff where){
stream.seekg(where, ios::end);
}
void EndianReader::seek(streampos where){
stream.seekg(where);
}
int EndianReader::position(){
return stream.tellg();
}
void EndianReader::readBytes(uint8_t * out, int length){
stream.read((char*) out, length);
}
vector<uint8_t> EndianReader::readBytes(int length){
vector<uint8_t> bytes;
for (int i = 0; i < length; i++){
uint8_t byte = 0;
stream.read((char*) &byte, 1);
if (stream.eof()){
throw Eof();
} else {
}
bytes.push_back(byte);
}
return bytes;
}
+/* a/b/c/d -> d */
+std::string stripDir(const std::string & str){
+ if (str.find("/") != std::string::npos || str.find( "\\") != std::string::npos){
+ std::string temp = str;
+ size_t rem = temp.find_last_of( "/" );
+ if (rem != std::string::npos){
+ return str.substr(rem+1,str.size());
+ }
+ rem = temp.find_last_of( "\\" );
+ if( rem != std::string::npos ){
+ return str.substr(rem+1,str.size());
+ }
+ }
+ return str;
+}
+
+}
+
+Filesystem::Filesystem(const AbsolutePath & path):
+dataPath(path){
+}
+
+#ifdef _WIN32
+Filesystem::AbsolutePath Filesystem::userDirectory(){
+ ostringstream str;
+ char path[MAX_PATH];
+ SHGetSpecialFolderPathA(0, path, CSIDL_APPDATA, false);
+ str << path << "/paintown/";
+ return Filesystem::AbsolutePath(str.str());
+}
+
+Filesystem::AbsolutePath Filesystem::configFile(){
+ ostringstream str;
+ char path[MAX_PATH];
+ SHGetSpecialFolderPathA(0, path, CSIDL_APPDATA, false);
+ str << path << "/paintown_configuration.txt";
+ return Filesystem::AbsolutePath(str.str());
+}
+#else
+Filesystem::AbsolutePath Filesystem::configFile(){
+ ostringstream str;
+ /* what if HOME isn't set? */
+ str << getenv("HOME") << "/.paintownrc";
+ return Filesystem::AbsolutePath(str.str());
+}
+
+Filesystem::AbsolutePath Filesystem::userDirectory(){
+ ostringstream str;
+ /* what if HOME isn't set? */
+ str << getenv("HOME") << "/.paintown/";
+ return Filesystem::AbsolutePath(str.str());
+}
+#endif
+
+Filesystem::AbsolutePath Filesystem::lookup(const RelativePath path){
+ /* first try the main data directory */
+ Filesystem::AbsolutePath final = dataPath.join(path);
+ if (::System::readable(final.path())){
+ return final;
+ }
+ /* then try the user directory, like ~/.paintown */
+ final = userDirectory().join(path);
+ if (::System::readable(final.path())){
+ return final;
+ }
+ /* then just look in the cwd */
+ if (::System::readable(path.path())){
+ return Filesystem::AbsolutePath(path.path());
+ }
+
+ ostringstream out;
+ out << "Cannot find " << path.path() << ". I looked in '" << dataPath.join(path).path() << "', '" << userDirectory().join(path).path() << "', and '" << path.path() << "'";
+
+ throw NotFound(__FILE__, __LINE__, out.str());
+}
+
+Filesystem::AbsolutePath Filesystem::lookupInsensitive(const Filesystem::AbsolutePath & directory, const Filesystem::RelativePath & path){
+ if (path.path() == ""){
+ throw NotFound(__FILE__, __LINE__, "Given empty path to lookup");
+ }
+ if (path.path() == "."){
+ return directory;
+ }
+ if (path.path() == ".."){
+ return directory.getDirectory();
+ }
+ if (path.isFile()){
+ vector<AbsolutePath> all = getFiles(directory, "*", true);
+ for (vector<AbsolutePath>::iterator it = all.begin(); it != all.end(); it++){
+ AbsolutePath & check = *it;
+ if (InsensitivePath(check.getFilename()) == path){
+ return check;
+ }
+ }
+
+ ostringstream out;
+ out << "Cannot find " << path.path() << " in " << directory.path();
+ throw NotFound(__FILE__, __LINE__, out.str());
+ } else {
+ return lookupInsensitive(lookupInsensitive(directory, path.firstDirectory()), path.removeFirstDirectory());
+ }
+}
+
+vector<Filesystem::AbsolutePath> Filesystem::findDirectoriesIn(const Filesystem::AbsolutePath & path){
+ vector<Filesystem::AbsolutePath> dirs;
+ DIR * dir = opendir(path.path().c_str());
+ if (dir == NULL){
+ return dirs;
+ }
+
+ struct dirent * entry = readdir(dir);
+ while (entry != NULL){
+ if (string(entry->d_name) != "." && string(entry->d_name) != ".."){
+ string total = path.path() + "/" + entry->d_name;
+ if (::System::isDirectory(total)){
+ dirs.push_back(AbsolutePath(total));
+ }
+ }
+ entry = readdir(dir);
+ }
+
+ closedir(dir);
+
+ return dirs;
+}
+
+vector<Filesystem::AbsolutePath> Filesystem::findDirectories(const RelativePath & path){
+ typedef vector<AbsolutePath> Paths;
+ Paths dirs;
+
+ Paths main_dirs = findDirectoriesIn(dataPath.join(path));
+ Paths user_dirs = findDirectoriesIn(userDirectory().join(path));
+ Paths here_dirs = findDirectoriesIn(Filesystem::AbsolutePath(path.path()));
+
+ dirs.insert(dirs.end(), main_dirs.begin(), main_dirs.end());
+ dirs.insert(dirs.end(), user_dirs.begin(), user_dirs.end());
+ dirs.insert(dirs.end(), here_dirs.begin(), here_dirs.end());
+
+ return dirs;
+}
+
+/* a/b/c/ -> a/b/c */
+static string removeTrailingSlash(string str){
+ while (str.size() > 0 && str[str.size() - 1] == '/'){
+ str = str.erase(str.size() - 1);
+ }
+ return str;
+}
+
+
+vector<Filesystem::AbsolutePath> Filesystem::getFiles(const AbsolutePath & dataPath, const string & find, bool caseInsensitive){
+#ifdef USE_ALLEGRO
+ struct al_ffblk info;
+ vector<AbsolutePath> files;
+
+ if ( al_findfirst( (dataPath.path() + "/" + find).c_str(), &info, FA_ALL ) != 0 ){
+ return files;
+ }
+ files.push_back(AbsolutePath(dataPath.path() + "/" + string(info.name)));
+ while ( al_findnext( &info ) == 0 ){
+ files.push_back(AbsolutePath(dataPath.path() + "/" + string(info.name)));
+ }
+ al_findclose( &info );
+ return files;
+#else
+ Util::Thread::ScopedLock scoped(lock);
+ vector<AbsolutePath> files;
+ DIRST sflEntry;
+ // bool ok = open_dir(&sflEntry, removeTrailingSlash(dataPath.path()).c_str());
+ bool ok = open_dir(&sflEntry, dataPath.path().c_str());
+ while (ok){
+ if (file_matches(sflEntry.file_name, find.c_str())){
+ files.push_back(AbsolutePath(dataPath.path() + "/" + string(sflEntry.file_name)));
+ }
+ ok = read_dir(&sflEntry);
+ }
+ close_dir(&sflEntry);
+ // Global::debug(0) << "Warning: Filesystem::getFiles() is not implemented yet for SDL" << endl;
+ return files;
+#endif
+}
+
+template <class X>
+static void append(vector<X> & destination, const vector<X> & source){
+ /*
+ for (typename vector<X>::const_iterator it = source.begin(); it != source.end(); it++){
+ destination.push_back(*it);
+ }
+ */
+ copy(source.begin(), source.end(), back_insert_iterator<vector<X> >(destination));
+}
+
+vector<Filesystem::AbsolutePath> Filesystem::getAllDirectories(const AbsolutePath & path){
+ vector<AbsolutePath> all = findDirectoriesIn(path);
+ vector<AbsolutePath> final;
+ append(final, all);
+ for (vector<AbsolutePath>::iterator it = all.begin(); it != all.end(); it++){
+ vector<AbsolutePath> more = getAllDirectories(*it);
+ append(final, more);
+ }
+ return final;
+}
+
+vector<Filesystem::AbsolutePath> Filesystem::getFilesRecursive(const AbsolutePath & dataPath, const string & find, bool caseInsensitive){
+ vector<AbsolutePath> directories = getAllDirectories(dataPath);
+ directories.push_back(dataPath);
+ vector<AbsolutePath> files;
+ for (vector<AbsolutePath>::iterator it = directories.begin(); it != directories.end(); it++){
+ vector<AbsolutePath> found = getFiles(*it, find, caseInsensitive);
+ append(files, found);
+ }
+ return files;
+}
+
+/*
+std::string find(const std::string path){
+ if (path.length() == 0){
+ throw NotFound("No path given");
+ }
+ if (path[0] == '/'){
+ string str(path);
+ str.erase(0, 1);
+ string out = lookup(str);
+ if (System::isDirectory(out)){
+ return sanitize(out + "/");
+ }
+ return sanitize(out);
+ }
+ string out = lookup(path);
+ if (System::isDirectory(out)){
+ return sanitize(out + "/");
+ }
+ return sanitize(out);
+}
+*/
+
+Filesystem::AbsolutePath Filesystem::find(const RelativePath & path){
+ if (path.isEmpty()){
+ throw NotFound(__FILE__, __LINE__, "No path given");
+ }
+
+ AbsolutePath out = lookup(path);
+ if (::System::isDirectory(out.path())){
+ return AbsolutePath(out.path() + "/");
+ }
+ return AbsolutePath(out.path());
+}
+
+Filesystem::AbsolutePath Filesystem::findInsensitive(const RelativePath & path){
+ try{
+ /* try sensitive lookup first */
+ return lookup(path);
+ } catch (const NotFound & fail){
+ }
+ /* get the base directory */
+ AbsolutePath directory = lookup(path.getDirectory());
+ return lookupInsensitive(directory, path.getFilename());
+}
+
+bool Filesystem::exists(const RelativePath & path){
+ try{
+ AbsolutePath absolute = find(path);
+ return true;
+ } catch (const NotFound & found){
+ return false;
+ }
+}
+
+bool Filesystem::exists(const AbsolutePath & path){
+ return ::System::readable(path.path());
+}
+
+Filesystem::RelativePath Filesystem::cleanse(const AbsolutePath & path){
+ string str = path.path();
+ if (str.find(dataPath.path()) == 0){
+ str.erase(0, dataPath.path().length());
+ } else if (str.find(userDirectory().path()) == 0){
+ str.erase(0, userDirectory().path().length());
+ }
+ return RelativePath(str);
}
diff --git a/util/file-system.h b/util/file-system.h
index bb432db0..1087e15f 100644
--- a/util/file-system.h
+++ b/util/file-system.h
@@ -1,263 +1,311 @@
#ifndef _paintown_file_system_h
#define _paintown_file_system_h
#include "exceptions/exception.h"
+#include "pointer.h"
+#include "thread.h"
#include <string>
#include <vector>
#include <stdint.h>
-namespace Filesystem{
+namespace Storage{
/* sorry for the crappy abbreviation, but can't collide with the
* Exception class here
*/
namespace Exc = ::Exception;
class Exception: public Exc::Base {
public:
Exception(const std::string & where, int line, const std::string & file);
Exception(const std::string & where, int line, const Exc::Base & nested, const std::string & file);
Exception(const Exception & copy);
virtual ~Exception() throw ();
virtual void throwSelf() const {
throw *this;
}
protected:
virtual const std::string getReason() const;
virtual Exc::Base * copy() const {
return new Exception(*this);
}
private:
std::string reason;
};
class NotFound: public Exception {
public:
NotFound(const std::string & where, int line, const std::string & file);
NotFound(const std::string & where, int line, const Exc::Base & nested, const std::string & file);
virtual ~NotFound() throw();
NotFound(const NotFound & copy);
virtual void throwSelf() const {
throw *this;
}
protected:
virtual Exc::Base * copy() const {
return new NotFound(*this);
}
};
class IllegalPath: public Exception {
public:
IllegalPath(const std::string & where, int line, const std::string & file);
IllegalPath(const std::string & where, int line, const Exc::Base & nested, const std::string & file);
virtual ~IllegalPath() throw();
IllegalPath(const IllegalPath & copy);
virtual void throwSelf() const {
throw *this;
}
protected:
virtual Exc::Base * copy() const {
return new IllegalPath(*this);
}
};
class Path{
public:
const std::string & path() const;
bool isEmpty() const;
virtual ~Path();
protected:
Path();
Path(const std::string & path);
Path(const Path & path);
virtual inline void setPath(const std::string & s){
mypath = s;
}
std::string mypath;
};
class InsensitivePath: public Path {
public:
InsensitivePath(const Path & what);
bool operator==(const Path & path) const;
};
/* relative path should not have the leading data directory on it, just
* the path within the paintown system.
*/
class RelativePath: public Path {
public:
explicit RelativePath();
explicit RelativePath(const std::string & path);
RelativePath(const RelativePath & path);
bool operator<(const RelativePath & path) const;
virtual RelativePath getDirectory() const;
virtual RelativePath getFilename() const;
RelativePath removeFirstDirectory() const;
RelativePath firstDirectory() const;
bool isFile() const;
/* a/ + b/ = a/b/ */
RelativePath join(const RelativePath & path) const;
RelativePath & operator=(const RelativePath & copy);
bool operator==(const RelativePath & path) const;
};
/* absolute paths should have the entire filesystem path on it */
class AbsolutePath: public Path {
public:
explicit AbsolutePath();
explicit AbsolutePath(const std::string & path);
AbsolutePath(const AbsolutePath & path);
AbsolutePath & operator=(const AbsolutePath & copy);
bool operator<(const AbsolutePath & path) const;
bool operator==(const AbsolutePath & path) const;
virtual AbsolutePath getDirectory() const;
virtual AbsolutePath getFilename() const;
AbsolutePath join(const RelativePath & path) const;
};
- /* given a relative path like sounds/arrow.png, prepend the proper
- * data path to it to give data/sounds/arrow.png
- */
- AbsolutePath find(const RelativePath & path);
-
- /* like `find' but ignores case */
- AbsolutePath findInsensitive(const RelativePath & path);
-
- /* findInsensitive but starts in the given absolute directory path */
- AbsolutePath lookupInsensitive(const AbsolutePath & directory, const RelativePath & path);
-
- void initialize();
-
- /* whether the file exists at all */
- bool exists(const RelativePath & path);
- bool exists(const AbsolutePath & path);
-
- /* remove the data path from a string
- * data/sounds/arrow.png -> sounds/arrow.png
- */
- RelativePath cleanse(const AbsolutePath & path);
-
- /* returns all the directories starting with the given path.
- * will look in the main data directory, the user directory, and
- * the current working directory.
- */
- std::vector<AbsolutePath> findDirectories(const RelativePath & path);
-
- /* basename, just get the filename and remove the directory part */
- std::string stripDir(const std::string & str);
-
- /* remove extension. foo.txt -> foo */
- std::string removeExtension(const std::string & str);
-
- /* user specific directory to hold persistent data */
- AbsolutePath userDirectory();
-
- /* user specific path to store the configuration file */
- AbsolutePath configFile();
-
- /* search a directory for some files matching pattern `find' */
- std::vector<AbsolutePath> getFiles(const AbsolutePath & dataPath, const std::string & find, bool caseInsensitive = false);
-
- /* same as getFiles but search directories recursively */
- std::vector<AbsolutePath> getFilesRecursive(const AbsolutePath & dataPath, const std::string & find, bool caseInsensitive = false);
-
- std::string invertSlashes(std::string str);
- std::string sanitize(std::string path);
-
class Eof: public std::exception {
public:
Eof(){
}
virtual ~Eof() throw (){
}
};
class EndianReader{
public:
EndianReader(std::ifstream & stream):
stream(stream){
}
virtual ~EndianReader(){
}
virtual int8_t readByte1(){
return convert(readBytes(sizeof(int8_t)));
}
virtual int16_t readByte2(){
return convert(readBytes(sizeof(int16_t)));
}
virtual int32_t readByte4(){
return convert(readBytes(sizeof(int32_t)));
}
virtual std::string readStringX(int length);
virtual std::string readString2(int length);
virtual void readBytes(uint8_t * out, int length);
virtual void seekEnd(std::streamoff where);
virtual void seek(std::streampos where);
virtual int position();
protected:
virtual int32_t convert(const std::vector<uint8_t> & bytes) = 0;
std::vector<uint8_t> readBytes(int length);
std::ifstream & stream;
};
/* combines bytes b0 b1 b2 b3 as b0 + b1*2^8 + b2*2^16 + b3*2^24 */
class LittleEndianReader: public EndianReader {
public:
LittleEndianReader(std::ifstream & stream):
EndianReader(stream){
}
protected:
virtual int32_t convert(const std::vector<uint8_t> & bytes){
uint32_t out = 0;
for (std::vector<uint8_t>::const_reverse_iterator it = bytes.rbegin(); it != bytes.rend(); it++){
out = (out << 8) + *it;
}
return out;
}
};
/* combines bytes b0 b1 b2 b3 as b0*2^24 + b1*2^16 + b2*2^8 + b3 */
class BigEndianReader: public EndianReader {
public:
BigEndianReader(std::ifstream & stream):
EndianReader(stream){
}
protected:
virtual int32_t convert(const std::vector<uint8_t> & bytes){
uint32_t out = 0;
for (std::vector<uint8_t>::const_iterator it = bytes.begin(); it != bytes.end(); it++){
out = (out << 8) + *it;
}
return out;
}
};
+
+ class System{
+ public:
+ System();
+ virtual ~System();
+
+ virtual AbsolutePath find(const RelativePath & path) = 0;
+ virtual RelativePath cleanse(const AbsolutePath & path) = 0;
+ virtual bool exists(const RelativePath & path) = 0;
+ virtual bool exists(const AbsolutePath & path) = 0;
+ virtual std::vector<AbsolutePath> getFilesRecursive(const AbsolutePath & dataPath, const std::string & find, bool caseInsensitive = false) = 0;
+ virtual std::vector<AbsolutePath> getFiles(const AbsolutePath & dataPath, const std::string & find, bool caseInsensitive = false) = 0;
+ virtual AbsolutePath configFile() = 0;
+ virtual AbsolutePath userDirectory() = 0;
+ virtual std::vector<AbsolutePath> findDirectories(const RelativePath & path) = 0;
+ virtual AbsolutePath findInsensitive(const RelativePath & path) = 0;
+ virtual AbsolutePath lookupInsensitive(const AbsolutePath & directory, const RelativePath & path) = 0;
+ };
+
+ System & instance();
+ extern Util::ReferenceCount<System> self;
+
+ std::string invertSlashes(std::string str);
+ std::string sanitize(std::string path);
+
+ /* remove extension. foo.txt -> foo */
+ std::string removeExtension(const std::string & str);
+
+ /* basename, just get the filename and remove the directory part */
+ std::string stripDir(const std::string & str);
}
+/*
+ * class Filesystem
+ * class NetworkStorage
+ * class ZipStorage
+ */
+class Filesystem: public Storage::System {
+public:
+ Filesystem(const Storage::AbsolutePath & dataPath);
+
+ typedef Storage::AbsolutePath AbsolutePath;
+ typedef Storage::RelativePath RelativePath;
+ typedef Storage::InsensitivePath InsensitivePath;
+ typedef Storage::Exception Exception;
+ typedef Storage::NotFound NotFound;
+
+ /* given a relative path like sounds/arrow.png, prepend the proper
+ * data path to it to give data/sounds/arrow.png
+ */
+ AbsolutePath find(const RelativePath & path);
+
+ /* like `find' but ignores case */
+ AbsolutePath findInsensitive(const RelativePath & path);
+
+ /* findInsensitive but starts in the given absolute directory path */
+ AbsolutePath lookupInsensitive(const AbsolutePath & directory, const RelativePath & path);
+
+ // void initialize();
+
+ /* whether the file exists at all */
+ bool exists(const RelativePath & path);
+ bool exists(const AbsolutePath & path);
+
+ /* remove the data path from a string
+ * data/sounds/arrow.png -> sounds/arrow.png
+ */
+ RelativePath cleanse(const AbsolutePath & path);
+
+ /* returns all the directories starting with the given path.
+ * will look in the main data directory, the user directory, and
+ * the current working directory.
+ */
+ std::vector<AbsolutePath> findDirectories(const RelativePath & path);
+
+ /* user specific directory to hold persistent data */
+ AbsolutePath userDirectory();
+
+ /* user specific path to store the configuration file */
+ AbsolutePath configFile();
+
+ /* search a directory for some files matching pattern `find' */
+ std::vector<AbsolutePath> getFiles(const AbsolutePath & dataPath, const std::string & find, bool caseInsensitive = false);
+
+ /* same as getFiles but search directories recursively */
+ std::vector<AbsolutePath> getFilesRecursive(const AbsolutePath & dataPath, const std::string & find, bool caseInsensitive = false);
+
+protected:
+ AbsolutePath lookup(const RelativePath path);
+ std::vector<AbsolutePath> findDirectoriesIn(const AbsolutePath & path);
+ std::vector<AbsolutePath> getAllDirectories(const AbsolutePath & path);
+
+protected:
+ Util::Thread::LockObject lock;
+ AbsolutePath dataPath;
+};
+
#endif
diff --git a/util/font.h b/util/font.h
index 3a92e062..f704063a 100644
--- a/util/font.h
+++ b/util/font.h
@@ -1,120 +1,120 @@
#ifndef _paintown_font_h
#define _paintown_font_h
#include <string>
#include <vector>
#include "bitmap.h"
// #include "ftalleg.h"
struct FONT;
namespace ftalleg{
class freetype;
}
-namespace Filesystem{
+namespace Storage{
class RelativePath;
class AbsolutePath;
}
/* handle allegro fonts and true type fonts */
class Font{
public:
Font();
virtual ~Font();
virtual void setSize( const int x, const int y ) = 0;
virtual int getSizeX() const = 0;
virtual int getSizeY() const = 0;
virtual int textLength( const char * text ) const = 0;
virtual int getHeight( const std::string & str ) const = 0;
virtual int getHeight() const = 0;
virtual void printf( int x, int y, int xSize, int ySize, Graphics::Color color, const Graphics::Bitmap & work, const std::string & str, int marker, ... ) const = 0;
virtual void printf( int x, int y, Graphics::Color color, const Graphics::Bitmap & work, const std::string & str, int marker, ... ) const = 0;
virtual void printfWrap( int x, int y, Graphics::Color color, const Graphics::Bitmap & work, int maxWidth, const std::string & str, int marker, ... ) const;
static const Font & getDefaultFont();
static const Font & getDefaultFont(int width, int height);
- static const Font & getFont( const Filesystem::RelativePath & name, const int x = 32, const int y = 32 );
- static const Font & getFont( const Filesystem::AbsolutePath & name, const int x = 32, const int y = 32 );
+ static const Font & getFont( const Storage::RelativePath & name, const int x = 32, const int y = 32 );
+ static const Font & getFont( const Storage::AbsolutePath & name, const int x = 32, const int y = 32 );
/* store all the freetype fonts forever */
// static std::vector< ftalleg::freetype * > cacheFreeType;
protected:
void printfWrapLine(int x, int & y, Graphics::Color color, const Graphics::Bitmap & work, int maxWidth, const char * line) const;
};
class NullFont: public Font {
public:
NullFont();
virtual ~NullFont();
virtual void setSize( const int x, const int y );
virtual int getSizeX() const;
virtual int getSizeY() const;
virtual int textLength( const char * text ) const;
virtual int getHeight( const std::string & str ) const;
virtual int getHeight() const;
virtual void printf( int x, int y, int xSize, int ySize, Graphics::Color color, const Graphics::Bitmap & work, const std::string & str, int marker, ... ) const;
virtual void printf( int x, int y, Graphics::Color color, const Graphics::Bitmap & work, const std::string & str, int marker, ... ) const;
};
#ifdef USE_ALLEGRO
class AllegroFont: public Font {
public:
AllegroFont( const FONT * const font );
AllegroFont( const AllegroFont & copy );
virtual ~AllegroFont();
virtual int getHeight() const;
virtual int getHeight( const std::string & str ) const;
virtual int textLength( const char * text ) const;
virtual void printf( int x, int y, Graphics::Color color, const Graphics::Bitmap & work, const std::string & str, int marker, ... ) const;
virtual void printf( int x, int y, int xSize, int ySize, Graphics::Color color, const Graphics::Bitmap & work, const std::string & str, int marker, ... ) const;
virtual void setSize( const int x, const int y );
virtual int getSizeX() const;
virtual int getSizeY() const;
private:
inline const FONT * getInternalFont() const {
return font;
}
const FONT * const font;
};
#endif
class FreeTypeFont: public Font {
public:
- FreeTypeFont(const Filesystem::AbsolutePath & filename);
+ FreeTypeFont(const Storage::AbsolutePath & filename);
FreeTypeFont(const FreeTypeFont & copy);
virtual ~FreeTypeFont();
virtual int getHeight() const;
virtual int getHeight( const std::string & str ) const;
virtual int textLength( const char * text ) const;
virtual void printf( int x, int y, Graphics::Color color, const Graphics::Bitmap & work, const std::string & str, int marker, ... ) const;
virtual void printf( int x, int y, int xSize, int ySize, Graphics::Color color, const Graphics::Bitmap & work, const std::string & str, int marker, ... ) const;
virtual void setSize( const int x, const int y );
virtual int getSizeX() const;
virtual int getSizeY() const;
private:
ftalleg::freetype * font;
int sizeX;
int sizeY;
bool own;
};
#endif
diff --git a/util/gui/animation.cpp b/util/gui/animation.cpp
index 68b004fe..68c6aa1f 100644
--- a/util/gui/animation.cpp
+++ b/util/gui/animation.cpp
@@ -1,413 +1,413 @@
#include "animation.h"
#include <vector>
#include <math.h>
#include <sstream>
#include "util/token.h"
#include "util/trans-bitmap.h"
#include "util/bitmap.h"
#include "globals.h"
#include "../debug.h"
#include "../funcs.h"
#include "../file-system.h"
using namespace std;
using namespace Gui;
// Temporary solution
static void renderSprite(const Graphics::Bitmap & bmp, const int x, const int y, const int alpha, const bool hflip, const bool vflip, const Graphics::Bitmap & work){
if (alpha != 255){
Graphics::Bitmap::transBlender( 0, 0, 0, alpha );
if (hflip && !vflip){
bmp.translucent().drawHFlip(x,y, work);
} else if (!hflip && vflip){
bmp.translucent().drawVFlip(x,y, work);
} else if (hflip && vflip){
bmp.translucent().drawHVFlip(x,y, work);
} else if (!hflip && !vflip){
bmp.translucent().draw(x,y, work);
}
} else {
if (hflip && !vflip){
bmp.drawHFlip(x,y, work);
} else if (!hflip && vflip){
bmp.drawVFlip(x,y, work);
} else if (hflip && vflip){
bmp.drawHVFlip(x,y, work);
} else if (!hflip && !vflip){
bmp.draw(x,y, work);
}
}
}
Frame::Frame(const Token *the_token, imageMap &images) throw (LoadException):
bmp(0),
time(0),
horizontalFlip(false),
verticalFlip(false),
alpha(255){
if ( *the_token != "frame" ){
throw LoadException(__FILE__, __LINE__, "Not an frame");
}
const Token & tok = *the_token;
/* The usual setup of an animation frame is
// use image -1 to not draw anything, it can be used to get a blinking effect
(frame (image NUM) (alpha NUM) (offset x y) (hflip 0|1) (vflip 0|1) (time NUM))
*/
TokenView view = tok.view();
while (view.hasMore()){
try{
const Token * token;
view >> token;
if (*token == "image"){
// get the number
int num;
token->view() >> num;
// now assign the bitmap
bmp = images[num];
} else if (*token == "alpha"){
// get alpha
token->view() >> alpha;
} else if (*token == "offset"){
// Get the offset location it defaults to 0,0
double x=0, y=0;
try {
token->view() >> x >> y;
} catch (const TokenException & ex){
}
offset.set(x,y);
} else if (*token == "hflip"){
// horizontal flip
token->view() >> horizontalFlip;
} else if (*token == "vflip"){
// horizontal flip
token->view() >> verticalFlip;
} else if (*token == "time"){
// time to display
token->view() >> time;
} else {
Global::debug( 3 ) << "Unhandled menu attribute: "<<endl;
if (Global::getDebug() >= 3){
token->print(" ");
}
}
} catch ( const TokenException & ex ) {
throw LoadException(__FILE__, __LINE__, ex, "Menu animation parse error");
} catch ( const LoadException & ex ) {
throw ex;
}
}
}
Frame::Frame(Graphics::Bitmap * bmp):
bmp(bmp),
time(0),
horizontalFlip(false),
verticalFlip(false),
alpha(255){
}
Frame::~Frame(){
}
void Frame::act(double xvel, double yvel){
scrollOffset.moveBy(xvel,yvel);
if (scrollOffset.getDistanceFromCenterX() >=bmp->getWidth()){
scrollOffset.setX(0);
} else if (scrollOffset.getDistanceFromCenterX() <= -(bmp->getWidth())){
scrollOffset.setX(0);
}
if (scrollOffset.getDistanceFromCenterY() >=bmp->getHeight()){
scrollOffset.setY(0);
} else if (scrollOffset.getDistanceFromCenterY() <= -(bmp->getHeight())){
scrollOffset.setY(0);
}
}
static bool closeFloat(double a, double b){
const double epsilon = 0.001;
return fabs(a-b) < epsilon;
}
void Frame::draw(const int xaxis, const int yaxis, const Graphics::Bitmap & work){
if (!bmp){
return;
}
if (!closeFloat(scrollOffset.getDistanceFromCenterX(), 0) || !closeFloat(scrollOffset.getDistanceFromCenterY(), 0)){
// Lets do some scrolling
// Graphics::Bitmap temp = Graphics::Bitmap::temporaryBitmap(bmp->getWidth(), bmp->getHeight());
//AnimationPoint loc;
AbsolutePoint loc;
if (scrollOffset.getRelativeX() < 0){
loc.setX(scrollOffset.getDistanceFromCenterX() + bmp->getWidth());
} else if (scrollOffset.getRelativeX() > 0){
loc.setX(scrollOffset.getDistanceFromCenterX() - bmp->getWidth());
}
if (scrollOffset.getRelativeY() < 0){
loc.setY(scrollOffset.getDistanceFromCenterY() + bmp->getHeight());
} else if (scrollOffset.getRelativeY() > 0){
loc.setY(scrollOffset.getDistanceFromCenterY() - bmp->getHeight());
}
/*
bmp->Blit((int) scrollOffset.getDistanceFromCenterX(), (int) scrollOffset.getDistanceFromCenterY(), temp);
bmp->Blit((int) scrollOffset.getDistanceFromCenterX(), (int) loc.getY(), temp);
bmp->Blit((int) loc.getX(), (int) scrollOffset.getDistanceFromCenterY(), temp);
bmp->Blit((int) loc.getX(), (int) loc.getY(), temp);
renderSprite(temp, (int)(xaxis+offset.getDistanceFromCenterX()), (int)(yaxis+offset.getDistanceFromCenterY()), alpha, horizontalFlip, verticalFlip, work);
*/
double x = xaxis+offset.getDistanceFromCenterX();
double y = yaxis+offset.getDistanceFromCenterY();
renderSprite(*bmp,
(int)(x + scrollOffset.getDistanceFromCenterX()),
(int)(y + scrollOffset.getDistanceFromCenterY()),
alpha, horizontalFlip, verticalFlip, work);
renderSprite(*bmp,
(int)(x + loc.getX()),
(int)(y + scrollOffset.getDistanceFromCenterY()),
alpha, horizontalFlip, verticalFlip, work);
renderSprite(*bmp,
(int)(x + scrollOffset.getDistanceFromCenterX()),
(int)(y + loc.getY()),
alpha, horizontalFlip, verticalFlip, work);
renderSprite(*bmp,
(int)(x + loc.getX()),
(int)(y + loc.getY()),
alpha, horizontalFlip, verticalFlip, work);
} else {
renderSprite(*bmp, (int)(xaxis+offset.getDistanceFromCenterX()), (int)(yaxis+offset.getDistanceFromCenterY()), alpha, horizontalFlip, verticalFlip, work);
}
}
Animation::Animation(const Token *the_token) throw (LoadException):
id(0),
depth(BackgroundBottom),
ticks(0),
currentFrame(0),
loop(0),
allowReset(true){
images[-1] = 0;
std::string basedir = "";
if ( *the_token != "anim" ){
throw LoadException(__FILE__, __LINE__, "Not an animation");
}
/* The usual setup of an animation is
The images must be listed prior to listing any frames, basedir can be used to set the directory where the images are located
loop will begin at the subsequent frame listed after loop
axis is the location in which the drawing must be placed
location *old* - used to render in background or foreground (0 == background [default]| 1 == foreground)
depth - used to render in background or foreground space (depth background bottom|middle|top) | (depth foreground bottom|midle|top)
reset - used to allow resetting of animation (0 == no | 1 == yes [default])
velocity - used to get a wrapping scroll effect while animating
window - area in which the item will be contained
(anim (id NUM)
(location NUM)
(depth background|foreground NUM)
(basedir LOCATION)
(image NUM FILE)
(velocity x y)
(axis x y)
(frame "Read comments above in constructor")
(loop)
(reset NUM)
(window x1 y1 x2 y2))
*/
const Token & tok = *the_token;
TokenView view = tok.view();
while (view.hasMore()){
try{
const Token * token;
view >> token;
if (*token == "id"){
// get the id
token->view() >> id;
} else if (*token == "location"){
// translate location to depth
int location = 0;
token->view() >> location;
if (location == 0){
depth = BackgroundBottom;
} else if (location == 1){
depth = ForegroundBottom;
}
} else if (*token == "depth"){
// get the depth
std::string name, level;
token->view() >> name >> level;
if (name == "background"){
if (level == "bottom"){
depth = BackgroundBottom;
} else if (level == "middle"){
depth = BackgroundMiddle;
} else if (level == "top"){
depth = BackgroundTop;
}
} else if (name == "foreground"){
if (level == "bottom"){
depth = ForegroundBottom;
} else if (level == "middle"){
depth = ForegroundMiddle;
} else if (level == "top"){
depth = ForegroundTop;
}
}
} else if (*token == "basedir"){
// set the base directory for loading images
token->view() >> basedir;
} else if (*token == "image"){
// add bitmaps by number to the map
int number;
std::string temp;
token->view() >> number >> temp;
- Graphics::Bitmap *bmp = new Graphics::Bitmap(Filesystem::find(Filesystem::RelativePath(basedir + temp)).path());
+ Graphics::Bitmap *bmp = new Graphics::Bitmap(Storage::instance().find(Filesystem::RelativePath(basedir + temp)).path());
if (bmp->getError()){
delete bmp;
} else {
images[number] = bmp;
}
} else if (*token == "axis"){
// Get the axis location it defaults to 0,0
double x=0, y=0;
try {
token->view() >> x >> y;
} catch (const TokenException & ex){
}
axis.set(x,y);
} else if (*token == "window"){
// Windowed area where to clip if necessary otherwise it defaults to max
double x1=0,x2=0, y1=0,y2=0;
try {
token->view() >> x1 >> y1 >> x2 >> y2;
} catch (const TokenException & ex){
}
window.set(x1,y1,x2,y2);
} else if (*token == "velocity"){
// This allows the animation to get a wrapping scroll action going on
double x=0, y=0;
try {
token->view() >> x >> y;
} catch (const TokenException & ex){
}
velocity.set(x,y);
} else if (*token == "frame"){
// new frame
Frame *frame = new Frame(token, images);
frames.push_back(frame);
} else if (*token == "loop"){
// start loop here
int l;
token->view() >> l;
if (l >= (int)frames.size()){
ostringstream out;
out << "Loop location is larger than the number of frames. Loop: " << loop << " Frames: " << frames.size();
throw LoadException(__FILE__, __LINE__, out.str());
}
loop = l;
} else if (*token == "reset"){
// Allow reset of animation
token->view() >> allowReset;
} else {
Global::debug( 3 ) << "Unhandled menu attribute: "<<endl;
if (Global::getDebug() >= 3){
token->print(" ");
}
}
} catch ( const TokenException & ex ) {
throw LoadException(__FILE__, __LINE__, ex, "Menu animation parse error");
} catch ( const LoadException & ex ) {
throw ex;
}
}
}
Animation::Animation(const std::string & background) throw (LoadException):
id(0),
depth(BackgroundBottom),
ticks(0),
currentFrame(0),
loop(0),
allowReset(true){
// add bitmap
- Graphics::Bitmap *bmp = new Graphics::Bitmap(Filesystem::find(Filesystem::RelativePath(background)).path());
+ Graphics::Bitmap *bmp = new Graphics::Bitmap(Storage::instance().find(Filesystem::RelativePath(background)).path());
if (bmp->getError()){
delete bmp;
throw LoadException(__FILE__,__LINE__, "Problem loading file: " + background);
} else {
images[0] = bmp;
}
Frame *frame = new Frame(bmp);
frames.push_back(frame);
}
Animation::Animation(Graphics::Bitmap * image):
id(0),
depth(BackgroundBottom),
ticks(0),
currentFrame(0),
loop(0),
allowReset(true){
images[0] = image;
Frame *frame = new Frame(image);
frames.push_back(frame);
}
Animation::~Animation(){
for (std::vector<Frame *>::iterator i = frames.begin(); i != frames.end(); ++i){
if (*i){
delete *i;
}
}
for (imageMap::iterator i = images.begin(); i != images.end(); ++i){
if (i->second){
delete i->second;
}
}
}
void Animation::act(){
// Used for scrolling
for (std::vector<Frame *>::iterator i = frames.begin(); i != frames.end(); ++i){
(*i)->act(velocity.getRelativeX(), velocity.getRelativeY());
}
if( frames[currentFrame]->time != -1 ){
ticks++;
if(ticks >= frames[currentFrame]->time){
ticks = 0;
forwardFrame();
}
}
}
void Animation::draw(const Graphics::Bitmap & work){
/* FIXME: should use sub-bitmaps here */
// Set clip from the axis default is 0,0,bitmap width, bitmap height
work.setClipRect(-(window.getPosition().getDistanceFromCenterX()),-(window.getPosition().getDistanceFromCenterY()),work.getWidth() - window.getPosition2().getDistanceFromCenterX(),work.getHeight() - window.getPosition2().getDistanceFromCenterY());
frames[currentFrame]->draw(axis.getDistanceFromCenterX(), axis.getDistanceFromCenterY(),work);
work.setClipRect(0,0,work.getWidth(),work.getHeight());
}
void Animation::forwardFrame(){
if (currentFrame < frames.size() -1){
currentFrame++;
} else {
currentFrame = loop;
}
}
void Animation::backFrame(){
if (currentFrame > loop){
currentFrame--;
} else {
currentFrame = frames.size() - 1;
}
}
diff --git a/util/init.cpp b/util/init.cpp
index cf218171..771f2ea0 100644
--- a/util/init.cpp
+++ b/util/init.cpp
@@ -1,591 +1,591 @@
#ifdef USE_ALLEGRO
#include <allegro.h>
#ifdef ALLEGRO_WINDOWS
#include <winalleg.h>
#endif
#endif
#ifdef USE_ALLEGRO5
#include <allegro5/allegro.h>
#include <allegro5/allegro_image.h>
#include <allegro5/allegro_primitives.h>
#endif
#ifdef USE_SDL
#include <SDL.h>
#endif
#ifndef WINDOWS
#include <signal.h>
#include <string.h>
#include <unistd.h>
#endif
#ifdef LINUX
#include <execinfo.h>
#endif
/* don't be a boring tuna */
// #warning you are ugly
#include "globals.h"
#include "init.h"
#include "network/network.h"
#include "thread.h"
#include <time.h>
#include <ostream>
#include "dumb/include/dumb.h"
#ifdef USE_ALLEGRO
#include "dumb/include/aldumb.h"
#include "loadpng/loadpng.h"
#include "gif/algif.h"
#endif
#include "bitmap.h"
#include "funcs.h"
#include "file-system.h"
#include "font.h"
#include "sound.h"
#include "configuration.h"
#include "music.h"
#include "loading.h"
#include "input/keyboard.h"
#include "message-queue.h"
#ifdef WII
#include <fat.h>
#endif
using namespace std;
volatile int Global::speed_counter4 = 0;
bool Global::rateLimit = true;
/* enough seconds for 136 years */
volatile unsigned int Global::second_counter = 0;
/* the original engine was running at 90 ticks per second, but we dont
* need to render that fast, so TICS_PER_SECOND is really fps and
* LOGIC_MULTIPLIER will be used to adjust the speed counter to its
* original value.
*/
const int Global::TICS_PER_SECOND = 40;
const double Global::LOGIC_MULTIPLIER = (double) 90 / (double) Global::TICS_PER_SECOND;
#ifdef USE_ALLEGRO
const int Global::WINDOWED = GFX_AUTODETECT_WINDOWED;
const int Global::FULLSCREEN = GFX_AUTODETECT_FULLSCREEN;
#else
/* FIXME: use enums here or something */
const int Global::WINDOWED = 0;
const int Global::FULLSCREEN = 1;
#endif
/* game counter, controls FPS */
static void inc_speed_counter(){
/* probably put input polling here, InputManager::poll(). no, don't do that.
* polling is done in the standardLoop now.
*/
Global::speed_counter4 += 1;
}
#ifdef USE_ALLEGRO
END_OF_FUNCTION(inc_speed_counter)
#endif
/* if you need to count seconds for some reason.. */
static void inc_second_counter() {
Global::second_counter += 1;
}
#ifdef USE_ALLEGRO
END_OF_FUNCTION(inc_second_counter)
#endif
#if !defined(WINDOWS) && !defined(WII) && !defined(MINPSPW) && !defined(PS3) && !defined(NDS) && !defined(NACL)
#ifdef LINUX
static void print_stack_trace(){
/* use addr2line on these addresses to get a filename and line number */
void *trace[128];
int frames = backtrace(trace, 128);
printf("Stack trace\n");
for (int i = 0; i < frames; i++){
printf(" %p\n", trace[i]);
}
}
#endif
static void handleSigSegV(int i, siginfo_t * sig, void * data){
const char * message = "Bug! Caught a memory violation. Shutting down..\n";
int dont_care = write(1, message, 48);
dont_care = dont_care;
#ifdef LINUX
print_stack_trace();
#endif
// Global::shutdown_message = "Bug! Caught a memory violation. Shutting down..";
Graphics::setGfxModeText();
#ifdef USE_ALLEGRO
allegro_exit();
#endif
#ifdef USE_SDL
SDL_Quit();
#endif
/* write to a log file or something because sigsegv shouldn't
* normally happen.
*/
exit(1);
}
#else
#endif
/* catch a socket being closed prematurely on unix */
#if !defined(WINDOWS) && !defined(WII) && !defined(MINPSPW) && !defined(PS3) && !defined(NDS) && !defined(NACL)
static void handleSigPipe( int i, siginfo_t * sig, void * data ){
}
/*
static void handleSigUsr1( int i, siginfo_t * sig, void * data ){
pthread_exit( NULL );
}
*/
#endif
static void registerSignals(){
#if !defined(WINDOWS) && !defined(WII) && !defined(MINPSPW) && !defined(PS3) && !defined(NDS) && !defined(NACL)
struct sigaction action;
memset( &action, 0, sizeof(struct sigaction) );
action.sa_sigaction = handleSigPipe;
sigaction( SIGPIPE, &action, NULL );
memset( &action, 0, sizeof(struct sigaction) );
action.sa_sigaction = handleSigSegV;
sigaction( SIGSEGV, &action, NULL );
/*
action.sa_sigaction = handleSigUsr1;
sigaction( SIGUSR1, &action, NULL );
*/
#endif
}
/* should probably call the janitor here or something */
static void close_paintown(){
Music::pause();
Graphics::setGfxModeText();
#ifdef USE_ALLEGRO
allegro_exit();
#endif
exit(0);
}
namespace Global{
extern int do_shutdown;
}
static void close_window(){
/* when do_shutdown is 1 the game will attempt to throw ShutdownException
* wherever it is. If the game is stuck or the code doesn't throw
* ShutdownException then when the user tries to close the window
* twice we just forcifully shutdown.
*/
Global::do_shutdown += 1;
if (Global::do_shutdown == 2){
close_paintown();
}
}
#ifdef USE_ALLEGRO
END_OF_FUNCTION(close_window)
#endif
#ifdef USE_ALLEGRO5
struct TimerInfo{
TimerInfo(void (*x)(), ALLEGRO_TIMER * y):
tick(x), timer(y){}
void (*tick)();
ALLEGRO_TIMER * timer;
};
static void * do_timer(void * info){
TimerInfo * timerInfo = (TimerInfo*) info;
ALLEGRO_EVENT_SOURCE * source = al_get_timer_event_source(timerInfo->timer);
ALLEGRO_EVENT_QUEUE * queue = al_create_event_queue();
al_register_event_source(queue, source);
while (true){
ALLEGRO_EVENT event;
al_wait_for_event(queue, &event);
timerInfo->tick();
}
al_destroy_event_queue(queue);
al_destroy_timer(timerInfo->timer);
delete timerInfo;
}
static Util::Thread::Id start_timer(void (*func)(), int frequency){
ALLEGRO_TIMER * timer = al_create_timer(ALLEGRO_BPS_TO_SECS(frequency));
if (timer == NULL){
Global::debug(0) << "Could not create timer" << endl;
}
al_start_timer(timer);
TimerInfo * info = new TimerInfo(func, timer);
Util::Thread::Id thread;
Util::Thread::createThread(&thread, NULL, (Util::Thread::ThreadFunction) do_timer, (void*) info);
return thread;
}
static void initSystem(ostream & out){
out << "Allegro5 initialize " << (al_init() ? "Ok" : "Failed") << endl;
uint32_t version = al_get_allegro_version();
int major = version >> 24;
int minor = (version >> 16) & 255;
int revision = (version >> 8) & 255;
int release = version & 255;
out << "Allegro5 version " << major << "." << minor << "." << revision << "." << release << endl;
al_init_image_addon();
al_init_primitives_addon();
al_install_keyboard();
al_set_app_name("Paintown");
start_timer(inc_speed_counter, Global::TICS_PER_SECOND);
start_timer(inc_second_counter, 1);
}
#endif
#ifdef USE_ALLEGRO
static void initSystem(ostream & out){
out << "Allegro version: " << ALLEGRO_VERSION_STR << endl;
out << "Allegro init: " <<allegro_init()<<endl;
out << "Install timer: " <<install_timer()<<endl;
/* png */
loadpng_init();
algif_init();
out<<"Install keyboard: "<<install_keyboard()<<endl;
/* do we need the mouse?? */
// out<<"Install mouse: "<<install_mouse()<<endl;
out<<"Install joystick: "<<install_joystick(JOY_TYPE_AUTODETECT)<<endl;
/* 16 bit color depth */
set_color_depth(16);
LOCK_VARIABLE( speed_counter4 );
LOCK_VARIABLE( second_counter );
LOCK_FUNCTION( (void *)inc_speed_counter );
LOCK_FUNCTION( (void *)inc_second_counter );
/* set up the timers */
out<<"Install game timer: "<< install_int_ex(inc_speed_counter, BPS_TO_TIMER(Global::TICS_PER_SECOND))<<endl;
out<<"Install second timer: "<<install_int_ex(inc_second_counter, BPS_TO_TIMER(1))<<endl;
/* keep running in the background */
set_display_switch_mode(SWITCH_BACKGROUND);
/* close window when the X is pressed */
LOCK_FUNCTION(close_window);
set_close_button_callback(close_window);
}
#endif
#ifdef USE_SDL
// static pthread_t events;
struct TimerInfo{
TimerInfo(void (*x)(), int y):
tick(x), frequency(y){}
void (*tick)();
int frequency;
};
static void * do_timer(void * arg){
TimerInfo info = *(TimerInfo *) arg;
uint32_t delay = (uint32_t)(1000.0 / (double) info.frequency);
/* assuming SDL_GetTicks() starts at 0, this should last for about 50 days
* before overflowing. overflow should work out fine. Assuming activate occurs
* when the difference between now and ticks is at least 6, the following will happen.
* ticks now now-ticks
* 4294967294 4294967294 0
* 4294967294 4294967295 1
* 4294967294 0 2
* 4294967294 1 3
* 4294967294 2 4
* 4294967294 3 5
* 4294967294 4 6
* Activate
* 3 5 2
* 3 6 3
* 3 7 4
* 3 8 5
* 3 9 6
* Activate
*
* Can 'now' ever be much larger than 'ticks' due to overflow?
* It doesn't seem like it.
*/
uint32_t ticks = SDL_GetTicks();
/* TODO: pass in some variable that tells this loop to quit */
while (true){
uint32_t now = SDL_GetTicks();
while (now - ticks >= delay){
// Global::debug(0) << "Tick!" << endl;
info.tick();
ticks += delay;
}
SDL_Delay(1);
}
delete (TimerInfo *) arg;
return NULL;
}
static Util::Thread::Id start_timer(void (*func)(), int frequency){
TimerInfo * speed = new TimerInfo(func, frequency);
/*
speed.tick = func;
speed.frequency = frequency;
*/
Util::Thread::Id thread;
Util::Thread::createThread(&thread, NULL, (Util::Thread::ThreadFunction) do_timer, (void*) speed);
return thread;
}
#if 0
static void * handleEvents(void * arg){
bool done = false;
while (!done){
SDL_Event event;
int ok = SDL_WaitEvent(&event);
if (ok){
switch (event.type){
case SDL_QUIT : {
done = true;
close_window();
break;
}
default : {
// Global::debug(0) << "Ignoring SDL event " << event.type << endl;
break;
}
}
}
}
return NULL;
}
#endif
/*
static void doSDLQuit(){
SDL_Event quit;
quit.type = SDL_QUIT;
SDL_PushEvent(&quit);
Global::debug(0) << "Waiting for SDL event handler to finish" << endl;
pthread_join(events, NULL);
SDL_Quit();
}
*/
static void initSystem(ostream & out){
out << "SDL Init: ";
int ok = SDL_Init(SDL_INIT_VIDEO |
SDL_INIT_AUDIO |
SDL_INIT_TIMER |
SDL_INIT_JOYSTICK |
SDL_INIT_NOPARACHUTE);
if (ok == 0){
out << "Ok" << endl;
} else {
out << "Failed (" << ok << ") - " << SDL_GetError() << endl;
exit(ok);
}
/* Just do SDL thread init
#ifdef MINPSPW
pthread_init();
#endif
*/
start_timer(inc_speed_counter, Global::TICS_PER_SECOND);
start_timer(inc_second_counter, 1);
try{
SDL_Surface * icon = SDL_LoadBMP(Filesystem::find(Filesystem::RelativePath("menu/icon.bmp")).path().c_str());
if (icon != NULL){
SDL_WM_SetIcon(icon, NULL);
}
} catch (const Filesystem::NotFound & failed){
Global::debug(0) << "Could not find window icon: " << failed.getTrace() << endl;
}
SDL_WM_SetCaption("Paintown", NULL);
SDL_EnableUNICODE(1);
SDL_JoystickEventState(1);
atexit(SDL_Quit);
// atexit(doSDLQuit);
}
#endif
/* mostly used for testing purposes */
bool Global::initNoGraphics(){
/* copy/pasting the init code isn't ideal, maybe fix it later */
ostream & out = Global::debug(0);
out << "-- BEGIN init --" << endl;
out << "Data path is " << Util::getDataPath2().path() << endl;
out << "Paintown version " << Global::getVersionString() << endl;
out << "Build date " << __DATE__ << " " << __TIME__ << endl;
#ifdef WII
/* <WinterMute> fatInitDefault will set working dir to argv[0] passed by launcher,
* or root of first device mounted
*/
out << "Fat init " << (fatInitDefault() == true ? "Ok" : "Failed") << endl;
#endif
/*
char buffer[512];
if (getcwd(buffer, 512) != 0){
printf("Working directory '%s'\n", buffer);
}
*/
- if (!Filesystem::exists(Util::getDataPath2())){
+ if (!Storage::instance().exists(Util::getDataPath2())){
Global::debug(0) << "Cannot find data path '" << Util::getDataPath2().path() << "'! Either use the -d switch to specify the data directory or find the data directory and move it to that path" << endl;
return false;
}
/* do implementation specific setup */
initSystem(out);
dumb_register_stdfiles();
// Sound::initialize();
- Filesystem::initialize();
+ // Filesystem::initialize();
Graphics::SCALE_X = GFX_X;
Graphics::SCALE_Y = GFX_Y;
Configuration::loadConfigurations();
const int sx = Configuration::getScreenWidth();
const int sy = Configuration::getScreenHeight();
Graphics::Bitmap::setFakeGraphicsMode(sx, sy);
/* music */
atexit(&dumb_exit);
out << "Initialize random number generator" << endl;
/* initialize random number generator */
srand(time(NULL));
registerSignals();
#ifdef HAVE_NETWORKING
out << "Initialize network" << endl;
Network::init();
atexit(Network::closeAll);
#endif
/* this mutex is used to show the loading screen while the game loads */
// Util::Thread::initializeLock(&Loader::loading_screen_mutex);
out << "-- END init --" << endl;
return true;
}
bool Global::init(int gfx){
ostream & out = Global::debug( 0 );
out << "-- BEGIN init --" << endl;
out << "Data path is " << Util::getDataPath2().path() << endl;
out << "Paintown version " << Global::getVersionString() << endl;
out << "Build date " << __DATE__ << " " << __TIME__ << endl;
#ifdef WII
/* <WinterMute> fatInitDefault will set working dir to argv[0] passed by launcher,
* or root of first device mounted
*/
out << "Fat init " << (fatInitDefault() == 0 ? "Ok" : "Failed") << endl;
#endif
/*
char buffer[512];
if (getcwd(buffer, 512) != 0){
printf("Working directory '%s'\n", buffer);
}
*/
/* do implementation specific setup */
initSystem(out);
dumb_register_stdfiles();
Sound::initialize();
- Filesystem::initialize();
+ // Filesystem::initialize();
Graphics::SCALE_X = GFX_X;
Graphics::SCALE_Y = GFX_Y;
Configuration::loadConfigurations();
const int sx = Configuration::getScreenWidth();
const int sy = Configuration::getScreenHeight();
if (gfx == -1){
gfx = Configuration::getFullscreen() ? Global::FULLSCREEN : Global::WINDOWED;
} else {
Configuration::setFullscreen(gfx == Global::FULLSCREEN);
}
/* set up the screen */
int gfxCode = Graphics::setGraphicsMode(gfx, sx, sy);
if (gfxCode == 0){
out << "Set graphics mode: Ok" << endl;
} else {
out << "Set graphics mode: Failed! (" << gfxCode << ")" << endl;
return false;
}
/* music */
atexit(&dumb_exit);
out << "Initialize random number generator" << endl;
/* initialize random number generator */
srand(time(NULL));
registerSignals();
#ifdef HAVE_NETWORKING
out << "Initialize network" << endl;
Network::init();
atexit(Network::closeAll);
#endif
/* this mutex is used to show the loading screen while the game loads */
Util::Thread::initializeLock(&Global::messageLock);
out << "-- END init --" << endl;
/*
const Font & font = Font::getDefaultFont();
// font.setSize(30, 30);
Bitmap temp(font.textLength("Loading") + 1, font.getHeight("Loading") + 1);
font.printf(0, 0, Bitmap::makeColor(255, 255, 255), temp, "Loading", 0);
temp.BlitToScreen(sx / 2, sy / 2);
*/
Graphics::Bitmap white(Graphics::getScreenBuffer());
- if (!Filesystem::exists(Util::getDataPath2())){
+ if (!Storage::instance().exists(Util::getDataPath2())){
Global::debug(0) << "Cannot find data path '" << Util::getDataPath2().path() << "'! Either use the -d switch to specify the data directory or find the data directory and move it to that path" << endl;
white.fill(Graphics::makeColor(255, 0, 0));
white.BlitToScreen();
Util::restSeconds(1);
return false;
} else {
white.fill(Graphics::makeColor(255, 255, 255));
white.BlitToScreen();
}
return true;
}
diff --git a/util/music.cpp b/util/music.cpp
index 3e5c5eb2..6cbec39e 100644
--- a/util/music.cpp
+++ b/util/music.cpp
@@ -1,461 +1,461 @@
#include "music.h"
#include <string>
#include <iostream>
#include "globals.h"
#include <algorithm>
// #include "defs.h"
#include "configuration.h"
#include "thread.h"
#include "funcs.h"
#include "file-system.h"
#include "music-player.h"
using namespace std;
static Music * instance = NULL;
static double volume = 1.0;
// static bool muted = false;
static Util::Thread::Id musicThread;
static Util::Thread::Lock musicMutex;
static bool alive = true;
static void * playMusic( void * );
#define synchronized for( int __l( ! Util::Thread::acquireLock(&musicMutex)); __l; __l = 0, Util::Thread::releaseLock(&musicMutex) )
#define LOCK Util::Thread::acquireLock(&musicMutex);
#define UNLOCK Util::Thread::releaseLock(&musicMutex);
/*
#undef LOCK
#undef UNLOCK
#define LOCK
#define UNLOCK
*/
static void * bogus_thread( void * x){
return NULL;
}
Music::Music(bool on):
playing(false),
enabled(on),
fading(0),
musicPlayer(NULL),
currentSong(""){
if (instance != NULL){
cerr << "Trying to instantiate music object twice!" << endl;
return;
}
volume = (double) Configuration::getMusicVolume() / 100.0;
instance = this;
Util::Thread::initializeLock(&musicMutex);
Global::debug(1) << "Creating music thread" << endl;
if (on){
Util::Thread::createThread(&musicThread, NULL, (Util::Thread::ThreadFunction) playMusic, (void *)instance);
} else {
/* FIXME: just don't create a thread at all.. */
Util::Thread::createThread(&musicThread, NULL, (Util::Thread::ThreadFunction) bogus_thread, NULL);
}
}
/*
static bool isAlive(){
bool f = false;
synchronized{
f = alive;
}
return f;
}
*/
static void * playMusic( void * _music ){
Music * music = (Music *) _music;
Global::debug(1) << "Playing music" << endl;
/*
unsigned int tick = 0;
unsigned int counter;
*/
bool playing = true;
while (playing){
LOCK;{
playing = alive;
music->doPlay();
}
UNLOCK;
Util::rest(10);
// Util::YIELD();
// pthread_yield();
}
// cout << "Done with music thread" << endl;
return NULL;
}
double Music::getVolume(){
double vol = 0;
LOCK;{
vol = volume;
}
UNLOCK;
return vol;
}
void Music::doPlay(){
if (this->playing){
double f = fading / 500.0;
switch (fading){
case -1: {
if (volume + f < 0){
fading = 0;
volume = 0;
} else {
volume += f;
this->_setVolume(volume);
}
break;
}
case 1: {
if (volume + f > 1.0){
fading = 0;
volume = 1.0;
} else {
volume += f;
this->_setVolume(volume);
}
break;
}
}
if (musicPlayer != NULL){
musicPlayer->poll();
}
}
}
/*
Music::Music( const char * song ):
volume( 1.0 ),
muted( false ),
player( NULL ),
music_file( NULL ){
loadSong( song );
}
Music::Music( const string & song ):
volume( 1.0 ),
muted( false ),
player( NULL ),
music_file( NULL ){
loadSong( song );
}
*/
void Music::fadeIn(double vol){
LOCK;{
// volume = vol;
instance->_fadeIn();
}
UNLOCK;
}
void Music::fadeOut( double vol ){
LOCK;{
// volume = vol;
instance->_fadeOut();
}
UNLOCK;
}
/* FIXME */
void Music::_fadeIn(){
// fading = 1;
}
void Music::_fadeOut(){
// fading = -1;
}
bool Music::loadSong( const char * song ){
bool loaded = false;
LOCK;{
if (instance != NULL){
loaded = instance->internal_loadSong(song);
}
}
UNLOCK;
return loaded;
// muted = false;
}
/* remove an element from a vector at index 'pos' and return it */
template< class Tx_ >
static Tx_ removeVectorElement( vector< Tx_ > & toRemove, int pos ){
int count = 0;
typename vector< Tx_ >::iterator it;
for ( it = toRemove.begin(); it != toRemove.end() && count < pos; count++, it++ );
if ( it == toRemove.end() ){
/* this isnt right, but whatever */
return toRemove.front();
}
Tx_ removed = toRemove[pos];
toRemove.erase(it);
return removed;
}
void Music::loadSong(vector<Filesystem::AbsolutePath> songs){
/*
cout << "Songs = " << &Songs << endl;
if ( ! loadSong( "music/song5.xm" ) ){
cerr << "Could not load music/song5.xm" << endl;
}
return;
*/
/*
vector<Filesystem::AbsolutePath> _songs = Songs;
vector<Filesystem::AbsolutePath> songs;
while ( ! _songs.empty() ){
int i = Util::rnd(_songs.size());
songs.push_back(removeVectorElement(_songs, i));
}
*/
/*
songs.clear();
songs.push_back( "music/song3.xm" );
*/
std::random_shuffle(songs.begin(), songs.end());
for (vector<Filesystem::AbsolutePath>::iterator it = songs.begin(); it != songs.end(); it++){
Global::debug(1) << "Trying to load song " << (*it).path() << endl;
if (loadSong((*it).path())){
break;
}
}
}
bool Music::loadSong( const string & song ){
return loadSong( song.c_str() );
}
void Music::_play(){
if (playing == false && musicPlayer != NULL){
musicPlayer->play();
playing = true;
}
}
void Music::play(){
LOCK;{
instance->_play();
}
UNLOCK;
}
void Music::_pause(){
playing = false;
if (musicPlayer != NULL){
musicPlayer->pause();
}
}
void Music::pause(){
LOCK;{
instance->_pause();
}
UNLOCK;
}
void Music::soften(){
LOCK;{
instance->_soften();
}
UNLOCK;
}
void Music::_soften(){
if (volume > 0.1){
volume -= 0.1;
} else {
volume = 0.0;
}
_setVolume(volume);
}
void Music::louden(){
LOCK;{
instance->_louden();
}
UNLOCK;
}
void Music::_louden(){
if ( volume < 0.9 ){
volume += 0.1;
} else {
volume = 1.0;
}
_setVolume(volume);
}
void Music::mute(){
setVolume(0);
}
void Music::setVolume( double vol ){
LOCK;{
volume = vol;
if ( volume > 1.0 ){
volume = 1.0;
}
if ( volume < 0 ){
volume = 0;
}
instance->_setVolume( volume );
}
UNLOCK;
}
void Music::_setVolume(double vol){
if (musicPlayer){
musicPlayer->setVolume(vol);
}
}
Music::~Music(){
LOCK;{
if (musicPlayer){
delete musicPlayer;
}
alive = false;
playing = false;
}
UNLOCK;
Global::debug( 1 ) << "Waiting for music thread to die" << endl;
Util::Thread::joinThread(musicThread);
}
static string getExtension(const char * path_){
string path(path_);
if (path.rfind('.') != string::npos){
return Util::lowerCaseAll(path.substr(path.rfind('.') + 1));
}
return "";
}
/* true if the file extension is something DUMB will probably recognize */
static bool isDumbFile(const char * path){
string extension = getExtension(path);
return extension == "mod" ||
extension == "s3m" ||
extension == "it" ||
extension == "xm";
}
static bool isGMEFile(const char * path){
string extension = getExtension(path);
return extension == "nsf" ||
extension == "spc" ||
extension == "gym";
}
static bool isOggFile(const char * path){
string extension = getExtension(path);
return extension == "ogg";
}
static bool isMp3File(const char * path){
string extension = getExtension(path);
return extension == "mp3";
}
bool Music::internal_loadSong( const char * path ){
if (!enabled){
return false;
}
// cout << "Trying to load '" << path << "'" << endl;
// Check current song and/or set it
if (currentSong.compare(std::string(path))==0){
return true;
} else {
currentSong = std::string(path);
}
if (musicPlayer != NULL){
delete musicPlayer;
musicPlayer = NULL;
}
try {
if (isDumbFile(path)){
musicPlayer = new Util::DumbPlayer(path);
musicPlayer->play();
playing = true;
} else if (isGMEFile(path)){
musicPlayer = new Util::GMEPlayer(path);
musicPlayer->play();
playing = true;
#ifdef HAVE_OGG
} else if (isOggFile(path)){
musicPlayer = new Util::OggPlayer(path);
musicPlayer->play();
playing = true;
#endif
#if defined(HAVE_MP3_MPG123) || defined(HAVE_MP3_MAD)
} else if (isMp3File(path)){
/* Utilize SDL mixer to handle mp3 */
musicPlayer = new Util::Mp3Player(path);
musicPlayer->play();
playing = true;
#endif
} else {
return false;
}
if (musicPlayer != NULL){
musicPlayer->setVolume(volume);
}
} catch (const Exception::Base & ex){
Global::debug(0) << "Could not open music file '" << path << "' because " << ex.getTrace() << endl;
//! FIXME Change from Base exception in the futer
return false;
}
return true;
}
void Music::changeSong(){
pause();
fadeIn(0.3);
- loadSong(Filesystem::getFiles(Filesystem::find(Filesystem::RelativePath("music/")), "*"));
+ loadSong(Storage::instance().getFiles(Storage::instance().find(Filesystem::RelativePath("music/")), "*"));
play();
}
#undef synchronized
#undef LOCK
#undef UNLOCK
diff --git a/util/resource.cpp b/util/resource.cpp
index af4d25f4..73b22e2f 100644
--- a/util/resource.cpp
+++ b/util/resource.cpp
@@ -1,52 +1,52 @@
#include "bitmap.h"
#include "resource.h"
#include "factory/collector.h"
#include "funcs.h"
#include "sound.h"
#include "load_exception.h"
#include "file-system.h"
#include <string>
#include <vector>
using namespace std;
Resource * Resource::resource = NULL;
Sound * Resource::getSound(const Filesystem::RelativePath & path) throw (LoadException){
- return resource->_getSound(Filesystem::find(path));
+ return resource->_getSound(Storage::instance().find(path));
}
Graphics::Bitmap * Resource::getBitmap(const Filesystem::RelativePath & path) throw (LoadException){
- return resource->_getBitmap(Filesystem::find(path));
+ return resource->_getBitmap(Storage::instance().find(path));
}
/* the resource is created in the Collector */
Resource::Resource(){
resource = this;
}
Resource::~Resource(){
for (std::map<std::string, Sound*>::iterator it = sounds.begin(); it != sounds.end(); it++){
delete (*it).second;
}
for (std::map<std::string, Graphics::Bitmap*>::iterator it = bitmaps.begin(); it != bitmaps.end(); it++){
delete (*it).second;
}
}
Sound * Resource::_getSound(const Filesystem::AbsolutePath & path) throw (LoadException){
Util::Thread::ScopedLock locked(lock);
if (sounds[path.path()] == NULL){
sounds[path.path()] = new Sound(path.path());
}
return sounds[path.path()];
}
Graphics::Bitmap * Resource::_getBitmap(const Filesystem::AbsolutePath & path) throw (LoadException){
Util::Thread::ScopedLock locked(lock);
if (bitmaps[path.path()] == NULL){
bitmaps[path.path()] = new Graphics::Bitmap(path.path());
}
return bitmaps[path.path()];
}
diff --git a/util/thread.h b/util/thread.h
index ef28cdac..d38f4b5d 100644
--- a/util/thread.h
+++ b/util/thread.h
@@ -1,252 +1,252 @@
#ifndef _paintown_thread_h
#define _paintown_thread_h
#ifdef USE_SDL
#include <SDL_thread.h>
#include <SDL_mutex.h>
#elif USE_ALLEGRO5
#include <allegro5/allegro5.h>
#else
#include <pthread.h>
// #include <semaphore.h>
#endif
#include "exceptions/exception.h"
#include "load_exception.h"
#include "token_exception.h"
#include "mugen/exception.h"
-#include "funcs.h"
+// #include "funcs.h"
#include "debug.h"
namespace Util{
/* Either uses pthreads or SDL_thread */
namespace Thread{
#ifdef USE_SDL
typedef SDL_mutex* Lock;
typedef SDL_Thread* Id;
typedef int (*ThreadFunction)(void*);
typedef SDL_cond* Condition;
// typedef SDL_semaphore* Semaphore;
#elif USE_ALLEGRO5
typedef ALLEGRO_MUTEX* Lock;
typedef ALLEGRO_THREAD* Id;
typedef void * (*ThreadFunction)(void*);
typedef ALLEGRO_COND* Condition;
// typedef SDL_semaphore* Semaphore;
#else
typedef pthread_mutex_t Lock;
typedef pthread_t Id;
typedef pthread_cond_t Condition;
// typedef sem_t Semaphore;
typedef void * (*ThreadFunction)(void*);
#endif
extern Id uninitializedValue;
bool isUninitialized(Id thread);
void initializeLock(Lock * lock);
void initializeCondition(Condition * condition);
void destroyCondition(Condition * condition);
int conditionWait(Condition * condition, Lock * lock);
int conditionSignal(Condition * condition);
/*
void initializeSemaphore(Semaphore * semaphore, unsigned int value);
void destroySemaphore(Semaphore * semaphore);
void semaphoreDecrease(Semaphore * semaphore);
void semaphoreIncrease(Semaphore * semaphore);
*/
int acquireLock(Lock * lock);
int releaseLock(Lock * lock);
void destroyLock(Lock * lock);
bool createThread(Id * thread, void * attributes, ThreadFunction function, void * arg);
void joinThread(Id thread);
void cancelThread(Id thread);
/* wraps a Lock in a c++ class */
class LockObject{
public:
LockObject();
void acquire() const;
void release() const;
void wait(volatile bool & check) const;
void signal() const;
virtual ~LockObject();
Lock lock;
Condition condition;
};
/* acquires/releases the lock in RAII fashion */
class ScopedLock{
public:
ScopedLock(const LockObject & lock);
~ScopedLock();
private:
const LockObject & lock;
};
}
class WaitThread{
public:
/* does not start a new thread yet */
WaitThread();
/* starts a thread */
WaitThread(Thread::ThreadFunction thread, void * arg);
/* starts a thread */
void start(Thread::ThreadFunction thread, void * arg);
bool isRunning();
void kill();
virtual ~WaitThread();
public:
/* actually runs the thread */
void doRun();
protected:
Thread::Lock doneLock;
Thread::Id thread;
volatile bool done;
void * arg;
Thread::ThreadFunction function;
};
/* wraps a boolean with lock/unlock while checking/setting it */
class ThreadBoolean{
public:
ThreadBoolean(volatile bool & what, Thread::Lock & lock);
bool get();
void set(bool value);
protected:
volatile bool & what;
Thread::Lock & lock;
};
/* Computes stuff in a separate thread and gives it back when you ask for it.
* As soon as the future is created a thread will start executing and compute
* whatever it is that the class is supposed to do. You can then call `get'
* on the future object to get the result. If the thread is still executing
* then `get' will block until the future completes. If the future has already
* completed then `get' will return immediately with the computed value.
* The use case is computing something that has to be used later:
* Future future; // might take a while to compute
* do_stuff_that_takes_a_while(); // future might finish sometime in here
* Object o = future.get(); // future is already done
*
* TODO: handle exceptions
*/
template<class X>
class Future{
protected:
/* WARNING: hack to find out the type of the exception */
/*
enum ExceptionType{
None,
Load,
Token,
Base,
Mugen
};
*/
public:
Future():
thing(0),
thread(Thread::uninitializedValue),
done(false),
exception(NULL){
/* future will increase the count */
// Thread::initializeSemaphore(&future, 0);
// future.acquire();
}
virtual ~Future(){
if (Thread::isUninitialized(thread)){
Thread::joinThread(thread);
}
// Thread::destroySemaphore(&future);
delete exception;
}
virtual X get(){
X out;
Exception::Base * failed = NULL;
future.acquire();
future.wait(done);
// Thread::semaphoreDecrease(&future);
if (exception != NULL){
failed = exception;
// exception->throwSelf();
}
out = thing;
// Thread::semaphoreIncrease(&future);
future.release();
if (failed){
failed->throwSelf();
}
return out;
}
virtual void start(){
if (!Thread::createThread(&thread, NULL, (Thread::ThreadFunction) runit, this)){
Global::debug(0) << "Could not create future thread. Blocking until its done" << std::endl;
runit(this);
// throw Exception::Base(__FILE__, __LINE__);
}
}
protected:
bool isDone(){
Thread::ScopedLock scoped(future);
return done;
}
static void * runit(void * arg){
Future<X> * me = (Future<X>*) arg;
try{
me->compute();
} catch (const LoadException & load){
me->exception = new LoadException(load);
} catch (const TokenException & t){
me->exception = new TokenException(t);
} catch (const MugenException & m){
me->exception = new MugenException(m);
} catch (const Exception::Base & base){
me->exception = new Exception::Base(base);
}
me->future.acquire();
me->done = true;
me->future.signal();
me->future.release();
// Thread::semaphoreIncrease(&me->future);
return NULL;
}
virtual void set(X x){
this->thing = x;
}
virtual void compute() = 0;
X thing;
Thread::Id thread;
Thread::LockObject future;
volatile bool done;
/* if any exceptions occur, throw them from `get' */
Exception::Base * exception;
};
}
#endif

File Metadata

Mime Type
text/x-diff
Expires
Thu, Jun 11, 10:39 AM (3 w, 5 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
68479
Default Alt Text
(97 KB)

Event Timeline