def listResources(self, resType, fullPaths=True): if resType in self.getResourcesTypes(): prefix = '' if fullPaths: prefix = self.directory return [ os.path.join(prefix, resName) for resName in self.resourcesNames if ResourcesTypes.isExtensionOfType(resName[-4:], resType) ] else: return []
def loadShader(self, name): ''' Loads the shader specified by the given name. @param name: The name of the shader, by convention it will be used as the basename of the shader file to load. @return: A pandac.PandaModules.Shader instance or None if the file was not found or could not get loaded. ''' exts = ResourcesTypes.getExtensions(PanoConstants.RES_TYPE_SHADERS) if len(exts) == 1: return self._loadInternal(PanoConstants.RES_TYPE_SHADERS, name + exts[0]) else: return self._loadInternal(PanoConstants.RES_TYPE_SHADERS, name)
def preloadResources(self, resType): ''' Pre-loads all discovered resources of the given type. For example preloadResources(PanoConstants.RES_TYPE_MODELS) will pre-load all models in all resource locations. @param resType: A constant that identifies the type of resources to preload. ''' if self.log.isEnabledFor(logging.DEBUG): self.log.debug('Preloading resource types %s' % ResourcesTypes.typeToStr(resType)) locations = self.resLocations.get(resType) if locations is not None: for loc in locations: self.preloadResourceLocation(loc.name, [resType], False)
def _storePreloaded(self, res, filename, location): ''' Stores a resource in the special storage allocated for preloaded resources. @param res: The loaded resource, a pano.resources.Resource instance. @param filename: The full path to the file that contains the resource. @param location: The name of the resource location containing the resource. ''' if self.log.isEnabledFor(logging.DEBUG): self.log.debug('adding pre-loaded resource %s of type %s' % (filename, ResourcesTypes.typeToStr(res.type))) perLocation = self.preloadStore.get(location) if perLocation is None: perLocation = {} perLocation[filename] = res self.preloadStore[location] = perLocation
class DirectoryResourcesLocation(AbstractResourceLocation): ''' Offers services for finding loading files from directories. ''' def __init__(self, directory, name, description, resTypes, hotswap=True, checkPeriod=10): AbstractResourceLocation.__init__(self, name, description, resTypes, hotswap, checkPeriod) self.log = logging.getLogger('pano.directoryResource') # the directory to look into for supported resource types self.directory = directory # a sorted list of all filenames of supported types that were found in self.directory self.resourcesNames = [] def dispose(self): self.resourcesNames = None def indexResources(self): # get a listing of the directory and match filenames against # all supported resource types try: filenames = dircache.listdir(self.directory) except Exception, e: # dircache.listdir can throw self.log.exception('error while calling dircache.listdir') return suffixes = [] for resType in self.resTypes: suffixes.extend(ResourcesTypes.getExtensions(resType)) suffixes = tuple(suffixes) self.resourcesNames = [ item for item in filenames if item.endswith(suffixes) ] self.resourcesNames.sort()
def _loadParsedResource(self, resType, resName, filename, location): ''' Handles loading of all parsed resources such as .pointer, .node, .item, etc. resources. Since parsed resources are all text based, we assume that they are encoded in UTF-8 in order to support multilingual elements. @param resType: The type of the resource. @param resName: The name to give to the newly constructed resource. @param filename: The full path to the file that contains the resource. @param location: The resource location found to contain this file, indicates that the resource has been located. ''' assert resType is not None and resType != PanoConstants.RES_TYPE_ALL, 'invalid resource type in loadGeneric' fileContents = location.getResourceAsString(filename, True) resObj = ResourcesTypes.constructParsedResource(resType, resName) resource = self.parsers[resType].parse(resObj, fileContents) return resource
def _listResourcesImpl(self, parent, resType, fullPaths = True): resFiles = [] directories = [] vfs = VirtualFileSystem.getGlobalPtr() filesList = vfs.scanDirectory(parent) if filesList is None: return directories for i in xrange(filesList.getNumFiles()): fileEntry = filesList.getFile(i) if fileEntry.isDirectory(): directories.append(fileEntry.getFilename()) continue if ResourcesTypes.isExtensionOfType(fileEntry.getFilename().getExtension(), resType): resFiles.append(fileEntry.getFilename().getFullpath() if fullPaths else fileEntry.getFilename().getBasename()) for dir in directories: resFiles.extend(self._listResourcesImpl(dir, resType, fullPaths)) return resFiles
def _createButtons(self, cfg): ''' Creates DirectGui elements for displaying the paging and scrolling buttons. The sprite names are read from the configuration. The create DirectButtons use sprites as images. @param cfg: a ConfigVars instance ''' # button to display next page of items nxPgBtnSprite = cfg.get(PanoConstants.CVAR_INVENTORY_NEXTPAGE_SPRITE) nxPgBtnPressedSprite = cfg.get( PanoConstants.CVAR_INVENTORY_NEXTPAGE_PRESSED_SPRITE) nxPgBtnHoverSprite = cfg.get( PanoConstants.CVAR_INVENTORY_NEXTPAGE_HOVER_SPRITE) nxPgBtnPos = cfg.getVec2(PanoConstants.CVAR_INVENTORY_NEXTPAGE_POS) # button to display previous page of items pvPgBtnSprite = cfg.get(PanoConstants.CVAR_INVENTORY_PREVPAGE_SPRITE) pvPgBtnPressedSprite = cfg.get( PanoConstants.CVAR_INVENTORY_PREVPAGE_PRESSED_SPRITE) pvPgBtnHoverSprite = cfg.get( PanoConstants.CVAR_INVENTORY_PREVPAGE_HOVER_SPRITE) pvPgBtnPos = cfg.getVec2(PanoConstants.CVAR_INVENTORY_PREVPAGE_POS) # button to scroll to next items scrNxBtnSprite = cfg.get( PanoConstants.CVAR_INVENTORY_SCROLLNEXT_SPRITE) scrNxBtnPressedSprite = cfg.get( PanoConstants.CVAR_INVENTORY_SCROLLNEXT_PRESSED_SPRITE) scrNxBtnHoverSprite = cfg.get( PanoConstants.CVAR_INVENTORY_SCROLLNEXT_HOVER_SPRITE) scrNxBtnPos = cfg.getVec2(PanoConstants.CVAR_INVENTORY_SCROLLNEXT_POS) # button to scroll to previous items scrPvBtnSprite = cfg.get( PanoConstants.CVAR_INVENTORY_SCROLLPREV_SPRITE) scrPvBtnPressedSprite = cfg.get( PanoConstants.CVAR_INVENTORY_SCROLLPREV_PRESSED_SPRITE) scrPvBtnHoverSprite = cfg.get( PanoConstants.CVAR_INVENTORY_SCROLLPREV_HOVER_SPRITE) scrPvBtnPos = cfg.getVec2(PanoConstants.CVAR_INVENTORY_SCROLLPREV_POS) sprites = self.game.getView().getSpritesFactory() origin = aspect2d.getRelativePoint(screen2d, VBase3(0, 0, 0)) # for every button define property name, position, callback, list of sprites for normal, pressed and hover state pagingButtons = [ ('nextPageButton', nxPgBtnPos, self._nextPageCallback, [(nxPgBtnSprite, 'next_page_sprite'), (nxPgBtnPressedSprite, 'next_page_pressed_sprite'), (nxPgBtnHoverSprite, 'next_page_hover_sprite')]), ('prevPageButton', pvPgBtnPos, self._previousPageCallback, [(pvPgBtnSprite, 'previous_page_sprite'), (pvPgBtnPressedSprite, 'previous_page_pressed_sprite'), (pvPgBtnHoverSprite, 'previous_page_hover_sprite')]), ('scrollNextButton', scrNxBtnPos, self._scrollNextCallback, [(scrNxBtnSprite, 'scroll_next_sprite'), (scrNxBtnPressedSprite, 'scroll_next_pressed_sprite'), (scrNxBtnHoverSprite, 'scroll_next_hover_sprite')]), ('scrollPrevButton', scrPvBtnPos, self._scrollPreviousCallback, [(scrPvBtnSprite, 'scroll_previous_sprite'), (scrPvBtnPressedSprite, 'scroll_previous_pressed_sprite'), (scrPvBtnHoverSprite, 'scroll_previous_hover_sprite')]), ] for buttonName, buttonPos, buttonCallback, spritesList in pagingButtons: buttonGeoms = [None, None, None, None] btnScrBounds = [0, 0, 0] i = 0 for spriteFile, spriteName in spritesList: print 'adding sprite %s' % spriteName if spriteFile is not None: spr = None if spriteFile.rindex('.') >= 0: ext = spriteFile[spriteFile.rindex('.'):] print ext if ResourcesTypes.isExtensionOfType( ext, PanoConstants.RES_TYPE_IMAGES): spr = Sprite(spriteName) spr.image = spriteFile else: spr = self.game.getResources().loadSprite(spriteFile) if spr: buttonGeoms[i] = sprites.createSprite(spr).nodepath buttonGeoms[i].setScale(1.0) btnScrBounds = aspect2d.getRelativePoint( screen2d, VBase3(spr.width, 1.0, spr.height)) - origin btnScrBounds[2] *= -1 i += 1 if buttonGeoms[0] is not None: b = DirectButton( geom=(buttonGeoms[0], buttonGeoms[1] if buttonGeoms[1] else buttonGeoms[0], buttonGeoms[2] if buttonGeoms[2] else buttonGeoms[0], buttonGeoms[3] if buttonGeoms[3] else buttonGeoms[0]), relief=None) b['geom_pos'] = (0, 0, 0) b.setTransparency(1) # if position is omitted from the configuration, put the button on the upper left corner if buttonPos is not None: b.setPos( aspect2d.getRelativePoint( screen2d, VBase3(buttonPos[0], 1.0, buttonPos[1]))) else: b.setPos(origin[0], 1.0, origin[2]) b.setScale(btnScrBounds[0], 1.0, btnScrBounds[2]) b.setFrameSize((0, btnScrBounds[0], 1.0, btnScrBounds[2])) b['command'] = buttonCallback b['extraArgs'] = (self.msn, ) b.hide() else: b = None setattr(self, buttonName, b)
def _loadInternal(self, resType, filename, locationName=None, preloading=False): ''' Manages the actual loading of a resource given the resource filename and the resource location that contains it. @param resType: A constant that identifies the type of the resource. @param filename: The filename of the resource. @param locationName: The name of the resource location containing the resource. This is optional. @return: A pano.resources.Resource instance if preloading is True, or the actual resource instance if preloading is False or finally None if the resource couldn't be found. ''' self.requests += 1 if locationName is not None: location = self.locationsByName.get(locationName) else: location = self.locateResource(resType, filename) if location is None: self.log.error('Failed to locate resource %s' % filename) return None # get the full path to query the cache, sticky and preload stores fullPath = location.getResourceFullPath(filename) if fullPath is None: self.log.error('Failed to get full path to resource %s' % filename) return None # resource locations can be sticky if location.sticky: resource = self._getStickyResource(fullPath, resType) if resource is not None: if self.log.isEnabledFor(logging.DEBUG): self.log.debug('Returning sticky resource %s' % fullPath) self.stickyLoads += 1 if not preloading: resource.requested = True return resource.data if not preloading else resource # if the location has a preload flag, then search first in the preload store if location.preload: resource = self._fetchPreloaded(fullPath, location.name) if resource is not None: self.preloadHits += 1 if not preloading: resource.requested = True return resource.data if not preloading else resource else: self.preloadMisses += 1 # then search in our cache # resource = self._cacheLookup(fullPath, location.name) # if resource is not None: # if self.log.isEnabledFor(logging.DEBUG): # self.log.debug('Returning cached instance of resource %s' % fullPath) # if not preloading: # resource.requested = True # return resource.data if not preloading else resource # finally load it from the resource location if ResourcesTypes.isParsedResource(resType): # Convention: construct resource name from the basename of the filename and by dropping the extension. resName = os.path.basename(filename) extIndex = resName.rfind('.') if extIndex >= 0: resName = resName[:extIndex] resData = self._loadParsedResource(resType, resName, fullPath, location) else: if ResourcesTypes.isPandaResource(resType): # for Panda resources we use the BaseLoader resName = filename try: if resType == PanoConstants.RES_TYPE_MODELS: resData = loader.loadModel(fullPath) elif resType == PanoConstants.RES_TYPE_TEXTURES or resType == PanoConstants.RES_TYPE_VIDEOS: resData = loader.loadTexture(fullPath) elif resType == PanoConstants.RES_TYPE_IMAGES: img = PNMImage() img.read(fullPath) resData = img elif resType == PanoConstants.RES_TYPE_MUSIC: resData = loader.loadMusic(fullPath) elif resType == PanoConstants.RES_TYPE_SFX: resData = loader.loadSfx(fullPath) elif resType == PanoConstants.RES_TYPE_SHADERS: resData = Shader.load(fullPath) except Exception: self.log.exception( 'Panda loader failed to load resource %s' % fullPath) return None elif ResourcesTypes.isStreamResource(resType): # we consider character based and binary based streams # by handling stream resources in a special way we can perhaps provide more efficient # handling of streams, i.e. memory mapped files, compressed streams, decryption, etc. resName = filename if resType == PanoConstants.RES_TYPE_SCRIPTS or resType == PanoConstants.RES_TYPE_TEXTS: resData = self._loadCharacterStream(fullPath, location) else: resData = self._loadBinaryStream(fullPath, location) elif ResourcesTypes.isOpaqueResource(resType): # opaque resources perform their own loading, we only load the file's contents without caring # about how it looks and pass it to the read() method. resName = os.path.basename(filename) resData = ResourcesTypes.constructOpaqueResource( resType, resName, filename) opaque = self._loadBinaryStream(fullPath, location) fp = StringIO.StringIO(opaque) resData.read(fp) if resData is None: self.log.error('Failed to load resource %s' % fullPath) return None resource = Resource(resName, resData, resType, fullPath, location.name) resource.sticky = location.sticky resource.preload = location.preload if not preloading: resource.requested = True # consider caching the resource if not resource.sticky and not resource.preload: self._cacheResource(fullPath, resource, location.name) elif resource.sticky: self._addStickyResource(fullPath, resource, location.name) # when we are preloading, return the Resource instance instead return resource.data if not preloading else resource