Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 4192 was 4167, checked in by bensch, 20 years ago

orxonox/trunk: check if file exists

File size: 18.9 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 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(this->getDataDir())+strlen(fileName)+1];
224      sprintf(fullName, "%s%s", this->getDataDir(), fileName);
225      // Checking for the type of resource \see ResourceType
226      switch(type)
227        {
228        case OBJ:
229          if (param1)
230            tmpResource->modelSize = *(float*)param1;
231          else
232            tmpResource->modelSize = 1.0;
233
234          if(ResourceManager::isFile(fullName))
235            tmpResource->pointer = new OBJModel(fullName, tmpResource->modelSize);
236          else
237            {
238              PRINTF(2)("Sorry, %s does not exist. Loading a cube-Model instead\n", fullName);
239              tmpResource->pointer = ResourceManager::load("cube", PRIM, prio, &tmpResource->modelSize);
240            }
241          break;
242        case PRIM:
243          if (param1)
244            tmpResource->modelSize = *(float*)param1;
245          else
246            tmpResource->modelSize = 1.0;
247
248          if (!strcmp(tmpResource->name, "cube"))
249            tmpResource->pointer = new PrimitiveModel(CUBE, tmpResource->modelSize);
250          else if (!strcmp(tmpResource->name, "sphere"))
251            tmpResource->pointer = new PrimitiveModel(SPHERE, tmpResource->modelSize);
252          else if (!strcmp(tmpResource->name, "plane"))
253            tmpResource->pointer = new PrimitiveModel(PLANE, tmpResource->modelSize);
254          else if (!strcmp(tmpResource->name, "cylinder"))
255            tmpResource->pointer = new PrimitiveModel(CYLINDER, tmpResource->modelSize);
256          else if (!strcmp(tmpResource->name, "cone"))
257            tmpResource->pointer = new PrimitiveModel(CONE, tmpResource->modelSize);
258          break;
259        case TTF:
260            if (param1)
261              tmpResource->ttfSize = *(int*)param1;
262            else
263              tmpResource->ttfSize = FONT_DEFAULT_SIZE;
264            if (param2)
265              {
266                Vector* tmpVec = (Vector*)param2;
267                tmpResource->ttfColorR = (int)tmpVec->x;
268                tmpResource->ttfColorG = (int)tmpVec->y;
269                tmpResource->ttfColorB = (int)tmpVec->z;
270              }
271            else
272              {
273                tmpResource->ttfColorR = FONT_DEFAULT_COLOR_R;
274                tmpResource->ttfColorG = FONT_DEFAULT_COLOR_G;
275                tmpResource->ttfColorB = FONT_DEFAULT_COLOR_B;
276              }
277           
278          if(isFile(fullName))
279            tmpResource->pointer = new Font(fullName,
280                                            tmpResource->ttfSize,
281                                            tmpResource->ttfColorR,
282                                            tmpResource->ttfColorG,
283                                            tmpResource->ttfColorB);
284          else
285            PRINTF(2)("Sorry, %s does not exist. Not loading Font\n", fullName);
286          break;
287        case IMAGE:
288          if(isFile(fullName))
289            {
290              PRINTF(4)("Image %s resides to %s\n", fileName, fullName);
291              tmpResource->pointer = new Texture(fullName);
292            }
293          else
294            {
295              tIterator<char>* iterator = imageDirs->getIterator();
296              tmpDir = iterator->nextElement();
297              //tmpDir = imageDirs->enumerate();
298              while(tmpDir)
299                {
300                  char* imgName = new char[strlen(tmpDir)+strlen(fileName)+1];
301                  sprintf(imgName, "%s%s", tmpDir, fileName);
302                  if(isFile(imgName))
303                    {
304                      PRINTF(4)("Image %s resides to %s\n", fileName, imgName);
305                      tmpResource->pointer = new Texture(imgName);
306                      delete []imgName;
307                      break;
308                    }
309                  delete []imgName;
310                  tmpDir = iterator->nextElement();
311                }
312              delete iterator;
313            }
314          if(!tmpResource)
315             PRINTF(2)("!!Image %s not Found!!\n", fileName);
316          break;
317        default:
318          tmpResource->pointer = NULL;
319          PRINTF(1)("No type found for %s.\n   !!This should not happen unless the Type is not supported yet.!!\n", tmpResource->name);
320          break;
321        }
322      this->resourceList->add(tmpResource);
323      delete []fullName;
324    }
325  if (tmpResource->pointer)
326    return tmpResource->pointer;
327  else 
328    {
329      PRINTF(2)("Resource %s could not be loaded\n", fileName);
330      delete tmpResource;
331      return NULL;
332    }
333}
334
335/**
336   \brief unloads a Resource
337   \param pointer The pointer to free
338   \returns true if successful (pointer found, and deleted), false otherwise
339   
340*/
341bool ResourceManager::unload(void* pointer, ResourcePriority prio)
342{
343  // if pointer is existent. and only one resource of this type exists.
344  Resource* tmpResource = this->locateResourceByPointer(pointer);
345  if (!tmpResource)
346    {
347      PRINTF(2)("Resource not Found %p\n", pointer);
348      return false;
349    }
350  else
351    unload(tmpResource, prio);
352}
353
354bool ResourceManager::unload(Resource* resource, ResourcePriority prio)
355{
356  if (resource->count > 0)
357    resource->count--;
358  if (resource->prio <= prio)
359    {
360      if (resource->count <= 0)
361        {
362          // deleting the Resource
363          switch(resource->type)
364            {
365            case OBJ:
366            case PRIM:
367              delete (Model*)resource->pointer;
368              break;
369            case IMAGE:
370              delete (Texture*)resource->pointer;
371              break;
372            case TTF:
373              delete (Font*)resource->pointer;
374              break;
375            default:
376              PRINTF(1)("NOT YET IMPLEMENTED !!FIX FIX!!\n");
377              return false;
378              break;
379            }
380          // deleting the List Entry:
381          PRINTF(4)("Resource %s safely removed.\n", resource->name);
382          delete []resource->name;
383          this->resourceList->remove(resource);
384        }
385      else
386        PRINTF(4)("Resource %s not removed, because there are still %d References to it.\n", resource->name, resource->count);
387    }
388  else
389    PRINTF(4)("not deleting resource %s because DeleteLevel to high\n", resource->name);
390  return true;
391}
392
393
394/**
395   \brief unloads all alocated Memory of Resources with a pririty lower than prio
396   \param prio The priority to delete
397*/
398bool ResourceManager::unloadAllByPriority(ResourcePriority prio)
399{
400  tIterator<Resource>* iterator = resourceList->getIterator();
401  Resource* enumRes = iterator->nextElement();
402  while (enumRes)
403    {
404      if (enumRes->prio <= prio)
405        if (enumRes->count == 0)
406          unload(enumRes, prio);
407        else
408          PRINTF(2)("unable to unload %s because there are still %d references to it\n",
409                   enumRes->name, enumRes->count);
410      //enumRes = resourceList->nextElement();
411      enumRes = iterator->nextElement();
412    }
413  delete iterator;
414}
415
416/**
417   \brief Searches for a Resource by some information
418   \param fileName The name to look for
419   \returns a Pointer to the Resource if found, NULL otherwise.
420*/
421Resource* ResourceManager::locateResourceByInfo(const char* fileName, ResourceType type, void* param1, void* param2, void* param3)
422{
423  //  Resource* enumRes = resourceList->enumerate();
424  tIterator<Resource>* iterator = resourceList->getIterator();
425  Resource* enumRes = iterator->nextElement();
426  while (enumRes)
427    {
428      if (enumRes->type == type && !strcmp(fileName, enumRes->name))
429        {
430          bool match = false;
431          bool subMatch = false;
432          switch (type)
433            {
434            case PRIM:
435            case OBJ:
436              if (!param1)
437                {
438                  if (enumRes->modelSize == 1.0)
439                    match = true;
440                }
441              else if (enumRes->modelSize == *(float*)param1)
442                match = true;
443              break;
444            case TTF:
445              if (!param1)
446                {
447                  if (enumRes->ttfSize == FONT_DEFAULT_SIZE)
448                    subMatch = true;
449                }
450              else if (enumRes->modelSize =- *(int*)param1)
451                subMatch = true;
452              if(subMatch)
453                {
454                  Vector* tmpVec = (Vector*)param2;
455                  if (!param2)
456                    {
457                      if(enumRes->ttfColorR == FONT_DEFAULT_COLOR_R &&
458                         enumRes->ttfColorG == FONT_DEFAULT_COLOR_G &&
459                         enumRes->ttfColorB == FONT_DEFAULT_COLOR_B )
460                        match = true;
461                    }
462                  else if (enumRes->ttfColorR == (int)tmpVec->x &&
463                           enumRes->ttfColorG == (int)tmpVec->y &&
464                           enumRes->ttfColorB == (int)tmpVec->z )
465                    match = true;
466                }
467
468              break;
469            default:
470              match = true;
471              break;
472            }
473          if (match)
474            {
475              delete iterator;
476              return enumRes;
477            }
478        }
479      enumRes = iterator->nextElement();
480    }
481  delete iterator;
482  return NULL;
483}
484
485/**
486   \brief Searches for a Resource by Pointer
487   \param pointer the Pointer to search for
488   \returns a Pointer to the Resource if found, NULL otherwise.
489*/
490Resource* ResourceManager::locateResourceByPointer(const void* pointer)
491{
492  //  Resource* enumRes = resourceList->enumerate();
493  tIterator<Resource>* iterator = resourceList->getIterator();
494  Resource* enumRes = iterator->nextElement();
495  while (enumRes)
496    {
497      if (pointer == enumRes->pointer)
498        {
499          delete iterator;
500          return enumRes;
501        }
502      enumRes = iterator->nextElement();
503    }
504  delete iterator;
505  return NULL;
506}
507
508/**
509   \brief Checks if it is a Directory
510   \param directoryName the Directory to check for
511   \returns true if it is a directory/symlink false otherwise
512*/
513bool ResourceManager::isDir(const char* directoryName)
514{
515  char* tmpDirName = NULL;
516  struct stat status;
517
518  // checking for the termination of the string given. If there is a "/" at the end cut it away
519  if (directoryName[strlen(directoryName)-1] == '/')
520    {
521      tmpDirName = new char[strlen(directoryName)+1];
522      strncpy(tmpDirName, directoryName, strlen(directoryName)-1);
523      tmpDirName[strlen(directoryName)-1] = '\0';
524    }
525  else
526    {
527      tmpDirName = new char[strlen(directoryName)+1];
528      strcpy(tmpDirName, directoryName);
529    }
530
531  if(!stat(tmpDirName, &status))
532    {
533      if (status.st_mode & (S_IFDIR
534#ifndef __WIN32__
535                            | S_IFLNK
536#endif
537                            ))
538        {
539          delete tmpDirName;
540          return true;
541        }
542      else
543        {
544          delete tmpDirName;
545          return false;
546        }
547    }
548  else
549    return false;
550}
551
552/**
553   \brief Checks if the file is either a Regular file or a Symlink
554   \param fileName the File to check for
555   \returns true if it is a regular file/symlink, false otherwise
556*/
557bool ResourceManager::isFile(const char* fileName)
558{
559  char* tmpFileName = ResourceManager::homeDirCheck(fileName);
560  // actually checks the File
561  struct stat status;
562  if (!stat(tmpFileName, &status))
563    {
564      if (status.st_mode & (S_IFREG
565#ifndef __WIN32__
566                            | S_IFLNK
567#endif
568                            ))
569        {
570          delete tmpFileName;
571          return true;
572        }
573      else
574        {
575          delete tmpFileName;
576          return false;
577        }
578    }
579  else 
580    {
581      delete tmpFileName;
582      return false;
583    }
584}
585
586/**
587   \brief touches a File on the disk (thereby creating it)
588   \param fileName The file to touch
589*/
590bool ResourceManager::touchFile(const char* fileName)
591{
592  char* tmpName = ResourceManager::homeDirCheck(fileName);
593
594  FILE* stream;
595  if( (stream = fopen (tmpName, "w")) == NULL)
596    {
597      PRINTF(1)("could not open %s fro writing\n", fileName);
598      return false;
599    }
600  fclose(stream);
601   
602  delete tmpName; 
603}
604
605/**
606   \brief deletes a File from disk
607   \param fileName the File to delete
608*/
609bool ResourceManager::deleteFile(const char* fileName)
610{
611  char* tmpName = ResourceManager::homeDirCheck(fileName);
612  unlink(tmpName);
613  delete tmpName;
614}
615
616/**
617    \param fileName the Name of the file to check
618    \returns The name of the file, including the HomeDir
619    IMPORTANT: this has to be deleted from the outside
620*/
621char* ResourceManager::homeDirCheck(const char* name)
622{
623  char* retName;
624  if (!strncmp(name, "~/", 2))
625    {
626      char tmpFileName[500];
627#ifdef __WIN32__
628      strcpy(tmpFileName, getenv("USERPROFILE"));
629#else
630      strcpy(tmpFileName, getenv("HOME"));
631#endif
632      retName = new char[strlen(tmpFileName)+strlen(name)];
633      sprintf(retName, "%s%s", tmpFileName, name+1);
634    }
635  else
636    {
637      retName = new char[strlen(name)+1];
638      strcpy(retName, name);
639    }
640  return retName;
641}
642
643/**
644    \param fileName the Name of the File to check
645    \returns The full name of the file, including the DataDir, and NULL if the file does not exist
646    IMPORTANT: this has to be deleted from the outside
647*/
648char* ResourceManager::getFullName(const char* fileName)
649{
650  char* retName = new char[strlen(ResourceManager::getInstance()->getDataDir()) + strlen(fileName)+1];
651  sprintf(retName, "%s%s", ResourceManager::getInstance()->getDataDir(), fileName);
652  if (ResourceManager::isFile(retName))
653    return retName;
654  else
655    {
656      delete retName;
657      return NULL;
658    }
659}
660
661
662/**
663   \brief outputs debug information about the ResourceManager
664*/
665void ResourceManager::debug(void)
666{
667  PRINT(0)("=RM===================================\n");
668  PRINT(0)("= RESOURCE-MANAGER DEBUG INFORMATION =\n");
669  PRINT(0)("======================================\n");
670  // if it is not initialized
671  PRINT(0)(" Reference is: %p\n", ResourceManager::singletonRef);
672  PRINT(0)(" Data-Directory is: %s\n", this->dataDir);
673  PRINT(0)(" List of Image-Directories: ");
674  tIterator<char>* tmpIt = imageDirs->getIterator();
675  char* tmpDir = tmpIt->nextElement();
676  while(tmpDir)
677    {
678      PRINT(0)("%s ",tmpDir);
679      tmpDir = tmpIt->nextElement();
680    }
681  delete tmpIt;
682  PRINT(0)("\n");
683
684  PRINT(0)("List of all stored Resources:\n");
685  tIterator<Resource>* iterator = resourceList->getIterator();
686  Resource* enumRes = iterator->nextElement();
687  while (enumRes)
688    {
689      PRINT(0)("-----------------------------------------\n");
690      PRINT(0)("Name: %s; References: %d; Type:", enumRes->name, enumRes->count);
691      switch (enumRes->type)
692        {
693        case OBJ:
694          PRINT(0)("ObjectModel\n");
695          break;
696        case PRIM:
697          PRINT(0)("PrimitiveModel\n");
698          break;
699        case IMAGE:
700          PRINT(0)("ImageFile (Texture)\n");
701          break;
702        default:
703          PRINT(0)("SoundFile\n");
704          break;
705        }
706      PRINT(0)("gets deleted at ");
707      switch(enumRes->prio)
708        {
709        default:
710        case RP_NO:
711          PRINT(0)("first posibility (0)\n");
712          break;
713        case RP_LEVEL:
714          PRINT(0)("the end of the Level (1)\n");
715          break;
716        case RP_CAMPAIGN:
717          PRINT(0)("the end of the campaign (2)\n");
718          break;
719        case RP_GAME:
720          PRINT(0)("when leaving the game (3)\n");
721          break;
722        }
723      enumRes = iterator->nextElement();
724    }
725  delete iterator;
726
727
728
729  PRINT(0)("==================================RM==\n");
730}
Note: See TracBrowser for help on using the repository browser.