Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: fixed bug with not loading the md2-texture

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