Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/orxonox/trunk/src/util/resource_manager.cc @ 4381

Last change on this file since 4381 was 4381, checked in by bensch, 19 years ago

orxonox/trunk: made include more local. stdincl.h not in base_object.h anymore

File size: 19.1 KB
Line 
1/*
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.
10
11   ### File Specific:
12   main-programmer: Benjamin Grauer
13   co-programmer: Patrick Boenzli
14*/
15
16#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_LOAD
17
18#include "resource_manager.h"
19
20// different resource Types
21#include "objModel.h"
22#include "primitive_model.h"
23#include "texture.h"
24#include "text_engine.h"
25
26#include "list.h"
27#include "sdlincl.h"
28
29// File Handling Includes
30#include <sys/types.h>
31#include <sys/stat.h>
32#include <unistd.h>
33
34using namespace std;
35
36/**
37   \brief standard constructor
38*/
39ResourceManager::ResourceManager () 
40{
41   this->setClassID(CL_RESOURCE_MANAGER, "ResourceManager");
42   this->dataDir = NULL;
43   this->setDataDir("./");
44   this->imageDirs = new tList<char>();
45   this->resourceList = new tList<Resource>();
46}
47
48/**
49   \returns the Instance to this ResourceManager
50*/
51ResourceManager* ResourceManager::getInstance(void)
52{
53  if (!ResourceManager::singletonRef)
54    ResourceManager::singletonRef = new ResourceManager();
55  return ResourceManager::singletonRef;
56}
57
58//! Singleton Reference to the ResourceManager
59ResourceManager* ResourceManager::singletonRef = NULL;
60
61/**
62   \brief standard destructor
63*/
64ResourceManager::~ResourceManager (void) 
65{
66  // deleting the Resources-List
67  this->unloadAllByPriority(RP_GAME);
68  delete this->resourceList;
69  // deleting the Directorie Lists
70  tIterator<char>* tmpIt = imageDirs->getIterator();
71  char* tmpDir = tmpIt->nextElement();
72  while(tmpDir)
73    {
74      delete []tmpDir;
75      tmpDir = tmpIt->nextElement();
76    }
77  delete tmpIt;
78
79  delete this->imageDirs;
80
81  ResourceManager::singletonRef = NULL;
82}
83
84/**
85   \brief sets the data main directory
86   \param dataDir the DataDirectory.
87*/
88bool ResourceManager::setDataDir(const char* dataDir)
89{
90  char* realDir = ResourceManager::homeDirCheck(dataDir);
91  if (isDir(realDir))
92    {
93      delete this->dataDir;
94      this->dataDir = new char[strlen(realDir)+1];
95      strcpy(this->dataDir, realDir);
96      delete realDir;
97      return true;
98    }
99  else
100    {
101      PRINTF(1)("%s is not a Directory, and can not be the Data Directory, leaving as %s \n", dataDir, this->dataDir);
102      delete realDir;
103      return false;
104    }
105}
106
107/**
108   \brief checks for the DataDirectory, by looking if
109   \param fileInside is inisde??
110*/
111bool ResourceManager::checkDataDir(const char* fileInside)
112{
113  bool retVal;
114  if (!isDir(this->dataDir))
115    {
116      PRINTF(1)("%s is not a directory\n", this->dataDir);
117      return false;
118    }
119 
120  char* testFile = new char[strlen(this->dataDir)+strlen(fileInside)+1];
121  sprintf(testFile, "%s%s", this->dataDir, fileInside);
122  retVal = isFile(testFile);
123  delete testFile;
124  return retVal;
125}
126
127/**
128   \brief adds a new Path for Images
129   \param imageDir The path to insert
130   \returns true, if the Path was well and injected (or already existent within the list)
131   false otherwise
132*/
133bool ResourceManager::addImageDir(const char* imageDir)
134{
135  // check if the param is a Directory
136  if (isDir(imageDir))
137    {
138      // check if the Directory has been added before
139      tIterator<char>* tmpImageDirs = imageDirs->getIterator();
140      char* tmpDir = tmpImageDirs->nextElement();
141      while(tmpDir)
142        {
143          if (!strcmp(tmpDir, imageDir))
144            {
145              PRINTF(4)("Path %s already loaded\n", imageDir);
146              delete tmpImageDirs;
147              return true;
148            }
149          tmpDir = tmpImageDirs->nextElement();
150        }
151      delete tmpImageDirs;
152
153      // adding the directory to the List
154      tmpDir  = new char[strlen(imageDir)+1];
155      strcpy(tmpDir, imageDir);
156      this->imageDirs->add(tmpDir);
157      return true;
158    }
159  else
160    {
161      PRINTF(1)("%s is not a Directory, and can not be added to the Paths of Images\n", dataDir);
162      return false;
163    }
164}
165
166/**
167   \brief loads resources
168   \param fileName The fileName of the resource to load
169   \param prio The ResourcePriority of this resource (will only be increased)
170   \returns a pointer to a desired Resource.
171*/
172void* ResourceManager::load(const char* fileName, ResourcePriority prio, void* param1, void* param2, void* param3)
173{
174  ResourceType tmpType;
175  if (!strncmp(fileName+(strlen(fileName)-4), ".obj", 4))
176    tmpType = OBJ;
177  else if (!strncmp(fileName+(strlen(fileName)-4), ".wav", 4))
178    tmpType = WAV;
179  else if (!strncmp(fileName+(strlen(fileName)-4), ".mp3", 4))
180    tmpType = MP3;
181  else if (!strncmp(fileName+(strlen(fileName)-4), ".ogg", 4))
182    tmpType = OGG;
183  else if (!strcmp(fileName, "cube") ||
184           !strcmp(fileName, "sphere") ||
185           !strcmp(fileName, "plane") ||
186           !strcmp(fileName, "cylinder") ||
187           !strcmp(fileName, "cone"))
188    tmpType = PRIM;
189  else if (!strncmp(fileName+(strlen(fileName)-4), ".ttf", 4))
190    tmpType = TTF;
191  else 
192    tmpType = IMAGE;
193
194  return this->load(fileName, tmpType, prio, param1, param2, param3);
195}
196
197/**
198   \brief loads resources
199   \param fileName The fileName of the resource to load
200   \param type The Type of Resource to load (\see ResourceType)
201   \param prio The ResourcePriority of this resource (will only be increased)
202   \returns a pointer to a desired Resource.
203*/
204void* ResourceManager::load(const char* fileName, ResourceType type, ResourcePriority prio, void* param1, void* param2, void* param3)
205{
206  // searching if the resource was loaded before.
207  Resource* tmpResource = this->locateResourceByInfo(fileName, type, param1, param2,param3);
208  if (tmpResource) // if the resource was loaded before.
209    {
210      PRINTF(4)("not loading cached resource %s\n", tmpResource->name);
211      tmpResource->count++;
212      if(tmpResource->prio < prio)
213        tmpResource->prio = prio;
214    }
215  else
216    {
217      char* tmpDir;
218      // Setting up the new Resource
219      tmpResource = new Resource;
220      tmpResource->count = 1;
221      tmpResource->type = type;
222      tmpResource->prio = prio;
223      tmpResource->pointer = NULL;
224      tmpResource->name = new char[strlen(fileName)+1];
225      strcpy(tmpResource->name, fileName);
226
227      // creating the full name. (directoryName + FileName)
228      char* fullName = new char[strlen(this->getDataDir())+strlen(fileName)+1];
229      sprintf(fullName, "%s%s", this->getDataDir(), fileName);
230      // Checking for the type of resource \see ResourceType
231      switch(type)
232        {
233        case OBJ:
234          if (param1)
235            tmpResource->modelSize = *(float*)param1;
236          else
237            tmpResource->modelSize = 1.0;
238
239          if(ResourceManager::isFile(fullName))
240            tmpResource->pointer = new OBJModel(fullName, tmpResource->modelSize);
241          else
242            {
243              PRINTF(2)("Sorry, %s does not exist. Loading a cube-Model instead\n", fullName);
244              tmpResource->pointer = ResourceManager::load("cube", PRIM, prio, &tmpResource->modelSize);
245            }
246          break;
247        case PRIM:
248          if (param1)
249            tmpResource->modelSize = *(float*)param1;
250          else
251            tmpResource->modelSize = 1.0;
252
253          if (!strcmp(tmpResource->name, "cube"))
254            tmpResource->pointer = new PrimitiveModel(CUBE, tmpResource->modelSize);
255          else if (!strcmp(tmpResource->name, "sphere"))
256            tmpResource->pointer = new PrimitiveModel(SPHERE, tmpResource->modelSize);
257          else if (!strcmp(tmpResource->name, "plane"))
258            tmpResource->pointer = new PrimitiveModel(PLANE, tmpResource->modelSize);
259          else if (!strcmp(tmpResource->name, "cylinder"))
260            tmpResource->pointer = new PrimitiveModel(CYLINDER, tmpResource->modelSize);
261          else if (!strcmp(tmpResource->name, "cone"))
262            tmpResource->pointer = new PrimitiveModel(CONE, tmpResource->modelSize);
263          break;
264        case TTF:
265            if (param1)
266              tmpResource->ttfSize = *(int*)param1;
267            else
268              tmpResource->ttfSize = FONT_DEFAULT_SIZE;
269            if (param2)
270              {
271                Vector* tmpVec = (Vector*)param2;
272                tmpResource->ttfColorR = (int)tmpVec->x;
273                tmpResource->ttfColorG = (int)tmpVec->y;
274                tmpResource->ttfColorB = (int)tmpVec->z;
275              }
276            else
277              {
278                tmpResource->ttfColorR = FONT_DEFAULT_COLOR_R;
279                tmpResource->ttfColorG = FONT_DEFAULT_COLOR_G;
280                tmpResource->ttfColorB = FONT_DEFAULT_COLOR_B;
281              }
282           
283          if(isFile(fullName))
284            tmpResource->pointer = new Font(fullName,
285                                            tmpResource->ttfSize,
286                                            tmpResource->ttfColorR,
287                                            tmpResource->ttfColorG,
288                                            tmpResource->ttfColorB);
289          else
290            PRINTF(2)("Sorry, %s does not exist. Not loading Font\n", fullName);
291          break;
292        case IMAGE:
293          if(isFile(fullName))
294            {
295              PRINTF(4)("Image %s resides to %s\n", fileName, fullName);
296              tmpResource->pointer = new Texture(fullName);
297            }
298          else
299            {
300              tIterator<char>* iterator = imageDirs->getIterator();
301              tmpDir = iterator->nextElement();
302              //tmpDir = imageDirs->enumerate();
303              while(tmpDir)
304                {
305                  char* imgName = new char[strlen(tmpDir)+strlen(fileName)+1];
306                  sprintf(imgName, "%s%s", tmpDir, fileName);
307                  if(isFile(imgName))
308                    {
309                      PRINTF(4)("Image %s resides to %s\n", fileName, imgName);
310                      tmpResource->pointer = new Texture(imgName);
311                      delete []imgName;
312                      break;
313                    }
314                  delete []imgName;
315                  tmpDir = iterator->nextElement();
316                }
317              delete iterator;
318            }
319          if(!tmpResource)
320             PRINTF(2)("!!Image %s not Found!!\n", fileName);
321          break;
322        default:
323          tmpResource->pointer = NULL;
324          PRINTF(1)("No type found for %s.\n   !!This should not happen unless the Type is not supported yet.!!\n", tmpResource->name);
325          break;
326        }
327      if (tmpResource->pointer)
328        this->resourceList->add(tmpResource);
329      delete []fullName;
330    }
331  if (tmpResource->pointer)
332    return tmpResource->pointer;
333  else 
334    {
335      PRINTF(2)("Resource %s could not be loaded\n", fileName);
336      delete tmpResource;
337      return NULL;
338    }
339}
340
341/**
342   \brief unloads a Resource
343   \param pointer The pointer to free
344   \returns true if successful (pointer found, and deleted), false otherwise
345   
346*/
347bool ResourceManager::unload(void* pointer, ResourcePriority prio)
348{
349  // if pointer is existent. and only one resource of this type exists.
350  Resource* tmpResource = this->locateResourceByPointer(pointer);
351  if (!tmpResource)
352    {
353      PRINTF(2)("Resource not Found %p\n", pointer);
354      return false;
355    }
356  else
357    unload(tmpResource, prio);
358}
359
360bool ResourceManager::unload(Resource* resource, ResourcePriority prio)
361{
362  if (resource->count > 0)
363    resource->count--;
364  if (resource->prio <= prio)
365    {
366      if (resource->count <= 0)
367        {
368          // deleting the Resource
369          switch(resource->type)
370            {
371            case OBJ:
372            case PRIM:
373              delete (Model*)resource->pointer;
374              break;
375            case IMAGE:
376              delete (Texture*)resource->pointer;
377              break;
378            case TTF:
379              delete (Font*)resource->pointer;
380              break;
381            default:
382              PRINTF(1)("NOT YET IMPLEMENTED !!FIX FIX!!\n");
383              return false;
384              break;
385            }
386          // deleting the List Entry:
387          PRINTF(4)("Resource %s safely removed.\n", resource->name);
388          delete []resource->name;
389          this->resourceList->remove(resource);
390        }
391      else
392        PRINTF(4)("Resource %s not removed, because there are still %d References to it.\n", resource->name, resource->count);
393    }
394  else
395    PRINTF(4)("not deleting resource %s because DeleteLevel to high\n", resource->name);
396  return true;
397}
398
399
400/**
401   \brief unloads all alocated Memory of Resources with a pririty lower than prio
402   \param prio The priority to delete
403*/
404bool ResourceManager::unloadAllByPriority(ResourcePriority prio)
405{
406  tIterator<Resource>* iterator = resourceList->getIterator();
407  Resource* enumRes = iterator->nextElement();
408  while (enumRes)
409    {
410      if (enumRes->prio <= prio)
411        if (enumRes->count == 0)
412          unload(enumRes, prio);
413        else
414          PRINTF(2)("unable to unload %s because there are still %d references to it\n",
415                   enumRes->name, enumRes->count);
416      //enumRes = resourceList->nextElement();
417      enumRes = iterator->nextElement();
418    }
419  delete iterator;
420}
421
422/**
423   \brief Searches for a Resource by some information
424   \param fileName The name to look for
425   \returns a Pointer to the Resource if found, NULL otherwise.
426*/
427Resource* ResourceManager::locateResourceByInfo(const char* fileName, ResourceType type, void* param1, void* param2, void* param3)
428{
429  //  Resource* enumRes = resourceList->enumerate();
430  tIterator<Resource>* iterator = resourceList->getIterator();
431  Resource* enumRes = iterator->nextElement();
432  while (enumRes)
433    {
434      if (enumRes->type == type && !strcmp(fileName, enumRes->name))
435        {
436          bool match = false;
437          bool subMatch = false;
438          switch (type)
439            {
440            case PRIM:
441            case OBJ:
442              if (!param1)
443                {
444                  if (enumRes->modelSize == 1.0)
445                    match = true;
446                }
447              else if (enumRes->modelSize == *(float*)param1)
448                match = true;
449              break;
450            case TTF:
451              if (!param1)
452                {
453                  if (enumRes->ttfSize == FONT_DEFAULT_SIZE)
454                    subMatch = true;
455                }
456              else if (enumRes->modelSize =- *(int*)param1)
457                subMatch = true;
458              if(subMatch)
459                {
460                  Vector* tmpVec = (Vector*)param2;
461                  if (!param2)
462                    {
463                      if(enumRes->ttfColorR == FONT_DEFAULT_COLOR_R &&
464                         enumRes->ttfColorG == FONT_DEFAULT_COLOR_G &&
465                         enumRes->ttfColorB == FONT_DEFAULT_COLOR_B )
466                        match = true;
467                    }
468                  else if (enumRes->ttfColorR == (int)tmpVec->x &&
469                           enumRes->ttfColorG == (int)tmpVec->y &&
470                           enumRes->ttfColorB == (int)tmpVec->z )
471                    match = true;
472                }
473
474              break;
475            default:
476              match = true;
477              break;
478            }
479          if (match)
480            {
481              delete iterator;
482              return enumRes;
483            }
484        }
485      enumRes = iterator->nextElement();
486    }
487  delete iterator;
488  return NULL;
489}
490
491/**
492   \brief Searches for a Resource by Pointer
493   \param pointer the Pointer to search for
494   \returns a Pointer to the Resource if found, NULL otherwise.
495*/
496Resource* ResourceManager::locateResourceByPointer(const void* pointer)
497{
498  //  Resource* enumRes = resourceList->enumerate();
499  tIterator<Resource>* iterator = resourceList->getIterator();
500  Resource* enumRes = iterator->nextElement();
501  while (enumRes)
502    {
503      if (pointer == enumRes->pointer)
504        {
505          delete iterator;
506          return enumRes;
507        }
508      enumRes = iterator->nextElement();
509    }
510  delete iterator;
511  return NULL;
512}
513
514/**
515   \brief Checks if it is a Directory
516   \param directoryName the Directory to check for
517   \returns true if it is a directory/symlink false otherwise
518*/
519bool ResourceManager::isDir(const char* directoryName)
520{
521  char* tmpDirName = NULL;
522  struct stat status;
523
524  // checking for the termination of the string given. If there is a "/" at the end cut it away
525  if (directoryName[strlen(directoryName)-1] == '/')
526    {
527      tmpDirName = new char[strlen(directoryName)+1];
528      strncpy(tmpDirName, directoryName, strlen(directoryName)-1);
529      tmpDirName[strlen(directoryName)-1] = '\0';
530    }
531  else
532    {
533      tmpDirName = new char[strlen(directoryName)+1];
534      strcpy(tmpDirName, directoryName);
535    }
536
537  if(!stat(tmpDirName, &status))
538    {
539      if (status.st_mode & (S_IFDIR
540#ifndef __WIN32__
541                            | S_IFLNK
542#endif
543                            ))
544        {
545          delete tmpDirName;
546          return true;
547        }
548      else
549        {
550          delete tmpDirName;
551          return false;
552        }
553    }
554  else
555    return false;
556}
557
558/**
559   \brief Checks if the file is either a Regular file or a Symlink
560   \param fileName the File to check for
561   \returns true if it is a regular file/symlink, false otherwise
562*/
563bool ResourceManager::isFile(const char* fileName)
564{
565  char* tmpFileName = ResourceManager::homeDirCheck(fileName);
566  // actually checks the File
567  struct stat status;
568  if (!stat(tmpFileName, &status))
569    {
570      if (status.st_mode & (S_IFREG
571#ifndef __WIN32__
572                            | S_IFLNK
573#endif
574                            ))
575        {
576          delete tmpFileName;
577          return true;
578        }
579      else
580        {
581          delete tmpFileName;
582          return false;
583        }
584    }
585  else 
586    {
587      delete tmpFileName;
588      return false;
589    }
590}
591
592/**
593   \brief touches a File on the disk (thereby creating it)
594   \param fileName The file to touch
595*/
596bool ResourceManager::touchFile(const char* fileName)
597{
598  char* tmpName = ResourceManager::homeDirCheck(fileName);
599
600  FILE* stream;
601  if( (stream = fopen (tmpName, "w")) == NULL)
602    {
603      PRINTF(1)("could not open %s fro writing\n", fileName);
604      return false;
605    }
606  fclose(stream);
607   
608  delete tmpName; 
609}
610
611/**
612   \brief deletes a File from disk
613   \param fileName the File to delete
614*/
615bool ResourceManager::deleteFile(const char* fileName)
616{
617  char* tmpName = ResourceManager::homeDirCheck(fileName);
618  unlink(tmpName);
619  delete tmpName;
620}
621
622/**
623    \param fileName the Name of the file to check
624    \returns The name of the file, including the HomeDir
625    IMPORTANT: this has to be deleted from the outside
626*/
627char* ResourceManager::homeDirCheck(const char* name)
628{
629  char* retName;
630  if (!strncmp(name, "~/", 2))
631    {
632      char tmpFileName[500];
633#ifdef __WIN32__
634      strcpy(tmpFileName, getenv("USERPROFILE"));
635#else
636      strcpy(tmpFileName, getenv("HOME"));
637#endif
638      retName = new char[strlen(tmpFileName)+strlen(name)];
639      sprintf(retName, "%s%s", tmpFileName, name+1);
640    }
641  else
642    {
643      retName = new char[strlen(name)+1];
644      strcpy(retName, name);
645    }
646  return retName;
647}
648
649/**
650    \param fileName the Name of the File to check
651    \returns The full name of the file, including the DataDir, and NULL if the file does not exist
652    IMPORTANT: this has to be deleted from the outside
653*/
654char* ResourceManager::getFullName(const char* fileName)
655{
656  char* retName = new char[strlen(ResourceManager::getInstance()->getDataDir())
657                           + strlen(fileName) + 1];
658  sprintf(retName, "%s%s", ResourceManager::getInstance()->getDataDir(), fileName);
659  if (ResourceManager::isFile(retName))
660    return retName;
661  else
662    {
663      delete retName;
664      return NULL;
665    }
666}
667
668
669/**
670   \brief outputs debug information about the ResourceManager
671*/
672void ResourceManager::debug(void)
673{
674  PRINT(0)("=RM===================================\n");
675  PRINT(0)("= RESOURCE-MANAGER DEBUG INFORMATION =\n");
676  PRINT(0)("======================================\n");
677  // if it is not initialized
678  PRINT(0)(" Reference is: %p\n", ResourceManager::singletonRef);
679  PRINT(0)(" Data-Directory is: %s\n", this->dataDir);
680  PRINT(0)(" List of Image-Directories: ");
681  tIterator<char>* tmpIt = imageDirs->getIterator();
682  char* tmpDir = tmpIt->nextElement();
683  while(tmpDir)
684    {
685      PRINT(0)("%s ",tmpDir);
686      tmpDir = tmpIt->nextElement();
687    }
688  delete tmpIt;
689  PRINT(0)("\n");
690
691  PRINT(0)("List of all stored Resources:\n");
692  tIterator<Resource>* iterator = resourceList->getIterator();
693  Resource* enumRes = iterator->nextElement();
694  while (enumRes)
695    {
696      PRINT(0)("-----------------------------------------\n");
697      PRINT(0)("Name: %s; References: %d; Type:", enumRes->name, enumRes->count);
698      switch (enumRes->type)
699        {
700        case OBJ:
701          PRINT(0)("ObjectModel\n");
702          break;
703        case PRIM:
704          PRINT(0)("PrimitiveModel\n");
705          break;
706        case IMAGE:
707          PRINT(0)("ImageFile (Texture)\n");
708          break;
709        default:
710          PRINT(0)("SoundFile\n");
711          break;
712        }
713      PRINT(0)("gets deleted at ");
714      switch(enumRes->prio)
715        {
716        default:
717        case RP_NO:
718          PRINT(0)("first posibility (0)\n");
719          break;
720        case RP_LEVEL:
721          PRINT(0)("the end of the Level (1)\n");
722          break;
723        case RP_CAMPAIGN:
724          PRINT(0)("the end of the campaign (2)\n");
725          break;
726        case RP_GAME:
727          PRINT(0)("when leaving the game (3)\n");
728          break;
729        }
730      enumRes = iterator->nextElement();
731    }
732  delete iterator;
733
734
735
736  PRINT(0)("==================================RM==\n");
737}
Note: See TracBrowser for help on using the repository browser.