Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/lib/util/loading/resource_manager.cc @ 7202

Last change on this file since 7202 was 7199, checked in by bensch, 18 years ago

orxonox/trunk: MultiType rework (now uses std::string) this is more compliant, and better to handle

File size: 32.4 KB
RevLine 
[4597]1/*
[1853]2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
[1855]10
11   ### File Specific:
[3655]12   main-programmer: Benjamin Grauer
[3672]13   co-programmer: Patrick Boenzli
[1853]14*/
15
[3655]16#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_LOAD
[1853]17
[7193]18#include "util/loading/resource_manager.h"
[1853]19
[6648]20#include "substring.h"
[4642]21#include "debug.h"
22
[6222]23#include <algorithm>
[6655]24#include <assert.h>
[6222]25
[3655]26// different resource Types
[4534]27#ifndef NO_MODEL
[3655]28#include "objModel.h"
[3657]29#include "primitive_model.h"
[4462]30#include "md2Model.h"
[4534]31#endif /* NO_MODEL */
32#ifndef NO_TEXTURES
[3655]33#include "texture.h"
[4534]34#endif /* NO_TEXTURES */
35#ifndef NO_TEXT
[5344]36#include "font.h"
[4534]37#endif /* NO_TEXT */
38#ifndef NO_AUDIO
[5930]39#include "sound_buffer.h"
[4961]40#include "ogg_player.h"
[4534]41#endif /* NO_AUDIO */
[5323]42#ifndef NO_SHADERS
43#include "shader.h"
44#endif /* NO_SHADERS */
[1853]45
[3655]46// File Handling Includes
47#include <sys/types.h>
48#include <sys/stat.h>
49#include <unistd.h>
50
[1856]51using namespace std;
[1853]52
[3245]53/**
[6647]54 * @brief standard constructor
[3245]55*/
[4597]56ResourceManager::ResourceManager ()
[3365]57{
[4597]58  this->setClassID(CL_RESOURCE_MANAGER, "ResourceManager");
59  this->setName("ResourceManager");
60
[5423]61  this->dataDir = new char[3];
62  strcpy(this->dataDir, "./");
[5480]63  this->tryDataDir("./data");
[7196]64
65  this->_cwd = NULL;
[3365]66}
[1853]67
[3658]68//! Singleton Reference to the ResourceManager
[3655]69ResourceManager* ResourceManager::singletonRef = NULL;
70
[3245]71/**
[6647]72 * @brief standard destructor
[3655]73*/
[4746]74ResourceManager::~ResourceManager ()
[3655]75{
[3660]76  // deleting the Resources-List
[3672]77  this->unloadAllByPriority(RP_GAME);
[5303]78
[6222]79  if (!this->resourceList.empty())
80    PRINTF(1)("Not removed all Resources, since there are still %d resources registered\n", this->resourceList.size());
[5303]81
[3660]82  // deleting the Directorie Lists
[6222]83  while (!this->imageDirs.empty())
[6640]84  {
[6642]85    delete[] this->imageDirs.back();
86    this->imageDirs.pop_back();
[6640]87  }
[3672]88
[5211]89  delete[] this->dataDir;
[7196]90  if (this->_cwd)
91    delete[] this->_cwd;
[3655]92  ResourceManager::singletonRef = NULL;
93}
[1853]94
[3655]95/**
[6647]96 * @brief sets the data main directory
[4836]97 * @param dataDir the DataDirectory.
[5480]98 */
[3883]99bool ResourceManager::setDataDir(const char* dataDir)
[3543]100{
[4341]101  char* realDir = ResourceManager::homeDirCheck(dataDir);
102  if (isDir(realDir))
[5480]103  {
104    delete[] this->dataDir;
105    if (dataDir[strlen(dataDir)-1] == '/' || dataDir[strlen(dataDir)-1] == '\\')
[3655]106    {
[5480]107      this->dataDir = new char[strlen(realDir)+1];
108      strcpy(this->dataDir, realDir);
[3655]109    }
[5480]110    else
111    {
112      this->dataDir = new char[strlen(realDir)+2];
113      strcpy(this->dataDir, realDir);
114      this->dataDir[strlen(realDir)] = '/';
115      this->dataDir[strlen(realDir)+1] = '\0';
116    }
117    delete[] realDir;
118    return true;
119  }
[3655]120  else
[5480]121  {
122    PRINTF(1)("%s is not a Directory, and can not be the Data Directory, leaving as %s \n", realDir, this->dataDir);
123    delete[] realDir;
124    return false;
125  }
126}
127
128/**
[6647]129 * @brief sets the data main directory
[5480]130 * @param dataDir the DataDirectory.
131 *
132 * this is essentially the same as setDataDir, but it ommits the error-message
133 */
134bool ResourceManager::tryDataDir(const char* dataDir)
135{
136  char* realDir = ResourceManager::homeDirCheck(dataDir);
137  if (isDir(realDir))
138  {
139    delete[] this->dataDir;
140    if (dataDir[strlen(dataDir)-1] == '/' || dataDir[strlen(dataDir)-1] == '\\')
[3655]141    {
[5480]142      this->dataDir = new char[strlen(realDir)+1];
143      strcpy(this->dataDir, realDir);
[3655]144    }
[5480]145    else
146    {
147      this->dataDir = new char[strlen(realDir)+2];
148      strcpy(this->dataDir, realDir);
149      this->dataDir[strlen(realDir)] = '/';
150      this->dataDir[strlen(realDir)+1] = '\0';
151    }
152    delete[] realDir;
153    return true;
154  }
[5483]155  delete[] realDir;
[5482]156  return false;
[3543]157}
[1853]158
[5480]159
[3660]160/**
[6647]161 * @brief checks for the DataDirectory, by looking if
[5480]162 * @param fileInside is iniside of the given directory.
[4091]163*/
[5480]164bool ResourceManager::verifyDataDir(const char* fileInside)
[4091]165{
166  bool retVal;
167  if (!isDir(this->dataDir))
[6640]168  {
169    PRINTF(1)("%s is not a directory\n", this->dataDir);
170    return false;
171  }
[4597]172
[4091]173  char* testFile = new char[strlen(this->dataDir)+strlen(fileInside)+1];
174  sprintf(testFile, "%s%s", this->dataDir, fileInside);
175  retVal = isFile(testFile);
[5208]176  delete[] testFile;
[4091]177  return retVal;
178}
179
[4653]180#ifndef NO_TEXTURES
[4091]181/**
[6647]182 * @brief adds a new Path for Images
[4836]183 * @param imageDir The path to insert
184 * @returns true, if the Path was well and injected (or already existent within the list)
[3660]185   false otherwise
186*/
[4370]187bool ResourceManager::addImageDir(const char* imageDir)
[3658]188{
[5335]189  if (imageDir == NULL)
190    return false;
191
192  char* newDir;
193  if (imageDir[strlen(imageDir)-1] == '/' || imageDir[strlen(imageDir)-1] == '\\')
194  {
195    newDir = new char[strlen(imageDir)+1];
196    strcpy(newDir, imageDir);
197  }
198  else
199  {
200    newDir = new char[strlen(imageDir)+2];
201    strcpy(newDir, imageDir);
202    newDir[strlen(imageDir)] = '/';
203    newDir[strlen(imageDir)+1] = '\0';
204  }
[3660]205  // check if the param is a Directory
[5335]206  if (isDir(newDir))
[6640]207  {
208    // check if the Directory has been added before
[6642]209    std::vector<char*>::const_iterator imageDir;
[6640]210    for (imageDir = this->imageDirs.begin(); imageDir != this->imageDirs.end(); imageDir++)
[3658]211    {
[6640]212      if (!strcmp(*imageDir, newDir))
[6222]213      {
[6640]214        PRINTF(3)("Path %s already loaded\n", newDir);
215        delete[] newDir;
216        return true;
[6222]217      }
[3658]218    }
[6640]219    // adding the directory to the List
220    this->imageDirs.push_back(newDir);
221    return true;
222  }
[3658]223  else
[6640]224  {
225    PRINTF(1)("%s is not a Directory, and can not be added to the Paths of Images\n", newDir);
226    delete[] newDir;
227    return false;
228  }
[3658]229}
[4534]230#endif /* NO_TEXTURES */
[3658]231
[3245]232/**
[6647]233 * @brief loads resources
[4836]234 * @param fileName: The fileName of the resource to load
235 * @param prio: The ResourcePriority of this resource (will only be increased)
[6645]236 * @param param0: an additional option to parse (see the constuctors for more help)
[4836]237 * @param param1: an additional option to parse (see the constuctors for more help)
238 * @param param2: an additional option to parse (see the constuctors for more help)
239 * @returns a pointer to a desired Resource.
[3655]240*/
[6645]241BaseObject* ResourceManager::load(const char* fileName, ResourcePriority prio,
[6648]242                                  const MultiType& param0, const MultiType& param1, const MultiType& param2)
[3655]243{
[5366]244  if (fileName == NULL)
245    return NULL;
[3655]246  ResourceType tmpType;
[4534]247#ifndef NO_MODEL
[4637]248#define __IF_OK
[5323]249  if (!strncasecmp(fileName+(strlen(fileName)-4), ".obj", 4))
[3655]250    tmpType = OBJ;
[4534]251  else if (!strncmp(fileName+(strlen(fileName)-4), ".md2", 4))
[4462]252    tmpType = MD2;
[5323]253  else if (!strcasecmp(fileName, "cube") ||
254           !strcasecmp(fileName, "sphere") ||
255           !strcasecmp(fileName, "plane") ||
256           !strcasecmp(fileName, "cylinder") ||
257           !strcasecmp(fileName, "cone"))
[4534]258    tmpType = PRIM;
259#endif /* NO_MODEL */
260#ifndef NO_AUDIO
[4637]261#ifdef __IF_OK
262  else
263#endif
264#define __IF_OK
[6640]265    if (!strncasecmp(fileName+(strlen(fileName)-4), ".wav", 4))
266      tmpType = WAV;
267    else if (!strncasecmp(fileName+(strlen(fileName)-4), ".mp3", 4))
268      tmpType = MP3;
269    else if (!strncasecmp(fileName+(strlen(fileName)-4), ".ogg", 4))
270      tmpType = OGG;
[4534]271#endif /* NO_AUDIO */
272#ifndef NO_TEXT
[4637]273#ifdef __IF_OK
[6640]274    else
[4637]275#endif
276#define __IF_OK
[6640]277      if (!strncasecmp(fileName+(strlen(fileName)-4), ".ttf", 4))
278        tmpType = TTF;
[4534]279#endif /* NO_TEXT */
[5323]280#ifndef NO_SHADERS
281#ifdef __IF_OK
[6640]282      else
[5323]283#endif
284#define __IF_OK
[6640]285        if (!strncasecmp(fileName+(strlen(fileName)-5), ".vert", 5))
286          tmpType = SHADER;
[5323]287#endif /* NO_SHADERS */
[4534]288#ifndef NO_TEXTURES
[4637]289#ifdef __IF_OK
[6640]290        else
[4637]291#else
292  if
293#endif
[6640]294          tmpType = IMAGE;
[4534]295#endif /* NO_TEXTURES */
[4653]296#undef __IF_OK
[6645]297  return this->load(fileName, tmpType, prio, param0, param1, param2);
[3655]298}
299
300/**
[6647]301 * @brief caches a Resource
[6641]302 *
303 * @see load;
304 *
[6650]305 * @brief returns true if ok, false otherwise.
[6641]306 * This function loads a Resource without applying it to an Object.
307 * This is for loading purposes, e.g, when the user is loading a Resource
308 * during the initialisation instead of at Runtime.
309 */
[6650]310bool ResourceManager::cache(const char* fileName, ResourceType type, ResourcePriority prio,
[6645]311                            const MultiType& param0, const MultiType& param1, const MultiType& param2)
[6641]312{
313  assert(fileName != NULL);
314
315  // searching if the resource was loaded before.
316  Resource* tmpResource;
317  // check if we already loaded this Resource
[6645]318  tmpResource = this->locateResourceByInfo(fileName, type, param0, param1, param2);
[6641]319  // otherwise load it
320  if (tmpResource == NULL)
[6645]321    tmpResource = this->loadResource(fileName, type, prio, param0, param1, param2);
[6641]322  // return cached pointer.
323  if (tmpResource != NULL) // if the resource was loaded before.
[6650]324  {
[6641]325    if(tmpResource->prio < prio)
326      tmpResource->prio = prio;
[6650]327    return true;
328  }
329  else
330    return false;
[6641]331}
332
[6651]333/**
334 * tells the ResourceManager to generate a Copy of the Resource.
335 * @brief resourcePointer: The Pointer to the resource to copy
336 * @returns the Resource pointed to resourcePointer.
337 */
338BaseObject* ResourceManager::copy(BaseObject* resourcePointer)
339{
340  Resource* tmp = locateResourceByPointer(resourcePointer);
341  if (tmp!=NULL)
342  {
343    tmp->count++;
344    return tmp->pointer;
345  }
346  else
347    return NULL;
348}
[6641]349
[6651]350
[6641]351/**
[6647]352 * @brief loads resources
[4836]353 * @param fileName: The fileName of the resource to load
[5306]354 * @param type: The Type of Resource to load.
[4836]355 * @param prio: The ResourcePriority of this resource (will only be increased)
[6645]356 * @param param0: an additional option to parse (see the constuctors for more help)
[4836]357 * @param param1: an additional option to parse (see the constuctors for more help)
358 * @param param2: an additional option to parse (see the constuctors for more help)
359 * @returns a pointer to a desired Resource.
[3245]360*/
[5304]361BaseObject* ResourceManager::load(const char* fileName, ResourceType type, ResourcePriority prio,
[6645]362                                  const MultiType& param0, const MultiType& param1, const MultiType& param2)
[3655]363{
[6640]364  assert(fileName != NULL);
[5366]365
[3658]366  // searching if the resource was loaded before.
[6640]367  Resource* tmpResource;
368  // check if we already loaded this Resource
[6645]369  tmpResource = this->locateResourceByInfo(fileName, type, param0, param1, param2);
[6640]370  // otherwise load it
371  if (tmpResource == NULL)
[6648]372  {
[6645]373    tmpResource = this->loadResource(fileName, type, prio, param0, param1, param2);
[6648]374  }
[6640]375  // return cached pointer.
[5306]376  if (tmpResource != NULL) // if the resource was loaded before.
[6640]377  {
378    tmpResource->count++;
379    if(tmpResource->prio < prio)
380      tmpResource->prio = prio;
[6648]381
[6640]382    return tmpResource->pointer;
383  }
[3677]384  else
[6640]385    return NULL;
386}
[3658]387
[6640]388
389/**
[6647]390 * @brief loads resources for internal purposes
[6640]391 * @param fileName: The fileName of the resource to load
392 * @param type: The Type of Resource to load.
393 * @param prio: The ResourcePriority of this resource (will only be increased)
[6645]394 * @param param0: an additional option to parse (see the constuctors for more help)
[6640]395 * @param param1: an additional option to parse (see the constuctors for more help)
396 * @param param2: an additional option to parse (see the constuctors for more help)
397 * @returns a pointer to a desired Resource.
398 */
399Resource* ResourceManager::loadResource(const char* fileName, ResourceType type, ResourcePriority prio,
[6645]400                                        const MultiType& param0, const MultiType& param1, const MultiType& param2)
[6640]401{
402  // Setting up the new Resource
403  Resource* tmpResource = new Resource;
404  tmpResource->count = 0;
405  tmpResource->type = type;
406  tmpResource->prio = prio;
407  tmpResource->pointer = NULL;
408  tmpResource->name = new char[strlen(fileName)+1];
409  strcpy(tmpResource->name, fileName);
410
411  // creating the full name. (directoryName + FileName)
412  char* fullName = ResourceManager::getFullName(fileName);
413  // Checking for the type of resource \see ResourceType
414  switch(type)
415  {
[4534]416#ifndef NO_MODEL
[6648]417    case OBJ:
418      if (param0.getType() != MT_NULL)
419        tmpResource->param[0] = param0;
420      else
421        tmpResource->param[0] = 1.0f;
[3790]422
[6648]423      if(ResourceManager::isFile(fullName))
424        tmpResource->pointer = new OBJModel(fullName, tmpResource->param[0].getFloat());
425      else
426      {
427        PRINTF(2)("File %s in %s does not exist. Loading a cube-Model instead\n", fileName, dataDir);
428        tmpResource->pointer = ResourceManager::load("cube", PRIM, prio, tmpResource->param[0].getFloat());
429      }
430      break;
431    case PRIM:
432      if (param0 != MT_NULL)
433        tmpResource->param[0] = param0;
434      else
435        tmpResource->param[0] = 1.0f;
[3790]436
[6648]437      if (!strcmp(tmpResource->name, "cube"))
438        tmpResource->pointer = new PrimitiveModel(PRIM_CUBE, tmpResource->param[0].getFloat());
439      else if (!strcmp(tmpResource->name, "sphere"))
440        tmpResource->pointer = new PrimitiveModel(PRIM_SPHERE, tmpResource->param[0].getFloat());
441      else if (!strcmp(tmpResource->name, "plane"))
442        tmpResource->pointer = new PrimitiveModel(PRIM_PLANE, tmpResource->param[0].getFloat());
443      else if (!strcmp(tmpResource->name, "cylinder"))
444        tmpResource->pointer = new PrimitiveModel(PRIM_CYLINDER, tmpResource->param[0].getFloat());
445      else if (!strcmp(tmpResource->name, "cone"))
446        tmpResource->pointer = new PrimitiveModel(PRIM_CONE, tmpResource->param[0].getFloat());
447      break;
448    case MD2:
449      if(ResourceManager::isFile(fullName))
450      {
451        tmpResource->param[0] = param0;
[7059]452        tmpResource->param[1] = param1;
[7199]453        tmpResource->pointer = new MD2Data(fullName, tmpResource->param[0].getCString(), tmpResource->param[1].getFloat());
[6648]454      }
455      break;
[4534]456#endif /* NO_MODEL */
457#ifndef NO_TEXT
[6648]458    case TTF:
459      if (param0 != MT_NULL)
460      {
461        assert(param0.getInt() >= 0);
462        tmpResource->param[0] = param0;
463      }
464      else
465        tmpResource->param[0] = FONT_DEFAULT_RENDER_SIZE;
[4597]466
[6648]467      if(isFile(fullName))
468        tmpResource->pointer = new Font(fullName, (unsigned int) tmpResource->param[0].getInt());
469      else
470        PRINTF(2)("%s does not exist in %s. Not loading Font\n", fileName, this->dataDir);
471      break;
[4534]472#endif /* NO_TEXT */
473#ifndef NO_AUDIO
[6648]474    case WAV:
475      if(isFile(fullName))
476        tmpResource->pointer = new SoundBuffer(fullName);
477      break;
478    case OGG:
479      if (isFile(fullName))
480        tmpResource->pointer = new OggPlayer(fullName);
481      break;
[4534]482#endif /* NO_AUDIO */
483#ifndef NO_TEXTURES
[6648]484    case IMAGE:
485      if (param0 != MT_NULL)
486        tmpResource->param[0] = param0;
487      else
488        tmpResource->param[0] = GL_TEXTURE_2D;
489      if(isFile(fullName))
[6640]490      {
[6648]491        PRINTF(4)("Image %s resides to %s\n", fileName, fullName);
[6859]492        tmpResource->pointer = new Texture(fullName, tmpResource->param[0].getInt());
[6648]493      }
494      else
495      {
496        std::vector<char*>::iterator imageDir;
497        for (imageDir = this->imageDirs.begin(); imageDir != this->imageDirs.end(); imageDir++)
[6640]498        {
[6648]499          char* imgName = new char[strlen(*imageDir)+strlen(fileName)+1];
500          sprintf(imgName, "%s%s", *imageDir, fileName);
501          if(isFile(imgName))
502          {
503            PRINTF(4)("Image %s resides to %s\n", fileName, imgName);
504            tmpResource->pointer = new Texture(imgName, tmpResource->param[0].getInt());
505            delete[] imgName;
506            break;
507          }
[6640]508          delete[] imgName;
509        }
510      }
[6648]511      if(!tmpResource)
512        PRINTF(2)("!!Image %s not Found!!\n", fileName);
513      break;
[4534]514#endif /* NO_TEXTURES */
[5323]515#ifndef NO_SHADERS
[6648]516    case SHADER:
517      if(ResourceManager::isFile(fullName))
[6640]518      {
[6648]519        if (param0 != MT_NULL)
[6640]520        {
[6648]521          MultiType param = param0; /// HACK
[7199]522          char* secFullName = ResourceManager::getFullName(param.getCString());
[6648]523          if (ResourceManager::isFile(secFullName))
524          {
525            tmpResource->param[0] = secFullName;
526            tmpResource->pointer = new Shader(fullName, secFullName);
527          }
528          delete[] secFullName;
[4597]529        }
[6648]530        else
531        {
532          tmpResource->param[0] = param0;
533          tmpResource->pointer = new Shader(fullName, NULL);
534        }
[6640]535      }
[6648]536      break;
[6640]537#endif /* NO_SHADERS */
[6648]538    default:
539      tmpResource->pointer = NULL;
540      PRINTF(1)("No type found for %s.\n   !!This should not happen unless the Type is not supported yet. JUST DO IT!!\n", tmpResource->name);
541      break;
[6640]542  }
[5216]543  if (tmpResource->pointer != NULL)
[6640]544    this->resourceList.push_back(tmpResource);
545  delete[] fullName;
546
547
548  if (tmpResource->pointer != NULL)
549    return tmpResource;
[4597]550  else
[6640]551  {
552    PRINTF(2)("Resource %s could not be loaded\n", fileName);
553    delete[] tmpResource->name;
554    delete tmpResource;
555    return NULL;
556  }
[3658]557}
558
559/**
[6647]560 * @brief unloads a Resource
[4836]561 * @param pointer: The pointer to free
562 * @param prio: the PriorityLevel to unload this resource
563 * @returns true if successful (pointer found, and deleted), false otherwise
[3658]564*/
[6651]565bool ResourceManager::unload(BaseObject* pointer, ResourcePriority prio)
[3658]566{
[5366]567  if (pointer == NULL)
568    return false;
[3658]569  // if pointer is existent. and only one resource of this type exists.
[3672]570  Resource* tmpResource = this->locateResourceByPointer(pointer);
[5366]571  if (tmpResource != NULL)
572    return unload(tmpResource, prio);
[3660]573  else
[5366]574  {
575    PRINTF(2)("Resource not Found %p\n", pointer);
576    return false;
577  }
[3660]578}
579
[4465]580/**
[6647]581 * @brief unloads a Resource
[4836]582 * @param resource: The resource to unloade
583 * @param prio the PriorityLevel to unload this resource
[5308]584 * @returns true on success, false otherwise.
[4465]585*/
[3660]586bool ResourceManager::unload(Resource* resource, ResourcePriority prio)
587{
[5306]588  if (resource == NULL)
589    return false;
[3665]590  if (resource->count > 0)
591    resource->count--;
[5306]592
[3660]593  if (resource->prio <= prio)
[6640]594  {
595    if (resource->count == 0)
[3658]596    {
[7193]597      delete resource->pointer;
[6640]598      // deleting the List Entry:
599      PRINTF(4)("Resource %s safely removed.\n", resource->name);
600      delete[] resource->name;
[6642]601      std::vector<Resource*>::iterator resourceIT = std::find(this->resourceList.begin(), this->resourceList.end(), resource);
[6640]602      this->resourceList.erase(resourceIT);
603      delete resource;
[3658]604    }
[6640]605    else
606      PRINTF(4)("Resource %s not removed, because there are still %d References to it.\n", resource->name, resource->count);
607  }
[3658]608  else
[3660]609    PRINTF(4)("not deleting resource %s because DeleteLevel to high\n", resource->name);
[3658]610  return true;
[3655]611}
612
[3660]613
[3655]614/**
[6647]615 * @brief unloads all alocated Memory of Resources with a pririty lower than prio
[4836]616 * @param prio The priority to delete
[3660]617*/
618bool ResourceManager::unloadAllByPriority(ResourcePriority prio)
619{
[6222]620  unsigned int removeCount;
621  for (unsigned int round = 0; round < 3; round++)
622  {
[6642]623    int index = this->resourceList.size() - 1;
[6222]624    removeCount = 0;
[6642]625    while (index >= 0)
[3660]626    {
[6642]627      if (this->resourceList[index]->prio <= prio)
[6640]628      {
[6642]629        if (this->resourceList[index]->count == 0)
630          unload(this->resourceList[index], prio);
[6640]631        else
[6222]632        {
[6664]633          if (round == 3)
634            PRINTF(2)("unable to unload %s because there are still %d references to it\n",
635                      this->resourceList[index]->name, this->resourceList[index]->count);
[6640]636          removeCount++;
[6222]637        }
[6640]638      }
[6642]639      index--;
[6640]640    }
641    if (removeCount == 0) break;
[6222]642  }
[3660]643}
644
[5994]645
[3660]646/**
[6647]647 * @brief Searches for a Resource by some information
[4836]648 * @param fileName: The name to look for
649 * @param type the Type of resource to locate.
[6645]650 * @param param0: an additional option to parse (see the constuctors for more help)
[4836]651 * @param param1: an additional option to parse (see the constuctors for more help)
652 * @param param2: an additional option to parse (see the constuctors for more help)
653 * @returns a Pointer to the Resource if found, NULL otherwise.
[3658]654*/
[4462]655Resource* ResourceManager::locateResourceByInfo(const char* fileName, ResourceType type,
[6648]656    const MultiType& param0, const MultiType& param1, const MultiType& param2) const
[3658]657{
[6642]658  std::vector<Resource*>::const_iterator resource;
[6222]659  for (resource = this->resourceList.begin(); resource != this->resourceList.end(); resource++)
660  {
661    if ((*resource)->type == type && !strcmp(fileName, (*resource)->name))
[6640]662    {
663      bool match = false;
664      switch (type)
665      {
[4534]666#ifndef NO_MODEL
[6648]667        case PRIM:
668        case OBJ:
669          if (param0 == MT_NULL)
670          {
671            if ((*resource)->param[0] == 1.0f)
672              match = true;
673          }
674          else if ((*resource)->param[0] == param0.getFloat())
[6640]675            match = true;
[6648]676          break;
677        case MD2:
[7059]678          if (param0 == MT_NULL && ((*resource)->param[0] == "") && param1 == MT_NULL && ((*resource)->param[0] == 1.0f))
[6648]679              match = true;
[7059]680          else if ((*resource)->param[0] == ((MultiType)param0).getString() && (*resource)->param[1] == ((MultiType)param1).getFloat())
[6640]681            match = true;
[6648]682          break;
[4534]683#endif /* NO_MODEL */
684#ifndef NO_TEXT
[6648]685        case TTF:
686          if (param0 == MT_NULL)
687          {
688            if ((*resource)->param[0] == FONT_DEFAULT_RENDER_SIZE)
689              match = true;
690          }
691          else if ((*resource)->param[0] == param0.getInt())
[6640]692            match = true;
[6648]693          break;
[4534]694#endif /* NO_TEXT */
[5323]695#ifndef NO_SHADERS
[6648]696        case SHADER:
697          if (param0 == MT_NULL)
698          {
699            if ((*resource)->param[0] == "")
700              match = true;
701          }
702          else if ((*resource)->param[0] == ((MultiType)param0).getString())
[6640]703            match = true;
[6859]704          break;
[5323]705#endif /* NO_SHADERS */
[6467]706#ifndef NO_TEXTURES
[6648]707        case IMAGE:
708          if (param0 == MT_NULL)
709          {
710            if ((*resource)->param[0] == GL_TEXTURE_2D)
711              match = true;
712          }
713          else if ((*resource)->param[0] ==  param0.getInt())
[6640]714            match = true;
[6859]715          break;
[6648]716#endif /* NO_TEXTURES */
717        default:
[6640]718          match = true;
[6648]719          break;
[6640]720      }
721      if (match)
722      {
723        return (*resource);
724      }
[3658]725    }
[6640]726  }
[3658]727  return NULL;
728}
729
730/**
[6647]731 * @brief Searches for a Resource by Pointer
[4836]732 * @param pointer the Pointer to search for
733 * @returns a Pointer to the Resource if found, NULL otherwise.
[6647]734 */
[5994]735Resource* ResourceManager::locateResourceByPointer(const void* pointer) const
[3658]736{
[3667]737  //  Resource* enumRes = resourceList->enumerate();
[6642]738  std::vector<Resource*>::const_iterator resource;
[6222]739  for (resource = this->resourceList.begin(); resource != this->resourceList.end(); resource++)
740    if (pointer == (*resource)->pointer)
[6640]741      return (*resource);
[3658]742  return NULL;
743}
744
[6648]745char* ResourceManager::toResourcableString(unsigned int i)
746{
747  int len = strlen(ResourceManager::ResourceTypeToChar(this->resourceList[i]->type));
748  len += strlen(this->resourceList[i]->name);
[7199]749  if (this->resourceList[i]->param[0].getCString()) len += strlen(this->resourceList[i]->param[0].getCString()) +1;
750  if (this->resourceList[i]->param[1].getCString()) len += strlen(this->resourceList[i]->param[1].getCString()) +1;
751  if (this->resourceList[i]->param[2].getCString()) len += strlen(this->resourceList[i]->param[2].getCString()) +1;
[6648]752  len += 10;
753  char* tmp = new char[len];
754  tmp[0] = '\0';
755  strcat( tmp, ResourceManager::ResourceTypeToChar(this->resourceList[i]->type));
756  strcat(tmp,",");
757  strcat (tmp, this->resourceList[i]->name);
[7199]758  if (this->resourceList[i]->param[0].getCString() && this->resourceList[i]->param[0].getCString() != '\0')
[6648]759  {
760    strcat(tmp,",");
[7199]761    strcat( tmp, this->resourceList[i]->param[0].getCString());
[6648]762  }
[7199]763  if (this->resourceList[i]->param[1].getCString() && this->resourceList[i]->param[1].getCString() != '\0')
[6648]764  {
765    strcat(tmp,",");
[7199]766    strcat( tmp, this->resourceList[i]->param[1].getCString());
[6648]767  }
[7199]768  if (this->resourceList[i]->param[2].getCString() && this->resourceList[i]->param[2].getCString() != '\0')
[6648]769  {
770    strcat(tmp,",");
[7199]771    strcat( tmp, this->resourceList[i]->param[2].getCString());
[6648]772  }
773  return tmp;
774}
775
[3658]776/**
[6648]777 * @brief caches a Resource from a ResourceableString created with the toResourcableString-function
778 * @param resourceableString the String to cache the resource from.
779 */
780bool ResourceManager::fromResourceableString(const char* resourceableString)
781{
782  SubString splits(resourceableString, ',');
783  splits.debug();
784  if (splits.getCount() == 2)
785    this->cache(splits[1], ResourceManager::stringToResourceType(splits[0]),
786                RP_LEVEL);
787  else if (splits.getCount() == 3)
[6650]788    return this->cache(splits[1], ResourceManager::stringToResourceType(splits[0]),
[6648]789                RP_LEVEL, splits[2]);
790  else if (splits.getCount() == 4)
[6650]791    return this->cache(splits[1], ResourceManager::stringToResourceType(splits[0]),
[6648]792                RP_LEVEL, splits[2], splits[3]);
793  else if (splits.getCount() == 5)
[6650]794    return this->cache(splits[1], ResourceManager::stringToResourceType(splits[0]),
[6648]795                RP_LEVEL, splits[2], splits[3], splits[4]);
796}
797
798
799/**
[6647]800 * @brief Checks if it is a Directory
[4836]801 * @param directoryName the Directory to check for
802 * @returns true if it is a directory/symlink false otherwise
[3655]803*/
804bool ResourceManager::isDir(const char* directoryName)
805{
[4462]806  if (directoryName == NULL)
807    return false;
808
[3883]809  char* tmpDirName = NULL;
[3655]810  struct stat status;
[3883]811
812  // checking for the termination of the string given. If there is a "/" at the end cut it away
[5113]813  if (directoryName[strlen(directoryName)-1] == '/' ||
814      directoryName[strlen(directoryName)-1] == '\\')
[6640]815  {
816    tmpDirName = new char[strlen(directoryName)];
817    strncpy(tmpDirName, directoryName, strlen(directoryName)-1);
818    tmpDirName[strlen(directoryName)-1] = '\0';
819  }
[3883]820  else
[6640]821  {
822    tmpDirName = new char[strlen(directoryName)+1];
823    strcpy(tmpDirName, directoryName);
824  }
[3883]825
[4032]826  if(!stat(tmpDirName, &status))
[6640]827  {
828    if (status.st_mode & (S_IFDIR
[3790]829#ifndef __WIN32__
[6640]830                          | S_IFLNK
[3790]831#endif
[6640]832                         ))
833    {
834      delete[] tmpDirName;
835      return true;
[3883]836    }
[6640]837    else
838    {
839      delete[] tmpDirName;
840      return false;
841    }
842  }
[3658]843  else
[5211]844  {
845    delete[] tmpDirName;
[4032]846    return false;
[5211]847  }
[3655]848}
849
850/**
[6647]851 * @brief Checks if the file is either a Regular file or a Symlink
[4836]852 * @param fileName the File to check for
853 * @returns true if it is a regular file/symlink, false otherwise
[3655]854*/
855bool ResourceManager::isFile(const char* fileName)
856{
[4462]857  if (fileName == NULL)
858    return false;
[4032]859  char* tmpFileName = ResourceManager::homeDirCheck(fileName);
860  // actually checks the File
[3655]861  struct stat status;
[4032]862  if (!stat(tmpFileName, &status))
[6640]863  {
864    if (status.st_mode & (S_IFREG
[3790]865#ifndef __WIN32__
[6640]866                          | S_IFLNK
[3790]867#endif
[6640]868                         ))
869    {
870      delete[] tmpFileName;
871      return true;
[4032]872    }
[6640]873    else
[4032]874    {
[5208]875      delete[] tmpFileName;
[4032]876      return false;
877    }
[6640]878  }
879  else
880  {
881    delete[] tmpFileName;
882    return false;
883  }
[4032]884}
885
[4166]886/**
[6647]887 * @brief touches a File on the disk (thereby creating it)
[4836]888 * @param fileName The file to touch
[4166]889*/
[4032]890bool ResourceManager::touchFile(const char* fileName)
891{
892  char* tmpName = ResourceManager::homeDirCheck(fileName);
[4462]893  if (tmpName == NULL)
894    return false;
[4032]895  FILE* stream;
896  if( (stream = fopen (tmpName, "w")) == NULL)
[6640]897  {
898    PRINTF(1)("could not open %s fro writing\n", fileName);
899    delete[] tmpName;
900    return false;
901  }
[4033]902  fclose(stream);
[4597]903
[5208]904  delete[] tmpName;
[4032]905}
906
[4166]907/**
[6647]908 * @brief deletes a File from disk
[4836]909 * @param fileName the File to delete
[4166]910*/
[4032]911bool ResourceManager::deleteFile(const char* fileName)
912{
[4462]913  if (fileName == NULL)
914    return false;
[4032]915  char* tmpName = ResourceManager::homeDirCheck(fileName);
916  unlink(tmpName);
[5208]917  delete[] tmpName;
[4032]918}
919
[4597]920/**
[4961]921 * @param name the Name of the file to check
922 * @returns The name of the file, including the HomeDir
923 * IMPORTANT: this has to be deleted from the outside
924 */
[4032]925char* ResourceManager::homeDirCheck(const char* name)
926{
[4462]927  if (name == NULL)
928    return NULL;
[4032]929  char* retName;
930  if (!strncmp(name, "~/", 2))
[6640]931  {
932    char tmpFileName[500];
[4032]933#ifdef __WIN32__
[6640]934    strcpy(tmpFileName, getenv("USERPROFILE"));
[4032]935#else
[6640]936    strcpy(tmpFileName, getenv("HOME"));
[4032]937#endif
[6640]938    retName = new char[strlen(tmpFileName)+strlen(name)];
939    sprintf(retName, "%s%s", tmpFileName, name+1);
940  }
[3655]941  else
[6640]942  {
943    retName = new char[strlen(name)+1];
944    strcpy(retName, name);
945  }
[4032]946  return retName;
[3655]947}
[3676]948
[4597]949/**
[7196]950 * @param name the relative name of the File/Directory.
951 * @returns a new char* with the name in abs-dir-format
952 */
953char* ResourceManager::getAbsDir(const char* name)
954{
955  if (name == NULL)
956    return NULL;
957  char* retName;
958  if (strncmp(name, "/", 1))
959  {
960    if (*name == '.' && *(name+1) != '.')
961      name++;
962    const char* absDir = ResourceManager::cwd();
963    retName = new char[strlen(absDir)+strlen(name)+1];
964    sprintf(retName, "%s%s", absDir, name);
965  }
966  else
967  {
968    retName = new char[strlen(name)+1];
969    strcpy(retName, name);
970  }
971  return retName;
972}
973
974
975/**
[4961]976 * @param fileName the Name of the File to check
977 * @returns The full name of the file, including the DataDir, and NULL if the file does not exist
[5219]978 * !!IMPORTANT: this has to be deleted from the outside!!
[4166]979*/
980char* ResourceManager::getFullName(const char* fileName)
981{
[5335]982  if (fileName == NULL || ResourceManager::getInstance()->getDataDir() == NULL)
[4462]983    return NULL;
984
[4216]985  char* retName = new char[strlen(ResourceManager::getInstance()->getDataDir())
[4597]986                           + strlen(fileName) + 1];
[4166]987  sprintf(retName, "%s%s", ResourceManager::getInstance()->getDataDir(), fileName);
[4462]988  if (ResourceManager::isFile(retName) || ResourceManager::isDir(retName))
[4167]989    return retName;
990  else
[6640]991  {
992    delete[] retName;
993    return NULL;
994  }
[4166]995}
[4032]996
[7196]997#ifdef __unix__
998  #include <unistd.h>
999#elif __WIN32__ || _MS_DOS_
1000  #include <dir.h>
1001#else
1002  #include <direct.h> /* Visual C++ */
1003#endif
1004/**
1005 * @returns the Current Woring Directory
1006 */
1007const char* ResourceManager::cwd()
1008{
1009  if (ResourceManager::getInstance()->_cwd == NULL)
1010  {
1011    char cwd[1024];
1012    char* errorCode = getcwd(cwd, 1024);
1013    if (errorCode == 0)
1014      return NULL;
[4032]1015
[7196]1016    ResourceManager::getInstance()->_cwd = new char[strlen(cwd)+1];
1017    strcpy(ResourceManager::getInstance()->_cwd, cwd);
1018  }
1019  return ResourceManager::getInstance()->_cwd;
1020}
1021
1022
[3676]1023/**
[6647]1024 * @brief checks wether a file is in the DataDir.
[5335]1025 * @param fileName the File to check if it is in the Data-Dir structure.
1026 * @returns true if the file exists, false otherwise
1027 */
1028bool ResourceManager::isInDataDir(const char* fileName)
1029{
1030  if (fileName == NULL || ResourceManager::getInstance()->getDataDir() == NULL)
1031    return false;
1032
1033  bool retVal = false;
1034  char* checkFile = new char[strlen(ResourceManager::getInstance()->getDataDir())
[6640]1035                             + strlen(fileName) + 1];
[5335]1036  sprintf(checkFile, "%s%s", ResourceManager::getInstance()->getDataDir(), fileName);
1037
1038  if (ResourceManager::isFile(checkFile) || ResourceManager::isDir(checkFile))
1039    retVal = true;
1040  else
1041    retVal = false;
1042  delete[] checkFile;
1043  return retVal;
1044}
1045
1046
1047/**
[6647]1048 * @brief outputs debug information about the ResourceManager
1049 */
[4746]1050void ResourceManager::debug() const
[3676]1051{
1052  PRINT(0)("=RM===================================\n");
1053  PRINT(0)("= RESOURCE-MANAGER DEBUG INFORMATION =\n");
1054  PRINT(0)("======================================\n");
1055  // if it is not initialized
1056  PRINT(0)(" Reference is: %p\n", ResourceManager::singletonRef);
1057  PRINT(0)(" Data-Directory is: %s\n", this->dataDir);
1058  PRINT(0)(" List of Image-Directories: ");
[6642]1059  std::vector<char*>::const_iterator imageDir;
[6222]1060  for (imageDir = this->imageDirs.begin(); imageDir != this->imageDirs.end(); imageDir++)
[6640]1061    PRINT(0)("%s ", (*imageDir));
[3676]1062  PRINT(0)("\n");
1063
1064  PRINT(0)("List of all stored Resources:\n");
[6642]1065  std::vector<Resource*>::const_iterator resource;
[6222]1066  for (resource = this->resourceList.begin(); resource != this->resourceList.end(); resource++)
1067
[6640]1068  {
1069    PRINT(0)("-----------------------------------------\n");
1070    PRINT(0)("Name: %s; References: %d; Type: %s ", (*resource)->name, (*resource)->count, ResourceManager::ResourceTypeToChar((*resource)->type));
1071
1072    PRINT(0)("gets deleted at ");
1073    switch((*resource)->prio)
[3676]1074    {
[6648]1075      default:
1076      case RP_NO:
1077        PRINT(0)("first posibility (0)\n");
1078        break;
1079      case RP_LEVEL:
1080        PRINT(0)("the end of the Level (1)\n");
1081        break;
1082      case RP_CAMPAIGN:
1083        PRINT(0)("the end of the campaign (2)\n");
1084        break;
1085      case RP_GAME:
1086        PRINT(0)("when leaving the game (3)\n");
1087        break;
[3676]1088    }
[6640]1089  }
[3676]1090
1091
1092
1093  PRINT(0)("==================================RM==\n");
1094}
[5306]1095
1096
1097/**
[6647]1098 * @brief converts a ResourceType into the corresponding String
[5306]1099 * @param type the ResourceType to translate
1100 * @returns the converted String.
1101 */
1102const char* ResourceManager::ResourceTypeToChar(ResourceType type)
1103{
[6646]1104  return ResourceManager::resourceNames[type];
1105}
1106
1107/**
1108 * @brief converts a String into a ResourceType (good for loading)
1109 * @param resourceType the name of the Type
1110 * @returns the Number of the Type, or 0 (defautl) if not found.
1111 */
1112ResourceType ResourceManager::stringToResourceType(const char* resourceType)
1113{
1114  assert(resourceType != NULL);
1115  for (unsigned int i = 0; i < RESOURCE_TYPE_SIZE; i++)
1116    if (!strcmp(resourceType, ResourceManager::resourceNames[i]))
1117      return (ResourceType)i;
1118  return (ResourceType)0;
1119}
1120
1121/**
1122 * The Names of the ResourceTypes
1123 */
1124const char* ResourceManager::resourceNames[] =
[6648]1125  {
[5306]1126#ifndef NO_MODEL
[6648]1127    "ObjectModel",
1128    "PrimitiveModel",
1129    "MD2-Data",
[5306]1130#endif
[6648]1131#ifndef NO_TEXT
1132    "Font",
[5306]1133#endif
1134#ifndef NO_AUDIO
[6648]1135    "Wav",
1136    "mp3",
1137    "ogg",
[5306]1138#endif
[6648]1139#ifndef NO_TEXTURES
1140    "Texture",
[5306]1141#endif
[5323]1142#ifndef NO_SHADERS
[6648]1143    "Shader",
[5323]1144#endif
[6648]1145
1146  };
Note: See TracBrowser for help on using the repository browser.