Download

Trying to gamma-correct images in GFx movie, but Scaleform BitmapData is bugged

My problem is that images I send to the GFxMoviePlayer using SetExternalTexture are too dark. I discovered the issue years ago, and I found out that to fix it, I have to open up the game editor, find the image I’m using, and uncheck SRGB. I was very careful for years to make sure that all textures meant for the game world were SRGB, and all textures meant for the UI were not SRGB (which causes UDK to lighten the textures). In some cases this meant duplicating textures.

Now I would like to send some arbitrary textures to a movie using GFxMoviePlayer.SetExternalTexture. The textures have already been set up as SRGB for use in the game world and I don’t want to duplicate every one of thousands of textures just so I can have a non-SRGB version. Of course, when I send the textures to the movie, they’re too dark. And now I’m looking for a way to fix that.

One thing I tried was writing some gamma-correction code in ActionScript. I could get that working, sort of, but I can’t use it in-game.

Here’s what I did: First I made a movie and used SetExternalTexture to display my character in the movie. The character showed up too dark and saturated. I took a screenshot of the too-dark character, and loaded that screenshot into Flash. I ran the following code on it, and I compared the result to the original file.

import flash.display.BitmapData;
import flash.geom.Rectangle;
import flash.geom.Point;

var bitmapData:BitmapData = new BeforeColorCorrection();

var rectangle:Rectangle = new Rectangle(0, 0, bitmapData.width, bitmapData.height);
var point:Point = new Point(0, 0);
var redGamma:Array = new Array(256);
var greenGamma:Array = new Array(256);
var blueGamma:Array = new Array(256);
var gamma:Number = 2.0;

var corrected:Number;
var i:int

for(i = 0; i <= 255; i++)
{
    corrected = 255 * Math.pow((i / 255.0), (1.0 / gamma));

    redGamma[i] = uint(corrected) << 16;
    greenGamma[i] = uint(corrected) << 8;
    blueGamma[i] = uint(corrected);
}

bitmapData.paletteMap(bitmapData, rectangle, point, redGamma, greenGamma, blueGamma);

var bitmap:Bitmap = new Bitmap(bitmapData);

addChild(bitmap);

The manual gamma correction isn’t too bad. I can work with that. I could load any texture from my game, run some gamma correction, and have it show up more or less the right color in the UI. But here’s the problem: The most important function in that code, BitmapData::paletteMap, doesn’t exist in Scaleform. I was only able to run the gamma correction in the default Flash player (from inside Flash Pro, click Control > Test). If I try running this code from the Scaleform Launcher, I get the warning

Warning: The method BitmapData::paletteMap() is not implemented

So now I’m getting to my questions:
Are any of you able to run BitmapData::paletteMap using the Scaleform Launcher? You can just copy/paste the test code from here. There’s no setup. Just copy the code from the Example section and paste it onto the timeline of a fresh document. See if you can run it with Control > Test. Then see if you can run it with the Scaleform Launcher. If you can run it, then it’s just my own Scaleform installation that’s messed up somehow.

But if you can’t run it, then Scaleform is bugged, and we’re never going to get a patch for it, so I’ll need to consider something else. Do any of you know how I might go about using UnrealScript to copy a reference to a texture, then lighten it? Or at least make a runtime copy of a texture and make it not-SRGB?

There are a bunch of unsupported AS3 functions in Scaleform. One I can think of is CacheAsBitmap(), which allows you to convert display objects (such as TextFields) to bitmaps, so you can apply image masks to them, etc.

I don’t believe there is anything we can do, other then work around it or implement our own solutions using other supported features.

Certain regex functions also don’t work in scaleform.