ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

text.cpp

Go to the documentation of this file.
00001 /* ResidualVM - A 3D game interpreter
00002  *
00003  * ResidualVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the AUTHORS
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "engines/stark/visual/text.h"
00024 
00025 #include "graphics/font.h"
00026 #include "graphics/pixelformat.h"
00027 #include "graphics/surface.h"
00028 
00029 #include "engines/stark/debug.h"
00030 #include "engines/stark/gfx/driver.h"
00031 #include "engines/stark/gfx/surfacerenderer.h"
00032 #include "engines/stark/gfx/texture.h"
00033 #include "engines/stark/scene.h"
00034 #include "engines/stark/services/services.h"
00035 #include "engines/stark/services/settings.h"
00036 
00037 #include "common/util.h"
00038 
00039 namespace Stark {
00040 
00041 VisualText::VisualText(Gfx::Driver *gfx) :
00042         Visual(TYPE),
00043         _gfx(gfx),
00044         _texture(nullptr),
00045         _bgTexture(nullptr),
00046         _color(Color(0, 0, 0)),
00047         _backgroundColor(Color(0, 0, 0, 0)),
00048         _align(Graphics::kTextAlignLeft),
00049         _targetWidth(600),
00050         _targetHeight(600),
00051         _fontType(FontProvider::kBigFont),
00052         _fontCustomIndex(-1) {
00053     _surfaceRenderer = _gfx->createSurfaceRenderer();
00054     _surfaceRenderer->setNoScalingOverride(true);
00055     _surfaceRenderer->setSnapToGrid(true);
00056 }
00057 
00058 VisualText::~VisualText() {
00059     freeTexture();
00060     delete _surfaceRenderer;
00061 }
00062 
00063 Common::Rect VisualText::getRect() {
00064     if (!_texture) {
00065         createTexture();
00066     }
00067     return _originalRect;
00068 }
00069 
00070 void VisualText::setText(const Common::String &text) {
00071     if (_text != text) {
00072         freeTexture();
00073         _text = text;
00074     }
00075 }
00076 
00077 void VisualText::setColor(const Color &color) {
00078     if (_color == color) {
00079         return;
00080     }
00081 
00082     freeTexture();
00083     _color = color;
00084 }
00085 
00086 void VisualText::setBackgroundColor(const Color &color) {
00087     if (color == _backgroundColor) {
00088         return;
00089     }
00090 
00091     freeTexture();
00092     _backgroundColor = color;
00093 }
00094 
00095 void VisualText::setAlign(Graphics::TextAlign align) {
00096     if (align != _align) {
00097         freeTexture();
00098         _align = align;
00099     }
00100 }
00101 
00102 void VisualText::setTargetWidth(uint32 width) {
00103     if (width != _targetWidth) {
00104         freeTexture();
00105         _targetWidth = width;
00106     }
00107 }
00108 
00109 void VisualText::setTargetHeight(uint32 height) {
00110     if (height != _targetHeight) {
00111         freeTexture();
00112         _targetHeight = height;
00113     }
00114 }
00115 
00116 void VisualText::setFont(FontProvider::FontType type, int32 customFontIndex) {
00117     if (type != _fontType || customFontIndex != _fontCustomIndex) {
00118         freeTexture();
00119         _fontType = type;
00120         _fontCustomIndex = customFontIndex;
00121     }
00122 }
00123 
00129 static float srgbToLinear(float x) {
00130     if (x <= 0.0f)
00131         return 0.0f;
00132     else if (x >= 1.0f)
00133         return 1.0f;
00134     else
00135         return powf(x, 1.8f);
00136 }
00137 
00139 static float linearToSrgb(float x) {
00140     if (x <= 0.0f)
00141         return 0.0f;
00142     else if (x >= 1.0f)
00143         return 1.0f;
00144     else
00145         return powf(x, 1.0f / 1.8f);
00146 }
00147 
00155 static void multiplyColorWithAlpha(Graphics::Surface *source) {
00156     assert(source->format == Gfx::Driver::getRGBAPixelFormat());
00157 
00158     for (uint y = 0; y < source->h; y++) {
00159         const uint8 *src = (const uint8 *) source->getBasePtr(0, y);
00160         uint8 *dst = (uint8 *) source->getBasePtr(0, y);
00161 
00162         for (uint x = 0; x < source->w; x++) {
00163             uint8 a, r, g, b;
00164             r = *src++;
00165             g = *src++;
00166             b = *src++;
00167             a = *src++;
00168 
00169             if (a == 0) {
00170                 r = 0;
00171                 g = 0;
00172                 b = 0;
00173 
00174             } else if (a != 0xFF) {
00175                 float aFloat = a / 255.f;
00176                 float linearR = srgbToLinear(r / 255.f);
00177                 float linearG = srgbToLinear(g / 255.f);
00178                 float linearB = srgbToLinear(b / 255.f);
00179 
00180                 linearR *= aFloat;
00181                 linearG *= aFloat;
00182                 linearB *= aFloat;
00183 
00184                 r = linearToSrgb(linearR) * 255.f;
00185                 g = linearToSrgb(linearG) * 255.f;
00186                 b = linearToSrgb(linearB) * 255.f;
00187             }
00188 
00189             *dst++ = r;
00190             *dst++ = g;
00191             *dst++ = b;
00192             *dst++ = a;
00193         }
00194     }
00195 }
00196 
00202 static void blendWithColor(Graphics::Surface *source, const Color &color) {
00203     assert(source->format == Gfx::Driver::getRGBAPixelFormat());
00204 
00205     float sRL = srgbToLinear(color.r / 255.f);
00206     float sGL = srgbToLinear(color.g / 255.f);
00207     float sBL = srgbToLinear(color.b / 255.f);
00208 
00209     for (uint y = 0; y < source->h; y++) {
00210         const uint8 *src = (const uint8 *) source->getBasePtr(0, y);
00211         uint8 *dst = (uint8 *) source->getBasePtr(0, y);
00212 
00213         for (uint x = 0; x < source->w; x++) {
00214             uint8 a, r, g, b;
00215             r = *src++;
00216             g = *src++;
00217             b = *src++;
00218             src++;
00219 
00220             a = r;
00221             if (a != 255) {
00222                 float aFloat = a / 255.f;
00223                 r = linearToSrgb(sRL * aFloat) * 255.f;
00224                 g = linearToSrgb(sGL * aFloat) * 255.f;
00225                 b = linearToSrgb(sBL * aFloat) * 255.f;
00226 
00227             } else {
00228                 r = color.r;
00229                 g = color.g;
00230                 b = color.b;
00231             }
00232 
00233             *dst++ = r;
00234             *dst++ = g;
00235             *dst++ = b;
00236             *dst++ = a;
00237         }
00238     }
00239 }
00240 
00241 void VisualText::createTexture() {
00242     Common::CodePage codePage = StarkSettings->getTextCodePage();
00243     Common::U32String unicodeText = Common::convertToU32String(_text.c_str(), codePage);
00244 
00245     // Get the font and required metrics
00246     const Graphics::Font *font = StarkFontProvider->getScaledFont(_fontType, _fontCustomIndex);
00247     uint scaledLineHeight = StarkFontProvider->getScaledFontHeight(_fontType, _fontCustomIndex);
00248     uint originalLineHeight = StarkFontProvider->getOriginalFontHeight(_fontType, _fontCustomIndex);
00249     uint maxScaledLineWidth = StarkGfx->scaleWidthOriginalToCurrent(_targetWidth);
00250 
00251     // Word wrap the text
00252     Common::Array<Common::U32String> lines;
00253     font->wordWrapText(unicodeText, maxScaledLineWidth, lines);
00254 
00255     // Use the actual font bounding box to prevent text from being cut off
00256     Common::Rect scaledRect;
00257     if (!lines.empty()) {
00258         scaledRect = font->getBoundingBox(lines[0]);
00259         for (uint i = 1; i < lines.size(); i++) {
00260             scaledRect.extend(font->getBoundingBox(lines[i], 0, scaledLineHeight * i));
00261         }
00262     }
00263 
00264     // Make sure lines have approximately consistent height regardless of the characters they use
00265     scaledRect.bottom = MAX<int16>(scaledRect.bottom, scaledLineHeight * lines.size());
00266 
00267     if (!isBlank()) {
00268         _originalRect.right = StarkGfx->scaleWidthCurrentToOriginal(scaledRect.right);
00269         _originalRect.bottom = originalLineHeight * lines.size();
00270     } else {
00271         // For Empty text, preserve the original width and height for being used as clicking area
00272         _originalRect.right = _targetWidth;
00273         _originalRect.bottom = _targetHeight;
00274     }
00275 
00276     // Create a surface to render to
00277     Graphics::Surface surface;
00278     surface.create(scaledRect.right, scaledRect.bottom, Gfx::Driver::getRGBAPixelFormat());
00279 
00280     // First render the text as white on a black background to produce an alpha mask
00281     uint32 black = surface.format.ARGBToColor(0xFF, 0, 0, 0);
00282     uint32 white = surface.format.ARGBToColor(0xFF, 0xFF, 0xFF, 0xFF);
00283 
00284     surface.fillRect(Common::Rect(surface.w, surface.h), black);
00285 
00286     // Render the lines to the surface
00287     for (uint i = 0; i < lines.size(); i++) {
00288         font->drawString(&surface, lines[i], 0, scaledLineHeight * i, surface.w, white, _align);
00289     }
00290 
00291     // Blend the text color with the alpha mask to produce an image of the text
00292     // of the correct color. Anti-aliased pixels use the full alpha range.
00293     blendWithColor(&surface, _color);
00294     multiplyColorWithAlpha(&surface);
00295 
00296     // Create a texture from the surface
00297     _texture = _gfx->createTexture(&surface);
00298     _texture->setSamplingFilter(Gfx::Texture::kNearest);
00299 
00300     surface.free();
00301 
00302     // If we have a background color, generate a 1x1px texture of that color
00303     if (_backgroundColor.a != 0) {
00304         surface.create(1, 1, Gfx::Driver::getRGBAPixelFormat());
00305 
00306         uint32 bgColor = surface.format.ARGBToColor(
00307                     _backgroundColor.a, _backgroundColor.r, _backgroundColor.g, _backgroundColor.b
00308                     );
00309 
00310         surface.fillRect(Common::Rect(surface.w, surface.h), bgColor);
00311         multiplyColorWithAlpha(&surface);
00312 
00313         _bgTexture = _gfx->createTexture(&surface);
00314 
00315         surface.free();
00316     }
00317 }
00318 
00319 void VisualText::freeTexture() {
00320     delete _texture;
00321     _texture = nullptr;
00322     delete _bgTexture;
00323     _bgTexture = nullptr;
00324 }
00325 
00326 void VisualText::render(const Common::Point &position) {
00327     if (!_texture) {
00328         createTexture();
00329     }
00330 
00331     if (_bgTexture) {
00332         _surfaceRenderer->render(_bgTexture, position, _texture->width(), _texture->height());
00333     }
00334 
00335     _surfaceRenderer->render(_texture, position);
00336 }
00337 
00338 void VisualText::resetTexture() {
00339     freeTexture();
00340 }
00341 
00342 bool VisualText::isBlank() {
00343     for (uint i = 0; i < _text.size(); ++i) {
00344         if (!Common::isSpace(_text[i])) {
00345             return false;
00346         }
00347     }
00348     return true;
00349 }
00350 
00351 } // End of namespace Stark


Generated on Sat Oct 19 2019 05:01:16 for ResidualVM by doxygen 1.7.1
curved edge   curved edge