1 /** @file clientresources.h  Client-side resource subsystem.
2  * @ingroup resource
3  *
4  * @authors Copyright © 2013-2015 Daniel Swanson <danij@dengine.net>
5  * @authors Copyright © 2016-2017 Jaakko Keränen <jaakko.keranen@iki.fi>
6  *
7  * @par License
8  * GPL: http://www.gnu.org/licenses/gpl.html
9  *
10  * <small>This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by the
12  * Free Software Foundation; either version 2 of the License, or (at your
13  * option) any later version. This program is distributed in the hope that it
14  * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
15  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
16  * Public License for more details. You should have received a copy of the GNU
17  * General Public License along with this program; if not, see:
18  * http://www.gnu.org/licenses</small>
19  */
20 
21 #ifndef DENG_CLIENT_RESOURCES_H
22 #define DENG_CLIENT_RESOURCES_H
23 
24 #include <QList>
25 #include <QMap>
26 #include <QSet>
27 #include <de/Error>
28 #include <de/Record>
29 #include <de/String>
30 #include <de/System>
31 
32 #include <doomsday/defs/ded.h>
33 #include <doomsday/filesys/wad.h>
34 #include <doomsday/filesys/zip.h>
35 #include <doomsday/uri.h>
36 #include <doomsday/resource/animgroup.h>
37 #include <doomsday/resource/mapmanifest.h>
38 #include <doomsday/resource/resources.h>
39 #include <doomsday/resource/colorpalette.h>
40 #include <doomsday/res/Texture>
41 #include <doomsday/res/TextureScheme>
42 
43 #include "resource/rawtexture.h"
44 
45 #include "AbstractFont"
46 #include "BitmapFont"
47 #include "CompositeBitmapFont"
48 #include "FontScheme"
49 #include "MaterialVariantSpec"
50 #include "resource/framemodel.h"
51 #include "resource/framemodeldef.h"
52 
53 class ClientMaterial;
54 
55 /**
56  * Subsystem for managing client-side resources.
57  *
58  * Resource pointers are considered @em eternal in the sense that they will
59  * continue to reference the same logical resource data, even after the engine
60  * is reset. Public resource identifiers (e.g., materialid_t) are similarly
61  * eternal.
62  *
63  * Resource names (paths) are semi-independant from the resources. There may be
64  * multiple names for any given resource (aliases). The only requirement is that
65  * their symbolic name must be unique among resources in the same scheme.
66  *
67  * @par Classification
68  *
69  * @em Runtime resources are not loaded until precached or actually needed. They
70  * may be cleared, in which case they will be reloaded when needed.
71  *
72  * @em System resources are loaded at startup and remain in memory all the time.
73  * After clearing they must be manually reloaded.
74  *
75  * @par Texture resources
76  *
77  * @em Clearing a texture is to 'undefine' it - any names bound to it will be
78  * deleted and any GL textures acquired for it are 'released'. The logical
79  * Texture instance used to represent it is also deleted.
80  *
81  * @em Releasing a texture will leave it defined (any names bound to it will
82  * persist) but any GL textures acquired for it are 'released'. Note that the
83  * logical Texture instance used to represent is NOT be deleted.
84  *
85  * @ingroup resource
86  */
87 class ClientResources : public Resources
88 {
89 public:
90     /// The referenced model def was not found. @ingroup errors
91     DENG2_ERROR(MissingModelDefError);
92 
93     /// The specified font id was invalid (out of range). @ingroup errors
94     DENG2_ERROR(UnknownFontIdError);
95 
96     typedef QMap<de::String, de::FontScheme *> FontSchemes;
97     typedef QList<AbstractFont *> AllFonts;
98 
99     static ClientResources &get();
100 
101 public:
102     /**
103      * Construct a new resource system, configuring all resource classes and
104      * the associated resource collection schemes.
105      */
106     ClientResources();
107 
108     void clear() override;
109     void clearAllRuntimeResources() override;
110     void clearAllSystemResources() override;
111 
112     void initSystemTextures() override;
113 
114     void reloadAllResources() override;
115 
116     /**
117      * Returns a rawtex_t for the given lump if one already exists; otherwise @c 0.
118      */
119     rawtex_t *rawTexture(lumpnum_t lumpNum);
120 
121     /**
122      * Get a rawtex_t data structure for a raw texture specified with a WAD lump
123      * number. Allocates a new rawtex_t if it hasn't been loaded yet.
124      */
125     rawtex_t *declareRawTexture(lumpnum_t lumpNum);
126 
127     /**
128      * Returns a list of pointers to all the raw textures in the collection.
129      */
130     QList<rawtex_t *> collectRawTextures() const;
131 
132     /**
133      * Determines if a manifest exists for a resource on @a path.
134      *
135      * @return @c true, if a manifest exists; otherwise @a false.
136      */
137     bool hasFont(de::Uri const &path) const;
138 
139     /**
140      * Convenient method of looking up a concrete font resource in the collection
141      * given it's unique identifier.
142      *
143      * @return  The associated font resource.
144      *
145      * @see toFontManifest(), FontManifest::hasResource()
146      */
font(fontid_t id)147     inline AbstractFont &font(fontid_t id) const {
148         return toFontManifest(id).resource();
149     }
150 
151     /**
152      * Returns the total number of resource manifests in the collection.
153      */
fontCount()154     de::duint fontCount() const { return allFonts().count(); }
155 
156     /**
157      * Find a resource manifest.
158      *
159      * @param search  The search term.
160      * @return Found unique identifier.
161      */
162     de::FontManifest &fontManifest(de::Uri const &search) const;
163 
164     /**
165      * Lookup a manifest by unique identifier.
166      *
167      * @param id  Unique identifier for the manifest to be looked up. Note
168      *            that @c 0 is not a valid identifier.
169      *
170      * @return  The associated manifest.
171      */
172     de::FontManifest &toFontManifest(fontid_t id) const;
173 
174     /**
175      * Lookup a subspace scheme by symbolic name.
176      *
177      * @param name  Symbolic name of the scheme.
178      * @return  Scheme associated with @a name.
179      *
180      * @throws UnknownSchemeError If @a name is unknown.
181      */
182     de::FontScheme &fontScheme(de::String name) const;
183 
184     /**
185      * Returns @c true iff a Scheme exists with the symbolic @a name.
186      */
187     bool knownFontScheme(de::String name) const;
188 
189     /**
190      * Returns a list of all the schemes for efficient traversal.
191      */
192     FontSchemes const &allFontSchemes() const;
193 
194     /**
195      * Returns the total number of manifest schemes in the collection.
196      */
fontSchemeCount()197     inline de::dint fontSchemeCount() const { return allFontSchemes().count(); }
198 
199     /**
200      * Clear all resources in all schemes.
201      *
202      * @see allFontSchemes(), FontScheme::clear().
203      */
clearAllFontSchemes()204     inline void clearAllFontSchemes() {
205         foreach(de::FontScheme *scheme, allFontSchemes()) {
206             scheme->clear();
207         }
208     }
209 
210     /**
211      * Returns a list of pointers to all the concrete resources in the collection,
212      * from all schemes.
213      */
214     AllFonts const &allFonts() const;
215 
216     /**
217      * Declare a resource in the collection, producing a (possibly new) manifest
218      * for a resource which may be defined later. If a manifest with the specified
219      * @a uri already exists the existing manifest will be returned.
220      *
221      * @param uri  Uri representing a path to the resource in the virtual hierarchy.
222      *
223      * @return  The associated manifest for this URI.
224      */
declareFont(de::Uri const & uri)225     inline de::FontManifest &declareFont(de::Uri const &uri) {
226         return fontScheme(uri.scheme()).declare(uri.path());
227     }
228 
229     /**
230      * Lookup the unique index attributed to the given @a modelDef.
231      *
232      * @return  Index of the definition; otherwise @c -1 if @a modelDef is unknown.
233      */
234     de::dint indexOf(FrameModelDef const *modelDef);
235 
236     /**
237      * Convenient method of looking up a concrete model resource in the collection
238      * given it's unique identifier. O(1)
239      *
240      * @return  The associated model resource.
241      */
242     FrameModel &model(modelid_t id);
243 
244     /**
245      * Determines if a model definition exists with the given @a id. O(n)
246      *
247      * @return  @c true, if a definition exists; otherwise @a false.
248      *
249      * @see modelDef()
250      */
251     bool hasModelDef(de::String id) const;
252 
253     /**
254      * Retrieve a model definition by it's unique @a index. O(1)
255      *
256      * @return  The associated model definition.
257      *
258      * @see modelDefCount()
259      */
260     FrameModelDef &modelDef(de::dint index);
261 
262     /**
263      * Lookup a model definition by it's unique @a id. O(n)
264      *
265      * @return  Found model definition.
266      *
267      * @see hasModelDef()
268      */
269     FrameModelDef &modelDef(de::String id);
270 
271     /**
272      * Lookup a model definition for the specified mobj @a stateIndex.
273      *
274      * @param stateIndex  Index of the mobj state.
275      * @param select      Model selector argument. There may be multiple models
276      *                    for a given mobj state. The selector determines which
277      *                    is used according to some external selection criteria.
278      *
279      * @return  Found model definition; otherwise @c nullptr.
280      */
281     FrameModelDef *modelDefForState(de::dint stateIndex, de::dint select = 0);
282 
283     /**
284      * Returns the total number of model definitions in the system.
285      *
286      * @see modelDef()
287      */
288     de::dint modelDefCount() const;
289 
290     /// @todo Refactor away. Used for animating particle/sky models.
291     void setModelDefFrame(FrameModelDef &modelDef, de::dint frame);
292 
293     /**
294      * Release all GL-textures in all schemes.
295      */
296     void releaseAllGLTextures();
297 
298     /**
299      * Release all GL-textures in schemes flagged 'runtime'.
300      */
301     void releaseAllRuntimeGLTextures();
302 
303     /**
304      * Release all GL-textures in schemes flagged 'system'.
305      */
306     void releaseAllSystemGLTextures();
307 
308     /**
309      * Release all GL-textures in the identified scheme.
310      *
311      * @param schemeName  Symbolic name of the texture scheme to process.
312      */
313     void releaseGLTexturesByScheme(de::String schemeName);
314 
315     /**
316      * Prepare a material variant specification in accordance to the specified
317      * usage context. If incomplete context information is supplied, suitable
318      * default values will be chosen in their place.
319      *
320      * @param contextId         Usage context identifier.
321      * @param flags             @ref textureVariantSpecificationFlags
322      * @param border            Border size in pixels (all edges).
323      * @param tClass            Color palette translation class.
324      * @param tMap              Color palette translation map.
325      * @param wrapS             GL texture wrap/clamp mode on the horizontal axis (texture-space).
326      * @param wrapT             GL texture wrap/clamp mode on the vertical axis (texture-space).
327      * @param minFilter         Logical DGL texture minification level.
328      * @param magFilter         Logical DGL texture magnification level.
329      * @param anisoFilter       @c -1= User preference else a logical DGL anisotropic filter level.
330      * @param mipmapped         @c true= use mipmapping.
331      * @param gammaCorrection   @c true= apply gamma correction to textures.
332      * @param noStretch         @c true= disallow stretching of textures.
333      * @param toAlpha           @c true= convert textures to alpha data.
334      *
335      * @return  The interned copy of the rationalized specification.
336      */
337     de::MaterialVariantSpec const &materialSpec(MaterialContextId contextId,
338         de::dint flags, byte border, de::dint tClass, de::dint tMap, de::dint wrapS, de::dint wrapT,
339         de::dint minFilter, de::dint magFilter, de::dint anisoFilter, bool mipmapped,
340         bool gammaCorrection, bool noStretch, bool toAlpha);
341 
342     /**
343      * Prepare a TextureVariantSpecification according to usage context. If the
344      * specification is incomplete suitable defaults are chosen automatically.
345      *
346      * @param tc      Usage context.
347      * @param flags   @ref textureVariantSpecificationFlags
348      * @param border  Border size in pixels (all edges).
349      * @param tClass  Color palette translation class.
350      * @param tMap    Color palette translation map.
351      *
352      * @return  The interned copy of the rationalized specification.
353      */
354     TextureVariantSpec const &textureSpec(texturevariantusagecontext_t tc,
355         de::dint flags, byte border, de::dint tClass, de::dint tMap, de::dint wrapS, de::dint wrapT,
356         de::dint minFilter, de::dint magFilter, de::dint anisoFilter,
357         dd_bool mipmapped, dd_bool gammaCorrection, dd_bool noStretch, dd_bool toAlpha);
358 
359     /**
360      * Prepare a TextureVariantSpecification according to usage context. If the
361      * specification is incomplete suitable defaults are chosen automatically.
362      *
363      * @return  A rationalized and valid TextureVariantSpecification.
364      */
365     TextureVariantSpec &detailTextureSpec(de::dfloat contrast);
366 
367     AbstractFont *newFontFromDef(ded_compositefont_t const &def);
368     AbstractFont *newFontFromFile(de::Uri const &uri, de::String filePath);
369 
370     /**
371      * Release all GL-textures for fonts in the identified scheme.
372      *
373      * @param schemeName  Symbolic name of the font scheme to process.
374      */
375     void releaseFontGLTexturesByScheme(de::String schemeName);
376 
377     /**
378      * Prepare resources for the current Map.
379      */
380     void cacheForCurrentMap();
381 
382     /**
383      * Add a variant of @a material to the cache queue for deferred preparation.
384      *
385      * @param material      Base material from which to derive a context variant.
386      * @param spec          Specification for the derivation of @a material.
387      * @param cacheGroups   @c true= variants for all materials in any applicable
388      *                      groups are desired; otherwise just specified material.
389      */
390     void cache(ClientMaterial &material, de::MaterialVariantSpec const &spec,
391                bool cacheGroups = true);
392 
393     /**
394      * Cache all resources needed to visualize models using the given @a modelDef.
395      */
396     void cache(FrameModelDef *modelDef);
397 
398     /**
399      * Precache resources from the set associated with the specified @a spriteId.
400      *
401      * @param spriteId      Unique identifier of the sprite set to cache.
402      * @param materialSpec  Specification to use when caching materials.
403      */
404     void cache(spritenum_t spriteId, de::MaterialVariantSpec const &materialSpec);
405 
406     /**
407      * Process all queued material cache tasks.
408      */
409     void processCacheQueue();
410 
411     /**
412      * Cancel all queued material cache tasks.
413      */
414     void purgeCacheQueue();
415 
416 public:  /// @todo Should be private:
417     void initModels();
418     void clearAllRawTextures();
419     void clearAllTextureSpecs();
420     void pruneUnusedTextureSpecs();
421 
422 public:
423     /**
424      * Register the console commands, variables, etc..., of this module.
425      */
426     static void consoleRegister();
427 
428 private:
429     DENG2_PRIVATE(d)
430 };
431 
432 DENG_EXTERN_C byte precacheMapMaterials, precacheSprites;
433 
434 #endif // DENG_CLIENT_RESOURCES_H
435