Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 4369 was 4356, checked in by bensch, 20 years ago

orxonox/trunk: fixed an error in the resource manager, when a texture could not be loaded it still returned a pointer into nothingness.
This is fixed

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