Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 4462 was 4462, checked in by bensch, 19 years ago

orxonox/trunk: md2Data loadable over the resourceManager

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