Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 4098 was 4091, checked in by bensch, 20 years ago

orxonox/trunk: now All options get loaded in new style (be aware, quiting only works with ESCAPE, not q, but of corse you can change this now in the GUI

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