/* orxonox - the future of 3D-vertical-scrollers Copyright (C) 2004 orx This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. ### File Specific: main-programmer: Benjamin Grauer co-programmer: ... */ #define DEBUG_SPECIAL_MODULE DEBUG_MODULE_LOAD #include "resource_manager.h" // different resource Types #include "objModel.h" #include "primitive_model.h" #include "texture.h" #include "list.h" // File Handling Includes #include #include #include using namespace std; /** \brief standard constructor */ ResourceManager::ResourceManager () { this->setClassName ("ResourceManager"); dataDir = NULL; imageDirs = new tList(); resourceList = new tList(); } ResourceManager* ResourceManager::getInstance(void) { if (!ResourceManager::singletonRef) ResourceManager::singletonRef = new ResourceManager(); return ResourceManager::singletonRef; } //! Singleton Reference to the ResourceManager ResourceManager* ResourceManager::singletonRef = NULL; //! The List of Resources, that has already been loaded. tList* ResourceManager::resourceList = NULL; //! The Data Directory, where all relevant Data is stored. char* ResourceManager::dataDir = NULL; //! A list of directories in which images are stored. tList* ResourceManager::imageDirs = NULL; /** \brief standard deconstructor */ ResourceManager::~ResourceManager (void) { delete resourceList; resourceList = NULL; ResourceManager::singletonRef = NULL; } /** \brief sets the data main directory \param dataDir the DataDirectory. */ bool ResourceManager::setDataDir(char* dataDir) { if (isDir(dataDir)) { ResourceManager::dataDir = new char[strlen(dataDir)+1]; strcpy(ResourceManager::dataDir, dataDir); } else { PRINTF(1)("%s is not a Directory, and can not be the Data Directory\n", dataDir); } } bool ResourceManager::addImageDir(char* imageDir) { if (isDir(imageDir)) { char* tmpDir = new char[strlen(imageDir)+1]; strcpy(tmpDir, imageDir); imageDirs->add(tmpDir); } else { PRINTF(1)("%s is not a Directory, and can not be added to the Paths of Images\n", dataDir); } } /** \brief loads resources \param fileName The fileName of the resource to load \returns a pointer to a desired Resource. */ void* ResourceManager::load(const char* fileName) { ResourceType tmpType; if (!strncmp(fileName+(strlen(fileName)-4), ".obj", 4)) tmpType = OBJ; else if (!strncmp(fileName+(strlen(fileName)-4), ".wav", 4)) tmpType = WAV; else if (!strncmp(fileName+(strlen(fileName)-4), ".mp3", 4)) tmpType = MP3; else if (!strncmp(fileName+(strlen(fileName)-4), ".ogg", 4)) tmpType = OGG; else if (!strcmp(fileName, "cube") || !strcmp(fileName, "sphere") || !strcmp(fileName, "plane") || !strcmp(fileName, "cylinder") || !strcmp(fileName, "cone")) tmpType = PRIM; else tmpType = IMAGE; return ResourceManager::load(fileName, tmpType); } /** \brief loads resources \param fileName The fileName of the resource to load \param type The Type of Resource to load (\see ResourceType) \returns a pointer to a desired Resource. */ void* ResourceManager::load(const char* fileName, ResourceType type) { // searching if the resource was loaded before. Resource* tmpResource = ResourceManager::locateResourceByName(fileName); char* tmpDir; if (!tmpResource) // if the resource was not loaded before. { // Setting up the new Resource tmpResource = new Resource; tmpResource->count = 1; tmpResource->type = type; tmpResource->name = new char[strlen(fileName)+1]; strcpy(tmpResource->name, fileName); // creating the full name. (directoryName + FileName) char* fullName = new char[strlen(dataDir)+strlen(fileName)+1]; sprintf(fullName, "%s%s", dataDir, fileName); // Checking for the type of resource \see ResourceType switch(type) { case OBJ: if(isFile(fullName)) tmpResource->pointer = new OBJModel(fullName); else { PRINTF(2)("Sorry, %s does not exist. Loading a cube-Model instead\n", fullName); tmpResource->pointer = ResourceManager::load("cube", PRIM); } break; case PRIM: if (!strcmp(tmpResource->name, "cube")) tmpResource->pointer = new PrimitiveModel(CUBE); else if (!strcmp(tmpResource->name, "sphere")) tmpResource->pointer = new PrimitiveModel(SPHERE); else if (!strcmp(tmpResource->name, "plane")) tmpResource->pointer = new PrimitiveModel(PLANE); else if (!strcmp(tmpResource->name, "cylinder")) tmpResource->pointer = new PrimitiveModel(CYLINDER); else if (!strcmp(tmpResource->name, "cone")) tmpResource->pointer = new PrimitiveModel(CONE); break; case IMAGE: if(isFile(fullName)) { tmpResource->pointer = new Texture(fullName); } else { tmpDir = imageDirs->enumerate(); while(tmpDir) { char* imgName = new char[strlen(tmpDir)+strlen(fileName)+1]; sprintf(imgName, "%s%s", tmpDir, fileName); if(isFile(imgName)) tmpResource->pointer = new Texture(imgName); delete []imgName; tmpDir = imageDirs->nextElement(); } } if(!tmpResource) PRINTF(2)("!!Image %s not Found!!\n", fileName); break; default: tmpResource->pointer = NULL; PRINTF(1)("No type found for %s.\n !!This should not happen unless the Type is not supported yet.!!\n", tmpResource->name); break; } // checking if the File really exists. if(!isFile(fullName)) { PRINTF(2)("Sorry, %s is not a regular file.\n", fullName); tmpResource->pointer = NULL; } resourceList->add(tmpResource); delete []fullName; } else { tmpResource->count++; } return tmpResource->pointer; } /** \brief unloads a Resource \param pointer The pointer to free \returns true if successful (pointer found, and deleted), false otherwise */ bool ResourceManager::unload(void* pointer) { // if pointer is existent. and only one resource of this type exists. Resource* tmpResource = ResourceManager::locateResourceByPointer(pointer); if (!tmpResource) { PRINTF(2)("Resource not Found %p\n", pointer); return false; } tmpResource->count--; if (tmpResource->count <= 0) { // deleting the Resource switch(tmpResource->type) { case OBJ: case PRIM: delete (Model*)tmpResource->pointer; break; case IMAGE: delete (Texture*)tmpResource->pointer; break; default: PRINTF(1)("NOT YET IMPLEMENTED FIX FIX\n"); return false; break; } // deleting the List Entry: PRINTF(4)("Resource %s Safely removed.\n", tmpResource->name); delete []tmpResource->name; resourceList->remove(tmpResource); } else PRINTF(4)("Resource not removed, because there are still %d References to it.\n", tmpResource->count); return true; } /** \brief Searches for a Resource by Name \param fileName The name to look for \returns a Pointer to the Resource if found, NULL otherwise. */ Resource* ResourceManager::locateResourceByName(const char* fileName) { Resource* enumRes = resourceList->enumerate(); while (enumRes) { if (!strcmp(fileName, enumRes->name)) return enumRes; enumRes = resourceList->nextElement(); } return NULL; } /** \brief Searches for a Resource by Pointer \param pointer the Pointer to search for \returns a Pointer to the Resource if found, NULL otherwise. */ Resource* ResourceManager::locateResourceByPointer(const void* pointer) { Resource* enumRes = resourceList->enumerate(); while (enumRes) { if (pointer == enumRes->pointer); return enumRes; enumRes = resourceList->nextElement(); } return NULL; } /** \brief Checks if it is a Directory \param directoryName the Directory to check for \returns true if it is a directory/symlink false otherwise */ bool ResourceManager::isDir(const char* directoryName) { struct stat status; stat(directoryName, &status); if (status.st_mode & (S_IFDIR | S_IFLNK)) return true; else return false; } /** \brief Checks if the file is either a Regular file or a Symlink \param fileName the File to check for \returns true if it is a regular file/symlink, false otherwise */ bool ResourceManager::isFile(const char* fileName) { struct stat status; stat(fileName, &status); if (status.st_mode & (S_IFREG | S_IFLNK)) return true; else return false; }