diff --git a/Engine/source/T3D/fps/guiClockHud.cpp b/Engine/source/T3D/fps/guiClockHud.cpp index 5a98444a88..cf3635dc40 100644 --- a/Engine/source/T3D/fps/guiClockHud.cpp +++ b/Engine/source/T3D/fps/guiClockHud.cpp @@ -130,10 +130,10 @@ void GuiClockHud::onRender(Point2I offset, const RectI &updateRect) dSprintf(buf,sizeof(buf), "%02d:%02d",mins,secs); // Center the text - offset.x += (getWidth() - mProfile->mFont->getStrWidth((const UTF8 *)buf)) / 2; - offset.y += (getHeight() - mProfile->mFont->getHeight()) / 2; + offset.x += (getWidth() - mProfile->mFont->getStringWidthScaled(String::ToString(buf), mProfile->mFontSize)) / 2; + offset.y += (getHeight() - mProfile->mFont->getScaledHeight(mProfile->mFontSize)) / 2; drawUtil->setBitmapModulation(mTextColor.toColorI()); - drawUtil->drawText(mProfile->mFont, offset, buf); + drawUtil->drawText(mProfile->mFont, offset, buf, mProfile->mFontSize); drawUtil->clearBitmapModulation(); // Border last diff --git a/Engine/source/T3D/fps/guiHealthTextHud.cpp b/Engine/source/T3D/fps/guiHealthTextHud.cpp index 9bde220de0..da503cc997 100644 --- a/Engine/source/T3D/fps/guiHealthTextHud.cpp +++ b/Engine/source/T3D/fps/guiHealthTextHud.cpp @@ -174,8 +174,8 @@ void GuiHealthTextHud::onRender(Point2I offset, const RectI &updateRect) S32 val = (S32)mValue; char buf[256]; dSprintf(buf, sizeof(buf), "%d", val); - offset.x += (getBounds().extent.x - mProfile->mFont->getStrWidth((const UTF8 *)buf)) / 2; - offset.y += (getBounds().extent.y - mProfile->mFont->getHeight()) / 2; + offset.x += (getBounds().extent.x - mProfile->mFont->getStringWidthScaled(String::ToString(buf), mProfile->mFontSize)) / 2; + offset.y += (getBounds().extent.y - mProfile->mFont->getScaledHeight(mProfile->mFontSize)) / 2; LinearColorF tColor = mTextColor; @@ -194,7 +194,7 @@ void GuiHealthTextHud::onRender(Point2I offset, const RectI &updateRect) } drawUtil->setBitmapModulation(tColor.toColorI()); - drawUtil->drawText(mProfile->mFont, offset, buf); + drawUtil->drawText(mProfile->mFont, offset, buf, mProfile->mFontSize); drawUtil->clearBitmapModulation(); // If enabled draw the border last diff --git a/Engine/source/T3D/fps/guiShapeNameHud.cpp b/Engine/source/T3D/fps/guiShapeNameHud.cpp index 377b05d92c..42eb6f302a 100644 --- a/Engine/source/T3D/fps/guiShapeNameHud.cpp +++ b/Engine/source/T3D/fps/guiShapeNameHud.cpp @@ -291,8 +291,8 @@ void GuiShapeNameHud::onRender( Point2I, const RectI &updateRect) /// @param opacity Opacity of name (a fraction). void GuiShapeNameHud::drawName(Point2I offset, const char *name, F32 opacity) { - F32 width = mProfile->mFont->getStrWidth((const UTF8 *)name) + mLabelPadding.x * 2; - F32 height = mProfile->mFont->getHeight() + mLabelPadding.y * 2; + F32 width = mProfile->mFont->getStringWidthScaled(String::ToString(name), mProfile->mFontSize) + mLabelPadding.x * 2; + F32 height = mProfile->mFont->getScaledHeight(mProfile->mFontSize) + mLabelPadding.y * 2; Point2I extent = Point2I(width, height); // Center the name @@ -308,7 +308,7 @@ void GuiShapeNameHud::drawName(Point2I offset, const char *name, F32 opacity) // Deal with opacity and draw. mTextColor.alpha = opacity; drawUtil->setBitmapModulation(mTextColor.toColorI()); - drawUtil->drawText(mProfile->mFont, offset + mLabelPadding, name); + drawUtil->drawText(mProfile->mFont, offset + mLabelPadding, name, mProfile->mFontSize); drawUtil->clearBitmapModulation(); // Border last diff --git a/Engine/source/afx/ui/afxGuiTextHud.cpp b/Engine/source/afx/ui/afxGuiTextHud.cpp index 46cbfc1a2e..b0bee7d2e7 100644 --- a/Engine/source/afx/ui/afxGuiTextHud.cpp +++ b/Engine/source/afx/ui/afxGuiTextHud.cpp @@ -295,8 +295,8 @@ void afxGuiTextHud::onRender( Point2I, const RectI &updateRect) void afxGuiTextHud::drawName(Point2I offset, const char *name, F32 opacity, LinearColorF* color) { // Center the name - offset.x -= mProfile->mFont->getStrWidth((const UTF8 *)name) / 2; - offset.y -= mProfile->mFont->getHeight(); + offset.x -= mProfile->mFont->getStringWidthScaled(String::ToString(name), mProfile->mFontSize) / 2; + offset.y -= mProfile->mFont->getScaledHeight(mProfile->mFontSize); // Deal with opacity and draw. LinearColorF draw_color = (color) ? *color : mTextColor; diff --git a/Engine/source/environment/editors/guiMeshRoadEditorCtrl.cpp b/Engine/source/environment/editors/guiMeshRoadEditorCtrl.cpp index 16e6bcd8cd..044698ad3c 100644 --- a/Engine/source/environment/editors/guiMeshRoadEditorCtrl.cpp +++ b/Engine/source/environment/editors/guiMeshRoadEditorCtrl.cpp @@ -1111,22 +1111,22 @@ void GuiMeshRoadEditorCtrl::renderScene(const RectI & updateRect) GFX->getDrawUtil()->setBitmapModulation(ColorI(128, 128, 128)); dStrcpy(buf, "Reset Profile: Double-click Start Node", 64); GFX->getDrawUtil()->drawTextN(mProfile->mFont, posi, buf, dStrlen(buf)); - posi.y -= mProfile->mFont->getCharHeight((U8)buf[0]) + 4; + posi.y -= mProfile->mFont->getCharHeightScaled((U8)buf[0], mProfile->mFontSize) + 4; dStrcpy(buf, "Move Node: Click and Drag Node", 64); GFX->getDrawUtil()->drawTextN(mProfile->mFont, posi, buf, dStrlen(buf)); - posi.y -= mProfile->mFont->getCharHeight((U8)buf[0]) + 4; + posi.y -= mProfile->mFont->getCharHeightScaled((U8)buf[0], mProfile->mFontSize) + 4; dStrcpy(buf, "Select Multiple Nodes: Ctrl-click Nodes", 64); GFX->getDrawUtil()->drawTextN(mProfile->mFont, posi, buf, dStrlen(buf)); - posi.y -= mProfile->mFont->getCharHeight((U8)buf[0]) + 4; + posi.y -= mProfile->mFont->getCharHeightScaled((U8)buf[0], mProfile->mFontSize) + 4; dStrcpy(buf, "Toggle Material: Shift-click Spline Segment", 64); GFX->getDrawUtil()->drawTextN(mProfile->mFont, posi, buf, dStrlen(buf)); - posi.y -= mProfile->mFont->getCharHeight((U8)buf[0]) + 4; + posi.y -= mProfile->mFont->getCharHeightScaled((U8)buf[0], mProfile->mFontSize) + 4; dStrcpy(buf, "Toggle Smoothing: Shift-click Node", 64); GFX->getDrawUtil()->drawTextN(mProfile->mFont, posi, buf, dStrlen(buf)); - posi.y -= mProfile->mFont->getCharHeight((U8)buf[0]) + 4; + posi.y -= mProfile->mFont->getCharHeightScaled((U8)buf[0], mProfile->mFontSize) + 4; dStrcpy(buf, "Delete Node: Alt-click Node", 64); GFX->getDrawUtil()->drawTextN(mProfile->mFont, posi, buf, dStrlen(buf)); - posi.y -= mProfile->mFont->getCharHeight((U8)buf[0]) + 4; + posi.y -= mProfile->mFont->getCharHeightScaled((U8)buf[0], mProfile->mFontSize) + 4; dStrcpy(buf, "Add Node: Ctrl-click Spline", 64); GFX->getDrawUtil()->drawTextN(mProfile->mFont, posi, buf, dStrlen(buf)); } diff --git a/Engine/source/gfx/gFont.cpp b/Engine/source/gfx/gFont.cpp index 05a3f55ac9..b108a76ca5 100644 --- a/Engine/source/gfx/gFont.cpp +++ b/Engine/source/gfx/gFont.cpp @@ -74,17 +74,18 @@ static S32 QSORT_CALLBACK GlyphMapCompare(const void *a, const void *b) } -const U32 GFont::csm_fileVersion = 3; +const U32 GFont::csm_fileVersion = 4; -String GFont::getFontCacheFilename(const String &faceName, U32 size) +String GFont::getFontCacheFilename(const String &faceName) { - return String::ToString("%s/%s %d (%s).uft", - Con::getVariable("$GUI::fontCacheDirectory"), faceName.c_str(), size, getCharSetName(0)); + return String::ToString("%s/%s (%s).uft", + Con::getVariable("$GUI::fontCacheDirectory"), faceName.c_str(), getCharSetName(0)); } GFont* GFont::load( const Torque::Path& path ) { FileStream stream; + U32 sdfSize = Con::getIntVariable("$GUI::Font::SDFSize", 64); stream.open( path.getFullPath(), Torque::FS::File::Read ); if ( stream.getStatus() != Stream::Ok ) @@ -100,7 +101,7 @@ GFont* GFont::load( const Torque::Path& path ) } else { - PlatformFont *platFont = createPlatformFont(ret->getFontFaceName(), ret->getFontSize(), ret->getFontCharSet()); + PlatformFont *platFont = createPlatformFont(ret->getFontFaceName(), sdfSize, ret->getFontCharSet()); if ( platFont == NULL ) { @@ -114,13 +115,15 @@ GFont* GFont::load( const Torque::Path& path ) return ret; } -Resource GFont::create(const String &faceName, U32 size, const char *cacheDirectory, U32 charset /* = TGE_ANSI_CHARSET */) +Resource GFont::create(const String &faceName, const char *cacheDirectory, U32 charset /* = TGE_ANSI_CHARSET */) { if( !cacheDirectory ) cacheDirectory = Con::getVariable( "$GUI::fontCacheDirectory" ); - - const Torque::Path path( String::ToString("%s/%s %d (%s).uft", - cacheDirectory, faceName.c_str(), size, getCharSetName(charset)) ); + + U32 sdfSize = Con::getIntVariable("$GUI::Font::SDFSize", 64); + + const Torque::Path path( String::ToString("%s/%s (%s).uft", + cacheDirectory, faceName.c_str(), getCharSetName(charset)) ); Resource ret; @@ -137,7 +140,7 @@ Resource GFont::create(const String &faceName, U32 size, const char *cach } // Otherwise attempt to have the platform generate a new font - PlatformFont *platFont = createPlatformFont(faceName, size, charset); + PlatformFont *platFont = createPlatformFont(faceName, sdfSize, charset); if (platFont == NULL) { @@ -166,7 +169,7 @@ Resource GFont::create(const String &faceName, U32 size, const char *cach else return ret; - return create(fontName, size, cacheDirectory, charset); + return create(fontName, cacheDirectory, charset); } // Create the actual GFont and set some initial properties @@ -174,13 +177,12 @@ Resource GFont::create(const String &faceName, U32 size, const char *cach font->mPlatformFont = platFont; font->mGFTFile = path; font->mFaceName = faceName; - font->mSize = size; + font->mSize = sdfSize; font->mCharSet = charset; - font->mHeight = platFont->getFontHeight(); - font->mBaseline = platFont->getFontBaseLine(); font->mAscent = platFont->getFontBaseLine(); - font->mDescent = platFont->getFontHeight() - platFont->getFontBaseLine(); + font->mBaseline = platFont->getFontBaseLine(); + font->mDescent = (font->mHeight - font->mBaseline); // Flag it to save when we exit font->mNeedSave = true; @@ -195,13 +197,11 @@ Resource GFont::create(const String &faceName, U32 size, const char *cach GFont::GFont() { - VECTOR_SET_ASSOCIATION(mCharInfoList); VECTOR_SET_ASSOCIATION(mTextureSheets); - std::fill_n(mRemapTable, Font_Table_MAX,-1); - - mCurX = mCurY = mCurSheet = -1; - + mCurX = mCurY = 0; + mCurSheet = -1; + mMaxRowHeight = 0; mPlatformFont = NULL; mSize = 0; mCharSet = 0; @@ -212,6 +212,7 @@ GFont::GFont() mNeedSave = false; mMutex = Mutex::createMutex(); + mCharMap.clear(); } GFont::~GFont() @@ -229,14 +230,10 @@ GFont::~GFont() stream.close(); } - S32 i; + mCharMap.clear(); - for(i = 0;i < mCharInfoList.size();i++) - { - SAFE_DELETE_ARRAY(mCharInfoList[i].bitmapData); - } - - for(i=0; imapEnd) mapEnd = i; - } + U32 charCode = entry.key; // The key (character code) + + mapCount++; // Count this character + + // Update the minimum and maximum character codes + if (charCode < mapBegin) mapBegin = charCode; + if (charCode > mapEnd) mapEnd = charCode; } + // Let's write out all the info we can on this font. Con::printf(" '%s' %dpt", mFaceName.c_str(), mSize); Con::printf(" - %d texture sheets, %d mapped characters.", mTextureSheets.size(), mapCount); @@ -276,18 +275,18 @@ bool GFont::loadCharInfo(const UTF16 ch) { PROFILE_SCOPE(GFont_loadCharInfo); - if(mRemapTable[ch] != -1) - return true; // Not really an error + auto it = mCharMap.find(ch); + if (it != mCharMap.end()) + return true; - if(mPlatformFont && mPlatformFont->isValidChar(ch)) + if (mPlatformFont && mPlatformFont->isValidChar(ch)) { - Mutex::lockMutex(mMutex); // the CharInfo returned by mPlatformFont is static data, must protect from changes. - PlatformFont::CharInfo &ci = mPlatformFont->getCharInfo(ch); + Mutex::lockMutex(mMutex); // the CharInfo returned by mPlatformFont is static data, must protect from changes. + PlatformFont::CharInfo& ci = mPlatformFont->getCharInfo(ch); if(ci.bitmapData) addBitmap(ci); - mCharInfoList.push_back(ci); - mRemapTable[ch] = mCharInfoList.size() - 1; + mCharMap[ch] = ci; mNeedSave = true; @@ -298,62 +297,199 @@ bool GFont::loadCharInfo(const UTF16 ch) return false; } -void GFont::addBitmap(PlatformFont::CharInfo &charInfo) +void GFont::generateSDF(const U8* bitmap, S32 width, S32 height, U8* sdfBitmap, S32 sdfWidth, S32 sdfHeight, const F32 spreadFactor) { - U32 nextCurX = U32(mCurX + charInfo.width ); /*7) & ~0x3;*/ - U32 nextCurY = U32(mCurY + mPlatformFont->getFontHeight()); // + 7) & ~0x3; + for (S32 y = 0; y < sdfHeight; ++y) + { + for (S32 x = 0; x < sdfWidth; ++x) + { + // Map SDF coordinates to original bitmap space + F32 scaledX = x * (F32)width / sdfWidth; + F32 scaledY = y * (F32)height / sdfHeight; + + F32 minDistInside = F32_MAX; + F32 minDistOutside = F32_MAX; + + // Define the region to sample + S32 regionSize = mCeil(spreadFactor); + S32 minX = mClamp((S32)scaledX - regionSize, 0, width - 1); + S32 maxX = mClamp((S32)scaledX + regionSize, 0, width - 1); + S32 minY = mClamp((S32)scaledY - regionSize, 0, height - 1); + S32 maxY = mClamp((S32)scaledY + regionSize, 0, height - 1); + + // Calculate distances to the closest "inside" and "outside" pixels + for (S32 by = minY; by <= maxY; ++by) + { + for (S32 bx = minX; bx <= maxX; ++bx) + { + bool isInside = bitmap[by * width + bx] > 128; + F32 dx = scaledX - bx; + F32 dy = scaledY - by; + F32 distSquared = dx * dx + dy * dy; + F32 dist = mSqrt(distSquared); + + if (isInside) + minDistInside = mMin(minDistInside, dist); + else + minDistOutside = mMin(minDistOutside, dist); + } + } + + // Compute the signed distance + F32 signedDist = minDistOutside - minDistInside; + + // Combine distances: inside values go from 0.5 to 1.0, outside values go from 0.5 to 0.0 + F32 normalizedDist; + if (signedDist > 0.0f) + { + // Inside the glyph + normalizedDist = 0.5f + mClampF(signedDist / spreadFactor, 0.0f, 0.5f); + } + else + { + // Outside the glyph + normalizedDist = 0.5f + mClampF(signedDist / spreadFactor, -0.5f, 0.0f); + } + // Scale to [0, 255] and write to the output bitmap + sdfBitmap[y * sdfWidth + x] = (U8)(255 * normalizedDist); + } + } +} - // These are here for postmortem debugging. - bool routeA = false, routeB = false; +void GFont::applyGaussianBlur(U8* sdfBitmap, S32 width, S32 height, F32 sigma) +{ + S32 kernelSize = 2 * (S32)(3 * sigma) + 1; + Vector kernel; - if(mCurSheet == -1 || nextCurY >= TextureSheetSize) + // Generate the Gaussian kernel + F32 sum = 0.0f; + for (S32 i = 0; i < kernelSize; ++i) { - routeA = true; - addSheet(); + F32 x = (F32)(i - kernelSize / 2); + kernel.push_back(mExp(-x * x / (2 * sigma * sigma))); + sum += kernel[i]; + } + for (S32 i = 0; i < kernelSize; ++i) + { + kernel[i] /= sum; // Normalize the kernel + } - // Recalc our nexts. - nextCurX = U32(mCurX + charInfo.width); // + 7) & ~0x3; - nextCurY = U32(mCurY + mPlatformFont->getFontHeight()); // + 7) & ~0x3; + // Apply the Gaussian blur to each pixel + FrameTemp blurredBitmap((width * height)); + for (S32 y = 0; y < height; ++y) + { + for (S32 x = 0; x < width; ++x) + { + F32 newValue = 0.0f; + for (S32 ky = -kernelSize / 2; ky <= kernelSize / 2; ++ky) + { + for (S32 kx = -kernelSize / 2; kx <= kernelSize / 2; ++kx) + { + S32 nx = mClamp(x + kx, 0, width - 1); + S32 ny = mClamp(y + ky, 0, height - 1); + F32 weight = kernel[(ky + kernelSize / 2)] * kernel[(kx + kernelSize / 2)]; + newValue += weight * sdfBitmap[ny * width + nx]; + } + } + blurredBitmap[y * width + x] = (U8)mClampF(newValue, 0.0f, 255.0f); + } } - if( nextCurX >= TextureSheetSize) + dMemcpy(sdfBitmap, blurredBitmap.address(), width * height); +} + +void GFont::padGlyphBitmap(const U8* original, S32 origWidth, S32 origHeight, U8* padded, S32 padWidth, S32 padHeight, S32 padding) +{ + // Initialize padded bitmap with zeros + dMemset(padded, 0, padWidth * padHeight); + + // Copy the original bitmap into the center of the padded bitmap + for (S32 y = 0; y < origHeight; ++y) { - routeB = true; - mCurX = 0; - mCurY = nextCurY; + for (S32 x = 0; x < origWidth; ++x) + { + S32 srcIndex = y * origWidth + x; + S32 dstIndex = (y + padding) * padWidth + (x + padding); + padded[dstIndex] = original[srcIndex]; + } + } +} - // Recalc our nexts. - nextCurX = U32(mCurX + charInfo.width); // + 7) & ~0x3; - nextCurY = U32(mCurY + mPlatformFont->getFontHeight()); // + 7) & ~0x3; +void GFont::addBitmap(PlatformFont::CharInfo &charInfo) +{ + const S32 padding = 24; + + // Dimensions for the padded bitmap and SDF + S32 paddedWidth = charInfo.width + (2 * padding); + S32 paddedHeight = charInfo.height + (2 * padding); + + // Allocate buffers + FrameTemp paddedBitmap(paddedWidth * paddedHeight); + padGlyphBitmap(charInfo.bitmapData, charInfo.width, charInfo.height, paddedBitmap, paddedWidth, paddedHeight, padding); + + S32 sdfWidth = paddedWidth; + S32 sdfHeight = paddedHeight; + + // Allocate buffer for SDF bitmap + FrameTemp sdfBitmap((sdfWidth * sdfHeight)); + + // Generate the SDF + F32 sdfSpread = 1.0f / (2.0f + (static_cast(paddedWidth / paddedHeight))); + sdfSpread = mMax(paddedWidth, paddedHeight) * sdfSpread; + generateSDF(paddedBitmap, paddedWidth, paddedHeight, sdfBitmap, sdfWidth, sdfHeight, sdfSpread); + applyGaussianBlur(sdfBitmap, sdfWidth, sdfHeight, 1.5f); // Apply blur: 1.5 - 2.5 for a moderate blur + + U32 nextCurX = U32(mCurX + sdfWidth); + U32 nextCurY = U32(mCurY + sdfHeight); + + if (mCurSheet == -1 || nextCurY > TextureSheetSize) + { + addSheet(); + nextCurX = U32(mCurX + sdfWidth); + nextCurY = U32(mCurY + sdfHeight); + } + + // If the current row exceeds the texture width, move to the next row + if (nextCurX > TextureSheetSize) { + mCurX = 0; // Start at the beginning of the row + mCurY += mMaxRowHeight; // Move down by the tallest glyph in the current row + mMaxRowHeight = 0; // Reset for the next row + + // Recalculate + nextCurX = U32(mCurX + sdfWidth); + nextCurY = U32(mCurY + sdfHeight); } - // Check the Y once more - sometimes we advance to a new row and run off - // the end. - if(nextCurY >= TextureSheetSize) + if (nextCurY >= TextureSheetSize) { - routeA = true; addSheet(); // Recalc our nexts. - nextCurX = U32(mCurX + charInfo.width); // + 7) & ~0x3; - nextCurY = U32(mCurY + mPlatformFont->getFontHeight()); // + 7) & ~0x3; + nextCurX = U32(mCurX + sdfWidth); + nextCurY = U32(mCurY + sdfHeight); } - charInfo.bitmapIndex = mCurSheet; - charInfo.xOffset = mCurX; - charInfo.yOffset = mCurY; + charInfo.bitmapIndex = mCurSheet; + charInfo.xOffset = mCurX; + charInfo.yOffset = mCurY; mCurX = nextCurX; - S32 x, y; GBitmap *bmp = mTextureSheets[mCurSheet].getBitmap(); AssertFatal(bmp->getFormat() == GFXFormatA8, "GFont::addBitmap - cannot added characters to non-greyscale textures!"); + S32 x, y; + for(y = 0;y < sdfHeight;y++) + for(x = 0;x < sdfWidth;x++) + *bmp->getAddress(x + charInfo.xOffset, y + charInfo.yOffset) = sdfBitmap[y * sdfWidth + x]; - for(y = 0;y < charInfo.height;y++) - for(x = 0;x < charInfo.width;x++) - *bmp->getAddress(x + charInfo.xOffset, y + charInfo.yOffset) = charInfo.bitmapData[y * charInfo.width + x]; + // update our width and height. + charInfo.width = sdfWidth; + charInfo.height = sdfHeight; + charInfo.yOrigin = charInfo.yOrigin + padding; + charInfo.xOrigin = charInfo.xOrigin - padding; + mMaxRowHeight = mMax(mMaxRowHeight, sdfHeight); mTextureSheets[mCurSheet].refresh(); } @@ -371,6 +507,7 @@ void GFont::addSheet() mCurX = 0; mCurY = 0; + mMaxRowHeight = 0; mCurSheet = mTextureSheets.size() - 1; } @@ -382,12 +519,36 @@ const PlatformFont::CharInfo &GFont::getCharInfo(const UTF16 in_charIndex) AssertFatal(in_charIndex, "GFont::getCharInfo - can't get info for char 0!"); - if(mRemapTable[in_charIndex] == -1) + auto it = mCharMap.find(in_charIndex); + if (it == mCharMap.end()) loadCharInfo(in_charIndex); - - AssertFatal(mRemapTable[in_charIndex] != -1, "No remap info for this character"); - return mCharInfoList[mRemapTable[in_charIndex]]; + return mCharMap[in_charIndex]; +} + +PlatformFont::CharInfo GFont::getScaledCharInfo(const UTF16 in_charIndex, U32 renderSize) { + PROFILE_SCOPE(GFont_getScaledCharInfo); + + AssertFatal(in_charIndex, "GFont::getScaledCharInfo - can't get info for char 0!"); + + // Retrieve the original character information. + auto it = mCharMap.find(in_charIndex); + if (it == mCharMap.end()) + loadCharInfo(in_charIndex); + + const PlatformFont::CharInfo& originalCharInfo = mCharMap[in_charIndex]; + + // Calculate the scaling factor. + const F32 renderScale = static_cast(renderSize) / mSize; + + // Create a scaled version of the character info. + PlatformFont::CharInfo scaledCharInfo = originalCharInfo; + + scaledCharInfo.xIncrement = getCharXIncrementScaled(in_charIndex, renderSize); + scaledCharInfo.xOrigin = static_cast((F32)originalCharInfo.xOrigin * renderScale); + scaledCharInfo.yOrigin = static_cast((F32)originalCharInfo.yOrigin * renderScale); + + return scaledCharInfo; } const PlatformFont::CharInfo &GFont::getDefaultCharInfo() @@ -399,177 +560,77 @@ const PlatformFont::CharInfo &GFont::getDefaultCharInfo() //----------------------------------------------------------------------------- -U32 GFont::getStrWidth(const UTF8* in_pString) +U32 GFont::getStringWidthScaled(const String& text, U32 renderSize) { - AssertFatal(in_pString != NULL, "GFont::getStrWidth: String is NULL, height is undefined"); - // If we ain't running debug... - if (in_pString == NULL || *in_pString == '\0') - return 0; - - return getStrNWidth(in_pString, dStrlen(in_pString)); + return getStringWidthScaled(text, renderSize, text.length()); } -U32 GFont::getStrWidthPrecise(const UTF8* in_pString) +U32 GFont::getStringWidthScaledPrecise(const String& text, U32 renderSize) { - AssertFatal(in_pString != NULL, "GFont::getStrWidth: String is NULL, height is undefined"); - // If we ain't running debug... - if (in_pString == NULL) - return 0; - - return getStrNWidthPrecise(in_pString, dStrlen(in_pString)); + return getStringWidthScaledPrecise(text, renderSize, text.length()); } -//----------------------------------------------------------------------------- -U32 GFont::getStrNWidth(const UTF8 *str, U32 n) +U32 GFont::getStringWidthScaled(const String& text, U32 renderSize, U32 length) { - // UTF8 conversion is expensive. Avoid converting in a tight loop. - FrameTemp str16(n + 1); - convertUTF8toUTF16N(str, str16, n + 1); - return getStrNWidth(str16, dStrlen(str16)); -} - -U32 GFont::getStrNWidth(const UTF16 *str, U32 n) -{ - AssertFatal(str != NULL, "GFont::getStrNWidth: String is NULL"); - - if (str == NULL || str[0] == '\0' || n == 0) - return 0; - - U32 totWidth = 0; - UTF16 curChar; - U32 charCount; - - for(charCount = 0; charCount < n; charCount++) - { - curChar = str[charCount]; - if(curChar == '\0') - break; + U32 totalWidth = 0; + const UTF16* utfString = text.utf16(); - if(isValidChar(curChar)) - { - const PlatformFont::CharInfo& rChar = getCharInfo(curChar); - totWidth += rChar.xIncrement; + for (U32 charCount = 0; charCount < length; charCount++) { + UTF16 c = utfString[charCount]; + if (isValidChar(c)) { + totalWidth += getCharXIncrementScaled(c, renderSize); } - else if (curChar == dT('\t')) - { - const PlatformFont::CharInfo& rChar = getCharInfo(dT(' ')); - totWidth += rChar.xIncrement * TabWidthInSpaces; + else if (c == dT('\t')) { + totalWidth += getCharXIncrementScaled(dT(' '), renderSize) * TabWidthInSpaces; } } - return(totWidth); -} - -U32 GFont::getStrNWidthPrecise(const UTF8 *str, U32 n) -{ - FrameTemp str16(n + 1); - convertUTF8toUTF16N(str, str16, n + 1); - return getStrNWidthPrecise(str16, dStrlen(str16)); + return totalWidth; } -U32 GFont::getStrNWidthPrecise(const UTF16 *str, U32 n) +U32 GFont::getStringWidthScaledPrecise(const String& text, U32 renderSize, U32 length) { - AssertFatal(str != NULL, "GFont::getStrNWidth: String is NULL"); - - if (str == NULL || str[0] == '\0' || n == 0) - return(0); - - U32 totWidth = 0; - UTF16 curChar; + U32 totalWidth = 0; + const UTF16* utfString = text.utf16(); U32 charCount = 0; - - for(charCount = 0; charCount < n; charCount++) - { - curChar = str[charCount]; - if(curChar == '\0') - break; - - if(isValidChar(curChar)) - { - const PlatformFont::CharInfo& rChar = getCharInfo(curChar); - totWidth += rChar.xIncrement; + + for (charCount = 0; charCount < length; charCount++) { + UTF16 c = utfString[charCount]; + if (isValidChar(c)) { + totalWidth += getCharXIncrementScaled(c, renderSize); } - else if (curChar == dT('\t')) - { - const PlatformFont::CharInfo& rChar = getCharInfo(dT(' ')); - totWidth += rChar.xIncrement * TabWidthInSpaces; + else if (c == dT('\t')) { + totalWidth += getCharXIncrementScaled(dT(' '), renderSize) * TabWidthInSpaces; } } - UTF16 endChar = str[getMin(charCount,n-1)]; + UTF16 endChar = utfString[getMin(charCount, length - 1)]; - if (isValidChar(endChar)) - { + if (isValidChar(endChar)) { const PlatformFont::CharInfo& rChar = getCharInfo(endChar); - if (rChar.width != rChar.xIncrement) - totWidth += (rChar.width - rChar.xIncrement); - } - - return(totWidth); -} - -U32 GFont::getBreakPos(const UTF16 *str16, U32 slen, U32 width, bool breakOnWhitespace) -{ - // Some early out cases. - if(slen==0) - return 0; - - U32 ret = 0; - U32 lastws = 0; - UTF16 c; - U32 charCount = 0; - - for( charCount=0; charCount < slen; charCount++) - { - c = str16[charCount]; - if(c == '\0') - break; - - if(c == dT('\t')) - c = dT(' '); - - if(!isValidChar(c)) - { - ret++; - continue; - } - - if(c == dT(' ')) - lastws = ret+1; - - const PlatformFont::CharInfo& rChar = getCharInfo(c); - if(rChar.width > width || rChar.xIncrement > width) - { - if(lastws && breakOnWhitespace) - return lastws; - return ret; + if (rChar.width != rChar.xIncrement) { + totalWidth += static_cast((rChar.width - rChar.xIncrement) * ((F32)renderSize / mSize) + 0.5f); } - - width -= rChar.xIncrement; - - ret++; } - return ret; + + return totalWidth; } -void GFont::wrapString(const UTF8 *txt, U32 lineWidth, Vector &startLineOffset, Vector &lineLen) +void GFont::wrapStringScaled(const UTF8* txt, U32 lineWidth, U32 renderSize, Vector& startLineOffset, Vector& lineLen) { - // TODO: Is this error still true? - //Con::errorf("GFont::wrapString(): Not yet converted to be UTF-8 safe"); - startLineOffset.clear(); lineLen.clear(); - if (!txt || !txt[0] || lineWidth < getCharWidth('W')) //make sure the line width is greater then a single character + if (!txt || !txt[0] || lineWidth < getCharWidthScaled('W', renderSize)) //make sure the line width is greater then a single character return; U32 len = dStrlen(txt); - U32 startLine; + U32 startLine; for (U32 i = 0; i < len;) { - U32 wide = 0; + U32 wide = 0; startLine = i; startLineOffset.push_back(startLine); @@ -578,22 +639,22 @@ void GFont::wrapString(const UTF8 *txt, U32 lineWidth, Vector &startLineOff U32 lineStrWidth = 0; for (; i < len; i++) { - if( txt[ i ] == '\n' ) + if (txt[i] == '\n') { needsNewLine = true; break; } - else if(isValidChar(txt[i])) + else if (isValidChar(txt[i])) { - lineStrWidth += getCharInfo(txt[i]).xIncrement; - if(txt[i] < 0) // symbols which code > 127 - { + lineStrWidth += getCharXIncrementScaled(txt[i], renderSize); + if (txt[i] < 0) // symbols which code > 127 + { wide++; i++; } - if( lineStrWidth > lineWidth ) + if (lineStrWidth > lineWidth) { needsNewLine = true; - break; + break; } } } @@ -605,12 +666,12 @@ void GFont::wrapString(const UTF8 *txt, U32 lineWidth, Vector &startLineOff return; } - S32 j; + S32 j; // Did we hit a hardwrap (newline character) in the string. - bool hardwrap = ( txt[i] == '\n' ); - - if ( hardwrap ) + bool hardwrap = (txt[i] == '\n'); + + if (hardwrap) { j = i; } @@ -618,10 +679,10 @@ void GFont::wrapString(const UTF8 *txt, U32 lineWidth, Vector &startLineOff // we need to backtrack until we find a space character // we don't do this for hardwrap(s) else - { + { for (j = i - 1; j >= startLine; j--) { - if ( dIsspace(txt[j]) || txt[i] == '\n' ) + if (dIsspace(txt[j]) || txt[i] == '\n') break; } @@ -641,11 +702,11 @@ void GFont::wrapString(const UTF8 *txt, U32 lineWidth, Vector &startLineOff // beginning of the next line. // We don't skip spaces after a hardwrap because they were obviously intended. for (i++; i < len; i++) - { - if ( txt[i] == '\n' ) + { + if (txt[i] == '\n') continue; - if ( dIsspace( txt[i] ) && !hardwrap ) + if (dIsspace(txt[i]) && !hardwrap) continue; break; @@ -653,58 +714,102 @@ void GFont::wrapString(const UTF8 *txt, U32 lineWidth, Vector &startLineOff } } +U32 GFont::getBreakPosScaled(const UTF16* str16, U32 slen, U32 width, U32 renderSize, bool breakOnWhitespace) +{ + // Some early out cases. + if (slen == 0) + return 0; + + U32 ret = 0; + U32 lastws = 0; + UTF16 c; + U32 charCount = 0; + + for (charCount = 0; charCount < slen; charCount++) + { + c = str16[charCount]; + if (c == '\0') + break; + + if (c == dT('\t')) + c = dT(' '); + + if (!isValidChar(c)) + { + ret++; + continue; + } + + if (c == dT(' ')) + lastws = ret + 1; + + if (getCharWidthScaled(c, renderSize) > width || getCharXIncrementScaled(c, renderSize) > width) + { + if (lastws && breakOnWhitespace) + return lastws; + return ret; + } + + width -= getCharXIncrementScaled(c, renderSize); + + ret++; + } + return ret; +} + //----------------------------------------------------------------------------- bool GFont::read(Stream& io_rStream) { - // Handle versioning - U32 version; - io_rStream.read(&version); - if(version != csm_fileVersion) - return false; - - char buf[256]; - io_rStream.readString(buf); - mFaceName = buf; - - io_rStream.read(&mSize); - io_rStream.read(&mCharSet); - - io_rStream.read(&mHeight); - io_rStream.read(&mBaseline); - io_rStream.read(&mAscent); - io_rStream.read(&mDescent); - - U32 size = 0; - io_rStream.read(&size); - mCharInfoList.setSize(size); - U32 i; - for(i = 0; i < size; i++) - { - PlatformFont::CharInfo *ci = &mCharInfoList[i]; - io_rStream.read(&ci->bitmapIndex); - io_rStream.read(&ci->xOffset); - io_rStream.read(&ci->yOffset); - io_rStream.read(&ci->width); - io_rStream.read(&ci->height); - io_rStream.read(&ci->xOrigin); - io_rStream.read(&ci->yOrigin); - io_rStream.read(&ci->xIncrement); - ci->bitmapData = NULL; + // Handle versioning + U32 version; + io_rStream.read(&version); + if (version != csm_fileVersion) + { + Con::errorf("Font file generated before SDF fonts were implemented!"); + return false; + } + + char buf[256]; + io_rStream.readString(buf); + mFaceName = buf; + + io_rStream.read(&mSize); + io_rStream.read(&mCharSet); + + io_rStream.read(&mHeight); + io_rStream.read(&mBaseline); + io_rStream.read(&mAscent); + io_rStream.read(&mDescent); + + U32 size = 0; + io_rStream.read(&size); + for(U32 i = 0; i < size; i++) + { + U32 charCode; + io_rStream.read(&charCode); + + PlatformFont::CharInfo ci; + io_rStream.read(&ci.bitmapIndex); + io_rStream.read(&ci.xOffset); + io_rStream.read(&ci.yOffset); + io_rStream.read(&ci.width); + io_rStream.read(&ci.height); + io_rStream.read(&ci.xOrigin); + io_rStream.read(&ci.yOrigin); + io_rStream.read(&ci.xIncrement); + ci.bitmapData = NULL; + + // Insert the character information into the map + mCharMap[charCode] = ci; // Insert the key-value pair into the map } U32 numSheets = 0; io_rStream.read(&numSheets); - for(i = 0; i < numSheets; i++) + for(U32 i = 0; i < numSheets; i++) { GBitmap *bmp = new GBitmap; - /*String path = String::ToString("%s/%s %d %d (%s).png", Con::getVariable("$GUI::fontCacheDirectory"), mFaceName.c_str(), mSize, i, getCharSetName(mCharSet)); - if(!bmp->readBitmap("png", path)) - { - delete bmp; - return false; - }*/ U32 len; io_rStream.read(&len); @@ -724,32 +829,6 @@ bool GFont::read(Stream& io_rStream) io_rStream.read(&mCurY); io_rStream.read(&mCurSheet); - // Read the remap table. - U32 minGlyph, maxGlyph; - io_rStream.read(&minGlyph); - io_rStream.read(&maxGlyph); - - if(maxGlyph >= minGlyph) - { - // Length of buffer.. - U32 buffLen; - io_rStream.read(&buffLen); - - // Read the buffer. - FrameTemp inBuff(buffLen); - io_rStream.read(buffLen, inBuff); - - // Decompress. - uLongf destLen = (static_cast(maxGlyph) - minGlyph + 1) * sizeof(S32); - uncompress((Bytef*)&mRemapTable[minGlyph], &destLen, (Bytef*)(S32*)inBuff, buffLen); - - AssertISV(destLen == (maxGlyph-minGlyph+1)*sizeof(S32), "GFont::read - invalid remap table data!"); - - // Make sure we've got the right endianness. - for(i = minGlyph; i <= maxGlyph; i++) - mRemapTable[i] = convertBEndianToHost(mRemapTable[i]); - } - return (io_rStream.getStatus() == Stream::Ok); } @@ -768,27 +847,34 @@ bool GFont::write(Stream& stream) stream.write(mAscent); stream.write(mDescent); - // Write char info list - stream.write(U32(mCharInfoList.size())); - U32 i; - for(i = 0; i < mCharInfoList.size(); i++) + // Write char info count + stream.write(U32(mCharMap.size())); + + // Write each character's info (iterate through the unordered_map) + for (const auto& entry : mCharMap) { - const PlatformFont::CharInfo *ci = &mCharInfoList[i]; - stream.write(ci->bitmapIndex); - stream.write(ci->xOffset); - stream.write(ci->yOffset); - stream.write(ci->width); - stream.write(ci->height); - stream.write(ci->xOrigin); - stream.write(ci->yOrigin); - stream.write(ci->xIncrement); - } + U32 charCode = entry.key; // Character code (U32) + stream.write(charCode); + const PlatformFont::CharInfo& ci = entry.value; // CharInfo associated with the character + + // Write each part of the CharInfo structure to the stream + stream.write(ci.bitmapIndex); + stream.write(ci.xOffset); + stream.write(ci.yOffset); + stream.write(ci.width); + stream.write(ci.height); + stream.write(ci.xOrigin); + stream.write(ci.yOrigin); + stream.write(ci.xIncrement); + } stream.write(mTextureSheets.size()); - for (i = 0; i < mTextureSheets.size(); i++) + for (U32 i = 0; i < mTextureSheets.size(); i++) { - /*String path = String::ToString("%s/%s %d %d (%s).png", Con::getVariable("$GUI::fontCacheDirectory"), mFaceName.c_str(), mSize, i, getCharSetName(mCharSet)); - mTextureSheets[i].getBitmap()->writeBitmap("png", path);*/ + // Debugging write out to images. + /*String path = String::ToString("%s/%s %d %d (%s).png", Con::getVariable("$GUI::fontCacheDirectory"), mFaceName.c_str(), mSize, i, getCharSetName(mCharSet)); + mTextureSheets[i].getBitmap()->writeBitmap("png", path);*/ + mTextureSheets[i].getBitmap()->writeBitmapStream("png", stream); } @@ -797,45 +883,6 @@ bool GFont::write(Stream& stream) stream.write(mCurY); stream.write(mCurSheet); - // Get the min/max we have values for, and only write that range out. - S32 minGlyph = S32_MAX, maxGlyph = 0; - - for(i = 0; i < 65536; i++) - { - if(mRemapTable[i] != -1) - { - if(i>maxGlyph) maxGlyph = i; - if(i= minGlyph) - { - // Put everything big endian, to be consistent. Do this inplace. - for(i = minGlyph; i <= maxGlyph; i++) - mRemapTable[i] = convertHostToBEndian(mRemapTable[i]); - - { - // Compress. - const U32 buffSize = 128 * 1024; - FrameTemp outBuff(buffSize); - uLongf destLen = buffSize * sizeof(S32); - compress2((Bytef*)(S32*)outBuff, &destLen, (Bytef*)(S32*)&mRemapTable[minGlyph], (static_cast(maxGlyph) - minGlyph + 1) * sizeof(S32), 9); - - // Write out. - stream.write((U32)destLen); - stream.write(destLen, outBuff); - } - - // Put us back to normal. - for(i = minGlyph; i <= maxGlyph; i++) - mRemapTable[i] = convertBEndianToHost(mRemapTable[i]); - } - return (stream.getStatus() == Stream::Ok); } @@ -847,11 +894,11 @@ void GFont::exportStrip(const char *fileName, U32 padding, U32 kerning) S32 heightMin=0, heightMax=0; - for(S32 i=0; i glyphList; - glyphList.reserve(mCharInfoList.size()); + glyphList.reserve(mCharMap.size()); U32 curWidth = 0; - for(S32 i=0; igetFormat()); - lastGlyphMap.charId = i; + lastGlyphMap.bitmap = new GBitmap(entry.value.width + kerning + 2 * padding, entry.value.height + 2 * padding, false, strip->getFormat()); + lastGlyphMap.charId = entry.key; // Copy the rect. - RectI ri(curWidth, getBaseline() - mCharInfoList[i].yOrigin, lastGlyphMap.bitmap->getWidth(), lastGlyphMap.bitmap->getHeight()); + RectI ri(curWidth, getBaseline() - entry.value.yOrigin, lastGlyphMap.bitmap->getWidth(), lastGlyphMap.bitmap->getHeight()); Point2I outRi(0,0); lastGlyphMap.bitmap->copyRect(strip, ri, outRi); // Update glyph attributes. - mCharInfoList[i].width = lastGlyphMap.bitmap->getWidth(); - mCharInfoList[i].height = lastGlyphMap.bitmap->getHeight(); - mCharInfoList[i].xOffset -= kerning + padding; - mCharInfoList[i].xIncrement += kerning; - mCharInfoList[i].yOffset -= padding; + entry.value.width = lastGlyphMap.bitmap->getWidth(); + entry.value.height = lastGlyphMap.bitmap->getHeight(); + entry.value.xOffset -= kerning + padding; + entry.value.xIncrement += kerning; + entry.value.yOffset -= padding; // Advance. curWidth += ri.extent.x; @@ -961,7 +1008,7 @@ void GFont::importStrip(const char *fileName, U32 padding, U32 kerning) S32 maxHeight = 0; for(U32 i = 0; i < glyphList.size(); i++) { - PlatformFont::CharInfo *ci = &mCharInfoList[glyphList[i].charId]; + PlatformFont::CharInfo *ci = &mCharMap[glyphList[i].charId]; if(ci->height > maxHeight) maxHeight = ci->height; @@ -1021,7 +1068,7 @@ void GFont::importStrip(const char *fileName, U32 padding, U32 kerning) for(S32 i=0; ibitmapIndex; mTextureSheets[bi]->getBitmap()->copyRect(glyphList[i].bitmap, RectI(0,0, glyphList[i].bitmap->getWidth(),glyphList[i].bitmap->getHeight()), Point2I(ci->xOffset, ci->yOffset)); } @@ -1038,7 +1085,7 @@ DefineEngineFunction( populateFontCacheString, void, ( const char *faceName, S32 "@param string The string to populate.\n" "@ingroup Font\n" ) { - Resource f = GFont::create(faceName, fontSize, Con::getVariable("$GUI::fontCacheDirectory")); + Resource f = GFont::create(faceName, Con::getVariable("$GUI::fontCacheDirectory")); if(f == NULL) { @@ -1053,7 +1100,7 @@ DefineEngineFunction( populateFontCacheString, void, ( const char *faceName, S32 } // This has the side effect of generating character info, including the bitmaps. - f->getStrWidthPrecise( string ); + f->getStringWidthScaledPrecise( String::ToString(string), fontSize ); } DefineEngineFunction( populateFontCacheRange, void, ( const char *faceName, S32 fontSize, U32 rangeStart, U32 rangeEnd ),, @@ -1065,7 +1112,7 @@ DefineEngineFunction( populateFontCacheRange, void, ( const char *faceName, S32 "@note We only support BMP-0, so code points range from 0 to 65535.\n" "@ingroup Font\n" ) { - Resource f = GFont::create(faceName, fontSize, Con::getVariable("$GUI::fontCacheDirectory")); + Resource f = GFont::create(faceName, Con::getVariable("$GUI::fontCacheDirectory")); if(f == NULL) { @@ -1153,13 +1200,14 @@ DefineEngineFunction( populateAllFontCacheString, void, ( const char *string ),, Resource theFont = ResourceManager::get().startResourceList( Resource::signature() ); Con::printf("Populating font cache with string '%s'", string); + U32 sdfSize = Con::getIntVariable("$GUI::Font::SDFSize", 64); while( theFont != NULL ) { if(theFont->hasPlatformFont()) { // This has the side effect of generating character info, including the bitmaps. - theFont->getStrWidthPrecise( string ); + theFont->getStringWidthScaledPrecise( String::ToString(string), sdfSize); } else { @@ -1227,7 +1275,7 @@ DefineEngineFunction( exportCachedFont, void, "@ingroup Font\n" ) { // Tell the font to export itself. - Resource f = GFont::create(faceName, fontSize, Con::getVariable("$GUI::fontCacheDirectory")); + Resource f = GFont::create(faceName, Con::getVariable("$GUI::fontCacheDirectory")); if(f == NULL) { @@ -1250,7 +1298,7 @@ DefineEngineFunction( importCachedFont, void, "@ingroup Font\n" ) { // Tell the font to import itself. - Resource f = GFont::create(faceName, fontSize, Con::getVariable("$GUI::fontCacheDirectory")); + Resource f = GFont::create(faceName, Con::getVariable("$GUI::fontCacheDirectory")); if(f == NULL) { @@ -1272,10 +1320,10 @@ DefineEngineFunction( duplicateCachedFont, void, "@param newFontName The name of the new font face.\n" "@ingroup Font\n" ) { - String newFontFile = GFont::getFontCacheFilename(newFontName, oldFontSize); + String newFontFile = GFont::getFontCacheFilename(newFontName); // Load the original font. - Resource font = GFont::create(oldFontName, oldFontSize, Con::getVariable("$GUI::fontCacheDirectory")); + Resource font = GFont::create(oldFontName, Con::getVariable("$GUI::fontCacheDirectory")); // Deal with inexplicably missing or failed to load fonts. if (font == NULL) diff --git a/Engine/source/gfx/gFont.h b/Engine/source/gfx/gFont.h index 2f5274af24..e7f707cb39 100644 --- a/Engine/source/gfx/gFont.h +++ b/Engine/source/gfx/gFont.h @@ -39,29 +39,76 @@ #ifndef _GFXTEXTUREHANDLE_H_ #include "gfx/gfxTextureHandle.h" #endif +#ifndef _TDICTIONARY_H_ +#include "core/util/tDictionary.h" +#endif GFX_DeclareTextureProfile(GFXFontTextureProfile); -#define Font_Table_MAX 65536 class GFont { public: + typedef Map typeCharMap; enum Constants { TabWidthInSpaces = 3, - TextureSheetSize = 256, + TextureSheetSize = 512, }; public: GFont(); virtual ~GFont(); - static Resource create(const String &faceName, U32 size, const char *cacheDirectory = 0, U32 charset = TGE_ANSI_CHARSET); + static Resource create(const String &faceName, const char *cacheDirectory = 0, U32 charset = TGE_ANSI_CHARSET); GFXTexHandle getTextureHandle(S32 index) const { return mTextureSheets[index]; } + ///---------------------------------- + /// SDF Functions + ///---------------------------------- + U32 getScaledHeight(U32 renderSize) const { + return static_cast(mHeight * (static_cast(renderSize) / mSize) + 0.5f); + } + + U32 getScaledBaseline(U32 renderSize) const { + return static_cast(mBaseline * (static_cast(renderSize) / mSize) + 0.5f); + } + + U32 getScaledAscent(U32 renderSize) const { + return static_cast(mAscent * (static_cast(renderSize) / mSize) + 0.5f); + } + + U32 getScaledDescent(U32 renderSize) const { + return static_cast(mDescent * (static_cast(renderSize) / mSize) + 0.5f); + } + + U32 getCharHeightScaled(const UTF16 in_charIndex, U32 renderSize) { + return static_cast(getCharHeight(in_charIndex) * + (static_cast(renderSize) / mSize) + 0.5f); + } + + U32 getCharWidthScaled(const UTF16 in_charIndex, U32 renderSize) { + return static_cast(getCharWidth(in_charIndex) * + (static_cast(renderSize) / mSize) + 0.5f); + } + + U32 getCharXIncrementScaled(const UTF16 in_charIndex, U32 renderSize) { + return static_cast(getCharXIncrement(in_charIndex) * + (static_cast(renderSize) / mSize) + 0.5f); + } + + U32 getStringWidthScaled(const String& text, U32 renderSize); + U32 getStringWidthScaledPrecise(const String& text, U32 renderSize); + + U32 getStringWidthScaled(const String& text, U32 renderSize, U32 length); + U32 getStringWidthScaledPrecise(const String& text, U32 renderSize, U32 length); + + void wrapStringScaled(const UTF8* txt, U32 lineWidth, U32 renderSize, Vector& startLineOffset, Vector& lineLen); + U32 getBreakPosScaled(const UTF16* str16, U32 slen, U32 width, U32 renderSize, bool breakOnWhitespace); + const PlatformFont::CharInfo& getCharInfo(const UTF16 in_charIndex); + PlatformFont::CharInfo getScaledCharInfo(const UTF16 in_charIndex, U32 renderSize); static const PlatformFont::CharInfo& getDefaultCharInfo(); U32 getCharHeight(const UTF16 in_charIndex); @@ -75,19 +122,6 @@ class GFont const U32 getAscent() const { return mAscent; } const U32 getDescent() const { return mDescent; } - U32 getBreakPos(const UTF16 *string, U32 strlen, U32 width, bool breakOnWhitespace); - - /// These are the preferred width functions. - U32 getStrNWidth(const UTF16*, U32 n); - U32 getStrNWidthPrecise(const UTF16*, U32 n); - - /// These UTF8 versions of the width functions will be deprecated, please avoid them. - U32 getStrWidth(const UTF8*); // Note: ignores c/r - U32 getStrNWidth(const UTF8*, U32 n); - U32 getStrWidthPrecise(const UTF8*); // Note: ignores c/r - U32 getStrNWidthPrecise(const UTF8*, U32 n); - void wrapString(const UTF8 *string, U32 width, Vector &startLineOffset, Vector &lineLen); - /// Dump information about this font to the console. void dumpInfo() const; @@ -114,7 +148,7 @@ class GFont } /// Get the filename for a cached font. - static String getFontCacheFilename(const String &faceName, U32 faceSize); + static String getFontCacheFilename(const String &faceName); /// Get the face name of the font. String getFontFaceName() const { return mFaceName; }; @@ -128,10 +162,11 @@ class GFont protected: bool loadCharInfo(const UTF16 ch); + void generateSDF(const U8* bitmap, S32 width, S32 height, U8* sdfBitmap, S32 sdfWidth, S32 sdfHeight, const F32 spreadFactor); + void applyGaussianBlur(U8* sdfBitmap, S32 width, S32 height, F32 sigma); + void padGlyphBitmap(const U8* original, S32 origWidth, S32 origHeight, U8* padded, S32 padWidth, S32 padHeight, S32 padding); void addBitmap(PlatformFont::CharInfo &charInfo); void addSheet(void); - void assignSheet(S32 sheetNum, GBitmap *bmp); - void *mMutex; private: @@ -143,6 +178,7 @@ class GFont S32 mCurX; S32 mCurY; S32 mCurSheet; + S32 mMaxRowHeight; bool mNeedSave; Torque::Path mGFTFile; @@ -155,12 +191,8 @@ class GFont U32 mAscent; U32 mDescent; - /// List of character info structures, must be accessed through the - /// getCharInfo(U32) function to account for remapping. - Vector mCharInfoList; - - /// Index remapping - S32 mRemapTable[Font_Table_MAX]; + // Cache charinfo into a map. + typeCharMap mCharMap; }; inline U32 GFont::getCharXIncrement(const UTF16 in_charIndex) @@ -183,7 +215,8 @@ inline U32 GFont::getCharHeight(const UTF16 in_charIndex) inline bool GFont::isValidChar(const UTF16 in_charIndex) const { - if(mRemapTable[in_charIndex] != -1) + auto it = mCharMap.find(in_charIndex); + if (it != mCharMap.end()) return true; if(mPlatformFont) diff --git a/Engine/source/gfx/gfxDrawUtil.cpp b/Engine/source/gfx/gfxDrawUtil.cpp index 40e6d15c50..2b2903e375 100644 --- a/Engine/source/gfx/gfxDrawUtil.cpp +++ b/Engine/source/gfx/gfxDrawUtil.cpp @@ -145,30 +145,30 @@ void GFXDrawUtil::setTextAnchorColor( const ColorI &ancColor ) //----------------------------------------------------------------------------- // Draw Text //----------------------------------------------------------------------------- -U32 GFXDrawUtil::drawText( GFont *font, const Point2I &ptDraw, const UTF16 *in_string, - const ColorI *colorTable, const U32 maxColorIndex, F32 rot ) +U32 GFXDrawUtil::drawText( GFont *font, const Point2I &ptDraw, const UTF16 *in_string, U32 renderSize, + const ColorI *colorTable, const U32 maxColorIndex, F32 rot) { - return drawTextN( font, ptDraw, in_string, dStrlen(in_string), colorTable, maxColorIndex, rot ); + return drawTextN( font, ptDraw, in_string, dStrlen(in_string), renderSize, colorTable, maxColorIndex, rot); } -U32 GFXDrawUtil::drawText( GFont *font, const Point2I &ptDraw, const UTF8 *in_string, - const ColorI *colorTable, const U32 maxColorIndex, F32 rot ) +U32 GFXDrawUtil::drawText( GFont *font, const Point2I &ptDraw, const UTF8 *in_string, U32 renderSize, + const ColorI *colorTable, const U32 maxColorIndex, F32 rot) { - return drawTextN( font, ptDraw, in_string, dStrlen(in_string), colorTable, maxColorIndex, rot ); + return drawTextN( font, ptDraw, in_string, dStrlen(in_string), renderSize, colorTable, maxColorIndex, rot); } -U32 GFXDrawUtil::drawText( GFont *font, const Point2F &ptDraw, const UTF8 *in_string, const ColorI *colorTable /*= NULL*/, const U32 maxColorIndex /*= 9*/, F32 rot /*= 0.f */ ) +U32 GFXDrawUtil::drawText( GFont *font, const Point2F &ptDraw, const UTF8 *in_string, U32 renderSize, const ColorI *colorTable /*= NULL*/, const U32 maxColorIndex /*= 9*/, F32 rot /*= 0.f */) { - return drawText(font,Point2I((S32)ptDraw.x,(S32)ptDraw.y),in_string,colorTable,maxColorIndex,rot); + return drawText(font,Point2I((S32)ptDraw.x,(S32)ptDraw.y),in_string, renderSize,colorTable,maxColorIndex,rot); } -U32 GFXDrawUtil::drawText( GFont *font, const Point2F &ptDraw, const UTF16 *in_string, const ColorI *colorTable /*= NULL*/, const U32 maxColorIndex /*= 9*/, F32 rot /*= 0.f */ ) +U32 GFXDrawUtil::drawText( GFont *font, const Point2F &ptDraw, const UTF16 *in_string, U32 renderSize, const ColorI *colorTable /*= NULL*/, const U32 maxColorIndex /*= 9*/, F32 rot /*= 0.f */) { - return drawText(font,Point2I((S32)ptDraw.x,(S32)ptDraw.y),in_string,colorTable,maxColorIndex,rot); + return drawText(font,Point2I((S32)ptDraw.x,(S32)ptDraw.y),in_string,renderSize,colorTable,maxColorIndex,rot); } -U32 GFXDrawUtil::drawTextN( GFont *font, const Point2I &ptDraw, const UTF8 *in_string, U32 n, - const ColorI *colorTable, const U32 maxColorIndex, F32 rot ) +U32 GFXDrawUtil::drawTextN( GFont *font, const Point2I &ptDraw, const UTF8 *in_string, U32 n, U32 renderSize, + const ColorI *colorTable, const U32 maxColorIndex, F32 rot) { // return on zero length strings if( n == 0 ) @@ -178,11 +178,11 @@ U32 GFXDrawUtil::drawTextN( GFont *font, const Point2I &ptDraw, const UTF8 *in_s FrameTemp ubuf( n + 1 ); // (n+1) to add space for null terminator convertUTF8toUTF16N(in_string, ubuf, n + 1); - return drawTextN( font, ptDraw, ubuf, n, colorTable, maxColorIndex, rot ); + return drawTextN( font, ptDraw, ubuf, n, renderSize, colorTable, maxColorIndex, rot); } U32 GFXDrawUtil::drawTextN( GFont *font, const Point2I &ptDraw, const UTF16 *in_string, - U32 n, const ColorI *colorTable, const U32 maxColorIndex, F32 rot ) + U32 n, U32 renderSize, const ColorI *colorTable, const U32 maxColorIndex, F32 rot) { // return on zero length strings if( n == 0 ) @@ -191,12 +191,12 @@ U32 GFXDrawUtil::drawTextN( GFont *font, const Point2I &ptDraw, const UTF16 *in_ // If it's over about 4000 verts we want to break it up if( n > 666 ) { - U32 left = drawTextN(font, ptDraw, in_string, 666, colorTable, maxColorIndex, rot); + U32 left = drawTextN(font, ptDraw, in_string, 666, renderSize, colorTable, maxColorIndex, rot); Point2I newDrawPt(left, ptDraw.y); const UTF16* str = (const UTF16*)in_string; - return drawTextN(font, newDrawPt, &(str[666]), n - 666, colorTable, maxColorIndex, rot); + return drawTextN(font, newDrawPt, &(str[666]), n - 666, renderSize, colorTable, maxColorIndex, rot); } PROFILE_START(GFXDevice_drawTextN); @@ -204,9 +204,13 @@ U32 GFXDrawUtil::drawTextN( GFont *font, const Point2I &ptDraw, const UTF16 *in_ const PlatformFont::CharInfo *tabci = NULL; S32 ptX = 0; + + F32 fontSize = (F32)renderSize; + + F32 renderScale = (F32)(fontSize / (F32)font->getFontSize()); // Queue everything for render. - mFontRenderBatcher->init(font, n); + mFontRenderBatcher->init(font, n, renderScale); U32 i; UTF16 c; @@ -290,7 +294,7 @@ U32 GFXDrawUtil::drawTextN( GFont *font, const Point2I &ptDraw, const UTF16 *in_ const U32 fontTabIncrement = tabci->xIncrement * GFont::TabWidthInSpaces; - ptX += fontTabIncrement; + ptX += fontTabIncrement * renderScale; // And skip rendering this character. continue; @@ -317,14 +321,14 @@ U32 GFXDrawUtil::drawTextN( GFont *font, const Point2I &ptDraw, const UTF16 *in_ return ptX + ptDraw.x; } -U32 GFXDrawUtil::drawTextN( GFont *font, const Point2F &ptDraw, const UTF8 *in_string, U32 n, const ColorI *colorTable /*= NULL*/, const U32 maxColorIndex /*= 9*/, F32 rot /*= 0.f */ ) +U32 GFXDrawUtil::drawTextN( GFont *font, const Point2F &ptDraw, const UTF8 *in_string, U32 n, U32 renderSize, const ColorI *colorTable /*= NULL*/, const U32 maxColorIndex /*= 9*/, F32 rot /*= 0.f */) { - return drawTextN(font,Point2I((S32)ptDraw.x,(S32)ptDraw.y),in_string,n,colorTable,maxColorIndex,rot); + return drawTextN(font,Point2I((S32)ptDraw.x,(S32)ptDraw.y),in_string,n, renderSize,colorTable,maxColorIndex,rot); } -U32 GFXDrawUtil::drawTextN( GFont *font, const Point2F &ptDraw, const UTF16 *in_string, U32 n, const ColorI *colorTable /*= NULL*/, const U32 maxColorIndex /*= 9*/, F32 rot /*= 0.f */ ) +U32 GFXDrawUtil::drawTextN( GFont *font, const Point2F &ptDraw, const UTF16 *in_string, U32 n, U32 renderSize, const ColorI *colorTable /*= NULL*/, const U32 maxColorIndex /*= 9*/, F32 rot /*= 0.f */) { - return drawTextN(font,Point2I((S32)ptDraw.x,(S32)ptDraw.y),in_string,n,colorTable,maxColorIndex,rot); + return drawTextN(font,Point2I((S32)ptDraw.x,(S32)ptDraw.y),in_string,n, renderSize,colorTable,maxColorIndex,rot); } //----------------------------------------------------------------------------- diff --git a/Engine/source/gfx/gfxDrawUtil.h b/Engine/source/gfx/gfxDrawUtil.h index 583feb4074..7ee13dd109 100644 --- a/Engine/source/gfx/gfxDrawUtil.h +++ b/Engine/source/gfx/gfxDrawUtil.h @@ -93,15 +93,15 @@ class GFXDrawUtil //----------------------------------------------------------------------------- // Draw Text //----------------------------------------------------------------------------- - U32 drawText( GFont *font, const Point2I &ptDraw, const UTF8 *in_string, const ColorI *colorTable = NULL, const U32 maxColorIndex = 9, F32 rot = 0.f ); - U32 drawTextN( GFont *font, const Point2I &ptDraw, const UTF8 *in_string, U32 n, const ColorI *colorTable = NULL, const U32 maxColorIndex = 9, F32 rot = 0.f ); - U32 drawText( GFont *font, const Point2I &ptDraw, const UTF16 *in_string, const ColorI *colorTable = NULL, const U32 maxColorIndex = 9, F32 rot = 0.f ); - U32 drawTextN( GFont *font, const Point2I &ptDraw, const UTF16 *in_string, U32 n, const ColorI *colorTable = NULL, const U32 maxColorIndex = 9, F32 rot = 0.f ); - - U32 drawText( GFont *font, const Point2F &ptDraw, const UTF8 *in_string, const ColorI *colorTable = NULL, const U32 maxColorIndex = 9, F32 rot = 0.f ); - U32 drawTextN( GFont *font, const Point2F &ptDraw, const UTF8 *in_string, U32 n, const ColorI *colorTable = NULL, const U32 maxColorIndex = 9, F32 rot = 0.f ); - U32 drawText( GFont *font, const Point2F &ptDraw, const UTF16 *in_string, const ColorI *colorTable = NULL, const U32 maxColorIndex = 9, F32 rot = 0.f ); - U32 drawTextN( GFont *font, const Point2F &ptDraw, const UTF16 *in_string, U32 n, const ColorI *colorTable = NULL, const U32 maxColorIndex = 9, F32 rot = 0.f ); + U32 drawText( GFont *font, const Point2I &ptDraw, const UTF8 *in_string, U32 renderSize = 12, const ColorI *colorTable = NULL, const U32 maxColorIndex = 9, F32 rot = 0.f); + U32 drawTextN( GFont *font, const Point2I &ptDraw, const UTF8 *in_string, U32 n, U32 renderSize = 12, const ColorI *colorTable = NULL, const U32 maxColorIndex = 9, F32 rot = 0.f); + U32 drawText( GFont *font, const Point2I &ptDraw, const UTF16 *in_string, U32 renderSize = 12, const ColorI *colorTable = NULL, const U32 maxColorIndex = 9, F32 rot = 0.f); + U32 drawTextN( GFont *font, const Point2I &ptDraw, const UTF16 *in_string, U32 n, U32 renderSize = 12, const ColorI *colorTable = NULL, const U32 maxColorIndex = 9, F32 rot = 0.f); + + U32 drawText( GFont *font, const Point2F &ptDraw, const UTF8 *in_string, U32 renderSize = 12, const ColorI *colorTable = NULL, const U32 maxColorIndex = 9, F32 rot = 0.f); + U32 drawTextN(GFont* font, const Point2F& ptDraw, const UTF8* in_string, U32 n, U32 renderSize = 12, const ColorI* colorTable = NULL, const U32 maxColorIndex = 9, F32 rot = 0.f); + U32 drawText(GFont* font, const Point2F& ptDraw, const UTF16* in_string, U32 renderSize = 12, const ColorI* colorTable = NULL, const U32 maxColorIndex = 9, F32 rot = 0.f); + U32 drawTextN(GFont* font, const Point2F& ptDraw, const UTF16* in_string, U32 n, U32 renderSize = 12, const ColorI* colorTable = NULL, const U32 maxColorIndex = 9, F32 rot = 0.f); //----------------------------------------------------------------------------- // Color Modulation diff --git a/Engine/source/gfx/gfxFontRenderBatcher.cpp b/Engine/source/gfx/gfxFontRenderBatcher.cpp index 4fce36b4e1..d1bbf80f75 100644 --- a/Engine/source/gfx/gfxFontRenderBatcher.cpp +++ b/Engine/source/gfx/gfxFontRenderBatcher.cpp @@ -22,11 +22,14 @@ #include "gfx/gfxFontRenderBatcher.h" #include "gfx/gFont.h" +#include "materials/shaderData.h" +#include "gfxDrawUtil.h" FontRenderBatcher::FontRenderBatcher() : mStorage(8096) { mFont = NULL; mLength = 0; + mRenderScale = 1.0f; if (!mFontSB) { GFXStateBlockDesc f; @@ -48,6 +51,17 @@ FontRenderBatcher::FontRenderBatcher() : mStorage(8096) f.setColorWrites(true, true, true, false); // NOTE: comment this out if alpha write is needed mFontSB = GFX->createStateBlock(f); } + + // Find ShaderData + ShaderData* shaderData; + mFontShader = Sim::findObject("SDFFontRenderingGUI", shaderData) ? shaderData->getShader() : NULL; + if (!mFontShader) + { + Con::errorf("FontRenderBatcher - could not find Font shader"); + } + // Create ShaderConstBuffer and Handles + mFontShaderConsts = mFontShader->allocConstBuffer(); + } void FontRenderBatcher::render( F32 rot, const Point2F &offset ) @@ -81,7 +95,6 @@ void FontRenderBatcher::render( F32 rot, const Point2F &offset ) mSheets[i]->startVertex = currentPt; const GFXTextureObject *tex = mFont->getTextureHandle(i); - for( S32 j = 0; j < mSheets[i]->numChars; j++ ) { // Get some general info to proceed with... @@ -89,8 +102,8 @@ void FontRenderBatcher::render( F32 rot, const Point2F &offset ) const PlatformFont::CharInfo &ci = mFont->getCharInfo( m.c ); // Where are we drawing it? - F32 drawY = offset.y + mFont->getBaseline() - ci.yOrigin * TEXT_MAG; - F32 drawX = offset.x + m.x + ci.xOrigin; + F32 drawY = offset.y + (F32(mFont->getBaseline() - F32(ci.yOrigin)) * mRenderScale); + F32 drawX = offset.x + ((m.x + F32(ci.xOrigin)) * mRenderScale); // Figure some values. const F32 texWidth = (F32)tex->getWidth(); @@ -102,9 +115,9 @@ void FontRenderBatcher::render( F32 rot, const Point2F &offset ) const F32 fillConventionOffset = GFX->getFillConventionOffset(); const F32 screenLeft = drawX - fillConventionOffset; - const F32 screenRight = drawX - fillConventionOffset + ci.width * TEXT_MAG; + const F32 screenRight = drawX - fillConventionOffset + (ci.width * mRenderScale) * TEXT_MAG; const F32 screenTop = drawY - fillConventionOffset; - const F32 screenBottom = drawY - fillConventionOffset + ci.height * TEXT_MAG; + const F32 screenBottom = drawY - fillConventionOffset + (ci.height * mRenderScale) * TEXT_MAG; // Build our vertices. We NEVER read back from the buffer, that's // incredibly slow, so for rotation do it into tmp. This code is @@ -172,8 +185,11 @@ void FontRenderBatcher::render( F32 rot, const Point2F &offset ) AssertFatal(currentPt <= mLength * 6, "FontRenderBatcher::render - too many verts for length of string!"); GFX->setVertexBuffer(verts); - GFX->setupGenericShaders( GFXDevice::GSAddColorTexture ); - + GFX->setShader(mFontShader); + GFX->setShaderConstBuffer(mFontShaderConsts); + MatrixF tempMatrix = GFX->getProjectionMatrix() * GFX->getViewMatrix() * GFX->getWorldMatrix(); + mFontShaderConsts->set(mFontShader->getShaderConstHandle("$modelView"), tempMatrix, GFXSCT_Float4x4); + // Now do an optimal render! for( S32 i = 0; i < mSheets.size(); i++ ) { @@ -182,10 +198,41 @@ void FontRenderBatcher::render( F32 rot, const Point2F &offset ) if(!mSheets[i]->numChars ) continue; + Point2I texDim = mFont->getTextureHandle(i).getWidthHeight(); + mFontShaderConsts->setSafe(mFontShader->getShaderConstHandle("$texDim"), Point2F(texDim.x, texDim.y)); GFX->setTexture( 0, mFont->getTextureHandle(i) ); GFX->drawPrimitive(GFXTriangleList, mSheets[i]->startVertex, mSheets[i]->numChars * 2); } + +#if 0 + for (S32 i = 0; i < mSheets.size(); i++) + { + // Do some early outs... + if (!mSheets[i]) + continue; + + if (!mSheets[i]->numChars) + continue; + + for (S32 j = 0; j < mSheets[i]->numChars; j++) + { + // Get some general info to proceed with... + const CharMarker& m = mSheets[i]->charIndex[j]; + const PlatformFont::CharInfo& ci = mFont->getCharInfo(m.c); + // Get some general info to proceed with... + F32 drawY = offset.y + ((mFont->getBaseline() - ci.yOrigin) * mRenderScale); + F32 drawX = offset.x + ((m.x + (F32)ci.xOrigin) * mRenderScale); + + // draw baseline + GFX->getDrawUtil()->drawLine(drawX, drawY + (mFont->getBaseline() * mRenderScale), drawX + (ci.width * mRenderScale), drawY + (mFont->getBaseline() * mRenderScale), ColorI::GREEN); + // draw origin line + GFX->getDrawUtil()->drawLine(drawX, drawY, drawX + (ci.width * mRenderScale), drawY, ColorI::RED); + // draw bounds + GFX->getDrawUtil()->drawRect(Point2F(drawX, drawY), Point2F(drawX + (ci.width * mRenderScale), drawY + (ci.height * mRenderScale)), ColorI::BLUE); + } + } +#endif } void FontRenderBatcher::queueChar( UTF16 c, S32 ¤tX, GFXVertexColor ¤tColor ) @@ -231,13 +278,13 @@ FontRenderBatcher::SheetMarker & FontRenderBatcher::getSheetMarker( U32 sheetID return *mSheets[sheetID]; } -void FontRenderBatcher::init( GFont *font, U32 n ) +void FontRenderBatcher::init( GFont *font, U32 n, F32 renderScale ) { // Clear out batched results dMemset(mSheets.address(), 0, mSheets.memSize()); mSheets.clear(); mStorage.freeBlocks(true); - + mRenderScale = renderScale; mFont = font; mLength = n; } diff --git a/Engine/source/gfx/gfxFontRenderBatcher.h b/Engine/source/gfx/gfxFontRenderBatcher.h index 25f707db49..9be3b988f1 100644 --- a/Engine/source/gfx/gfxFontRenderBatcher.h +++ b/Engine/source/gfx/gfxFontRenderBatcher.h @@ -50,18 +50,23 @@ class FontRenderBatcher Vector mSheets; GFont *mFont; U32 mLength; + F32 mRenderScale; GFXStateBlockRef mFontSB; SheetMarker &getSheetMarker(U32 sheetID); + // font shader. + GFXShaderRef mFontShader; + GFXShaderConstBufferRef mFontShaderConsts; + public: FontRenderBatcher(); - void init(GFont *font, U32 n); + void init(GFont *font, U32 n, F32 renderScale); void queueChar(UTF16 c, S32 ¤tX, GFXVertexColor ¤tColor); void render(F32 rot, const Point2F &offset ); }; -#endif \ No newline at end of file +#endif diff --git a/Engine/source/gfx/sim/debugDraw.cpp b/Engine/source/gfx/sim/debugDraw.cpp index 3bb149f3b3..1ab4a07260 100644 --- a/Engine/source/gfx/sim/debugDraw.cpp +++ b/Engine/source/gfx/sim/debugDraw.cpp @@ -222,7 +222,7 @@ void DebugDrawer::render(bool clear) { setupStateBlocks(); String fontCacheDir = Con::getVariable("$GUI::fontCacheDirectory"); - mFont = GFont::create("Arial", 12, fontCacheDir); + mFont = GFont::create("Arial", fontCacheDir); } SimTime curTime = Sim::getCurrentTime(); diff --git a/Engine/source/gui/buttons/guiCheckBoxCtrl.cpp b/Engine/source/gui/buttons/guiCheckBoxCtrl.cpp index 93e51168bd..d8b72b98de 100644 --- a/Engine/source/gui/buttons/guiCheckBoxCtrl.cpp +++ b/Engine/source/gui/buttons/guiCheckBoxCtrl.cpp @@ -166,12 +166,12 @@ void GuiCheckBoxCtrl::autoSize() } U32 bmpWidth = bmpArrayRect0Width + 2 + mIndent; - U32 strWidth = mProfile->mFont->getStrWidthPrecise( mButtonText ); + U32 strWidth = mProfile->mFont->getStringWidthScaledPrecise( String::ToString(mButtonText), mProfile->mFontSize); width = bmpWidth + strWidth + 2; U32 bmpHeight = mProfile->mBitmapArrayRects[0].extent.y; - U32 fontHeight = mProfile->mFont->getHeight(); + U32 fontHeight = mProfile->mFont->getScaledHeight(mProfile->mFontSize); height = getMax( bmpHeight, fontHeight ) + 4; diff --git a/Engine/source/gui/buttons/guiIconButtonCtrl.cpp b/Engine/source/gui/buttons/guiIconButtonCtrl.cpp index b9288ec7e9..0b0626c3c0 100644 --- a/Engine/source/gui/buttons/guiIconButtonCtrl.cpp +++ b/Engine/source/gui/buttons/guiIconButtonCtrl.cpp @@ -187,7 +187,7 @@ bool GuiIconButtonCtrl::resize(const Point2I &newPosition, const Point2I &newExt if ( mTextLocation != TextLocNone && mButtonText && mButtonText[0] ) { - U32 strWidth = mProfile->mFont->getStrWidthPrecise( mButtonText ); + U32 strWidth = mProfile->mFont->getStringWidthScaledPrecise(String::ToString(mButtonText), mProfile->mFontSize); if ( mTextLocation == TextLocLeft || mTextLocation == TextLocRight ) { @@ -382,22 +382,22 @@ void GuiIconButtonCtrl::renderButton( Point2I &offset, const RectI& updateRect ) if ( mTextLocation == TextLocRight ) { - Point2I start( mTextMargin, ( getHeight() - mProfile->mFont->getHeight() ) / 2 ); + Point2I start( mTextMargin, ( getHeight() - mProfile->mFont->getScaledHeight(mProfile->mFontSize) ) / 2 ); if (mBitmap && mIconLocation != IconLocNone ) { start.x = iconRect.extent.x + mButtonMargin.x + mTextMargin; } drawer->setBitmapModulation(fontColor); - drawer->drawText( mProfile->mFont, start + offset, text, mProfile->mFontColors ); + drawer->drawText( mProfile->mFont, start + offset, text, mProfile->mFontSize, mProfile->mFontColors ); } if ( mTextLocation == TextLocLeft ) { - Point2I start( mTextMargin, ( getHeight() - mProfile->mFont->getHeight() ) / 2 ); + Point2I start( mTextMargin, ( getHeight() - mProfile->mFont->getScaledHeight(mProfile->mFontSize) ) / 2 ); drawer->setBitmapModulation(fontColor); - drawer->drawText( mProfile->mFont, start + offset, text, mProfile->mFontColors ); + drawer->drawText( mProfile->mFont, start + offset, text, mProfile->mFontSize, mProfile->mFontColors ); } if ( mTextLocation == TextLocCenter ) @@ -406,19 +406,19 @@ void GuiIconButtonCtrl::renderButton( Point2I &offset, const RectI& updateRect ) if (mBitmap && mIconLocation == IconLocLeft ) { start.set( ( getWidth() - textWidth - iconRect.extent.x ) / 2 + iconRect.extent.x, - ( getHeight() - mProfile->mFont->getHeight() ) / 2 ); + ( getHeight() - mProfile->mFont->getScaledHeight(mProfile->mFontSize) ) / 2 ); } else - start.set( ( getWidth() - textWidth ) / 2, ( getHeight() - mProfile->mFont->getHeight() ) / 2 ); + start.set( ( getWidth() - textWidth ) / 2, ( getHeight() - mProfile->mFont->getScaledHeight(mProfile->mFontSize) ) / 2 ); drawer->setBitmapModulation( fontColor ); - drawer->drawText( mProfile->mFont, start + offset, text, mProfile->mFontColors ); + drawer->drawText( mProfile->mFont, start + offset, text, mProfile->mFontSize, mProfile->mFontColors ); } if ( mTextLocation == TextLocBottom ) { Point2I start; - start.set( ( getWidth() - textWidth ) / 2, getHeight() - mProfile->mFont->getHeight() - mTextMargin ); + start.set( ( getWidth() - textWidth ) / 2, getHeight() - mProfile->mFont->getScaledHeight(mProfile->mFontSize) - mTextMargin ); // If the text is longer then the box size // it will get clipped, force Left Justify @@ -426,7 +426,7 @@ void GuiIconButtonCtrl::renderButton( Point2I &offset, const RectI& updateRect ) start.x = 0; drawer->setBitmapModulation( fontColor ); - drawer->drawText( mProfile->mFont, start + offset, text, mProfile->mFontColors ); + drawer->drawText( mProfile->mFont, start + offset, text, mProfile->mFontSize, mProfile->mFontColors ); } } diff --git a/Engine/source/gui/containers/guiFormCtrl.cpp b/Engine/source/gui/containers/guiFormCtrl.cpp index 3bf3289f47..a0f7e42e06 100644 --- a/Engine/source/gui/containers/guiFormCtrl.cpp +++ b/Engine/source/gui/containers/guiFormCtrl.cpp @@ -140,8 +140,8 @@ bool GuiFormCtrl::onWake() mThumbSize.set( mProfile->mBitmapArrayRects[0].extent.x, mProfile->mBitmapArrayRects[0].extent.y ); mThumbSize.setMax( mProfile->mBitmapArrayRects[1].extent ); - if(mFont->getHeight() > mThumbSize.y) - mThumbSize.y = mFont->getHeight(); + if(mFont->getScaledHeight(mProfile->mFontSize) > mThumbSize.y) + mThumbSize.y = mFont->getScaledHeight(mProfile->mFontSize); } else { @@ -208,7 +208,7 @@ bool GuiFormCtrl::resize(const Point2I &newPosition, const Point2I &newExtent) return false; // Should the caption be modified because the title bar is too small? - S32 textWidth = mProfile->mFont->getStrWidth(mCaption); + S32 textWidth = mProfile->mFont->getStringWidthScaled(mCaption, mProfile->mFontSize); S32 newTextArea = getWidth() - mThumbSize.x - mProfile->mBitmapArrayRects[4].extent.x; if(newTextArea < textWidth) { @@ -224,7 +224,7 @@ bool GuiFormCtrl::resize(const Point2I &newPosition, const Point2I &newExtent) dStrcat(buf, (const char*)mCaption, i); dStrcat(buf, "...", i); - textWidth = mProfile->mFont->getStrWidth(buf); + textWidth = mProfile->mFont->getStringWidthScaled(String::ToString(buf), mProfile->mFontSize); if(textWidth < newTextArea) { diff --git a/Engine/source/gui/containers/guiPaneCtrl.cpp b/Engine/source/gui/containers/guiPaneCtrl.cpp index d646e2f44d..e9cdd54972 100644 --- a/Engine/source/gui/containers/guiPaneCtrl.cpp +++ b/Engine/source/gui/containers/guiPaneCtrl.cpp @@ -117,8 +117,8 @@ bool GuiPaneControl::onWake() mThumbSize.set( mProfile->mBitmapArrayRects[0].extent.x, mProfile->mBitmapArrayRects[0].extent.y ); mThumbSize.setMax( mProfile->mBitmapArrayRects[1].extent ); - if( mProfile->mFont->getHeight() > mThumbSize.y ) - mThumbSize.y = mProfile->mFont->getHeight(); + if( mProfile->mFont->getScaledHeight(mProfile->mFontSize) > mThumbSize.y ) + mThumbSize.y = mProfile->mFont->getScaledHeight(mProfile->mFontSize); } else { @@ -209,6 +209,7 @@ void GuiPaneControl::onRender(Point2I offset, const RectI &updateRect) mProfile->mFont, Point2I(mThumbSize.x, 0) + offset, mCaption, + mProfile->mFontSize, mProfile->mFontColors ); } @@ -266,6 +267,7 @@ void GuiPaneControl::onRender(Point2I offset, const RectI &updateRect) mProfile->mFont, Point2I(mThumbSize.x, 0) + offset, mCaption, + mProfile->mFontSize, mProfile->mFontColors ); } diff --git a/Engine/source/gui/containers/guiTabBookCtrl.cpp b/Engine/source/gui/containers/guiTabBookCtrl.cpp index a9810654ed..a1d5daf9c4 100644 --- a/Engine/source/gui/containers/guiTabBookCtrl.cpp +++ b/Engine/source/gui/containers/guiTabBookCtrl.cpp @@ -632,7 +632,7 @@ S32 GuiTabBookCtrl::calculatePageTabWidth( GuiTabPageCtrl *page ) GFont *font = mProfile->mFont; - return font->getStrNWidth( text, dStrlen(text) ); + return font->getStringWidthScaled( String::ToString(text), mProfile->mFontSize, dStrlen(text) ); } diff --git a/Engine/source/gui/containers/guiWindowCtrl.cpp b/Engine/source/gui/containers/guiWindowCtrl.cpp index bda7b0bfc7..3beeff7213 100644 --- a/Engine/source/gui/containers/guiWindowCtrl.cpp +++ b/Engine/source/gui/containers/guiWindowCtrl.cpp @@ -1385,7 +1385,7 @@ void GuiWindowCtrl::onRender(Point2I offset, const RectI &updateRect) // different color usage here. NOTE: it currently CAN overdraw the controls // if mis-positioned or 'scrunched' in a small width. drawUtil->setBitmapModulation(mProfile->mFontColor); - S32 textWidth = mProfile->mFont->getStrWidth((const UTF8 *)mText); + S32 textWidth = mProfile->mFont->getStringWidthScaled(mText, mProfile->mFontSize); Point2I start(0,0); // Align the horizontal @@ -1398,8 +1398,8 @@ void GuiWindowCtrl::onRender(Point2I offset, const RectI &updateRect) // If the text is longer then the box size, (it'll get clipped) so force Left Justify if( textWidth > winRect.extent.x ) start.set( 0, 0 ); // center the vertical -// start.y = ( winRect.extent.y - ( font->getHeight() - 2 ) ) / 2; - drawUtil->drawText( mProfile->mFont, start + offset + mProfile->mTextOffset, mText ); +// start.y = ( winRect.extent.y - ( font->getScaledHeight(mProfile->mFontSize) - 2 ) ) / 2; + drawUtil->drawText( mProfile->mFont, start + offset + mProfile->mTextOffset, mText, mProfile->mFontSize); // Deal with rendering the titlebar controls AssertFatal(root, "Unable to get the root GuiCanvas."); diff --git a/Engine/source/gui/controls/guiConsole.cpp b/Engine/source/gui/controls/guiConsole.cpp index 3eb81e7e8f..d2397b4f57 100644 --- a/Engine/source/gui/controls/guiConsole.cpp +++ b/Engine/source/gui/controls/guiConsole.cpp @@ -94,7 +94,7 @@ S32 GuiConsole::getMaxWidth(S32 startIndex, S32 endIndex) S32 result = 0; for(S32 i = startIndex; i <= endIndex; i++) - result = getMax(result, (S32)(mFont->getStrWidth((const UTF8 *)mFilteredLog[i].mString))); + result = getMax(result, (S32)(mFont->getStringWidthScaled(mFilteredLog[i].mString, mProfile->mFontSize))); return(result + 6); } @@ -170,7 +170,7 @@ void GuiConsole::onPreRender() //find the max cell width for the new entries S32 newMax = getMaxWidth(prevSize, mFilteredLog.size() - 1); if(newMax > mCellSize.x) - mCellSize.set(newMax, mFont->getHeight()); + mCellSize.set(newMax, mFont->getScaledHeight(mProfile->mFontSize)); //set the array size mSize.set(1, mFilteredLog.size()); @@ -195,7 +195,7 @@ void GuiConsole::onRenderCell(Point2I offset, Point2I cell, bool /*selected*/, b case ConsoleLogEntry::Error: GFX->getDrawUtil()->setBitmapModulation(mProfile->mFontColorNA); break; default: AssertFatal(false, "GuiConsole::onRenderCell - Unrecognized ConsoleLogEntry type, update this."); } - GFX->getDrawUtil()->drawText(mFont, Point2I(offset.x + 3, offset.y), entry.mString, mProfile->mFontColors); + GFX->getDrawUtil()->drawText(mFont, Point2I(offset.x + 3, offset.y), entry.mString, mProfile->mFontSize, mProfile->mFontColors); } //----------------------------------------------------------------------------- @@ -219,7 +219,7 @@ void GuiConsole::setDisplayFilters(bool errors, bool warns, bool normal) //find the max cell width for the new entries S32 newMax = getMaxWidth(0, mFilteredLog.size() - 1); - mCellSize.set(newMax, mFont->getHeight()); + mCellSize.set(newMax, mFont->getScaledHeight(mProfile->mFontSize)); //set the array size mSize.set(1, mFilteredLog.size()); @@ -281,4 +281,4 @@ DefineEngineMethod(GuiConsole, refresh, void, (), , "Refreshes the displayed messages.") { object->refresh(); -} \ No newline at end of file +} diff --git a/Engine/source/gui/controls/guiConsoleTextCtrl.cpp b/Engine/source/gui/controls/guiConsoleTextCtrl.cpp index 81241e32ec..679eb25516 100644 --- a/Engine/source/gui/controls/guiConsoleTextCtrl.cpp +++ b/Engine/source/gui/controls/guiConsoleTextCtrl.cpp @@ -98,14 +98,14 @@ void GuiConsoleTextCtrl::calcResize() U32 ctrlWidth = 0; for ( U32 i = 0; i < mLineLen.size(); i++ ) { - U32 width = mFont->getStrNWidth( mResult.c_str() + mStartLineOffset[i], mLineLen[i] ); + U32 width = mFont->getStringWidthScaled( String::ToString(mResult.c_str() + mStartLineOffset[i]), mProfile->mFontSize, mLineLen[i] ); if ( width > ctrlWidth ) ctrlWidth = width; } // The height is the number of lines times the height of the font. - U32 ctrlHeight = mLineLen.size() * mFont->getHeight(); + U32 ctrlHeight = mLineLen.size() * mFont->getScaledHeight(mProfile->mFontSize); setExtent( Point2I( ctrlWidth, ctrlHeight ) + mProfile->mTextOffset * 2 ); } @@ -122,7 +122,7 @@ void GuiConsoleTextCtrl::onPreRender() // Of the resulting string we will be printing, // Find the number of lines and length of each. - mProfile->mFont->wrapString( mResult, U32_MAX, mStartLineOffset, mLineLen ); + mProfile->mFont->wrapStringScaled( mResult, U32_MAX, mProfile->mFontSize, mStartLineOffset, mLineLen ); } else mResult = String::EmptyString; @@ -153,11 +153,11 @@ void GuiConsoleTextCtrl::onRender( Point2I offset, const RectI &updateRect ) { Point2I tempOffset = offset; tempOffset += mProfile->mTextOffset; - tempOffset.y += i * font->getHeight(); + tempOffset.y += i * font->getScaledHeight(mProfile->mFontSize); const UTF8 *line = mResult.c_str() + mStartLineOffset[i]; U32 lineLen = mLineLen[i]; - GFX->getDrawUtil()->drawTextN( font, tempOffset, line, lineLen, mProfile->mFontColors ); + GFX->getDrawUtil()->drawTextN( font, tempOffset, line, lineLen, mProfile->mFontSize, mProfile->mFontColors ); } } diff --git a/Engine/source/gui/controls/guiGameListMenuCtrl.cpp b/Engine/source/gui/controls/guiGameListMenuCtrl.cpp index 4637a22852..8f45d0459d 100644 --- a/Engine/source/gui/controls/guiGameListMenuCtrl.cpp +++ b/Engine/source/gui/controls/guiGameListMenuCtrl.cpp @@ -239,7 +239,7 @@ void GuiGameListMenuCtrl::onRenderListOption(Row* row, Point2I currentOffset) // calculate text to be at the center between the arrows GFont* font = profile->mFont; StringTableEntry text = row->mOptions[row->mSelectedOption].mDisplayText; - S32 textWidth = font->getStrWidth(text); + S32 textWidth = font->getStringWidthScaled(String::ToString(text), profile->mFontSize); S32 columnWidth = profile->mHitAreaLowerRight.x * xScale - profile->mRightPad - columnSplit; S32 columnCenter = columnSplit + (columnWidth >> 1); S32 textStartX = columnCenter - (textWidth >> 1); @@ -363,7 +363,7 @@ void GuiGameListMenuCtrl::onRenderSliderOption(Row* row, Point2I currentOffset) char stringVal[32]; dSprintf(stringVal, 32, "%f", row->mValue); - S32 textWidth = font->getStrWidth(stringVal); + S32 textWidth = font->getStringWidthScaled(String::ToString(stringVal), profile->mFontSize); S32 columnWidth = profile->mHitAreaLowerRight.x * xScale - profile->mRightPad - columnSplit; S32 columnCenter = columnSplit + (columnWidth >> 1); S32 textStartX = columnCenter - (textWidth >> 1); diff --git a/Engine/source/gui/controls/guiGameListOptionsCtrl.cpp b/Engine/source/gui/controls/guiGameListOptionsCtrl.cpp index f4d40ebe6a..9e0b6d25b1 100644 --- a/Engine/source/gui/controls/guiGameListOptionsCtrl.cpp +++ b/Engine/source/gui/controls/guiGameListOptionsCtrl.cpp @@ -145,7 +145,7 @@ void GuiGameListOptionsCtrl::onRender(Point2I offset, const RectI &updateRect) // calculate text to be at the center between the arrows GFont * font = profile->mFont; StringTableEntry text = myRow->mOptions[myRow->mSelectedOption]; - S32 textWidth = font->getStrWidth(text); + S32 textWidth = font->getStringWidthScaled(String::ToString(text), profile->mFontSize); S32 columnWidth = profile->mHitAreaLowerRight.x * xScale - profile->mRightPad - columnSplit; S32 columnCenter = columnSplit + (columnWidth >> 1); S32 textStartX = columnCenter - (textWidth >> 1); diff --git a/Engine/source/gui/controls/guiGameSettingsCtrl.cpp b/Engine/source/gui/controls/guiGameSettingsCtrl.cpp index fff03c24bf..b64de5d55a 100644 --- a/Engine/source/gui/controls/guiGameSettingsCtrl.cpp +++ b/Engine/source/gui/controls/guiGameSettingsCtrl.cpp @@ -249,7 +249,7 @@ void GuiGameSettingsCtrl::onRenderListOption(Point2I currentOffset) // calculate text to be at the center between the arrows GFont* font = mProfile->mFont; StringTableEntry text = mOptions[mSelectedOption].mDisplayText; - S32 textWidth = font->getStrWidth(text); + S32 textWidth = font->getStringWidthScaled(String::ToString(text), mProfile->mFontSize); S32 columnWidth = xScale - mRightPad - mColumnSplit; S32 columnCenter = mColumnSplit + (columnWidth >> 1); S32 textStartX = columnCenter - (textWidth >> 1); @@ -339,7 +339,7 @@ void GuiGameSettingsCtrl::onRenderSliderOption(Point2I currentOffset) char stringVal[32]; dSprintf(stringVal, 32, "%.1f", mValue); - //S32 stringWidth = font->getStrWidth(stringVal); //adaptive width + //S32 stringWidth = font->getStringWidthScaled(String::ToString(stringVal), mProfile->mFontSize); //adaptive width Point2I textOffset(sliderRect.point.x + sliderRect.extent.x, 0); // render the option text itself diff --git a/Engine/source/gui/controls/guiListBoxCtrl.cpp b/Engine/source/gui/controls/guiListBoxCtrl.cpp index 66328b2b33..4a3c78a70f 100644 --- a/Engine/source/gui/controls/guiListBoxCtrl.cpp +++ b/Engine/source/gui/controls/guiListBoxCtrl.cpp @@ -1014,14 +1014,14 @@ void GuiListBoxCtrl::updateSize() S32 maxWidth = 1; for ( U32 i = 0; i < mItems.size(); i++ ) { - S32 width = font->getStrWidth( mItems[i]->itemText ); + S32 width = font->getStringWidthScaled( String::ToString(mItems[i]->itemText), mProfile->mFontSize); if( width > maxWidth ) maxWidth = width; } mItemSize.x = maxWidth + 6; } - mItemSize.y = font->getHeight() + 2; + mItemSize.y = font->getScaledHeight(mProfile->mFontSize) + 2; Point2I newExtent( mItemSize.x, mItemSize.y * mItems.size() ); setExtent( newExtent ); diff --git a/Engine/source/gui/controls/guiMLTextCtrl.cpp b/Engine/source/gui/controls/guiMLTextCtrl.cpp index 34e5e4100e..d08fd6b766 100644 --- a/Engine/source/gui/controls/guiMLTextCtrl.cpp +++ b/Engine/source/gui/controls/guiMLTextCtrl.cpp @@ -369,11 +369,13 @@ void GuiMLTextCtrl::onPreRender() void GuiMLTextCtrl::drawAtomText(bool sel, U32 start, U32 end, Atom *atom, Line *line, Point2I offset) { GFont *font = atom->style->font->fontRes; + U32 fontSize = atom->style->font->size; + U32 xOff = 0; if(start != atom->textStart) { const UTF16* buff = mTextBuffer.getPtr() + atom->textStart; - xOff += font->getStrNWidth(buff, start - atom->textStart); + xOff += font->getStringWidthScaled(String::ToString(buff), fontSize, start - atom->textStart); } Point2I drawPoint(offset.x + atom->xStart + xOff, offset.y + atom->yStart); @@ -402,19 +404,19 @@ void GuiMLTextCtrl::drawAtomText(bool sel, U32 start, U32 end, Atom *atom, Line shadowColor.alpha = (S32)(mAlpha * shadowColor.alpha); drawer->setBitmapModulation(shadowColor); drawer->drawTextN(font, drawPoint + atom->style->shadowOffset, - tmp, tmpLen, mAllowColorChars ? mProfile->mFontColors : NULL); + tmp, tmpLen, fontSize, mAllowColorChars ? mProfile->mFontColors : NULL); } color.alpha = (S32)(mAlpha * color.alpha); drawer->setBitmapModulation(color); - drawer->drawTextN(font, drawPoint, tmp, end-start, mAllowColorChars ? mProfile->mFontColors : NULL); + drawer->drawTextN(font, drawPoint, tmp, end-start, fontSize, mAllowColorChars ? mProfile->mFontColors : NULL); //if the atom was "clipped", see if we need to draw a "..." at the end if (atom->isClipped) { Point2I p2 = drawPoint; - p2.x += font->getStrNWidthPrecise(tmp, tmpLen); - drawer->drawTextN(font, p2, "...", 3, mAllowColorChars ? mProfile->mFontColors : NULL); + p2.x += font->getStringWidthScaledPrecise(String::ToString(tmp), fontSize, tmpLen); + drawer->drawTextN(font, p2, "...", 3, fontSize, mAllowColorChars ? mProfile->mFontColors : NULL); } } else @@ -422,19 +424,19 @@ void GuiMLTextCtrl::drawAtomText(bool sel, U32 start, U32 end, Atom *atom, Line RectI rect; rect.point.x = drawPoint.x; rect.point.y = line->y + offset.y; - rect.extent.x = font->getStrNWidth(tmp, tmpLen) + 1; + rect.extent.x = font->getStringWidthScaled(String::ToString(tmp), fontSize, tmpLen) + 1; rect.extent.y = line->height + 1; drawer->drawRectFill(rect, mProfile->mFillColorHL); drawer->setBitmapModulation( mProfile->mFontColorHL ); // over-ride atom color: - drawer->drawTextN(font, drawPoint, tmp, tmpLen, mAllowColorChars ? mProfile->mFontColors : NULL); + drawer->drawTextN(font, drawPoint, tmp, tmpLen, fontSize, mAllowColorChars ? mProfile->mFontColors : NULL); //if the atom was "clipped", see if we need to draw a "..." at the end if (atom->isClipped) { Point2I p2 = drawPoint; - p2.x += font->getStrNWidthPrecise(tmp, end - atom->textStart); - drawer->drawTextN(font, p2, "...", 3, mAllowColorChars ? mProfile->mFontColors : NULL); + p2.x += font->getStringWidthScaledPrecise(String::ToString(tmp), fontSize, end - atom->textStart); + drawer->drawTextN(font, p2, "...", 3, fontSize, mAllowColorChars ? mProfile->mFontColors : NULL); } } @@ -442,7 +444,7 @@ void GuiMLTextCtrl::drawAtomText(bool sel, U32 start, U32 end, Atom *atom, Line { drawPoint.y += atom->baseLine + 2; Point2I p2 = drawPoint; - p2.x += font->getStrNWidthPrecise(tmp, end - atom->textStart); + p2.x += font->getStringWidthScaledPrecise(String::ToString(tmp), fontSize, end - atom->textStart); drawer->drawLine(drawPoint, p2, color); } } @@ -715,7 +717,7 @@ void GuiMLTextCtrl::getCursorPositionAndColor(Point2I &cursorTop, Point2I &curso { S32 x = 0; S32 y = 0; - S32 height = (mProfile && mProfile->mFont) ? mProfile->mFont->getHeight() : 0; + S32 height = (mProfile && mProfile->mFont) ? mProfile->mFont->getScaledHeight(mProfile->mFontSize) : 0; color = mProfile->mCursorColor; for(Line *walk = mLineList; walk; walk = walk->next) { @@ -743,9 +745,10 @@ void GuiMLTextCtrl::getCursorPositionAndColor(Point2I &cursorTop, Point2I &curso // it's in the text block... x = awalk->xStart; GFont *font = awalk->style->font->fontRes; + U32 fontSize = awalk->style->font->size; const UTF16* buff = mTextBuffer.getPtr() + awalk->textStart; - x += font->getStrNWidth(buff, mCursorPosition - awalk->textStart);// - 1); + x += font->getStringWidthScaled(String::ToString(buff), fontSize, mCursorPosition - awalk->textStart);// - 1); color = awalk->style->color; goto done; @@ -1138,9 +1141,10 @@ S32 GuiMLTextCtrl::getTextPosition(const Point2I& localCoords) continue; // it's in the text block... GFont *font = awalk->style->font->fontRes; + U32 fontSize = awalk->style->font->size; const UTF16 *tmp16 = mTextBuffer.getPtr() + awalk->textStart; - U32 bp = font->getBreakPos(tmp16, awalk->len, localCoords.x - awalk->xStart, false); + U32 bp = font->getBreakPosScaled(tmp16, awalk->len, localCoords.x - awalk->xStart, fontSize, false); return awalk->textStart + bp; } return walk->textStart + walk->len; @@ -1158,6 +1162,13 @@ GuiMLTextCtrl::Font *GuiMLTextCtrl::allocFont(const char *faceName, U32 faceName !dStrncmp(walk->faceName, faceName, faceNameLen) && size == walk->size) return walk; + + F32 dpiScaling = 1.0f; + GuiCanvas* cv = dynamic_cast(Sim::findObject("Canvas")); + if (cv) + { + dpiScaling = cv->getDpiScalingFactor(); + } // Create! Font *ret; @@ -1166,9 +1177,9 @@ GuiMLTextCtrl::Font *GuiMLTextCtrl::allocFont(const char *faceName, U32 faceName dStrncpy(ret->faceName, faceName, faceNameLen); ret->faceName[faceNameLen] = '\0'; ret->faceNameLen = faceNameLen; - ret->size = size; + ret->size = size * dpiScaling; ret->next = mFontList; - ret->fontRes = GFont::create(ret->faceName, size, GuiControlProfile::sFontCacheDirectory); + ret->fontRes = GFont::create(ret->faceName, GuiControlProfile::sFontCacheDirectory); if(ret->fontRes != NULL) { ret->next = mFontList; @@ -1233,7 +1244,7 @@ void GuiMLTextCtrl::emitNewLine(U32 textStart) mCurClipX = 0; Line *l = (Line *) mViewChunker.alloc(sizeof(Line)); - l->height = mCurStyle->font->fontRes->getHeight(); + l->height = mCurStyle->font->fontRes->getScaledHeight(mCurStyle->font->size); l->y = mCurY; l->textStart = mLineStart; l->len = textStart - l->textStart; @@ -1371,8 +1382,8 @@ void GuiMLTextCtrl::emitTextToken(U32 textStart, U32 len) a->style = mCurStyle; mCurStyle->used = true; - a->baseLine = font->getBaseline(); - a->descent = font->getDescent(); + a->baseLine = font->getScaledBaseline(a->style->font->size); + a->descent = font->getScaledDescent(a->style->font->size); a->textStart = textStart; a->len = len; a->isClipped = false; @@ -1463,6 +1474,7 @@ GuiMLTextCtrl::Atom *GuiMLTextCtrl::splitAtomListEmit(Atom *list, U32 width) while(list) { GFont *font = list->style->font->fontRes; + U32 fontSize = list->style->font->size; U32 breakPos; const UTF16 *tmp16 = mTextBuffer.getPtr() + list->textStart; @@ -1472,7 +1484,7 @@ GuiMLTextCtrl::Atom *GuiMLTextCtrl::splitAtomListEmit(Atom *list, U32 width) if (mCurClipX > 0) { //find out how many character's fit within the given width - breakPos = font->getBreakPos(tmp16, list->len, width - totalWidth, false); + breakPos = font->getBreakPosScaled(tmp16, list->len, width - totalWidth, fontSize, false); //if there isn't room for even the first character... if (breakPos == 0) @@ -1486,8 +1498,8 @@ GuiMLTextCtrl::Atom *GuiMLTextCtrl::splitAtomListEmit(Atom *list, U32 width) //if our text doesn't fit within the clip region, add a "..." else if (breakPos != list->len) { - U32 etcWidth = font->getStrNWidthPrecise("...", 3); - breakPos = font->getBreakPos(tmp16, list->len, width - totalWidth - etcWidth, false); + U32 etcWidth = font->getStringWidthScaledPrecise("...", fontSize, 3); + breakPos = font->getBreakPosScaled(tmp16, list->len, width - totalWidth - etcWidth,fontSize, false); //again, if there isn't even room for a single character before the "...." if (breakPos == 0) @@ -1513,7 +1525,7 @@ GuiMLTextCtrl::Atom *GuiMLTextCtrl::splitAtomListEmit(Atom *list, U32 width) else { //set the atom width == to the string length - list->width = font->getStrNWidthPrecise(tmp16, breakPos); + list->width = font->getStringWidthScaledPrecise(String::ToString(tmp16), fontSize, breakPos); //set the pointer to the last atom that fit within the clip region clipAtom = list; @@ -1521,12 +1533,12 @@ GuiMLTextCtrl::Atom *GuiMLTextCtrl::splitAtomListEmit(Atom *list, U32 width) } else { - breakPos = font->getBreakPos(tmp16, list->len, width - totalWidth, true); + breakPos = font->getBreakPosScaled(tmp16, list->len, width - totalWidth, fontSize, true); if(breakPos == 0 || (breakPos < list->len && mTextBuffer.getChar(list->textStart + breakPos - 1)!= ' ' && emitted)) break; //set the atom width == to the string length - list->width = font->getStrNWidthPrecise(tmp16, breakPos); + list->width = font->getStringWidthScaledPrecise(String::ToString(tmp16), fontSize, breakPos); } //update the total width @@ -1565,13 +1577,14 @@ GuiMLTextCtrl::Atom *GuiMLTextCtrl::splitAtomListEmit(Atom *list, U32 width) if (adjustClipAtom && clipAtom) { GFont *font = clipAtom->style->font->fontRes; + U32 fontSize = clipAtom->style->font->size; U32 breakPos; - U32 etcWidth = font->getStrNWidthPrecise("...", 3); + U32 etcWidth = font->getStringWidthScaledPrecise("...", fontSize, 3); const UTF16 *tmp16 = mTextBuffer.getPtr() + clipAtom->textStart; - breakPos = font->getBreakPos(tmp16, clipAtom->len, clipAtom->width - etcWidth, false); + breakPos = font->getBreakPosScaled(tmp16, clipAtom->len, clipAtom->width - etcWidth, fontSize, false); if (breakPos != 0) { clipAtom->isClipped = true; @@ -2196,6 +2209,7 @@ char* GuiMLTextCtrl::stripControlChars(const char *inString) { if (! bool(inString)) return NULL; + U32 maxBufLength = 64; char *strippedBuffer = Con::getReturnBuffer(maxBufLength); char *stripBufPtr = &strippedBuffer[0]; diff --git a/Engine/source/gui/controls/guiPopUpCtrl.cpp b/Engine/source/gui/controls/guiPopUpCtrl.cpp index ad4fafe4e7..57153bb605 100644 --- a/Engine/source/gui/controls/guiPopUpCtrl.cpp +++ b/Engine/source/gui/controls/guiPopUpCtrl.cpp @@ -213,17 +213,17 @@ void GuiPopupTextListCtrl::onRenderCell(Point2I offset, Point2I cell, bool selec // Draw the first column getColumn(mList[cell.y].text, buff, 0, "\t"); - GFX->getDrawUtil()->drawText( mFont, Point2I( textXOffset, offset.y ), buff ); // Used mTextOffset as a margin for the text list rather than the hard coded value of '4'. + GFX->getDrawUtil()->drawText( mFont, Point2I( textXOffset, offset.y ), buff, mProfile->mFontSize); // Used mTextOffset as a margin for the text list rather than the hard coded value of '4'. // Draw the second column to the right getColumn(mList[cell.y].text, buff, 1, "\t"); - S32 txt_w = mFont->getStrWidth(buff); + S32 txt_w = mFont->getStringWidthScaled(String::ToString(buff), mProfile->mFontSize); - GFX->getDrawUtil()->drawText( mFont, Point2I( offset.x+size.x-mProfile->mTextOffset.x-txt_w, offset.y ), buff ); // Used mTextOffset as a margin for the text list rather than the hard coded value of '4'. + GFX->getDrawUtil()->drawText( mFont, Point2I( offset.x+size.x-mProfile->mTextOffset.x-txt_w, offset.y ), buff, mProfile->mFontSize); // Used mTextOffset as a margin for the text list rather than the hard coded value of '4'. } else { - GFX->getDrawUtil()->drawText( mFont, Point2I( textXOffset, offset.y ), mList[cell.y].text ); // Used mTextOffset as a margin for the text list rather than the hard coded value of '4'. + GFX->getDrawUtil()->drawText( mFont, Point2I( textXOffset, offset.y ), mList[cell.y].text, mProfile->mFontSize); // Used mTextOffset as a margin for the text list rather than the hard coded value of '4'. } } @@ -1005,9 +1005,9 @@ void GuiPopUpMenuCtrl::onRender( Point2I offset, const RectI &updateRect ) } // renderSlightlyRaisedBox(r, mProfile); // Used to be the only 'else' condition to mInAction above. - S32 txt_w = mProfile->mFont->getStrWidth(mText); + S32 txt_w = mProfile->mFont->getStringWidthScaled(String::ToString(mText), mProfile->mFontSize); localStart.x = 0; - localStart.y = (getHeight() - (mProfile->mFont->getHeight())) / 2; + localStart.y = (getHeight() - (mProfile->mFont->getScaledHeight(mProfile->mFontSize))) / 2; // align the horizontal switch (mProfile->mAlignment) @@ -1092,28 +1092,28 @@ void GuiPopUpMenuCtrl::onRender( Point2I offset, const RectI &updateRect ) // Draw the first column getColumn( mText, buff, 0, "\t" ); - drawUtil->drawText( mProfile->mFont, globalStart, buff, mProfile->mFontColors ); + drawUtil->drawText( mProfile->mFont, globalStart, buff, mProfile->mFontSize, mProfile->mFontColors ); // Draw the second column to the right getColumn( mText, buff, 1, "\t" ); - S32 colTxt_w = mProfile->mFont->getStrWidth( buff ); + S32 colTxt_w = mProfile->mFont->getStringWidthScaled(String::ToString(buff), mProfile->mFontSize); if ( mProfile->getChildrenProfile() && !mProfile->mBitmapArrayRects.empty()) { // We're making use of a bitmap border, so take into account the // right cap of the border. RectI* bitmapBounds = mProfile->mBitmapArrayRects.address(); Point2I textpos = localToGlobalCoord( Point2I( getWidth() - colTxt_w - bitmapBounds[2].extent.x, localStart.y ) ); - drawUtil->drawText( mProfile->mFont, textpos, buff, mProfile->mFontColors ); + drawUtil->drawText( mProfile->mFont, textpos, buff, mProfile->mFontSize, mProfile->mFontColors ); } else { Point2I textpos = localToGlobalCoord( Point2I( getWidth() - colTxt_w - 12, localStart.y ) ); - drawUtil->drawText( mProfile->mFont, textpos, buff, mProfile->mFontColors ); + drawUtil->drawText( mProfile->mFont, textpos, buff, mProfile->mFontSize, mProfile->mFontColors ); } } else { - drawUtil->drawText( mProfile->mFont, globalStart, mText, mProfile->mFontColors ); + drawUtil->drawText( mProfile->mFont, globalStart, mText, mProfile->mFontSize, mProfile->mFontColors ); } // If we're rendering a bitmap border, then it will take care of the arrow. @@ -1233,8 +1233,8 @@ void GuiPopUpMenuCtrl::onAction() bool setScroll = false; for ( U32 i = 0; i < mEntries.size(); ++i ) - if ( S32(mProfile->mFont->getStrWidth( mEntries[i].buf )) > textWidth ) - textWidth = mProfile->mFont->getStrWidth( mEntries[i].buf ); + if ( S32(mProfile->mFont->getStringWidthScaled( String::ToString(mEntries[i].buf), mProfile->mFontSize )) > textWidth ) + textWidth = mProfile->mFont->getStringWidthScaled(String::ToString(mEntries[i].buf), mProfile->mFontSize); S32 sbWidth = mSc->getControlProfile()->mBorderThickness * 2 + mSc->scrollBarThickness(); // Calculate the scroll bar width if ( textWidth > ( getWidth() - sbWidth-mProfile->mTextOffset.x - mSc->getChildMargin().x * 2 ) ) // The text draw area to test against is the width of the drop-down minus the scroll bar width, the text margin and the scroll bar child margins. @@ -1248,7 +1248,7 @@ void GuiPopUpMenuCtrl::onAction() width += textSpace; } - mTl->setCellSize(Point2I(width, mProfile->mFont->getHeight() + textSpace)); + mTl->setCellSize(Point2I(width, mProfile->mFont->getScaledHeight(mProfile->mFontSize) + textSpace)); for ( U32 j = 0; j < mEntries.size(); ++j ) mTl->addEntry( mEntries[j].id, mEntries[j].buf ); diff --git a/Engine/source/gui/controls/guiPopUpCtrlEx.cpp b/Engine/source/gui/controls/guiPopUpCtrlEx.cpp index 45183285d0..4e39efd682 100644 --- a/Engine/source/gui/controls/guiPopUpCtrlEx.cpp +++ b/Engine/source/gui/controls/guiPopUpCtrlEx.cpp @@ -288,20 +288,20 @@ void GuiPopupTextListCtrlEx::onRenderCell(Point2I offset, Point2I cell, bool sel // Draw the first column getColumn(mList[cell.y].text, buff, 0, "\t"); - GFX->getDrawUtil()->drawText( mFont, Point2I( textXOffset, offset.y ), buff ); // Used mTextOffset as a margin for the text list rather than the hard coded value of '4'. + GFX->getDrawUtil()->drawText( mFont, Point2I( textXOffset, offset.y ), buff, mProfile->mFontSize); // Used mTextOffset as a margin for the text list rather than the hard coded value of '4'. // Draw the second column to the right getColumn(mList[cell.y].text, buff, 1, "\t"); - S32 txt_w = mFont->getStrWidth(buff); + S32 txt_w = mFont->getStringWidthScaled(String::ToString(buff), mProfile->mFontSize); - GFX->getDrawUtil()->drawText( mFont, Point2I( offset.x+size.x-mProfile->mTextOffset.x-txt_w, offset.y ), buff ); // Used mTextOffset as a margin for the text list rather than the hard coded value of '4'. + GFX->getDrawUtil()->drawText( mFont, Point2I( offset.x+size.x-mProfile->mTextOffset.x-txt_w, offset.y ), buff, mProfile->mFontSize); // Used mTextOffset as a margin for the text list rather than the hard coded value of '4'. } else { if ((mList[cell.y].id == -2) || (!hasCategories())) - GFX->getDrawUtil()->drawText( mFont, Point2I( textXOffset, offset.y ), mList[cell.y].text ); // Used mTextOffset as a margin for the text list rather than the hard coded value of '4'. + GFX->getDrawUtil()->drawText( mFont, Point2I( textXOffset, offset.y ), mList[cell.y].text, mProfile->mFontSize); // Used mTextOffset as a margin for the text list rather than the hard coded value of '4'. else - GFX->getDrawUtil()->drawText( mFont, Point2I( textXOffset + 8, offset.y ), mList[cell.y].text ); // Used mTextOffset as a margin for the text list rather than the hard coded value of '4'. + GFX->getDrawUtil()->drawText( mFont, Point2I( textXOffset + 8, offset.y ), mList[cell.y].text, mProfile->mFontSize); // Used mTextOffset as a margin for the text list rather than the hard coded value of '4'. } } @@ -1185,9 +1185,9 @@ void GuiPopUpMenuCtrlEx::onRender(Point2I offset, const RectI &updateRect) } // renderSlightlyRaisedBox(r, mProfile); // Used to be the only 'else' condition to mInAction above. - S32 txt_w = mProfile->mFont->getStrWidth(mText); + S32 txt_w = mProfile->mFont->getStringWidthScaled(String::ToString(mText), mProfile->mFontSize); localStart.x = 0; - localStart.y = (getHeight() - (mProfile->mFont->getHeight())) / 2; + localStart.y = (getHeight() - (mProfile->mFont->getScaledHeight(mProfile->mFontSize))) / 2; // align the horizontal switch (mProfile->mAlignment) @@ -1272,28 +1272,28 @@ void GuiPopUpMenuCtrlEx::onRender(Point2I offset, const RectI &updateRect) // Draw the first column getColumn( mText, buff, 0, "\t" ); - drawUtil->drawText( mProfile->mFont, globalStart, buff, mProfile->mFontColors ); + drawUtil->drawText( mProfile->mFont, globalStart, buff, mProfile->mFontSize, mProfile->mFontColors ); // Draw the second column to the right getColumn( mText, buff, 1, "\t" ); - S32 colTxt_w = mProfile->mFont->getStrWidth( buff ); + S32 colTxt_w = mProfile->mFont->getStringWidthScaled(String::ToString(buff), mProfile->mFontSize); if ( mProfile->getChildrenProfile() && mProfile->mBitmapArrayRects.size() ) { // We're making use of a bitmap border, so take into account the // right cap of the border. RectI* bitmapBounds = mProfile->mBitmapArrayRects.address(); Point2I textpos = localToGlobalCoord( Point2I( getWidth() - colTxt_w - bitmapBounds[2].extent.x, localStart.y ) ); - drawUtil->drawText( mProfile->mFont, textpos, buff, mProfile->mFontColors ); + drawUtil->drawText( mProfile->mFont, textpos, buff, mProfile->mFontSize, mProfile->mFontColors ); } else { Point2I textpos = localToGlobalCoord( Point2I( getWidth() - colTxt_w - 12, localStart.y ) ); - drawUtil->drawText( mProfile->mFont, textpos, buff, mProfile->mFontColors ); + drawUtil->drawText( mProfile->mFont, textpos, buff, mProfile->mFontSize, mProfile->mFontColors ); } } else { - drawUtil->drawText( mProfile->mFont, globalStart, mText, mProfile->mFontColors ); + drawUtil->drawText( mProfile->mFont, globalStart, mText, mProfile->mFontSize, mProfile->mFontColors ); } // If we're rendering a bitmap border, then it will take care of the arrow. @@ -1435,8 +1435,8 @@ void GuiPopUpMenuCtrlEx::onAction() bool setScroll = false; for ( U32 i = 0; i < mEntries.size(); ++i ) - if ( S32(mProfile->mFont->getStrWidth( mEntries[i].buf )) > textWidth ) - textWidth = mProfile->mFont->getStrWidth( mEntries[i].buf ); + if ( S32(mProfile->mFont->getStringWidthScaled(String::ToString(mEntries[i].buf), mProfile->mFontSize)) > textWidth ) + textWidth = mProfile->mFont->getStringWidthScaled(String::ToString(mEntries[i].buf), mProfile->mFontSize); //if(textWidth > getWidth()) S32 sbWidth = mSc->getControlProfile()->mBorderThickness * 2 + mSc->scrollBarThickness(); // Calculate the scroll bar width @@ -1452,8 +1452,8 @@ void GuiPopUpMenuCtrlEx::onAction() width += textSpace; } - //mTl->setCellSize(Point2I(width, mFont->getHeight()+3)); - mTl->setCellSize(Point2I(width, mProfile->mFont->getHeight() + textSpace)); // Modified the above line to use textSpace rather than the '3' as this is what is used below. + //mTl->setCellSize(Point2I(width, mFont->getScaledHeight(mProfile->mFontSize)+3)); + mTl->setCellSize(Point2I(width, mProfile->mFont->getScaledHeight(mProfile->mFontSize) + textSpace)); // Modified the above line to use textSpace rather than the '3' as this is what is used below. mTl->clear(); for (U32 j = 0; j < mEntries.size(); ++j) @@ -1504,7 +1504,7 @@ void GuiPopUpMenuCtrlEx::onAction() //Calc for the width of the scroll bar // if(textWidth >= width) // width += 20; - // mTl->setCellSize(Point2I(width,mFont->getHeight() + textSpace)); + // mTl->setCellSize(Point2I(width,mFont->getScaledHeight(mProfile->mFontSize) + textSpace)); //Pop menu list above the button // scrollPoint.set(pointInGC.x, menuSpace - 1); // Removed as calculated outside the 'if', and was wrong to begin with @@ -1529,7 +1529,7 @@ void GuiPopUpMenuCtrlEx::onAction() //Calc for the width of the scroll bar // if(textWidth >= width) // width += 20; - // mTl->setCellSize(Point2I(width,mFont->getHeight() + textSpace)); + // mTl->setCellSize(Point2I(width,mFont->getScaledHeight(mProfile->mFontSize) + textSpace)); setScroll = true; } } diff --git a/Engine/source/gui/controls/guiSliderCtrl.cpp b/Engine/source/gui/controls/guiSliderCtrl.cpp index c5f4a90b6d..c3ee00095e 100644 --- a/Engine/source/gui/controls/guiSliderCtrl.cpp +++ b/Engine/source/gui/controls/guiSliderCtrl.cpp @@ -184,7 +184,7 @@ bool GuiSliderCtrl::onWake() // mouse scroll increment percentage is 5% of the range mIncAmount = ( ( mRange.y - mRange.x ) * 0.05 ); - if( ( mThumbSize.y + mProfile->mFont->getHeight() - 4 ) <= getExtent().y ) + if( ( mThumbSize.y + mProfile->mFont->getScaledHeight(mProfile->mFontSize) - 4 ) <= getExtent().y ) mDisplayValue = true; else mDisplayValue = false; @@ -513,7 +513,7 @@ void GuiSliderCtrl::onRender(Point2I offset, const RectI &updateRect) Point2I textStart = thumb.point; - S32 txt_w = mProfile->mFont->getStrWidth((const UTF8 *)buf); + S32 txt_w = mProfile->mFont->getStringWidthScaled(String::ToString(buf), mProfile->mFontSize); textStart.x += (S32)((thumb.extent.x/2.0f)); textStart.y += thumb.extent.y - 2; //19 @@ -524,7 +524,7 @@ void GuiSliderCtrl::onRender(Point2I offset, const RectI &updateRect) textStart.x -=((textStart.x + txt_w) - (offset.x+getWidth())); drawUtil->setBitmapModulation(mProfile->mFontColor); - drawUtil->drawText(mProfile->mFont, textStart, buf, mProfile->mFontColors); + drawUtil->drawText(mProfile->mFont, textStart, buf, mProfile->mFontSize, mProfile->mFontColors); } renderChildControls(offset, updateRect); } diff --git a/Engine/source/gui/controls/guiTextCtrl.cpp b/Engine/source/gui/controls/guiTextCtrl.cpp index 00b2bac2c9..4be6cf0b75 100644 --- a/Engine/source/gui/controls/guiTextCtrl.cpp +++ b/Engine/source/gui/controls/guiTextCtrl.cpp @@ -175,9 +175,9 @@ void GuiTextCtrl::autoResize() Point2I newExtents = getExtent(); if ( mProfile->mAutoSizeWidth ) - newExtents.x = mProfile->mFont->getStrWidth((const UTF8 *) mText ); + newExtents.x = mProfile->mFont->getStringWidthScaled(String::ToString(mText), mProfile->mFontSize); if ( mProfile->mAutoSizeHeight ) - newExtents.y = mProfile->mFont->getHeight() + 4; + newExtents.y = mProfile->mFont->getScaledHeight(mProfile->mFontSize) + 4; setExtent( newExtents ); } diff --git a/Engine/source/gui/controls/guiTextEditCtrl.cpp b/Engine/source/gui/controls/guiTextEditCtrl.cpp index ea30740b54..544b6ac2d0 100644 --- a/Engine/source/gui/controls/guiTextEditCtrl.cpp +++ b/Engine/source/gui/controls/guiTextEditCtrl.cpp @@ -374,9 +374,9 @@ S32 GuiTextEditCtrl::calculateCursorPos( const Point2I &globalPos ) continue; if(mPasswordText) - charLength += mProfile->mFont->getCharXIncrement( mPasswordMask[0] ); + charLength += mProfile->mFont->getCharXIncrementScaled( mPasswordMask[0], mProfile->mFontSize); else - charLength += mProfile->mFont->getCharXIncrement( c ); + charLength += mProfile->mFont->getCharXIncrementScaled( c, mProfile->mFontSize); if ( charLength > curX ) break; @@ -1278,11 +1278,11 @@ void GuiTextEditCtrl::drawText( const RectI &drawRect, bool isFocused ) paddingRightBottom = paddingLeftTop; // Center vertically: - drawPoint.y += ( ( drawRect.extent.y - paddingLeftTop.y - paddingRightBottom.y - S32( mProfile->mFont->getHeight() ) ) / 2 ) + paddingLeftTop.y; + drawPoint.y += ( ( drawRect.extent.y - paddingLeftTop.y - paddingRightBottom.y - S32( mProfile->mFont->getScaledHeight(mProfile->mFontSize) ) ) / 2 ) + paddingLeftTop.y; // Align horizontally: - S32 textWidth = mProfile->mFont->getStrNWidth(textBuffer.getPtr(), textBuffer.length()); + S32 textWidth = mProfile->mFont->getStringWidthScaled(String::ToString(textBuffer.getPtr()), mProfile->mFontSize, textBuffer.length()); switch( mProfile->mAlignment ) { @@ -1331,13 +1331,13 @@ void GuiTextEditCtrl::drawText( const RectI &drawRect, bool isFocused ) // Alright, we want to terminate things momentarily. if(mCursorPos > 0) { - cursorOffset = mProfile->mFont->getStrNWidth(textBuffer.getPtr(), mCursorPos); + cursorOffset = mProfile->mFont->getStringWidthScaled(String::ToString(textBuffer.getPtr()), mProfile->mFontSize, mCursorPos); } else cursorOffset = 0; if( tempChar && mProfile->mFont->isValidChar( tempChar ) ) - charWidth = mProfile->mFont->getCharWidth( tempChar ); + charWidth = mProfile->mFont->getCharWidthScaled( tempChar, mProfile->mFontSize); else charWidth = paddingRightBottom.x; @@ -1378,7 +1378,7 @@ void GuiTextEditCtrl::drawText( const RectI &drawRect, bool isFocused ) cursorEnd.x = cursorStart.x; - S32 cursorHeight = mProfile->mFont->getHeight(); + S32 cursorHeight = mProfile->mFont->getScaledHeight(mProfile->mFontSize); if ( cursorHeight < drawRect.extent.y ) { cursorStart.y = drawPoint.y; @@ -1406,8 +1406,8 @@ void GuiTextEditCtrl::drawText( const RectI &drawRect, bool isFocused ) { GFX->getDrawUtil()->setBitmapModulation( fontColor ); const UTF16* preString2 = textBuffer.getPtr(); - GFX->getDrawUtil()->drawText( mProfile->mFont, tempOffset, preString2, mProfile->mFontColors ); - tempOffset.x += mProfile->mFont->getStrNWidth(preString2, mBlockStart); + GFX->getDrawUtil()->drawText( mProfile->mFont, tempOffset, preString2, mProfile->mFontSize, mProfile->mFontColors ); + tempOffset.x += mProfile->mFont->getStringWidthScaled(String::ToString(preString2), mProfile->mFontSize, mBlockStart); } //draw the highlighted portion @@ -1416,14 +1416,14 @@ void GuiTextEditCtrl::drawText( const RectI &drawRect, bool isFocused ) const UTF16* highlightBuff = textBuffer.getPtr() + mBlockStart; U32 highlightBuffLen = mBlockEnd-mBlockStart; - S32 highlightWidth = mProfile->mFont->getStrNWidth(highlightBuff, highlightBuffLen); + S32 highlightWidth = mProfile->mFont->getStringWidthScaled(String::ToString(highlightBuff), mProfile->mFontSize, highlightBuffLen); GFX->getDrawUtil()->drawRectFill( Point2I( tempOffset.x, drawRect.point.y ), Point2I( tempOffset.x + highlightWidth, drawRect.point.y + drawRect.extent.y - 1), mProfile->mFontColorSEL ); GFX->getDrawUtil()->setBitmapModulation( mProfile->mFontColorHL ); - GFX->getDrawUtil()->drawTextN( mProfile->mFont, tempOffset, highlightBuff, highlightBuffLen, mProfile->mFontColors ); + GFX->getDrawUtil()->drawTextN( mProfile->mFont, tempOffset, highlightBuff, highlightBuffLen, mProfile->mFontSize, mProfile->mFontColors ); tempOffset.x += highlightWidth; } @@ -1434,7 +1434,7 @@ void GuiTextEditCtrl::drawText( const RectI &drawRect, bool isFocused ) U32 finalBuffLen = textBuffer.length() - mBlockEnd; GFX->getDrawUtil()->setBitmapModulation( fontColor ); - GFX->getDrawUtil()->drawTextN( mProfile->mFont, tempOffset, finalBuff, finalBuffLen, mProfile->mFontColors ); + GFX->getDrawUtil()->drawTextN( mProfile->mFont, tempOffset, finalBuff, finalBuffLen, mProfile->mFontSize, mProfile->mFontColors ); } //draw the cursor diff --git a/Engine/source/gui/controls/guiTextListCtrl.cpp b/Engine/source/gui/controls/guiTextListCtrl.cpp index 174687f792..3ac4007edf 100644 --- a/Engine/source/gui/controls/guiTextListCtrl.cpp +++ b/Engine/source/gui/controls/guiTextListCtrl.cpp @@ -225,7 +225,7 @@ void GuiTextListCtrl::onRenderCell(Point2I offset, Point2I cell, bool selected, } } - GFX->getDrawUtil()->drawTextN(mFont, pos, text, slen, mProfile->mFontColors); + GFX->getDrawUtil()->drawTextN(mFont, pos, text, slen, mProfile->mFontSize, mProfile->mFontColors); if(clipped) GFX->setClipRect( saveClipRect ); @@ -245,9 +245,9 @@ U32 GuiTextListCtrl::getRowWidth(Entry *row) const char *nextCol = dStrchr(text, '\t'); U32 textWidth; if(nextCol) - textWidth = mFont->getStrNWidth((const UTF8*)text, nextCol - text); + textWidth = mFont->getStringWidthScaled(text, mProfile->mFontSize, nextCol - text); else - textWidth = mFont->getStrWidth((const UTF8*)text); + textWidth = mFont->getStringWidthScaled(text, mProfile->mFontSize); if(mColumnOffsets[index] >= 0) width = getMax(width, mColumnOffsets[index] + textWidth); if(!nextCol) @@ -371,7 +371,7 @@ void GuiTextListCtrl::setSize(Point2I newSize) mCellSize.x = maxWidth + 8; } - mCellSize.y = mFont->getHeight() + mRowHeightPadding; + mCellSize.y = mFont->getScaledHeight(mProfile->mFontSize) + mRowHeightPadding; } Point2I newExtent( newSize.x * mCellSize.x + mHeaderDim.x, newSize.y * mCellSize.y + mHeaderDim.y ); diff --git a/Engine/source/gui/controls/guiTreeViewCtrl.cpp b/Engine/source/gui/controls/guiTreeViewCtrl.cpp index e1589aed5a..219283549d 100644 --- a/Engine/source/gui/controls/guiTreeViewCtrl.cpp +++ b/Engine/source/gui/controls/guiTreeViewCtrl.cpp @@ -612,7 +612,7 @@ S32 GuiTreeViewCtrl::Item::getDisplayTextWidth(GFont *font) char *buf = (char*)txtAlloc.alloc(bufLen); getDisplayText(bufLen, buf); - return font->getStrWidth(buf); + return font->getStringWidthScaledPrecise(String::ToString(buf), mProfile->mFontSize); } //----------------------------------------------------------------------------- @@ -1848,7 +1848,7 @@ bool GuiTreeViewCtrl::onWake() if(mProfile->mAutoSizeHeight) { // make sure it's big enough for both bitmap AND font... - mItemHeight = getMax((S32)mFont->getHeight(), (S32)mProfile->mBitmapArrayRects[0].extent.y); + mItemHeight = getMax((S32)mFont->getScaledHeight(mProfile->mFontSize), (S32)mProfile->mBitmapArrayRects[0].extent.y); } mFlags.set(RebuildVisible); @@ -2013,7 +2013,7 @@ bool GuiTreeViewCtrl::_hitTest(const Point2I & pnt, Item* & item, BitSet32 & fla char *buf = (char*)txtAlloc.alloc(bufLen); item->getDisplayText(bufLen, buf); - min += mProfile->mFont->getStrWidth(buf); + min += mProfile->mFont->getStringWidthScaledPrecise(String::ToString(buf), mProfile->mFontSize); if(pos.x < min) flags.set(OnText); @@ -3909,7 +3909,7 @@ void GuiTreeViewCtrl::onRenderCell(Point2I offset, Point2I cell, bool, bool ) item->getDisplayText(bufLen, displayText); // Draw the rollover/selected bitmap, if one was specified. - drawRect.extent.x = mProfile->mFont->getStrWidth( displayText ) + ( 2 * mTextOffset ); + drawRect.extent.x = mProfile->mFont->getStringWidthScaledPrecise(String::ToString(displayText), mProfile->mFontSize); if ( item->mState.test( Item::Selected ) && mTexSelected ) drawer->drawBitmapStretch( mTexSelected, drawRect ); else if ( item->mState.test( Item::MouseOverText ) && mTexRollover ) @@ -3941,7 +3941,7 @@ void GuiTreeViewCtrl::onRenderCell(Point2I offset, Point2I cell, bool, bool ) drawer->setBitmapModulation( fontColor ); // Center the text horizontally. - S32 height = (mItemHeight - mProfile->mFont->getHeight()) / 2; + S32 height = (mItemHeight - mProfile->mFont->getScaledHeight(mProfile->mFontSize)) / 2; if(height > 0) drawRect.point.y += height; @@ -3949,7 +3949,7 @@ void GuiTreeViewCtrl::onRenderCell(Point2I offset, Point2I cell, bool, bool ) // JDD - offset by two pixels or so to keep the text from rendering RIGHT ONTOP of the outline drawRect.point.x += 2; - drawer->drawText( mProfile->mFont, drawRect.point, displayText, mProfile->mFontColors ); + drawer->drawText( mProfile->mFont, drawRect.point, displayText, mProfile->mFontSize, mProfile->mFontColors ); if ( mRenamingItem == item && mRenameCtrl ) { @@ -4003,8 +4003,8 @@ bool GuiTreeViewCtrl::renderTooltip( const Point2I &hoverPos, const Point2I& cur U32 bufLen = item->getDisplayTextLength() + 1; char *buf = (char*)txtAlloc.alloc(bufLen); item->getDisplayText(bufLen, buf); - textExt.x = mProfile->mFont->getStrWidth(buf); - textExt.y = mProfile->mFont->getHeight(); + textExt.x = mTooltipProfile->mFont->getStringWidthScaledPrecise(String::ToString(buf), mTooltipProfile->mFontSize); + textExt.y = mTooltipProfile->mFont->getScaledHeight(mTooltipProfile->mFontSize); if( pScrollParent->isRectCompletelyVisible(RectI(textStart, textExt)) ) render = false; diff --git a/Engine/source/gui/core/guiCanvas.cpp b/Engine/source/gui/core/guiCanvas.cpp index d03e815246..85b4510399 100644 --- a/Engine/source/gui/core/guiCanvas.cpp +++ b/Engine/source/gui/core/guiCanvas.cpp @@ -164,7 +164,8 @@ GuiCanvas::GuiCanvas(): GuiControl(), mDisplayWindow(true), mMenuBarCtrl(nullptr), mMenuBackground(nullptr), - mConstrainMouse(false) + mConstrainMouse(false), + mDpiScalingFactor(1.0f) { setBounds(0, 0, 640, 480); mAwake = true; @@ -286,7 +287,10 @@ bool GuiCanvas::onAdd() mPlatformWindow->appEvent .notify(this, &GuiCanvas::handleAppEvent); mPlatformWindow->displayEvent.notify(this, &GuiCanvas::handlePaintEvent); mPlatformWindow->setInputController( dynamic_cast(this) ); + mDpiScalingFactor = mPlatformWindow->getDisplayDpiFactor(); } + + mDpiScalingFactor *= Platform::getDisplayScaleFactor(); // Need to get painted, too! :) Process::notify(this, &GuiCanvas::paint, PROCESS_RENDER_ORDER); diff --git a/Engine/source/gui/core/guiCanvas.h b/Engine/source/gui/core/guiCanvas.h index 64493c7ddf..8fc7fca778 100644 --- a/Engine/source/gui/core/guiCanvas.h +++ b/Engine/source/gui/core/guiCanvas.h @@ -178,7 +178,7 @@ class GuiCanvas : public GuiControl, public IProcessInput Point2I mHoverPosition; bool mHoverPositionSet; U32 mHoverLeftControlTime; - + F32 mDpiScalingFactor; public: /// Setting for how to handle 'enableKeyboardTranslation' and 'setNativeAcceleratorsEnabled' requests. enum KeyTranslationMode @@ -485,6 +485,7 @@ class GuiCanvas : public GuiControl, public IProcessInput void clearMouseButtonDown(void) { mMouseButtonDown = false; } void setConsumeLastInputEvent(bool flag) { mConsumeLastInputEvent = flag; } bool getLastCursorPoint(Point2I& pt) const { pt = mLastCursorPt; return mLastCursorEnabled; } + F32 getDpiScalingFactor() { return mDpiScalingFactor; } StringTableEntry getLastInputDeviceType(); }; diff --git a/Engine/source/gui/core/guiControl.cpp b/Engine/source/gui/core/guiControl.cpp index 6a888485d9..3fa3539fee 100644 --- a/Engine/source/gui/core/guiControl.cpp +++ b/Engine/source/gui/core/guiControl.cpp @@ -489,20 +489,20 @@ bool GuiControl::defaultTooltipRender( const Point2I &hoverPos, const Point2I &c Vector startLineOffsets, lineLengths; - font->wrapString( renderTip, U32_MAX, startLineOffsets, lineLengths ); + font->wrapStringScaled( renderTip, U32_MAX, mTooltipProfile->mFontSize, startLineOffsets, lineLengths ); // The width is the longest line. U32 tipWidth = 0; for ( U32 i = 0; i < lineLengths.size(); i++ ) { - U32 width = font->getStrNWidth( renderTip.c_str() + startLineOffsets[i], lineLengths[i] ); + U32 width = font->getStringWidthScaledPrecise( String::ToString(renderTip.c_str() + startLineOffsets[i]), mTooltipProfile->mFontSize, lineLengths[i] ); if ( width > tipWidth ) tipWidth = width; } // The height is the number of lines times the height of the font. - U32 tipHeight = lineLengths.size() * font->getHeight(); + U32 tipHeight = lineLengths.size() * font->getScaledHeight(mTooltipProfile->mFontSize); // Vars used: // Screensize (for position check) @@ -550,11 +550,11 @@ bool GuiControl::defaultTooltipRender( const Point2I &hoverPos, const Point2I &c for ( U32 i = 0; i < lineLengths.size(); i++ ) { - Point2I start( hMargin, vMargin + i * font->getHeight() ); + Point2I start( hMargin, vMargin + i * font->getScaledHeight(mTooltipProfile->mFontSize) ); const UTF8 *line = renderTip.c_str() + startLineOffsets[i]; U32 lineLen = lineLengths[i]; - drawUtil->drawTextN( font, start + offset, line, lineLen, mProfile->mFontColors ); + drawUtil->drawTextN( font, start + offset, line, lineLen, mTooltipProfile->mFontSize, mTooltipProfile->mFontColors ); } GFX->setClipRect( oldClip ); @@ -624,8 +624,8 @@ void GuiControl::renderJustifiedText(Point2I offset, Point2I extent, const char GFont *font = mProfile->mFont; if(!font) return; - S32 textWidth = font->getStrWidthPrecise((const UTF8*)text); - U32 textHeight = font->getHeight(); + S32 textWidth = font->getStringWidthScaled(String::ToString(text), mProfile->mFontSize, dStrlen(text)); + U32 textHeight = font->getScaledHeight(mProfile->mFontSize); Point2I start( 0, 0 ); @@ -674,11 +674,11 @@ void GuiControl::renderJustifiedText(Point2I offset, Point2I extent, const char default: // Center vertical. - start.y = ( extent.y - font->getHeight() ) / 2; + start.y = ( extent.y - textHeight) / 2; break; } - GFX->getDrawUtil()->drawText( font, start + offset, text, mProfile->mFontColors ); + GFX->getDrawUtil()->drawText( font, start + offset, text, mProfile->mFontSize, mProfile->mFontColors); } //============================================================================= @@ -2421,7 +2421,7 @@ U32 GuiControl::clipText( String &text, U32 clipWidth ) const { PROFILE_SCOPE( GuiControl_clipText ); - U32 textWidth = mProfile->mFont->getStrWidthPrecise( text ); + U32 textWidth = mProfile->mFont->getStringWidthScaled( text, mProfile->mFontSize ); if ( textWidth <= clipWidth ) return textWidth; @@ -2431,7 +2431,7 @@ U32 GuiControl::clipText( String &text, U32 clipWidth ) const // than clipWidth... // Note this would be more efficient without calling - // getStrWidthPrecise each loop iteration. eg. get the + // getStringWidthScaledPrecise each loop iteration. eg. get the // length of each char, store in a temporary U32 array, // and then remove the number we need from the end all at once. @@ -2442,7 +2442,7 @@ U32 GuiControl::clipText( String &text, U32 clipWidth ) const text.erase( text.length() - 1, 1 ); temp = text; temp += "..."; - textWidth = mProfile->mFont->getStrWidthPrecise( temp ); + textWidth = mProfile->mFont->getStringWidthScaled( temp, mProfile->mFontSize); if ( textWidth <= clipWidth ) { diff --git a/Engine/source/gui/core/guiTypes.cpp b/Engine/source/gui/core/guiTypes.cpp index 528ea54254..19a7d1dc5e 100644 --- a/Engine/source/gui/core/guiTypes.cpp +++ b/Engine/source/gui/core/guiTypes.cpp @@ -34,6 +34,7 @@ #include "sfx/sfxTrack.h" #include "sfx/sfxTypes.h" #include "console/engineAPI.h" +#include "gui/core/guiCanvas.h" //#define DEBUG_SPEW @@ -471,6 +472,14 @@ bool GuiControlProfile::onAdd() // Make sure we have an up-to-date children profile getChildrenProfile(); + + F32 dpiScaling = 1.0f; + GuiCanvas* cv = dynamic_cast(Sim::findObject("Canvas")); + if (cv) + { + dpiScaling = cv->getDpiScalingFactor(); + } + mFontSize *= dpiScaling; return true; } @@ -484,7 +493,7 @@ void GuiControlProfile::onStaticModified(const char* slotName, const char* newVa !dStricmp(slotName, "fontSize" ) ) { // Reload the font - mFont = GFont::create(mFontType, mFontSize, sFontCacheDirectory, mFontCharset); + mFont = GFont::create(mFontType, sFontCacheDirectory, mFontCharset); if ( mFont == NULL ) Con::errorf("Failed to load/create profile font (%s/%d)", mFontType, mFontSize); } @@ -687,7 +696,7 @@ void GuiControlProfile::decLoadCount() bool GuiControlProfile::loadFont() { - mFont = GFont::create( mFontType, mFontSize, sFontCacheDirectory, mFontCharset ); + mFont = GFont::create( mFontType, sFontCacheDirectory, mFontCharset ); if( mFont == NULL ) { Con::errorf( "GuiControlProfile::loadFont - Failed to load/create profile font (%s/%d)", mFontType, mFontSize ); @@ -702,7 +711,7 @@ DefineEngineMethod( GuiControlProfile, getStringWidth, S32, (const char* string) "@param string String to get the width of." "@return width of the string in pixels." ) { - return (object->mFont) ? object->mFont->getStrNWidth( string, dStrlen( string ) ) : -1; + return (object->mFont) ? object->mFont->getStringWidthScaled( String::ToString(string), object->mFontSize, dStrlen( string ) ) : -1; } DefineEngineMethod(GuiControlProfile, getBitmap, const char*, (), , "get name") diff --git a/Engine/source/gui/editor/guiDebugger.cpp b/Engine/source/gui/editor/guiDebugger.cpp index 4ad0e66833..c325cce53a 100644 --- a/Engine/source/gui/editor/guiDebugger.cpp +++ b/Engine/source/gui/editor/guiDebugger.cpp @@ -138,11 +138,11 @@ void DbgFileView::AdjustCellSize() S32 maxWidth = 1; for (U32 i = 0; i < mFileView.size(); i++) { - S32 cellWidth = gFileXOffset + mFont->getStrWidth((const UTF8 *)mFileView[i].text); + S32 cellWidth = gFileXOffset + mFont->getStringWidthScaled(String::ToString(mFileView[i].text), mProfile->mFontSize); maxWidth = getMax(maxWidth, cellWidth); } - mCellSize.set(maxWidth, mFont->getHeight() + 2); + mCellSize.set(maxWidth, mFont->getScaledHeight(mProfile->mFontSize) + 2); setSize(mSize); } @@ -393,7 +393,7 @@ S32 DbgFileView::findMouseOverChar(const char *text, S32 stringPosition) *bufPtr = '\0'; // Is the resulting string long enough to include the current // mouse position? - if ((S32)mFont->getStrWidth((const UTF8 *)tempBuf) > stringPosition) { + if ((S32)mFont->getStringWidthScaled(String::ToString(tempBuf), mProfile->mFontSize) > stringPosition) { // Yep. // Restore the character. *bufPtr = c; @@ -660,12 +660,12 @@ void DbgFileView::onRenderCell(Point2I offset, Point2I cell, bool selected, bool if (mFileView[cell.y].breakOnLine) { GFX->getDrawUtil()->setBitmapModulation(mProfile->mFontColorHL); - GFX->getDrawUtil()->drawText(mFont, cellOffset, "#"); + GFX->getDrawUtil()->drawText(mFont, cellOffset, "#", mProfile->mFontSize); } else if (mFileView[cell.y].breakPosition) { GFX->getDrawUtil()->setBitmapModulation(mProfile->mFontColor); - GFX->getDrawUtil()->drawText(mFont, cellOffset, "-"); + GFX->getDrawUtil()->drawText(mFont, cellOffset, "-", mProfile->mFontSize); } cellOffset.x += 8; @@ -673,7 +673,7 @@ void DbgFileView::onRenderCell(Point2I offset, Point2I cell, bool selected, bool if (mFileName == mPCFileName && (cell.y + 1 == mPCCurrentLine)) { GFX->getDrawUtil()->setBitmapModulation(mProfile->mFontColorHL); - GFX->getDrawUtil()->drawText(mFont, cellOffset, "=>"); + GFX->getDrawUtil()->drawText(mFont, cellOffset, "=>", mProfile->mFontSize); } //by this time, the cellOffset has been incremented by 44 - the value of gFileXOffset @@ -695,11 +695,11 @@ void DbgFileView::onRenderCell(Point2I offset, Point2I cell, bool selected, bool //get the end coord tempBuf[mBlockEnd] = '\0'; - endPos = mFont->getStrWidth((const UTF8 *)tempBuf); + endPos = mFont->getStringWidthScaled(String::ToString(tempBuf), mProfile->mFontSize); //get the start coord tempBuf[mBlockStart] = '\0'; - startPos = mFont->getStrWidth((const UTF8 *)tempBuf); + startPos = mFont->getStringWidthScaled(String::ToString(tempBuf), mProfile->mFontSize); //draw the hilite GFX->getDrawUtil()->drawRectFill(RectI(cellOffset.x + startPos, cellOffset.y - 3, endPos - startPos + 2, mCellSize.y + 6), mProfile->mFillColorHL); @@ -708,5 +708,5 @@ void DbgFileView::onRenderCell(Point2I offset, Point2I cell, bool selected, bool //draw the line of text GFX->getDrawUtil()->setBitmapModulation(mFileView[cell.y].breakOnLine ? mProfile->mFontColorHL : mProfile->mFontColor); - GFX->getDrawUtil()->drawText(mFont, cellOffset, mFileView[cell.y].text); + GFX->getDrawUtil()->drawText(mFont, cellOffset, mFileView[cell.y].text, mProfile->mFontSize); } diff --git a/Engine/source/gui/editor/guiMenuBar.cpp b/Engine/source/gui/editor/guiMenuBar.cpp index cae69d291c..6b30d84023 100644 --- a/Engine/source/gui/editor/guiMenuBar.cpp +++ b/Engine/source/gui/editor/guiMenuBar.cpp @@ -263,7 +263,7 @@ void GuiMenuBar::onPreRender() if (mMenuList[i].bitmapIndex == -1) { // Text only - mMenuList[i].bounds.set(curX, 0, mProfile->mFont->getStrWidth(mMenuList[i].text) + (mHorizontalMargin * 2), getHeight() - (mVerticalMargin * 2)); + mMenuList[i].bounds.set(curX, 0, mProfile->mFont->getStringWidthScaled(String::ToString(mMenuList[i].text), mProfile->mFontSize) + (mHorizontalMargin * 2), getHeight() - (mVerticalMargin * 2)); } else @@ -273,7 +273,7 @@ void GuiMenuBar::onPreRender() { // Draw the bitmap and the text RectI *bitmapBounds = mProfile->mBitmapArrayRects.address(); - mMenuList[i].bounds.set(curX, 0, bitmapBounds[mMenuList[i].bitmapIndex].extent.x + mProfile->mFont->getStrWidth(mMenuList[i].text) + (mHorizontalMargin * 2), getHeight() + (mVerticalMargin * 2)); + mMenuList[i].bounds.set(curX, 0, bitmapBounds[mMenuList[i].bitmapIndex].extent.x + mProfile->mFont->getStringWidthScaled(String::ToString((mMenuList[i].text) + (mHorizontalMargin * 2)), mProfile->mFontSize), getHeight() + (mVerticalMargin * 2)); } else @@ -381,7 +381,7 @@ void GuiMenuBar::onRender(Point2I offset, const RectI &updateRect) Point2I start; start.x = mMenuList[i].bounds.point.x + mHorizontalMargin; - start.y = mMenuList[i].bounds.point.y + (mMenuList[i].bounds.extent.y - mProfile->mFont->getHeight()) / 2; + start.y = mMenuList[i].bounds.point.y + (mMenuList[i].bounds.extent.y - mProfile->mFont->getScaledHeight(mProfile->mFontSize)) / 2; // Draw the border if (mMenuList[i].drawBorder) @@ -416,13 +416,13 @@ void GuiMenuBar::onRender(Point2I offset, const RectI &updateRect) { start.x += mBitmapMargin; drawUtil->setBitmapModulation(fontColor); - drawUtil->drawText(mProfile->mFont, start + offset, mMenuList[i].text, mProfile->mFontColors); + drawUtil->drawText(mProfile->mFont, start + offset, mMenuList[i].text, mProfile->mFontSize, mProfile->mFontColors); } } else { drawUtil->setBitmapModulation(fontColor); - drawUtil->drawText(mProfile->mFont, start + offset, mMenuList[i].text, mProfile->mFontColors); + drawUtil->drawText(mProfile->mFont, start + offset, mMenuList[i].text, mProfile->mFontSize, mProfile->mFontColors); } } diff --git a/Engine/source/gui/editor/guiParticleGraphCtrl.cpp b/Engine/source/gui/editor/guiParticleGraphCtrl.cpp index e1e6481a4e..c9b5b28537 100644 --- a/Engine/source/gui/editor/guiParticleGraphCtrl.cpp +++ b/Engine/source/gui/editor/guiParticleGraphCtrl.cpp @@ -238,7 +238,7 @@ void GuiParticleGraphCtrl::onRender(Point2I offset, const RectI &updateRect) dSprintf(number, 32, "%4.3f %4.3f", plotPoint.x, plotPoint.y); - S32 textWidth = (S32)font->getStrWidth((const UTF8*)number);; + S32 textWidth = (S32)font->getStringWidthScaled(String::ToString(number), profile->mFontSize); textWidth /= 2; if((((S32)posX - (textWidth/2)) < comparePos.x) || (((S32)posX - textWidth) <= 0)) @@ -255,7 +255,7 @@ void GuiParticleGraphCtrl::onRender(Point2I offset, const RectI &updateRect) } pDrawUtil->setBitmapModulation( profile->mFontColor ); - pDrawUtil->drawText( font, Point2I(posX, posY + 5) - Point2I(size >> 1, size), number ); + pDrawUtil->drawText( font, Point2I(posX, posY + 5) - Point2I(size >> 1, size), number, mProfile->mFontSize); pDrawUtil->clearBitmapModulation(); } } @@ -968,13 +968,13 @@ bool GuiParticleGraphCtrl::renderGraphTooltip(Point2I cursorPos, StringTableEntr Point2I screensize = pCanvas->getWindowSize(); Point2I offset = cursorPos; Point2I textBounds; - S32 textWidth = font->getStrWidth(tooltip); + S32 textWidth = font->getStringWidthScaled(String::ToString(tooltip), mTooltipProfile->mFontSize); //Offset below cursor image offset.y -= root->getCursorExtent().y; //Create text bounds. textBounds.x = textWidth+8; - textBounds.y = font->getHeight() + 4; + textBounds.y = font->getScaledHeight(mProfile->mFontSize) + 4; // Check position/width to make sure all of the tooltip will be rendered // 5 is given as a buffer against the edge @@ -999,8 +999,8 @@ bool GuiParticleGraphCtrl::renderGraphTooltip(Point2I cursorPos, StringTableEntr // Draw the text centered in the tool tip box pDrawUtil->setBitmapModulation( mTooltipProfile->mFontColor ); Point2I start; - start.set( ( textBounds.x - textWidth) / 2, ( textBounds.y - font->getHeight() ) / 2 ); - pDrawUtil->drawText( font, start + offset, tooltip, mProfile->mFontColors ); + start.set( ( textBounds.x - textWidth) / 2, ( textBounds.y - font->getScaledHeight(mProfile->mFontSize) ) / 2 ); + pDrawUtil->drawText( font, start + offset, tooltip, mProfile->mFontSize, mProfile->mFontColors ); pDrawUtil->clearBitmapModulation(); return true; diff --git a/Engine/source/gui/editor/guiSeparatorCtrl.cpp b/Engine/source/gui/editor/guiSeparatorCtrl.cpp index bb6b6c9032..1c4d075be4 100644 --- a/Engine/source/gui/editor/guiSeparatorCtrl.cpp +++ b/Engine/source/gui/editor/guiSeparatorCtrl.cpp @@ -99,7 +99,7 @@ void GuiSeparatorCtrl::onRender(Point2I offset, const RectI &updateRect) // text, and then the rest of the separator. S32 posx = offset.x + mMargin; - S32 fontheight = mProfile->mFont->getHeight(); + S32 fontheight = mProfile->mFont->getScaledHeight(mProfile->mFontSize); S32 seppos = (fontheight - 2) / 2 + offset.y; if( mTextLeftMargin > 0 ) { @@ -109,7 +109,7 @@ void GuiSeparatorCtrl::onRender(Point2I offset, const RectI &updateRect) } GFX->getDrawUtil()->setBitmapModulation( mProfile->mFontColor ); - posx = GFX->getDrawUtil()->drawText(mProfile->mFont, Point2I(posx,offset.y), mText, mProfile->mFontColors); + posx = GFX->getDrawUtil()->drawText(mProfile->mFont, Point2I(posx,offset.y), mText, mProfile->mFontSize, mProfile->mFontColors); RectI rect( Point2I( posx, seppos ), Point2I( getWidth() - posx + offset.x, 2 ) ); diff --git a/Engine/source/gui/editor/popupMenu.cpp b/Engine/source/gui/editor/popupMenu.cpp index 783453f02a..7e153041cc 100644 --- a/Engine/source/gui/editor/popupMenu.cpp +++ b/Engine/source/gui/editor/popupMenu.cpp @@ -381,8 +381,8 @@ void PopupMenu::showPopup(GuiCanvas *owner, S32 x /* = -1 */, S32 y /* = -1 */) if (!mMenuItems[i].mVisible) continue; - S32 iTextWidth = font->getStrWidth(mMenuItems[i].mText.c_str()); - S32 iAcceleratorWidth = mMenuItems[i].mAccelerator ? font->getStrWidth(mMenuItems[i].mAccelerator) : 0; + S32 iTextWidth = font->getStringWidthScaled(mMenuItems[i].mText, profile->mFontSize); + S32 iAcceleratorWidth = mMenuItems[i].mAccelerator ? font->getStringWidthScaled(String::ToString(mMenuItems[i].mAccelerator), profile->mFontSize) : 0; if (iTextWidth > textWidth) textWidth = iTextWidth; @@ -392,7 +392,7 @@ void PopupMenu::showPopup(GuiCanvas *owner, S32 x /* = -1 */, S32 y /* = -1 */) width = textWidth + acceleratorWidth + maxBitmapSize.x * 2 + 2 + 4; - mTextList->setCellSize(Point2I(width, font->getHeight() + 2)); + mTextList->setCellSize(Point2I(width, font->getScaledHeight(profile->mFontSize) + 2)); mTextList->clearColumnOffsets(); mTextList->addColumnOffset(-1); // add an empty column in for the bitmap index. mTextList->addColumnOffset(maxBitmapSize.x + 1); diff --git a/Engine/source/gui/game/guiMessageVectorCtrl.cpp b/Engine/source/gui/game/guiMessageVectorCtrl.cpp index 313b7a2659..50f0497b52 100644 --- a/Engine/source/gui/game/guiMessageVectorCtrl.cpp +++ b/Engine/source/gui/game/guiMessageVectorCtrl.cpp @@ -281,7 +281,7 @@ void GuiMessageVectorCtrl::lineInserted(const U32 arg) } Point2I newExtent = getExtent(); - newExtent.y = (mProfile->mFont->getHeight() + mLineSpacingPixels) * getMax(numLines, U32(1)); + newExtent.y = (mProfile->mFont->getScaledHeight(mProfile->mFontSize) + mLineSpacingPixels) * getMax(numLines, U32(1)); setExtent(newExtent); if(fullyScrolled) pScroll->scrollTo(0, 0x7FFFFFFF); @@ -327,7 +327,7 @@ void GuiMessageVectorCtrl::lineDeleted(const U32 arg) numLines += mLineWrappings[i].numLines; } - U32 newHeight = (mProfile->mFont->getHeight() + mLineSpacingPixels) * getMax(numLines, U32(1)); + U32 newHeight = (mProfile->mFont->getScaledHeight(mProfile->mFontSize) + mLineSpacingPixels) * getMax(numLines, U32(1)); resize(getPosition(), Point2I(getWidth(), newHeight)); } @@ -338,7 +338,7 @@ void GuiMessageVectorCtrl::vectorDeleted() AssertFatal(mLineWrappings.size() == 0, "Error, line wrappings not properly cleared out!"); mMessageVector = NULL; - U32 newHeight = mProfile->mFont->getHeight() + mLineSpacingPixels; + U32 newHeight = mProfile->mFont->getScaledHeight(mProfile->mFontSize) + mLineSpacingPixels; resize(getPosition(), Point2I(getWidth(), newHeight)); } @@ -469,13 +469,13 @@ void GuiMessageVectorCtrl::createLineWrapping(LineWrapping& rWrapping, const cha } // Ok, there's some actual text in this line. How long is it? - U32 baseLength = mProfile->mFont->getStrNWidthPrecise((const UTF8 *)&string[rLine.start], rLine.end-rLine.start+1); + U32 baseLength = mProfile->mFont->getStringWidthScaledPrecise(String::ToString(string[rLine.start]), mProfile->mFontSize, rLine.end-rLine.start+1); if (baseLength > splitWidth) { // DMMNOTE: Replace with bin search eventually U32 currPos = 0; U32 breakPos = 0; for (currPos = 0; currPos < rLine.end-rLine.start+1; currPos++) { - U32 currLength = mProfile->mFont->getStrNWidthPrecise((const UTF8 *)&string[rLine.start], currPos+1); + U32 currLength = mProfile->mFont->getStringWidthScaledPrecise(String::ToString(string[rLine.start]), mProfile->mFontSize, currPos+1); if (currLength > splitWidth) { // Make sure that the currPos has advanced, then set the breakPoint. @@ -658,8 +658,8 @@ bool GuiMessageVectorCtrl::onWake() for (U32 i = 0; i < 256; i++) { if (mProfile->mFont->isValidChar(U8(i))) { - if (mProfile->mFont->getCharWidth(U8(i)) > mMinSensibleWidth) - mMinSensibleWidth = mProfile->mFont->getCharWidth(U8(i)); + if (mProfile->mFont->getCharWidthScaled(U8(i), mProfile->mFontSize) > mMinSensibleWidth) + mMinSensibleWidth = mProfile->mFont->getCharWidthScaled(U8(i), mProfile->mFontSize); } } @@ -686,7 +686,7 @@ void GuiMessageVectorCtrl::onRender(Point2I offset, Parent::onRender(offset, updateRect); if (isAttached()) { - U32 linePixels = mProfile->mFont->getHeight() + mLineSpacingPixels; + U32 linePixels = mProfile->mFont->getScaledHeight(mProfile->mFontSize) + mLineSpacingPixels; U32 currLine = 0; ColorI lastColor = mProfile->mFontColor; for (U32 i = 0; i < mMessageVector->getNumLines(); i++) { @@ -697,7 +697,7 @@ void GuiMessageVectorCtrl::onRender(Point2I offset, Point2I globalCheck = localToGlobalCoord(localStart); U32 globalRangeStart = globalCheck.y; - U32 globalRangeEnd = globalCheck.y + mProfile->mFont->getHeight(); + U32 globalRangeEnd = globalCheck.y + mProfile->mFont->getScaledHeight(mProfile->mFontSize); if (globalRangeStart > updateRect.point.y + updateRect.extent.y || globalRangeEnd < updateRect.point.y) { currLine++; @@ -717,7 +717,7 @@ void GuiMessageVectorCtrl::onRender(Point2I offset, drawer->setBitmapModulation(lastColor); drawer->setTextAnchorColor(mProfile->mFontColor); strWidth = drawer->drawTextN(mProfile->mFont, globalStart, &mMessageVector->getLine(i).message[walkAcross->start], - walkAcross->end - walkAcross->start + 1, mProfile->mFontColors, mMaxColorIndex); + walkAcross->end - walkAcross->start + 1, mProfile->mFontSize, mProfile->mFontColors, mMaxColorIndex); drawer->getBitmapModulation(&lastColor); // in case an embedded color tag changed it } else { drawer->getBitmapModulation( &lastColor ); @@ -789,7 +789,7 @@ void GuiMessageVectorCtrl::findSpecialFromCoord(const Point2I& point, S32* speci return; } - U32 linePixels = mProfile->mFont->getHeight() + mLineSpacingPixels; + U32 linePixels = mProfile->mFont->getScaledHeight(mProfile->mFontSize) + mLineSpacingPixels; if ((point.x < 0 || point.x >= getWidth()) || (point.y < 0 || point.y >= getHeight())) { @@ -851,8 +851,9 @@ void GuiMessageVectorCtrl::findSpecialFromCoord(const Point2I& point, S32* speci } while (line) { - U32 newX = currX + mProfile->mFont->getStrNWidth((const UTF8 *)mMessageVector->getLine(elemIndex).message, - line->end - line->start + 1); + U32 newX = currX + mProfile->mFont->getStringWidthScaled( String::ToString(mMessageVector->getLine(elemIndex).message), + mProfile->mFontSize, + line->end - line->start + 1); if (point.x < newX) { // That's the one! *specialLine = elemIndex; diff --git a/Engine/source/gui/shaderEditor/guiShaderNode.cpp b/Engine/source/gui/shaderEditor/guiShaderNode.cpp index 65dea429d2..cd8f920355 100644 --- a/Engine/source/gui/shaderEditor/guiShaderNode.cpp +++ b/Engine/source/gui/shaderEditor/guiShaderNode.cpp @@ -147,10 +147,10 @@ void GuiShaderNode::renderNode(Point2I offset, const RectI& updateRect, const S3 drawer->drawRoundedRect(15.0f, headRect, header); // draw header text. - U32 strWidth = mProfile->mFont->getStrWidth(mTitle.c_str()); + U32 strWidth = mProfile->mFont->getStringWidthScaled(mTitle, mProfile->mFontSize); Point2I headerPos = Point2I((getExtent().x / 2) - (strWidth / 2), (headerSize / 2) - (mProfile->mFont->getFontSize() / 2)); drawer->setBitmapModulation(mProfile->mFontColor); - drawer->drawText(mProfile->mFont, headerPos + offset, mTitle); + drawer->drawText(mProfile->mFont, headerPos + offset, mTitle, mProfile->mFontSize); drawer->clearBitmapModulation(); if (mInputNodes.size() > 0 || mOutputNodes.size() > 0) @@ -160,7 +160,7 @@ void GuiShaderNode::renderNode(Point2I offset, const RectI& updateRect, const S3 drawer->setBitmapModulation(mProfile->mFontColor); for (NodeInput* input : mInputNodes) { - drawer->drawText(mProfile->mFont, slotPos + offset, input->name); + drawer->drawText(mProfile->mFont, slotPos + offset, input->name, mProfile->mFontSize); if (input->pos == Point2I::Zero || mPrevNodeSize != nodeSize) input->pos = Point2I(-(nodeSize / 2) + 1, slotPos.y + ((mProfile->mFont->getFontSize() / 2) - (nodeSize / 2))); @@ -173,10 +173,10 @@ void GuiShaderNode::renderNode(Point2I offset, const RectI& updateRect, const S3 slotPos = Point2I(getExtent().x, headerSize + (nodeSize / 2)); for (NodeOutput* output : mOutputNodes) { - strWidth = mProfile->mFont->getStrWidth(output->name.c_str()); + strWidth = mProfile->mFont->getStringWidthScaled(output->name, mProfile->mFontSize); slotPos.x = getExtent().x - strWidth - textPadX; - drawer->drawText(mProfile->mFont, slotPos + offset, output->name); + drawer->drawText(mProfile->mFont, slotPos + offset, output->name, mProfile->mFontSize); if (output->pos == Point2I::Zero || mPrevNodeSize != nodeSize) output->pos = Point2I(getExtent().x - (nodeSize / 2) - 1 , slotPos.y + ((mProfile->mFont->getFontSize() / 2) - (nodeSize / 2))); diff --git a/Engine/source/gui/theora/guiTheoraCtrl.cpp b/Engine/source/gui/theora/guiTheoraCtrl.cpp index cb5722d85e..91d4dd17a7 100644 --- a/Engine/source/gui/theora/guiTheoraCtrl.cpp +++ b/Engine/source/gui/theora/guiTheoraCtrl.cpp @@ -221,7 +221,7 @@ void GuiTheoraCtrl::onRender(Point2I offset, const RectI &updateRect) mTheoraTexture.getNumDroppedFrames() ); drawUtil->setBitmapModulation( mProfile->mFontColors[ 0 ] ); - drawUtil->drawText( mProfile->mFont, localToGlobalCoord( Point2I( 0, 0 ) ), info, mProfile->mFontColors ); + drawUtil->drawText( mProfile->mFont, localToGlobalCoord( Point2I( 0, 0 ) ), info, mProfile->mFontSize, mProfile->mFontColors ); } } else diff --git a/Engine/source/gui/worldEditor/creator.cpp b/Engine/source/gui/worldEditor/creator.cpp index c268787eb2..7bffa611f2 100644 --- a/Engine/source/gui/worldEditor/creator.cpp +++ b/Engine/source/gui/worldEditor/creator.cpp @@ -324,7 +324,7 @@ void CreatorTree::buildNode(Node * node, U32 tab) // grab width if(bool(mProfile->mFont) && child->mName) { - S32 width = (tab + 1) * mTabSize + mProfile->mFont->getStrWidth(child->mName) + mTxtOffset; + S32 width = (tab + 1) * mTabSize + mProfile->mFont->getStringWidthScaled(String::ToString(child->mName), mProfile->mFontSize) + mTxtOffset; if(width > mMaxWidth) mMaxWidth = width; } @@ -475,5 +475,5 @@ void CreatorTree::onRenderCell(Point2I offset, Point2I cell, bool, bool) drawer->setBitmapModulation(fontColor); //node->isSelected() ? mProfile->mFontColorHL : mProfile->mFontColor); drawer->drawText( mProfile->mFont, Point2I( offset.x + mTxtOffset + mTabSize * ( node->mTab + 1 ), offset.y ), - node->mName); + node->mName, mProfile->mFontSize); } diff --git a/Engine/source/gui/worldEditor/gizmo.cpp b/Engine/source/gui/worldEditor/gizmo.cpp index 0c5b066142..37096a1b74 100644 --- a/Engine/source/gui/worldEditor/gizmo.cpp +++ b/Engine/source/gui/worldEditor/gizmo.cpp @@ -228,7 +228,7 @@ bool GizmoProfile::onAdd() return false; const char* fontCacheDirectory = Con::getVariable("$GUI::fontCacheDirectory"); - font = GFont::create( "Arial", 10, fontCacheDirectory, TGE_ANSI_CHARSET); + font = GFont::create( "Arial", fontCacheDirectory, TGE_ANSI_CHARSET); if ( !font ) { Con::errorf( "GizmoProfile::onAdd - failed to load font!" ); @@ -1469,7 +1469,7 @@ void Gizmo::renderText( const RectI &viewPort, const MatrixF &modelView, const M char buf[2]; buf[0] = axisText[i]; buf[1] = '\0'; drawer->setBitmapModulation(textColor); - drawer->drawText( mProfile->font, Point2I((S32)sPos.x, (S32)sPos.y), buf ); + drawer->drawText( mProfile->font, Point2I((S32)sPos.x, (S32)sPos.y), buf, 10); } } } diff --git a/Engine/source/gui/worldEditor/guiDecalEditorCtrl.cpp b/Engine/source/gui/worldEditor/guiDecalEditorCtrl.cpp index 5a2f545b27..284bdc9dd2 100644 --- a/Engine/source/gui/worldEditor/guiDecalEditorCtrl.cpp +++ b/Engine/source/gui/worldEditor/guiDecalEditorCtrl.cpp @@ -477,15 +477,15 @@ void GuiDecalEditorCtrl::renderGui( Point2I offset, const RectI &updateRect ) char buf[256]; dSprintf( buf, 256, "%0.3f", pixelSize ); - const U32 width = font->getStrWidth((const UTF8 *)buf);; + const U32 width = font->getStringWidthScaled(String::ToString(buf), mProfile->mFontSize); const Point2I posi( (U32)screenPos.x, (U32)screenPos.y + 12 ); const Point2I minPt(posi.x - width / 2 - 2, posi.y - 1); - const Point2I maxPt(posi.x + width / 2 + 2, posi.y + font->getHeight() + 1); + const Point2I maxPt(posi.x + width / 2 + 2, posi.y + font->getScaledHeight(mProfile->mFontSize) + 1); GFXDrawUtil *drawer = GFX->getDrawUtil(); drawer->drawRectFill( minPt, maxPt, bgColor ); GFX->getDrawUtil()->setBitmapModulation( textColor ); - GFX->getDrawUtil()->drawText( mProfile->mFont, Point2I( posi.x - width / 2, posi.y ), buf ); + GFX->getDrawUtil()->drawText( mProfile->mFont, Point2I( posi.x - width / 2, posi.y ), buf, mProfile->mFontSize ); } } } diff --git a/Engine/source/gui/worldEditor/worldEditor.cpp b/Engine/source/gui/worldEditor/worldEditor.cpp index a67b4ec7d3..b2827519c2 100644 --- a/Engine/source/gui/worldEditor/worldEditor.cpp +++ b/Engine/source/gui/worldEditor/worldEditor.cpp @@ -1414,19 +1414,19 @@ void WorldEditor::renderMousePopupInfo() return; } - U32 width = mProfile->mFont->getStrWidth((const UTF8 *)buf); + U32 width = mProfile->mFont->getStringWidthScaled(String::ToString(buf), mProfile->mFontSize); Point2I posi( mLastMouseEvent.mousePoint.x, mLastMouseEvent.mousePoint.y + 12 ); if ( mRenderPopupBackground ) { Point2I minPt(posi.x - width / 2 - 2, posi.y - 1); - Point2I maxPt(posi.x + width / 2 + 2, posi.y + mProfile->mFont->getHeight() + 1); + Point2I maxPt(posi.x + width / 2 + 2, posi.y + mProfile->mFont->getScaledHeight(mProfile->mFontSize) + 1); GFX->getDrawUtil()->drawRectFill(minPt, maxPt, mPopupBackgroundColor); } GFX->getDrawUtil()->setBitmapModulation(mPopupTextColor); - GFX->getDrawUtil()->drawText(mProfile->mFont, Point2I(posi.x - width / 2, posi.y), buf); + GFX->getDrawUtil()->drawText(mProfile->mFont, Point2I(posi.x - width / 2, posi.y), buf, mProfile->mFontSize); } void WorldEditor::renderPaths(SimObject *obj) @@ -1686,7 +1686,7 @@ void WorldEditor::renderScreenObj( SceneObject *obj, const Point3F& projPos, con { const char * str = parseObjectFormat(obj, mObjTextFormat); - Point2I extent(mProfile->mFont->getStrWidth((const UTF8 *)str), mProfile->mFont->getHeight()); + Point2I extent(mProfile->mFont->getStringWidthScaled(String::ToString(str), mProfile->mFontSize), mProfile->mFont->getScaledHeight(mProfile->mFontSize)); Point2I pos(sPos); @@ -1701,7 +1701,7 @@ void WorldEditor::renderScreenObj( SceneObject *obj, const Point3F& projPos, con drawer->drawBitmapStretch( classIcon, renderRect ); drawer->setBitmapModulation( ColorI(255,255,255,255) ); - drawer->drawText(mProfile->mFont, pos, str); + drawer->drawText(mProfile->mFont, pos, str, mProfile->mFontSize); if ( obj->isLocked() ) drawer->drawBitmap( mDefaultClassEntry.mLockedHandle, renderPos ); @@ -1715,7 +1715,7 @@ void WorldEditor::renderScreenObj( SceneObject *obj, const Point3F& projPos, con } }else{ drawer->setBitmapModulation(mObjectTextColor); - drawer->drawText(mProfile->mFont, pos, str); + drawer->drawText(mProfile->mFont, pos, str, mProfile->mFontSize); }; } @@ -1747,7 +1747,7 @@ void WorldEditor::renderScreenObj( SceneObject *obj, const Point3F& projPos, con noteTextColor.alpha = 255 * fade; drawer->setBitmapModulation(noteTextColor); - drawer->drawText(mProfile->mFont, pos, noteObj->getNote().c_str()); + drawer->drawText(mProfile->mFont, pos, noteObj->getNote().c_str(), mProfile->mFontSize); } } diff --git a/Engine/source/platform/platform.h b/Engine/source/platform/platform.h index acb929a9f4..82feb7310c 100644 --- a/Engine/source/platform/platform.h +++ b/Engine/source/platform/platform.h @@ -174,6 +174,7 @@ namespace Platform void restartInstance(); void postQuitMessage(const S32 in_quitVal); void forceShutdown(S32 returnValue); + F32 getDisplayScaleFactor(); // Debug void outputDebugString(const char *string, ...); diff --git a/Engine/source/platformMac/macPlatform.mm b/Engine/source/platformMac/macPlatform.mm index acf286d24a..513ca35692 100644 --- a/Engine/source/platformMac/macPlatform.mm +++ b/Engine/source/platformMac/macPlatform.mm @@ -77,6 +77,11 @@ [NSApp performSelector:@selector(terminate:) withObject:nil afterDelay:0.0]; } +F32 Platform::getDisplayScaleFactor(){ + CGFloat backingScaleFactor = [NSScreen mainScreen].backingScaleFactor; + return (float)backingScaleFactor; +} + //----------------------------------------------------------------------------- void Platform::debugBreak() { diff --git a/Engine/source/platformPOSIX/POSIXMain.cpp b/Engine/source/platformPOSIX/POSIXMain.cpp index 3e873a27b3..282790fc54 100644 --- a/Engine/source/platformPOSIX/POSIXMain.cpp +++ b/Engine/source/platformPOSIX/POSIXMain.cpp @@ -69,6 +69,10 @@ void Platform::shutdown() Cleanup(); } +F32 Platform::getDisplayScaleFactor() { + return 1.0f; +} + //------------------------------------------------------------------------------ @@ -104,4 +108,4 @@ int main(int argc, const char **argv) return TorqueMain(argc, argv); } #endif -#endif \ No newline at end of file +#endif diff --git a/Engine/source/platformWin32/winWindow.cpp b/Engine/source/platformWin32/winWindow.cpp index 011884ce4a..7cea30614d 100644 --- a/Engine/source/platformWin32/winWindow.cpp +++ b/Engine/source/platformWin32/winWindow.cpp @@ -152,6 +152,13 @@ void Platform::restartInstance() } } +F32 Platform::getDisplayScaleFactor() { + HDC hdc = GetDC(NULL); + int dpi = GetDeviceCaps(hdc, LOGPIXELSX); + + return (F32)dpi / 96.0f; +} + ///just check if the app's global mutex exists, and if so, ///return true - otherwise, false. Should be called before ExcludeOther /// at very start of app execution. diff --git a/Engine/source/windowManager/platformWindow.h b/Engine/source/windowManager/platformWindow.h index 4aa2806e83..d9dd266046 100644 --- a/Engine/source/windowManager/platformWindow.h +++ b/Engine/source/windowManager/platformWindow.h @@ -509,6 +509,13 @@ class PlatformWindow /// Mac Carbon OpenGL typically needs a WindowRef /// virtual void* getPlatformDrawable() const = 0; + + /// + /// Get the dpi scaling factor for this display. + /// + /// F32 value of the scaling factor, diagonal dpi / 96.0f + virtual F32 getDisplayDpiFactor() const = 0; + protected: virtual void _setFullscreen(const bool fullScreen) {}; virtual void _setVideoMode(const GFXVideoMode &mode) = 0; diff --git a/Engine/source/windowManager/sdl/sdlWindow.cpp b/Engine/source/windowManager/sdl/sdlWindow.cpp index d713d359c8..9483e450fc 100644 --- a/Engine/source/windowManager/sdl/sdlWindow.cpp +++ b/Engine/source/windowManager/sdl/sdlWindow.cpp @@ -715,6 +715,21 @@ const UTF16 *PlatformWindowSDL::getCurtainWindowClassName() return str.utf16(); } +F32 PlatformWindowSDL::getDisplayDpiFactor() const +{ + int displayIdx = SDL_GetWindowDisplayIndex(mWindowHandle); + + F32 ddpi, dpiX, dpiY; + if (SDL_GetDisplayDPI(displayIdx, &ddpi, &dpiX, &dpiY) != 0) + { + Con::errorf("SDL GetDisplayDPI: %s, returning 1.0f", SDL_GetError()); + return 1.0f; + } + + + return 1.0f / (ddpi / 96.0f); +} + void PlatformWindowSDL::setKeyboardTranslation(const bool enabled) { mEnableKeyboardTranslation = enabled; diff --git a/Engine/source/windowManager/sdl/sdlWindow.h b/Engine/source/windowManager/sdl/sdlWindow.h index 7fb852809d..9e95d7fff4 100644 --- a/Engine/source/windowManager/sdl/sdlWindow.h +++ b/Engine/source/windowManager/sdl/sdlWindow.h @@ -188,5 +188,7 @@ class PlatformWindowSDL : public PlatformWindow /// Return the platform specific object needed to create or attach an /// accelerated graohics drawing context on or to the window void* getPlatformDrawable() const override { return mWindowHandle; } + + F32 getDisplayDpiFactor() const override; }; #endif diff --git a/Templates/BaseGame/game/core/rendering/scripts/gfxData/shaders.tscript b/Templates/BaseGame/game/core/rendering/scripts/gfxData/shaders.tscript index 099b382db5..ccccafbdcb 100644 --- a/Templates/BaseGame/game/core/rendering/scripts/gfxData/shaders.tscript +++ b/Templates/BaseGame/game/core/rendering/scripts/gfxData/shaders.tscript @@ -154,6 +154,19 @@ singleton ShaderData( CubemapSaveShader ) //----------------------------------------------------------------------------- // GUI shaders //----------------------------------------------------------------------------- +singleton ShaderData( SDFFontRenderingGUI ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/fixedFunction/addColorTextureV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/fixedFunction/sdfFontRenderP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/fixedFunction/gl/addColorTextureV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/fixedFunction/gl/sdfFontRenderP.glsl"; + + samplerNames[0] = "$diffuseMap"; + + pixVersion = 3.0; +}; + singleton ShaderData( RoundedRectangleGUI ) { DXVertexShaderFile = $Core::CommonShaderPath @ "/fixedFunction/addColorTextureV.hlsl"; diff --git a/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/sdfFontRenderP.glsl b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/sdfFontRenderP.glsl new file mode 100644 index 0000000000..d75d8f4349 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/sdfFontRenderP.glsl @@ -0,0 +1,86 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +in vec4 color; +in vec2 texCoord; + +uniform sampler2D diffuseMap; +uniform vec2 texDim; + +out vec4 OUT_col; + +// Customizable parameters +float sdfThreshold = 0.55; // Center threshold for the edge of the glyph + // Min: 0.4 , Max: 0.6 +float slopeMultiplier = 0.5; // Multiplies the slope of the transition + // Min: 0.5 (softer edges), Max: 4.0 (sharper edges) +float inBias = 0.0; // Shifts the threshold inward + // Min: -0.05 (slightly thinner), Max: 0.0 (default, no inward shift) +float outBias = 0.01; // Shifts the threshold outward + // Min: 0.0 (default, no outward shift), Max: 0.05 (slightly thicker) +float smoothness = 0.05; // Controls the falloff region + // Min: 0.005 (very sharp edges), Max: 0.05 (soft, anti-aliased edges) +int supersample = 4; // Supersampling factor + // Min: 1 (no supersampling), Max: 8 (high-quality, computationally expensive) +float alphaThreshold = 0.1; // Sets the alpha threshold + +void main() +{ + float distance = texture(diffuseMap, texCoord).a; + + float adjustedThreshold = sdfThreshold + inBias - outBias; + + float edge = (distance - adjustedThreshold) * slopeMultiplier; + + // Apply smoothing for anti-aliasing + float alpha = smoothstep(-smoothness, smoothness, edge); + + // Supersampling for high-quality edges + if (supersample > 1) + { + vec2 texelSize = 1.0 / texDim; + vec2 offsets[4]; + offsets[0] = vec2(-0.5, -0.5) * texelSize; + offsets[1] = vec2( 0.5, -0.5) * texelSize; + offsets[2] = vec2(-0.5, 0.5) * texelSize; + offsets[3] = vec2( 0.5, 0.5) * texelSize; + + float totalAlpha = 0.0; + for (int i = 0; i < supersample; ++i) + { + vec2 offsetCoord = texCoord + offsets[i % 4]; + float sampleDist = texture(diffuseMap, offsetCoord).a; + float sampleEdge = (sampleDist - adjustedThreshold) * slopeMultiplier; + totalAlpha += smoothstep(-smoothness, smoothness, sampleEdge); + } + alpha = totalAlpha / float(supersample); + } + + // Discard fragments with alpha below the threshold + if (alpha < alphaThreshold) + discard; + + // Debug: Uncomment to visualize alpha field + //OUT_col = vec4(alpha, alpha, alpha, 1.0); + + OUT_col = vec4(color.rgb, alpha); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/sdfFontRenderP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/sdfFontRenderP.hlsl new file mode 100644 index 0000000000..7f34713d33 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/sdfFontRenderP.hlsl @@ -0,0 +1,90 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../shaderModel.hlsl" + +struct Conn +{ + float4 HPOS : TORQUE_POSITION; + float4 color : COLOR; + float2 texCoord : TEXCOORD0; +}; + +TORQUE_UNIFORM_SAMPLER2D(diffuseMap, 0); +uniform float2 texDim; + +// Customizable parameters +static const float sdfThreshold = 0.52; // Center threshold for the edge of the glyph + // Min: 0.4 , Max: 0.6 +static const float slopeMultiplier = 0.5; // Multiplies the slope of the transition + // Min: 0.5 (softer edges), Max: 4.0 (sharper edges) +static const float inBias = 0.01; // Shifts the threshold inward + // Min: 0.0 (default, no inward shift), Max: 0.05 (slightly thinner) +static const float outBias = 0.02; // Shifts the threshold outward + // Min: 0.0 (default, no outward shift), Max: 0.05 (slightly thicker) +static const float smoothness = 0.05; // Controls the falloff region + // Min: 0.005 (very sharp edges), Max: 0.05 (soft, anti-aliased edges) +static const int supersample = 1; // Supersampling factor + // Min: 1 (no supersampling), Max: 8 (high-quality, computationally expensive) +static const float alphaThreshold = 0.1; // Sets the alpha threshold + +float4 main( Conn IN ) : TORQUE_TARGET0 +{ + float distance = TORQUE_TEX2D(diffuseMap, IN.texCoord).a; + + float adjustedThreshold = sdfThreshold + inBias - outBias; + + float edge = (distance - adjustedThreshold) * slopeMultiplier; + + // Smooth edges using the distance field + float alpha = smoothstep(-smoothness, smoothness, edge); + + if(supersample > 1) + { + float2 texelSize = float2(1.0f / texDim.x, 1.0f / texDim.y); + float2 offsets[4] = { + float2(-0.5, -0.5) * texelSize, + float2(0.5, -0.5) * texelSize, + float2(-0.5, 0.5) * texelSize, + float2(0.5, 0.5) * texelSize + }; + + float totalAlpha = 0.0; + for(uint i = 0; i < (uint)supersample; ++i) + { + float2 offsetCoord = IN.texCoord + offsets[i % 4]; + float sampleDist = TORQUE_TEX2D(diffuseMap, offsetCoord).a; + float sampleEdge = (sampleDist - adjustedThreshold) * slopeMultiplier; + totalAlpha += smoothstep(-smoothness, smoothness, sampleEdge); + } + alpha = totalAlpha / float(supersample); + } + + // Alpha lower than min discard. + if(alpha < alphaThreshold) + discard; + + // Debug: Uncomment to visualize alpha field + //return float4(alpha, alpha, alpha, 1.0); + + return float4(IN.color.rgb, alpha); +} \ No newline at end of file