Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/orxonox/branches/physics/src/util/resource_manager.cc @ 4311

Last change on this file since 4311 was 4295, checked in by bensch, 20 years ago

orxonox/branches/physics: a better check for the data-directory

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