Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/orxonox/branches/md2_loader/src/util/resource_manager.cc @ 4147

Last change on this file since 4147 was 4139, checked in by patrick, 20 years ago

orxonox/branches/md2_loader: merged trunk into branche using: svn merge ../trunk/ md2_loader -r 4063:HEAD

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 "md2Model.h"
23#include "primitive_model.h"
24#include "texture.h"
25#include "text_engine.h"
26
27#include "list.h"
28
29// File Handling Includes
30#include <sys/types.h>
31#include <sys/stat.h>
32#include <unistd.h>
33
34using namespace std;
35
36/**
37   \brief standard constructor
38*/
39ResourceManager::ResourceManager () 
40{
41   this->setClassName ("ResourceManager");
42   this->dataDir = NULL;
43   this->setDataDir("./");
44   this->imageDirs = new tList<char>();
45   this->resourceList = new tList<Resource>();
46}
47
48/**
49   \returns the Instance to this ResourceManager
50*/
51ResourceManager* ResourceManager::getInstance(void)
52{
53  if (!ResourceManager::singletonRef)
54    ResourceManager::singletonRef = new ResourceManager();
55  return ResourceManager::singletonRef;
56}
57
58//! Singleton Reference to the ResourceManager
59ResourceManager* ResourceManager::singletonRef = NULL;
60
61/**
62   \brief standard destructor
63*/
64ResourceManager::~ResourceManager (void) 
65{
66  // deleting the Resources-List
67  this->unloadAllByPriority(RP_GAME);
68  delete this->resourceList;
69  // deleting the Directorie Lists
70  tIterator<char>* tmpIt = imageDirs->getIterator();
71  char* tmpDir = tmpIt->nextElement();
72  while(tmpDir)
73    {
74      delete []tmpDir;
75      tmpDir = tmpIt->nextElement();
76    }
77  delete tmpIt;
78
79  delete this->imageDirs;
80
81  ResourceManager::singletonRef = NULL;
82}
83
84/**
85   \brief sets the data main directory
86   \param dataDir the DataDirectory.
87*/
88bool ResourceManager::setDataDir(const char* dataDir)
89{
90  if (isDir(dataDir))
91    {
92      delete this->dataDir;
93      this->dataDir = new char[strlen(dataDir)+1];
94      strcpy(this->dataDir, dataDir);
95      return true;
96    }
97  else
98    {
99      PRINTF(1)("%s is not a Directory, and can not be the Data Directory, leaving as %s \n", dataDir, this->dataDir);
100      return false;
101    }
102}
103
104/**
105   \brief checks for the DataDirectory, by looking if
106   \param fileInside is inisde??
107*/
108bool ResourceManager::checkDataDir(const char* fileInside)
109{
110  bool retVal;
111  if (!isDir(this->dataDir))
112    {
113      PRINTF(1)("%s is not a directory\n", this->dataDir);
114      return false;
115    }
116 
117  char* testFile = new char[strlen(this->dataDir)+strlen(fileInside)+1];
118  sprintf(testFile, "%s%s", this->dataDir, fileInside);
119  retVal = isFile(testFile);
120  delete testFile;
121  return retVal;
122}
123
124/**
125   \brief adds a new Path for Images
126   \param imageDir The path to insert
127   \returns true, if the Path was well and injected (or already existent within the list)
128   false otherwise
129*/
130bool ResourceManager::addImageDir(char* imageDir)
131{
132  // check if the param is a Directory
133  if (isDir(imageDir))
134    {
135      // check if the Directory has been added before
136      tIterator<char>* tmpImageDirs = imageDirs->getIterator();
137      char* tmpDir = tmpImageDirs->nextElement();
138      while(tmpDir)
139        {
140          if (!strcmp(tmpDir, imageDir))
141            {
142              PRINTF(4)("Path %s already loaded\n", imageDir);
143              delete tmpImageDirs;
144              return true;
145            }
146          tmpDir = tmpImageDirs->nextElement();
147        }
148      delete tmpImageDirs;
149
150      // adding the directory to the List
151      tmpDir  = new char[strlen(imageDir)+1];
152      strcpy(tmpDir, imageDir);
153      this->imageDirs->add(tmpDir);
154      return true;
155    }
156  else
157    {
158      PRINTF(1)("%s is not a Directory, and can not be added to the Paths of Images\n", dataDir);
159      return false;
160    }
161}
162
163/**
164   \brief loads resources
165   \param fileName The fileName of the resource to load
166   \param prio The ResourcePriority of this resource (will only be increased)
167   \returns a pointer to a desired Resource.
168*/
169void* ResourceManager::load(const char* fileName, ResourcePriority prio, void* param1, void* param2, void* param3)
170{
171  ResourceType tmpType;
172  if (!strncmp(fileName+(strlen(fileName)-4), ".obj", 4))
173    tmpType = OBJ;
174  else if (!strncmp(fileName+(strlen(fileName)-4), ".wav", 4))
175    tmpType = WAV;
176  else if (!strncmp(fileName+(strlen(fileName)-4), ".mp3", 4))
177    tmpType = MP3;
178  else if (!strncmp(fileName+(strlen(fileName)-4), ".ogg", 4))
179    tmpType = OGG;
180  else if (!strcmp(fileName, "cube") ||
181           !strcmp(fileName, "sphere") ||
182           !strcmp(fileName, "plane") ||
183           !strcmp(fileName, "cylinder") ||
184           !strcmp(fileName, "cone"))
185    tmpType = PRIM;
186  else if (!strncmp(fileName+(strlen(fileName)-4), ".ttf", 4))
187    tmpType = TTF;
188  else 
189    tmpType = IMAGE;
190
191  return this->load(fileName, tmpType, prio, param1, param2, param3);
192}
193
194/**
195   \brief loads resources
196   \param fileName The fileName of the resource to load
197   \param type The Type of Resource to load (\see ResourceType)
198   \param prio The ResourcePriority of this resource (will only be increased)
199   \returns a pointer to a desired Resource.
200*/
201void* ResourceManager::load(const char* fileName, ResourceType type, ResourcePriority prio, void* param1, void* param2, void* param3)
202{
203  // searching if the resource was loaded before.
204  Resource* tmpResource = this->locateResourceByInfo(fileName, type, param1, param2,param3);
205  if (tmpResource) // if the resource was loaded before.
206    {
207      PRINTF(4)("not loading cached resource %s\n", tmpResource->name);
208      tmpResource->count++;
209      if(tmpResource->prio < prio)
210        tmpResource->prio = prio;
211    }
212  else
213    {
214      char* tmpDir;
215      // Setting up the new Resource
216      tmpResource = new Resource;
217      tmpResource->count = 1;
218      tmpResource->type = type;
219      tmpResource->prio = prio;
220      tmpResource->name = new char[strlen(fileName)+1];
221      strcpy(tmpResource->name, fileName);
222
223      // creating the full name. (directoryName + FileName)
224      char* fullName = new char[strlen(this->getDataDir())+strlen(fileName)+1];
225      sprintf(fullName, "%s%s", this->getDataDir(), fileName);
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(ResourceManager::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.