Oolite 1.91.0.7604-240417-a536cbe
Loading...
Searching...
No Matches
OOCombinedEmissionMapGenerator.m
Go to the documentation of this file.
1/*
2
3OOCombinedEmissionMapGenerator.m
4
5
6Copyright (C) 2010-2013 Jens Ayton
7
8Permission is hereby granted, free of charge, to any person obtaining a copy
9of this software and associated documentation files (the "Software"), to deal
10in the Software without restriction, including without limitation the rights
11to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12copies of the Software, and to permit persons to whom the Software is
13furnished to do so, subject to the following conditions:
14
15The above copyright notice and this permission notice shall be included in all
16copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24SOFTWARE.
25
26*/
27
29
30#import "OOColor.h"
32#import "OOTextureScaling.h"
33#import "OOTextureInternal.h"
36
37
38#define DUMP_COMBINER 0
39
40
41static OOColor *ModulateColor(OOColor *a, OOColor *b);
42static void ScaleToMatch(OOPixMap *pmA, OOPixMap *pmB);
43
44
45@interface OOCombinedEmissionMapGenerator (Private)
46
47- (id) initWithEmissionMapSpec:(NSDictionary *)emissionMapSpec
48 emissionColor:(OOColor *)emissionColor
49 diffuseMap:(OOTexture *)diffuseMap
50 diffuseColor:(OOColor *)diffuseColor
51 illuminationMapSpec:(NSDictionary *)illuminationMapSpec
52 illuminationColor:(OOColor *)illuminationColor
53 isCombinedMap:(BOOL)isCombinedMap
54 optionsSpecifier:(NSDictionary *)spec;
55
56- (NSString *)constructCacheKey;
57
58@end
59
60
62
63- (id) initWithEmissionMapSpec:(NSDictionary *)emissionMapSpec
64 emissionColor:(OOColor *)emissionColor
65 diffuseMap:(OOTexture *)diffuseMap
66 diffuseColor:(OOColor *)diffuseColor
67 illuminationMapSpec:(NSDictionary *)illuminationMapSpec
68 illuminationColor:(OOColor *)illuminationColor
69 optionsSpecifier:(NSDictionary *)spec
70{
71 return [self initWithEmissionMapSpec:emissionMapSpec
72 emissionColor:emissionColor
73 diffuseMap:diffuseMap
74 diffuseColor:diffuseColor
75 illuminationMapSpec:illuminationMapSpec
76 illuminationColor:illuminationColor
78 optionsSpecifier:spec];
79}
80
81
82- (id) initWithEmissionAndIlluminationMapSpec:(NSDictionary *)emissionAndIlluminationMapSpec
83 diffuseMap:(OOTexture *)diffuseMap
84 diffuseColor:(OOColor *)diffuseColor
85 emissionColor:(OOColor *)emissionColor
86 illuminationColor:(OOColor *)illuminationColor
87 optionsSpecifier:(NSDictionary *)spec
88{
89 return [self initWithEmissionMapSpec:emissionAndIlluminationMapSpec
90 emissionColor:emissionColor
91 diffuseMap:diffuseMap
92 diffuseColor:diffuseColor
93 illuminationMapSpec:nil
94 illuminationColor:illuminationColor
95 isCombinedMap:YES
96 optionsSpecifier:spec];
97}
98
99
100- (id) initWithEmissionMapSpec:(NSDictionary *)emissionMapSpec
101 emissionColor:(OOColor *)emissionColor
102 diffuseMap:(OOTexture *)diffuseMap
103 diffuseColor:(OOColor *)diffuseColor
104 illuminationMapSpec:(NSDictionary *)illuminationMapSpec
105 illuminationColor:(OOColor *)illuminationColor
106 isCombinedMap:(BOOL)isCombinedMap
107 optionsSpecifier:(NSDictionary *)spec
108{
109 if (emissionMapSpec == nil && illuminationMapSpec == nil)
110 {
111 [self release];
112 return nil;
113 }
114
115 NSParameterAssert(illuminationMapSpec == nil || !isCombinedMap);
116
117 uint32_t options;
118 GLfloat anisotropy;
119 GLfloat lodBias;
120 OOInterpretTextureSpecifier(spec, NULL, &options, &anisotropy, &lodBias, YES);
121 options = OOApplyTextureOptionDefaults(options);
122
123 if ((self = [super initWithPath:@"<generated emission map>" options:options]))
124 {
125 /* Illumination contribution is:
126 illuminationMap * illuminationColor * diffuseMap * diffuseColor
127 Since illuminationColor and diffuseColor aren't used otherwise,
128 we may as well combine them up front.
129 */
130 illuminationColor = ModulateColor(diffuseColor, illuminationColor);
131
132 if ([emissionColor isWhite]) emissionColor = nil;
133 if ([illuminationColor isWhite]) illuminationColor = nil;
134 if (!isCombinedMap && illuminationMapSpec == nil) diffuseMap = nil; // Diffuse map is only used with illumination
135
136 // Insert extraShrink flag here instead of using extraOptions later because we need it in cache key too.
137 NSMutableDictionary *emissionSpec = [emissionMapSpec mutableCopy];
138 [emissionSpec oo_setBool:YES forKey:kOOTextureSpecifierExtraShrinkKey];
139 _emissionSpec = emissionSpec;
140
141 NSMutableDictionary *illuminationSpec = [illuminationMapSpec mutableCopy];
142 [illuminationSpec oo_setBool:YES forKey:kOOTextureSpecifierExtraShrinkKey];
143 _illuminationSpec = illuminationSpec;
144
145 _diffuseMap = [diffuseMap retain];
146
147 _emissionColor = [emissionColor retain];
148 _illuminationColor = [illuminationColor retain];
149 _isCombinedMap = isCombinedMap;
150
151 _textureOptions = options;
152 _anisotropy = anisotropy;
153 _lodBias = lodBias;
154
155 _cacheKey = [self constructCacheKey];
156
157 if ([OOTexture existingTextureForKey:_cacheKey] == nil)
158 {
159 /* Extract pixmap from diffuse map. This must be done in the main
160 thread even if scheduling is fixed, because it might involve
161 reading back pixels from OpenGL.
162 */
163 if (diffuseMap != nil)
164 {
165 _diffusePx = [diffuseMap copyPixMapRepresentation];
166#ifndef NDEBUG
167 _diffuseDesc = [[diffuseMap shortDescription] copy];
168#endif
169 }
170
171 /* Extract emission and illumination pixmaps from loaders. Ideally,
172 this would be done asynchronously, but that requires dependency
173 management in OOAsyncWorkManager.
174 */
175 OOTextureDataFormat format;
176 if (_emissionSpec != nil)
177 {
178 OOTextureLoader *emissionMapLoader = [OOTextureLoader loaderWithTextureSpecifier:_emissionSpec
180 folder:@"Textures"];
181 [emissionMapLoader getResult:&_emissionPx format:&format originalWidth:NULL originalHeight:NULL];
182#ifndef NDEBUG
183 _emissionDesc = [[emissionMapLoader shortDescription] copy];
184#endif
185 }
186 if (_illuminationSpec != nil)
187 {
188 OOTextureLoader *illuminationMapLoader = [OOTextureLoader loaderWithTextureSpecifier:_illuminationSpec
190 folder:@"Textures"];
191 [illuminationMapLoader getResult:&_illuminationPx format:&format originalWidth:NULL originalHeight:NULL];
192#ifndef NDEBUG
193 _illuminationDesc = [[illuminationMapLoader shortDescription] copy];
194#endif
195 }
196 }
197 }
198
199 return self;
200}
201
202
203- (NSString *)constructCacheKey
204{
205 NSMutableString *cacheKey = [NSMutableString string];
206
207 if (_isCombinedMap) [cacheKey appendString:@"combined emission and illumination map;"];
208 else if (_emissionSpec == nil) [cacheKey appendString:@"illumination map;"];
209 else if (_illuminationSpec == nil) [cacheKey appendString:@"emission map;"];
210 else [cacheKey appendString:@"merged emission and illumination map;"];
211
212 NSString *emissionDesc = nil;
213 if (_emissionSpec != nil)
214 {
215 emissionDesc = OOTextureCacheKeyForSpecifier(_emissionSpec);
216 [cacheKey appendFormat:@"emission:{%@}", emissionDesc];
217 if (_emissionColor != nil) [cacheKey appendFormat:@"*%@", [_emissionColor rgbaDescription]];
218 [cacheKey appendString:@";"];
219 }
220
221 NSString *illuminationDesc = nil;
222 if (_isCombinedMap)
223 {
224 illuminationDesc = [NSString stringWithFormat:@"%@:a", emissionDesc];
225 }
226 else if (_illuminationSpec != nil)
227 {
228 illuminationDesc = OOTextureCacheKeyForSpecifier(_illuminationSpec);
229 }
230
231 if (illuminationDesc != nil)
232 {
233 [cacheKey appendFormat:@"illumination:{%@}*{%@}", illuminationDesc, [_diffuseMap cacheKey]];
234 if (_illuminationColor != nil) [cacheKey appendFormat:@"*%@", [_illuminationColor rgbaDescription]];
235 [cacheKey appendString:@";"];
236 }
237
238 return cacheKey;
239}
240
241
242- (void) dealloc
243{
244 DESTROY(_emissionSpec);
245 DESTROY(_illuminationSpec);
246 DESTROY(_diffuseMap);
247
248 OOFreePixMap(&_emissionPx);
249 OOFreePixMap(&_illuminationPx);
250 OOFreePixMap(&_diffusePx);
251 DESTROY(_emissionColor);
252 DESTROY(_illuminationColor);
253
254#ifndef NDEBUG
255 DESTROY(_diffuseDesc);
256 DESTROY(_emissionDesc);
257 DESTROY(_illuminationDesc);
258#endif
259
260 [super dealloc];
261}
262
263
264#ifndef NDEBUG
265- (NSString *) descriptionComponents
266{
267 NSMutableString *result = [NSMutableString string];
268 BOOL haveIllumination = NO;
269
270 if (_emissionDesc != nil)
271 {
272 [result appendFormat:@"emission map: %@", _emissionDesc];
273 if (_isCombinedMap)
274 {
275 [result appendString:@".rgb"];
276 }
277 if (_emissionColor != nil)
278 {
279 [result appendFormat:@" * %@", [_emissionColor rgbaDescription]];
280 }
281
282 if (_isCombinedMap)
283 {
284 [result appendFormat:@", illumination map: %@.a", _emissionDesc];
285 haveIllumination = YES;
286 }
287 }
288
289 if (_illuminationDesc != nil)
290 {
291 if (_emissionDesc != nil) [result appendString:@", "];
292 [result appendFormat:@"illumination map: %@", _illuminationDesc];
293 haveIllumination = YES;
294 }
295
296 if (haveIllumination)
297 {
298 if (_diffuseDesc != nil)
299 {
300 [result appendFormat:@" * %@", _diffuseDesc];
301 }
302 if (_illuminationColor != nil)
303 {
304 [result appendFormat:@" * %@", [_illuminationColor rgbaDescription]];
305 }
306 }
307
308 return result;
309}
310#endif
311
312
313- (uint32_t) textureOptions
314{
315 return _textureOptions;
316}
317
318
319- (GLfloat) anisotropy
320{
321 return _anisotropy;
322}
323
324
325- (GLfloat) lodBias
326{
327 return _lodBias;
328}
329
330
331- (NSString *) cacheKey
332{
333 return _cacheKey;
334}
335
336
337- (void) loadTexture
338{
339 OOPixMap illuminationPx = kOONullPixMap;
340 BOOL haveEmission = NO, haveIllumination = NO, haveDiffuse = NO;
341
342#if DUMP_COMBINER
343 static unsigned sTexID = 0;
344 unsigned texID = ++sTexID, dumpCount = 0;
345
346#define DUMP(pm, label) OODumpPixMap(pm, [NSString stringWithFormat:@"lightmap %u.%u - %@", texID, ++dumpCount, label]);
347#else
348#define DUMP(pm, label) do {} while (0)
349#endif
350
351 haveEmission = !OOIsNullPixMap(_emissionPx);
352 if (haveEmission) DUMP(_emissionPx, @"source emission map");
353
354 // Extract illumination component if emission_and_illumination_map.
355 if (haveEmission && _isCombinedMap && OOPixMapFormatHasAlpha(_emissionPx.format))
356 {
357 OOPixMapToRGBA(&_emissionPx);
358 illuminationPx = OODuplicatePixMap(_emissionPx, 0);
359 OOExtractPixMapChannel(&illuminationPx, 3, YES);
360 haveIllumination = YES;
361 DUMP(illuminationPx, @"extracted illumination map");
362 }
363
364 // Tint emission map if necessary.
365 if (haveEmission && _emissionColor != nil)
366 {
367 OOPixMapModulateUniform(&_emissionPx, [_emissionColor redComponent], [_emissionColor greenComponent], [_emissionColor blueComponent], 1.0);
368 DUMP(_emissionPx, @"modulated emission map");
369 }
370
371 if (!OOIsNullPixMap(_illuminationPx))
372 {
373 NSAssert(!_isCombinedMap, @"OOCombinedEmissionMapGenerator configured with both illumination map and combined emission/illumination map.");
374
375 illuminationPx = _illuminationPx;
376 _illuminationPx.pixels = NULL;
377 haveIllumination = YES;
378 DUMP(illuminationPx, @"source illumination map");
379 }
380
381 // Tint illumination map if necessary.
382 if (haveIllumination && _illuminationColor != nil)
383 {
384 OOPixMapModulateUniform(&illuminationPx, [_illuminationColor redComponent], [_illuminationColor greenComponent], [_illuminationColor blueComponent], 1.0);
385 DUMP(illuminationPx, @"modulated illumination map");
386 }
387
388 // Load diffuse map and combine with illumination map.
389 haveDiffuse = !OOIsNullPixMap(_diffusePx);
390 if (haveDiffuse) DUMP(_diffusePx, @"source diffuse map");
391
392 if (haveIllumination && haveDiffuse)
393 {
394 // Modulate illumination with diffuse map.
395 ScaleToMatch(&_diffusePx, &illuminationPx);
396 OOPixMapToRGBA(&_diffusePx);
397 OOPixMapModulatePixMap(&illuminationPx, _diffusePx);
398 DUMP(illuminationPx, @"combined diffuse and illumination map");
399 }
400 OOFreePixMap(&_diffusePx);
401
402 if (haveIllumination)
403 {
404 if (haveEmission)
405 {
406 OOPixMapToRGBA(&illuminationPx);
407 OOPixMapAddPixMap(&_emissionPx, illuminationPx);
408 OOFreePixMap(&illuminationPx);
409 DUMP(_emissionPx, @"combined emission and illumination map");
410 }
411 else if (haveIllumination)
412 {
413 // No explicit emission map -> modulated illumination map is our only emission map.
414 _emissionPx = illuminationPx;
415 haveEmission = YES;
416 illuminationPx.pixels = NULL;
417 }
418 haveIllumination = NO; // Either way, illumination is now baked into emission.
419 }
420
421 (void)haveEmission;
422 (void)haveIllumination;
423
424 // Done: emissionPx now contains combined emission map.
425 OOCompactPixMap(&_emissionPx);
426 if (OOIsValidPixMap(_emissionPx))
427 {
428 _data = _emissionPx.pixels;
429 _width = _emissionPx.width;
430 _height = _emissionPx.height;
431 _rowBytes = _emissionPx.rowBytes;
432 _format = _emissionPx.format;
433
434 _emissionPx.pixels = NULL; // So it won't be freed by -dealloc.
435 }
436 if (_data == NULL)
437 {
438 OOLogERR(@"texture.combinedEmissionMap.error", @"Unknown error loading %@", self);
439 }
440}
441
442@end
443
444
446{
447 if (a == nil) return b;
448 if (b == nil) return a;
449
450 OORGBAComponents ac, bc;
451 ac = [a rgbaComponents];
452 bc = [b rgbaComponents];
453
454 ac.r *= bc.r;
455 ac.g *= bc.g;
456 ac.b *= bc.b;
457 ac.a *= bc.a;
458
460}
461
462
463static void ScaleToMatch(OOPixMap *pmA, OOPixMap *pmB)
464{
465 NSCParameterAssert(pmA != NULL && pmB != NULL && OOIsValidPixMap(*pmA) && OOIsValidPixMap(*pmB));
466
467 OOPixMapDimension minWidth = MIN(pmA->width, pmB->width);
468 OOPixMapDimension minHeight = MIN(pmA->height, pmB->height);
469
470 if (pmA->width != minWidth || pmA->height != minHeight)
471 {
472 *pmA = OOScalePixMap(*pmA, minWidth, minHeight, NO);
473 }
474 if (pmB->width != minWidth || pmB->height != minHeight)
475 {
476 *pmB = OOScalePixMap(*pmB, minWidth, minHeight, NO);
477 }
478}
#define DESTROY(x)
Definition OOCocoa.h:77
#define DUMP(pm, label)
static OOColor * ModulateColor(OOColor *a, OOColor *b)
static void ScaleToMatch(OOPixMap *pmA, OOPixMap *pmB)
#define OOLogERR(class, format,...)
Definition OOLogging.h:112
#define MIN(A, B)
Definition OOMaths.h:111
BOOL OOPixMapModulateUniform(OOPixMap *ioPixMap, float f0, float f1, float f2, float f3)
BOOL OOExtractPixMapChannel(OOPixMap *ioPixMap, uint8_t channelIndex, BOOL compactWhenDone)
BOOL OOPixMapAddPixMap(OOPixMap *ioDstPixMap, OOPixMap otherPixMap)
BOOL OOPixMapModulatePixMap(OOPixMap *ioDstPixMap, OOPixMap otherPixMap)
BOOL OOPixMapToRGBA(OOPixMap *ioPixMap)
uint_fast32_t OOPixMapDimension
Definition OOPixMap.h:33
void OOFreePixMap(OOPixMap *ioPixMap)
Definition OOPixMap.m:86
OOPixMapFormat
Definition OOPixMap.h:39
const OOPixMap kOONullPixMap
Definition OOPixMap.m:31
OOINLINE BOOL OOIsNullPixMap(OOPixMap pixMap)
Definition OOPixMap.h:60
BOOL OOIsValidPixMap(OOPixMap pixMap)
Definition OOPixMap.m:42
BOOL OOPixMapFormatHasAlpha(OOPixMapFormat format) PURE_FUNC
Definition OOPixMap.m:232
OOPixMap OODuplicatePixMap(OOPixMap srcPixMap, size_t desiredSize)
Definition OOPixMap.m:95
OOINLINE void OOCompactPixMap(OOPixMap *ioPixMap)
Definition OOPixMap.h:103
return nil
OOPixMap OOScalePixMap(OOPixMap srcPixMap, OOPixMapDimension dstWidth, OOPixMapDimension dstHeight, BOOL leaveSpaceForMipMaps)
OOTextureFlags OOApplyTextureOptionDefaults(OOTextureFlags options)
Definition OOTexture.m:855
BOOL OOInterpretTextureSpecifier(id specifier, NSString **outName, OOTextureFlags *outOptions, float *outAnisotropy, float *outLODBias, BOOL ignoreExtract)
Definition OOTexture.m:694
NSString * OOTextureCacheKeyForSpecifier(id specifier)
Definition OOTexture.m:924
OOColor * colorWithRGBAComponents:(OORGBAComponents components)
Definition OOColor.m:109
OORGBAComponents rgbaComponents()
Definition OOColor.m:379
id initWithEmissionMapSpec:emissionColor:diffuseMap:diffuseColor:illuminationMapSpec:illuminationColor:isCombinedMap:optionsSpecifier:(NSDictionary *emissionMapSpec, [emissionColor] OOColor *emissionColor, [diffuseMap] OOTexture *diffuseMap, [diffuseColor] OOColor *diffuseColor, [illuminationMapSpec] NSDictionary *illuminationMapSpec, [illuminationColor] OOColor *illuminationColor, [isCombinedMap] BOOL isCombinedMap, [optionsSpecifier] NSDictionary *spec)
id loaderWithTextureSpecifier:extraOptions:folder:(id specifier,[extraOptions] uint32_t extraOptions,[folder] NSString *folder)
BOOL getResult:format:originalWidth:originalHeight:(OOPixMap *result,[format] OOTextureDataFormat *outFormat,[originalWidth] uint32_t *outWidth,[originalHeight] uint32_t *outHeight)
OOPixMap copyPixMapRepresentation()
Definition OOTexture.m:326
OOPixMapDimension height
Definition OOPixMap.h:50
void * pixels
Definition OOPixMap.h:49
OOPixMapDimension width
Definition OOPixMap.h:50