Bootstrap]
Zip = ../Media/packs/ogrecore.zip
# Resource locations to be added to the default path
[General]
Filesystem =.../../Media
Filesystem =.../../Media/Fonts
Filesystem =.../Media/materials/programs
Filesystem =.../../Media/materials/scripts
Filesystem =.../../Media/materials/textures
Filesystem =.../../Media/models
Filesystem =.../../Media/Overlays
Filesystem =.../../Media/particle
Filesystem = ../Media/datafiles/Fonts
Filesystem =.../../Media/datafiles/imagesets
Filesystem =.../../Media/datafiles/layouts
Filesystem =.../../Media/datafiles/looknfeel
Filesystem = ../Media/datafiles/Schemes
Filesystem =.../../Media/datafiles/lua_scripts
Filesystem =.../../Media/deferredshadingmedia
Zip = ../Media/packs/cubemap.zip
Zip = ../Media/packs/cubemapsjs.zip
Zip = ../Media/packs/dragon.zip
Zip = ../Media/packs/fresneldemo.zip
Zip = ../Media/packs/ogretestmap.zip
Zip = ../Media/packs/skybox.zip
Code 7-1 is quite clear. The two resource components in the file are "Bootstrap" and "General ". "General" is the default system group and always exists. When you add resources to this group, no new resource group will be created. In the example, the bootstrap group means to only target the resource object of the Ogre demo framework exampleapplication. It is a random name (you can also use it in your implementation ), it will not be specially processed like General.
Filesystem and zip indicate the type of files used: filesystem indicates the file system-based resource "file "; zip indicates that the resource path is the "file" of a zip compressed file ". If you implement a custom "file" type, you can call it here.
Resource Positioning
A frequently asked question is, "If there is no resource. cfg, how can I set the resource location ?" Let's take a look at the code in exampleapplication. h. Code 7-2 shows how to read the resources. cfg file.
Code 7-2: code used to parse the resources. cfg file in the exampleapplication framework
// Load resource paths from config file
Configfile CF;
Cf. Load ("resources. cfg ");
// Go through all sections & settings in the file
Configfile: sectioniterator SECI = Cf. getsectioniterator ();
String secname, typename, archname;
While (SECI. hasmoreelements ())
{
Secname = SECI. peeknextkey ();
Configfile: settingsmultimap * settings = SECI. getnext ();
Configfile: settingsmultimap: iterator I;
For (I = settings-> begin (); I! = Settings-> end (); ++ I)
{
Typename = I-> first;
Archname = I-> second;
Resourcegroupmanager: getsingleton (). addresourcelocation (
Archname, typename, secname );
}
}
Note: resources. cfg is only for the convenience of the files provided by the demo program. You cannot find any method to process the resources. cfg file in the Ogre API. The configfile class (and its internal class) is part of the ogre; it is used to read and parse the format used by the script. You can use this class to process your own configuration files, which is as simple as processing the Ogre custom scripts.
The above Code (Code 7-2) is called by all ogre demo programs to parse and read the resource configuration file resources. cfg. It iterates each segment in the outer iteration file (each segment is also a group name, bootstrap and General), and then records each segment through each name/value pair. Finally, call the addresourcelocation () method of resourcegroupmanager for each name/value pair to set the resource location.
In code 7-1, the core of the script is only addresourcelocation (). The following is a hard code example (Code 7-3) that achieves the same effect as the preceding configuration file code ).
Code 7-3: direct, hard-coded to achieve the same effect as code 7-2
Resourcegroupmanager * RGM = resourcegroupmanager:; getsingletonptr ();
RGM-> addresourcelocation (".../../Media/packs/ogrecore.zip", "Zip", "Bootstrap ");
RGM-> addresourcelocation (".../../Media/", "filesystem", "General ");
RGM-> addresourcelocation (".../../Media/fonts", "filesystem", "General ");
// You can add other required resource locations later
Here, you can note that the path settings for resource positioning in the above Code are relative system paths. This does not mean that the Ogre resource positioning cannot support absolute paths, but if you decide to use absolute paths, the program may become invalid when it is installed on machines of other users. Therefore, it is a good habit to use relative paths when preparing various directories.
Resource Initialization
Resource Initialization must be supported in a certain sequence. Before formally adding a resource, you must first initialize the corresponding resource group. Before initializing the resource, you need to create the required rendering window, because parsing the resource script may depend on the GPU configuration.
Warning read the above text carefully, because the most common problems in the Ogre Forum are caused by the above reasons.
Code: 7-4 initialize resource Positioning
// Initialize all previously defined resource groups
Resourcegroupmanager: getsingleton (). initialiseallresourcegroup ();
// Or initialize a Resource Group
Resourcegroupmanager: getsingleton (). intialiseresourcegroup ("general ");
Resourcegroupmanager: getsingleton (). intialiseresourcegroup ("Bootstrap ");
In code 7-4, there are two different initialization methods. The first method is provided to the lazy to initialize all uninitialized resource groups at a time. The following describes how to initialize a resource group each time you want to more accurately control the initialization process.
Detach a resource
You can detach resources from the memory (either individually or in a group) whenever you want ). Ogre will help you maintain code security. When you use resources again elsewhere, ogre will help you reload your code. If you are still using resources when uninstalling ogre, ogre will help you disable this uninstalling action (at least for resources related to 3D rendering ).
The following code shows all the interfaces for detaching resources of the Resource Group Manager resourcegroupmanager:
Resourcegroupmanager: getsingleton (). unloadresourcegroup ("Bootstrap", true );
Resourcegroupmanager: getsingleton (). unloadunreferencedresourcesingroup ("Bootstrap", true );
The first line of code provides a method to detach an entire resource group, while the second line only unmounts resources that are not currently referenced. When a resource is detached, its data is removed from the memory, but the corresponding instance and declaration information still exist (when used again, the system is responsible for re-loading ).
The true parameter in the method tells the system to detach the resources that we are allowed to detach. In other words, this call method does not detach the resources that we mark as "undetachable. By default, the method uses the default parameter false to detach all resources.
Clear or destroy resource groups
Literally, clearing and destroying resource groups are not very different, but you should pay special attention to the nuances of these two operations during execution.
Clearing a resource group is only responsible for detaching and deleting Resources in the Resource Group:
Resourcegroupmanager: getsingleton (). clearresourcegroup ("Bootstrap ");
The destruction of resource groups not only clears the resources in the group, but also destroys the Resource Group itself:
Resourcegroupmanager: getsingleton (). destroyresourcegroup ("Bootstrap ");
Detach a single resource
If you want to carefully manage the lifecycle of each resource, you can call the unload method of the resource to perform the uninstallation.
// Assume that pentity is a pointer to an entity instance.
Meshptr = pentity-> getmesh ();
Meshptr-> unload ();
Load and reload a Resource Group
Here is a method that can load all resources in the same resource group:
Resourcegroupmanager: getsingleton (). loadresourcegroup ("Bootstrap ");
You can also use additional parameters to define the loaded resources, including "World Map" and other "normal" resources. See the call of the following two methods:
// For example, to load or reload a world map only, call the following method:
Resourcegroupmanager: getsingleton (). loadresourcegroup ("Bootstrap", false, true );
// Load only or re-load Resources in the "normal" group:
Resourcegroupmanager: getsingleton (). loadresourcegroup ("Bootstrap", true, false );
Resource Group-loaded callback events
If a listener object is registered in resource management, ogre will notify you of various loading times when loading resources. The most common application of this function is interesting functions such as loading entries on the UI interface.
Code 7-5: shows an empty near-code UI window implemented by implementing the resource listening interface resourcegrouplistene (a type called progressmeter is created here)
// Note: The progressmeter used in this example is a fictitious type.
Class loadingprogresslistener: Public resourcegrouplistener
{
Public:
Loadingprogresslistener (progressmeter & Meter ):
M_progressmeter (meter) {m_currentresource = 0 ;}
// Resource Group resourcegrouplistener event Method
// Called when the resource group starts parsing the script
Void resourcegroupscriptingstarted (const string & groupname,
Size "_ tscriptcount ){}
// Called when a script starts to be parsed
Void scriptparsestarted (const string & scriptname ){}
// Called when a script has been parsed
Void scriptparseended (){}
// Called when the script in the Resource Group is parsed
Void resourcegroupscriptingended (const string & groupname ){}
// Called when loading resources in the Resource Group
Void resourcegrouploadstarted (const string & groupname, size_t resourcecount)
{M_rescount = resourcecount ;}
// Called when loading a resource
Void resourceloadstarted (const resourceptr & Resource ){}
// Called when a Resource load ends
Void resourceloadended ();
// Called when the world ry starts loading
Void worldgeometrystagestarted (const string & Description ){}
// Called when the world map is loaded
Void worldgeometrystageended ();
// Called when all resources in the Resource Group are loaded
Void resourcegrouploadended (const string & groupname ){}
PRIVATE:
Int m_rescount;
Int m_currentresource;
Progressmeter & m_progressmeter;
};
Void loadingprogresslistener: worldgeometrystageended ()
{
// Increase the current resource quantity
M_currentresource ++;
// Update the progress bar size by percentage
M_progressmeter.updateprogress (float) m_currentresource/(float) m_rescount );
}
Void loadingprogresslistener: resourceloadended ()
{
// Increase the current resource quantity
M_currentresource ++;
// Update the progress bar size by percentage
M_progressmeter.updateprogress (float) m_currentresource/(float) m_rescount );
}
// Use the progressmeter class instance to initialize a listener
Loadingprogresslistener listener (m_progressmeter );
// Register the listener in resourcegroupmanager in your code
Resourcegroupmanager: getsingleton (). addresourcegrouplistener (& listener );
In code 7-5 above, we show the implementation code of "loading progress bar" in the UI. In the code, we only care about the update progress bar action after loading each resource, rather than whether it is a world map or a separate resource. For other methods of resource manager callback, we are only responsible for implementing the corresponding virtual functions, and do not do specific work (because it is the implementation of virtual interfaces, they are of no use except simple "exist ).
We can note that the progressmeter class in the sample code is not a member of the Ogre framework. Let's assume that it is the type you implement in your own application.
Archive in ogre )"
The most basic description of the concept of "Archive" in ogre is to store a series of files in a folder. Both files and files can be compressed. The value of archive itself is that it provides a file access portal for ogre.
Ogre implements operations on files in an archive through the archive interface. You can implement different file situations in your own applications as needed (as long as you inherit the archive interface, it will be well supported by the system ). By default, the disk directory is a basic file implementation method. In the release version of ogre, you will find the archive type implemented based on ZIP files, and you can directly perform operations on files in PKZIP compression format.
These two different archive implementations have their own advantages. When building and testing applications, it is more suitable for direct operations on hard disks, this allows you to quickly change and convert files when testing errors, without the need for tedious compression and decompression operations. In the release version, you may need a zip file with a high compression ratio to compress Resources in the released program.
As mentioned earlier in this book, various file systems are also used as plug-ins to "Insert" the Ogre framework. You can also expand the file implementation method you need. Although the filersystemarchive of Disk Files and ziparchive of compressed files are sufficient in most cases, it does not mean that you cannot expand the file, for example, a "Network File" that directly transmits data over a LAN is implemented ".
Archivemanager)
The following describes how to implement a new "ARCHIVE" type. Here, myarchive inherits from the archive interface. Then implement the corresponding factory method myarchivefactory and register it in the Document Manager archivemanager.
Class myarchive: Public Archive
{
// The specific implementation is omitted here
}
Class myarchivefactory: Public archivefactory
{
// Some methods for implementing archivefactory are omitted here
Archive * createinstance (const string & name ){
Return new myarchive (name, "myarchivetype ");
}
};
Void function ()
{
Myarchivefactory * factory = new myarchivefactory;
Archivemanager: getsingleton (). addarchivefactory (factory );
}
Code 7-6: register a new archive type to ogre
After registering a factory method with the archive manager, you can use the new archive type in the program or script with confidence. For example, in the previous example, the system calls the ziparchive object to process the corresponding compressed file by parsing the "Zip" keyword in the resources. cfg file. If you change "Zip" to "myarchivetype", you can use the custom file format myarchive to process the file system.
Custom Resource loading through custom "archives"
Here, we can recall the concept of manually creating and loading resources. We can also achieve the same work in "archives. This is because ogre only uses the archive interface to operate resource files, and does not care whether the so-called "resource file" is always saved on the hard disk or just created in the memory zone through the program. Based on this feature, we can use archive to dynamically generate the desired "resource file" in the memory ". Here is a more practical example. In many games, game data is stored through a file called "wad" [1. You can copy the required wad files to the memory when the program runs. Dynamically create a file by copying the required part of the wad file ing memory for use by the application. This processing method can well encapsulate the differences between different data file formats, and then use the Ogre resource management system to process files in non-Ogre formats, in order to expand the Ogre.
Conclusion
Resource Manager in 3D applications is generally not a complex topic, but it is very important. Poor resource managers can lead to lower execution efficiency and complaints from users. Therefore, based on the knowledge learned in this chapter, you should use the resource manager to maintain resource usage as flexibly as possible in your applications, you can also implement your own resource management policies when necessary. Ogre provides you with a set of universal and flexible resource management interfaces to help you work.