Apparently, \0 is not always a zero-width character? Not including it as part of the string measurement may cut off the final word on the line when using certain fonts together with outlines and wrapping. Test case: • Font: M+ 2p black (downloadable at https://mplus-fonts.osdn.jp/mplus-outline-fonts/download/index-en.html#download, "M+ TESTFLIGHT 060" release) • ☑ Use Outline • ☑ Use Custom Text Extents • ☑ Wrap • ☐ Scroll Mode (doesn't seem to be affected) • Text: A, 20
1455 lines
58 KiB
C++
1455 lines
58 KiB
C++
/********************************************************************************
|
|
Copyright (C) 2012 Hugh Bailey <obs.jim@gmail.com>
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
|
********************************************************************************/
|
|
|
|
|
|
#include "Main.h"
|
|
|
|
#include <memory>
|
|
|
|
#include <gdiplus.h>
|
|
|
|
|
|
#define ClampVal(val, minVal, maxVal) \
|
|
if(val < minVal) val = minVal; \
|
|
else if(val > maxVal) val = maxVal;
|
|
|
|
#define MAX_TEX_SIZE_W 8192
|
|
#define MAX_TEX_SIZE_H 8192
|
|
#define MIN_TEX_SIZE_W 32
|
|
#define MIN_TEX_SIZE_H 32
|
|
|
|
inline DWORD GetAlphaVal(UINT opacityLevel)
|
|
{
|
|
return ((opacityLevel*255/100)&0xFF) << 24;
|
|
}
|
|
|
|
|
|
class TextOutputSource : public ImageSource
|
|
{
|
|
bool bUpdateTexture;
|
|
|
|
String strCurrentText;
|
|
Texture *texture;
|
|
float scrollValue;
|
|
float showExtentTime;
|
|
|
|
int mode;
|
|
String strText;
|
|
String strFile;
|
|
|
|
String strFont;
|
|
int size;
|
|
DWORD color;
|
|
UINT opacity;
|
|
UINT globalOpacity;
|
|
int scrollSpeed;
|
|
bool bBold, bItalic, bUnderline, bVertical;
|
|
|
|
UINT backgroundOpacity;
|
|
DWORD backgroundColor;
|
|
|
|
bool bUseOutline;
|
|
float outlineSize;
|
|
DWORD outlineColor;
|
|
UINT outlineOpacity;
|
|
|
|
bool bUseExtents;
|
|
UINT extentWidth, extentHeight;
|
|
|
|
bool bWrap;
|
|
bool bScrollMode;
|
|
int align;
|
|
|
|
Vect2 baseSize;
|
|
SIZE textureSize;
|
|
bool bUsePointFiltering;
|
|
|
|
bool bMonitoringFileChanges;
|
|
OSFileChangeData *fileChangeMonitor;
|
|
|
|
std::unique_ptr<SamplerState> sampler;
|
|
|
|
bool bDoUpdate;
|
|
|
|
SamplerState *ss;
|
|
|
|
XElement *data;
|
|
|
|
void DrawOutlineText(Gdiplus::Graphics *graphics,
|
|
Gdiplus::Font &font,
|
|
const Gdiplus::GraphicsPath &path,
|
|
const Gdiplus::StringFormat &format,
|
|
const Gdiplus::Brush *brush)
|
|
{
|
|
|
|
Gdiplus::GraphicsPath *outlinePath;
|
|
|
|
outlinePath = path.Clone();
|
|
|
|
// Outline color and size
|
|
UINT tmpOpacity = (UINT)((((float)opacity * 0.01f) * ((float)outlineOpacity * 0.01f)) * 100.0f);
|
|
Gdiplus::Pen pen(Gdiplus::Color(GetAlphaVal(tmpOpacity) | (outlineColor&0xFFFFFF)), outlineSize);
|
|
pen.SetLineJoin(Gdiplus::LineJoinRound);
|
|
|
|
// Widen the outline
|
|
// It seems that Widen has a huge performance impact on DrawPath call, screw it! We're talking about freaking seconds in some extreme cases...
|
|
//outlinePath->Widen(&pen);
|
|
|
|
// Draw the outline
|
|
graphics->DrawPath(&pen, outlinePath);
|
|
|
|
// Draw the text
|
|
graphics->FillPath(brush, &path);
|
|
|
|
delete outlinePath;
|
|
}
|
|
|
|
HFONT GetFont()
|
|
{
|
|
HFONT hFont = NULL;
|
|
|
|
LOGFONT lf;
|
|
zero(&lf, sizeof(lf));
|
|
lf.lfHeight = size;
|
|
lf.lfWeight = bBold ? FW_BOLD : FW_DONTCARE;
|
|
lf.lfItalic = bItalic;
|
|
lf.lfUnderline = bUnderline;
|
|
lf.lfQuality = ANTIALIASED_QUALITY;
|
|
|
|
if(strFont.IsValid())
|
|
{
|
|
scpy_n(lf.lfFaceName, strFont, 31);
|
|
|
|
hFont = CreateFontIndirect(&lf);
|
|
}
|
|
|
|
if(!hFont)
|
|
{
|
|
scpy_n(lf.lfFaceName, TEXT("Arial"), 31);
|
|
hFont = CreateFontIndirect(&lf);
|
|
}
|
|
|
|
return hFont;
|
|
}
|
|
|
|
void UpdateCurrentText()
|
|
{
|
|
if(bMonitoringFileChanges)
|
|
{
|
|
OSMonitorFileDestroy(fileChangeMonitor);
|
|
fileChangeMonitor = NULL;
|
|
|
|
bMonitoringFileChanges = false;
|
|
}
|
|
|
|
if(mode == 0)
|
|
strCurrentText = strText;
|
|
|
|
else if(mode == 1 && strFile.IsValid())
|
|
{
|
|
XFile textFile;
|
|
if(textFile.Open(strFile, XFILE_READ | XFILE_SHARED, XFILE_OPENEXISTING))
|
|
{
|
|
textFile.ReadFileToString(strCurrentText);
|
|
}
|
|
else
|
|
{
|
|
strCurrentText = TEXT("");
|
|
AppWarning(TEXT("TextSource::UpdateTexture: could not open specified file (invalid file name or access violation)"));
|
|
}
|
|
|
|
if (fileChangeMonitor = OSMonitorFileStart (strFile))
|
|
bMonitoringFileChanges = true;
|
|
}
|
|
else
|
|
strCurrentText = TEXT("");
|
|
}
|
|
|
|
void SetStringFormat(Gdiplus::StringFormat &format)
|
|
{
|
|
UINT formatFlags;
|
|
|
|
formatFlags = Gdiplus::StringFormatFlagsNoFitBlackBox
|
|
| Gdiplus::StringFormatFlagsMeasureTrailingSpaces;
|
|
|
|
|
|
if(bVertical)
|
|
formatFlags |= Gdiplus::StringFormatFlagsDirectionVertical
|
|
| Gdiplus::StringFormatFlagsDirectionRightToLeft;
|
|
|
|
format.SetFormatFlags(formatFlags);
|
|
format.SetTrimming(Gdiplus::StringTrimmingWord);
|
|
|
|
if(bUseExtents && bWrap)
|
|
switch(align)
|
|
{
|
|
case 0:
|
|
if(bVertical)
|
|
format.SetLineAlignment(Gdiplus::StringAlignmentFar);
|
|
else
|
|
format.SetAlignment(Gdiplus::StringAlignmentNear);
|
|
break;
|
|
case 1:
|
|
if(bVertical)
|
|
format.SetLineAlignment(Gdiplus::StringAlignmentCenter);
|
|
else
|
|
format.SetAlignment(Gdiplus::StringAlignmentCenter);
|
|
break;
|
|
case 2:
|
|
if(bVertical)
|
|
format.SetLineAlignment(Gdiplus::StringAlignmentNear);
|
|
else
|
|
format.SetAlignment(Gdiplus::StringAlignmentFar);
|
|
break;
|
|
}
|
|
else if(bUseExtents && bVertical && !bWrap)
|
|
format.SetLineAlignment(Gdiplus::StringAlignmentFar);
|
|
else if(bVertical)
|
|
format.SetLineAlignment(Gdiplus::StringAlignmentFar);
|
|
|
|
}
|
|
|
|
float ProcessScrollMode(Gdiplus::Graphics *graphics, Gdiplus::Font *font, Gdiplus::RectF &layoutBox, Gdiplus::StringFormat *format)
|
|
{
|
|
StringList strList;
|
|
Gdiplus::RectF boundingBox;
|
|
|
|
float offset = layoutBox.Height;
|
|
|
|
Gdiplus::RectF l2(0.0f ,0.0f , layoutBox.Width, 32000.0f); // Really, it needs to be OVER9000
|
|
|
|
strCurrentText.FindReplace(L"\n\r", L"\n");
|
|
strCurrentText.GetTokenList(strList,'\n');
|
|
|
|
if(strList.Num() != 0)
|
|
strCurrentText.Clear();
|
|
else
|
|
return 0.0f;
|
|
|
|
for(int i = strList.Num() - 1; i >= 0; i--)
|
|
{
|
|
strCurrentText.InsertString(0, TEXT("\n"));
|
|
strCurrentText.InsertString(0, strList.GetElement((unsigned int)i).Array());
|
|
|
|
if(strCurrentText.IsValid())
|
|
{
|
|
graphics->MeasureString(strCurrentText, -1, font, l2, &boundingBox);
|
|
offset = layoutBox.Height - boundingBox.Height;
|
|
}
|
|
|
|
if(offset < 0)
|
|
break;
|
|
}
|
|
|
|
return offset;
|
|
}
|
|
|
|
void UpdateTexture()
|
|
{
|
|
HFONT hFont;
|
|
Gdiplus::Status stat;
|
|
Gdiplus::RectF layoutBox;
|
|
SIZE textSize;
|
|
float offset;
|
|
|
|
Gdiplus::RectF boundingBox(0.0f, 0.0f, 32.0f, 32.0f);
|
|
|
|
UpdateCurrentText();
|
|
|
|
hFont = GetFont();
|
|
if(!hFont)
|
|
return;
|
|
|
|
Gdiplus::StringFormat format(Gdiplus::StringFormat::GenericTypographic());
|
|
|
|
SetStringFormat(format);
|
|
|
|
HDC hdc = CreateCompatibleDC(NULL);
|
|
|
|
Gdiplus::Font font(hdc, hFont);
|
|
Gdiplus::Graphics *graphics = new Gdiplus::Graphics(hdc);
|
|
|
|
graphics->SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAlias);
|
|
|
|
if(strCurrentText.IsValid())
|
|
{
|
|
// Apparently, \0 is not always a zero-width character?
|
|
// Not including it as part of the string measurement may cut off the final word
|
|
// on the line when using certain fonts together with outlines and wrapping.
|
|
INT strLength = strCurrentText.Length() + 1;
|
|
if(bUseExtents && bWrap)
|
|
{
|
|
layoutBox.X = layoutBox.Y = 0;
|
|
layoutBox.Width = float(extentWidth);
|
|
layoutBox.Height = float(extentHeight);
|
|
|
|
if(bUseOutline)
|
|
{
|
|
//Note: since there's no path widening in DrawOutlineText the padding is half than what it was supposed to be.
|
|
layoutBox.Width -= outlineSize;
|
|
layoutBox.Height -= outlineSize;
|
|
}
|
|
|
|
if(!bVertical && bScrollMode)
|
|
{
|
|
offset = ProcessScrollMode(graphics, &font, layoutBox, &format);
|
|
|
|
boundingBox = layoutBox;
|
|
boundingBox.Y = offset;
|
|
if(offset < 0)
|
|
boundingBox.Height -= offset;
|
|
}
|
|
else
|
|
{
|
|
stat = graphics->MeasureString(strCurrentText, strLength, &font, layoutBox, &format, &boundingBox);
|
|
if(stat != Gdiplus::Ok)
|
|
AppWarning(TEXT("TextSource::UpdateTexture: Gdiplus::Graphics::MeasureString failed: %u"), (int)stat);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
stat = graphics->MeasureString(strCurrentText, strLength, &font, Gdiplus::PointF(0.0f, 0.0f), &format, &boundingBox);
|
|
if(stat != Gdiplus::Ok)
|
|
AppWarning(TEXT("TextSource::UpdateTexture: Gdiplus::Graphics::MeasureString failed: %u"), (int)stat);
|
|
if(bUseOutline)
|
|
{
|
|
//Note: since there's no path widening in DrawOutlineText the padding is half than what it was supposed to be.
|
|
boundingBox.Width += outlineSize;
|
|
boundingBox.Height += outlineSize;
|
|
}
|
|
}
|
|
}
|
|
|
|
delete graphics;
|
|
|
|
DeleteDC(hdc);
|
|
hdc = NULL;
|
|
DeleteObject(hFont);
|
|
|
|
if(bVertical)
|
|
{
|
|
if(boundingBox.Width<size)
|
|
{
|
|
textSize.cx = size;
|
|
boundingBox.Width = float(size);
|
|
}
|
|
else
|
|
textSize.cx = LONG(boundingBox.Width + EPSILON);
|
|
|
|
textSize.cy = LONG(boundingBox.Height + EPSILON);
|
|
}
|
|
else
|
|
{
|
|
if(boundingBox.Height<size)
|
|
{
|
|
textSize.cy = size;
|
|
boundingBox.Height = float(size);
|
|
}
|
|
else
|
|
textSize.cy = LONG(boundingBox.Height + EPSILON);
|
|
|
|
textSize.cx = LONG(boundingBox.Width + EPSILON);
|
|
}
|
|
|
|
if(bUseExtents)
|
|
{
|
|
if(bWrap)
|
|
{
|
|
textSize.cx = extentWidth;
|
|
textSize.cy = extentHeight;
|
|
}
|
|
else
|
|
{
|
|
if(LONG(extentWidth) > textSize.cx)
|
|
textSize.cx = extentWidth;
|
|
if(LONG(extentHeight) > textSize.cy)
|
|
textSize.cy = extentHeight;
|
|
}
|
|
}
|
|
|
|
//textSize.cx &= 0xFFFFFFFE;
|
|
//textSize.cy &= 0xFFFFFFFE;
|
|
|
|
textSize.cx += textSize.cx%2;
|
|
textSize.cy += textSize.cy%2;
|
|
|
|
ClampVal(textSize.cx, MIN_TEX_SIZE_W, MAX_TEX_SIZE_W);
|
|
ClampVal(textSize.cy, MIN_TEX_SIZE_H, MAX_TEX_SIZE_H);
|
|
|
|
//----------------------------------------------------------------------
|
|
// write image
|
|
|
|
{
|
|
HDC hTempDC = CreateCompatibleDC(NULL);
|
|
|
|
BITMAPINFO bi;
|
|
zero(&bi, sizeof(bi));
|
|
|
|
void* lpBits;
|
|
|
|
BITMAPINFOHEADER &bih = bi.bmiHeader;
|
|
bih.biSize = sizeof(bih);
|
|
bih.biBitCount = 32;
|
|
bih.biWidth = textSize.cx;
|
|
bih.biHeight = textSize.cy;
|
|
bih.biPlanes = 1;
|
|
|
|
HBITMAP hBitmap = CreateDIBSection(hTempDC, &bi, DIB_RGB_COLORS, &lpBits, NULL, 0);
|
|
|
|
Gdiplus::Bitmap bmp(textSize.cx, textSize.cy, 4*textSize.cx, PixelFormat32bppARGB, (BYTE*)lpBits);
|
|
|
|
graphics = new Gdiplus::Graphics(&bmp);
|
|
|
|
Gdiplus::SolidBrush *brush = new Gdiplus::SolidBrush(Gdiplus::Color(GetAlphaVal(opacity)|(color&0x00FFFFFF)));
|
|
|
|
DWORD bkColor;
|
|
|
|
if(backgroundOpacity == 0 && scrollSpeed !=0)
|
|
bkColor = 1<<24 | (color&0x00FFFFFF);
|
|
else
|
|
bkColor = ((strCurrentText.IsValid() || bUseExtents) ? GetAlphaVal(backgroundOpacity) : GetAlphaVal(0)) | (backgroundColor&0x00FFFFFF);
|
|
|
|
if((textSize.cx > boundingBox.Width || textSize.cy > boundingBox.Height) && !bUseExtents)
|
|
{
|
|
stat = graphics->Clear(Gdiplus::Color( 0x00000000));
|
|
if(stat != Gdiplus::Ok)
|
|
AppWarning(TEXT("TextSource::UpdateTexture: Graphics::Clear failed: %u"), (int)stat);
|
|
|
|
Gdiplus::SolidBrush *bkBrush = new Gdiplus::SolidBrush(Gdiplus::Color( bkColor ));
|
|
|
|
graphics->FillRectangle(bkBrush, boundingBox);
|
|
|
|
delete bkBrush;
|
|
}
|
|
else
|
|
{
|
|
stat = graphics->Clear(Gdiplus::Color( bkColor ));
|
|
if(stat != Gdiplus::Ok)
|
|
AppWarning(TEXT("TextSource::UpdateTexture: Graphics::Clear failed: %u"), (int)stat);
|
|
}
|
|
|
|
graphics->SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAlias);
|
|
graphics->SetCompositingMode(Gdiplus::CompositingModeSourceOver);
|
|
graphics->SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
|
|
|
|
if(strCurrentText.IsValid())
|
|
{
|
|
if(bUseOutline)
|
|
{
|
|
boundingBox.Offset(outlineSize/2, outlineSize/2);
|
|
|
|
Gdiplus::FontFamily fontFamily;
|
|
Gdiplus::GraphicsPath path;
|
|
|
|
font.GetFamily(&fontFamily);
|
|
|
|
path.AddString(strCurrentText, -1, &fontFamily, font.GetStyle(), font.GetSize(), boundingBox, &format);
|
|
|
|
DrawOutlineText(graphics, font, path, format, brush);
|
|
}
|
|
else
|
|
{
|
|
stat = graphics->DrawString(strCurrentText, -1, &font, boundingBox, &format, brush);
|
|
if(stat != Gdiplus::Ok)
|
|
AppWarning(TEXT("TextSource::UpdateTexture: Graphics::DrawString failed: %u"), (int)stat);
|
|
}
|
|
}
|
|
|
|
delete brush;
|
|
delete graphics;
|
|
|
|
//----------------------------------------------------------------------
|
|
// upload texture
|
|
|
|
if(textureSize.cx != textSize.cx || textureSize.cy != textSize.cy)
|
|
{
|
|
if(texture)
|
|
{
|
|
delete texture;
|
|
texture = NULL;
|
|
}
|
|
|
|
mcpy(&textureSize, &textSize, sizeof(textureSize));
|
|
texture = CreateTexture(textSize.cx, textSize.cy, GS_BGRA, lpBits, FALSE, FALSE);
|
|
}
|
|
else if(texture)
|
|
texture->SetImage(lpBits, GS_IMAGEFORMAT_BGRA, 4*textSize.cx);
|
|
|
|
if(!texture)
|
|
{
|
|
AppWarning(TEXT("TextSource::UpdateTexture: could not create texture"));
|
|
DeleteObject(hFont);
|
|
}
|
|
|
|
DeleteDC(hTempDC);
|
|
DeleteObject(hBitmap);
|
|
}
|
|
}
|
|
|
|
public:
|
|
inline TextOutputSource(XElement *data)
|
|
{
|
|
this->data = data;
|
|
UpdateSettings();
|
|
|
|
SamplerInfo si;
|
|
zero(&si, sizeof(si));
|
|
si.addressU = GS_ADDRESS_REPEAT;
|
|
si.addressV = GS_ADDRESS_REPEAT;
|
|
si.borderColor = 0;
|
|
si.filter = GS_FILTER_LINEAR;
|
|
ss = CreateSamplerState(si);
|
|
globalOpacity = 100;
|
|
|
|
Log(TEXT("Using text output"));
|
|
}
|
|
|
|
~TextOutputSource()
|
|
{
|
|
if(texture)
|
|
{
|
|
delete texture;
|
|
texture = NULL;
|
|
}
|
|
|
|
delete ss;
|
|
|
|
if(bMonitoringFileChanges)
|
|
{
|
|
OSMonitorFileDestroy(fileChangeMonitor);
|
|
}
|
|
}
|
|
|
|
void Preprocess()
|
|
{
|
|
if(bMonitoringFileChanges)
|
|
{
|
|
if (OSFileHasChanged(fileChangeMonitor))
|
|
bUpdateTexture = true;
|
|
}
|
|
|
|
if(bUpdateTexture)
|
|
{
|
|
bUpdateTexture = false;
|
|
UpdateTexture();
|
|
}
|
|
}
|
|
|
|
void Tick(float fSeconds)
|
|
{
|
|
if(scrollSpeed != 0 && texture)
|
|
{
|
|
scrollValue += fSeconds*float(scrollSpeed)/(bVertical?(-1.0f)*float(textureSize.cy):float(textureSize.cx));
|
|
while(scrollValue > 1.0f)
|
|
scrollValue -= 1.0f;
|
|
while(scrollValue < -1.0f)
|
|
scrollValue += 1.0f;
|
|
}
|
|
|
|
if(showExtentTime > 0.0f)
|
|
showExtentTime -= fSeconds;
|
|
|
|
if(bDoUpdate)
|
|
{
|
|
bDoUpdate = false;
|
|
bUpdateTexture = true;
|
|
}
|
|
}
|
|
|
|
void Render(const Vect2 &pos, const Vect2 &size)
|
|
{
|
|
if(texture)
|
|
{
|
|
//EnableBlending(FALSE);
|
|
|
|
Vect2 sizeMultiplier = size/baseSize;
|
|
Vect2 newSize = Vect2(float(textureSize.cx), float(textureSize.cy))*sizeMultiplier;
|
|
|
|
if(bUseExtents)
|
|
{
|
|
Vect2 extentVal = Vect2(float(extentWidth), float(extentHeight))*sizeMultiplier;
|
|
if(showExtentTime > 0.0f)
|
|
{
|
|
Shader *pShader = GS->GetCurrentPixelShader();
|
|
Shader *vShader = GS->GetCurrentVertexShader();
|
|
|
|
Color4 rectangleColor = Color4(0.0f, 1.0f, 0.0f, 1.0f);
|
|
if(showExtentTime < 1.0f)
|
|
rectangleColor.w = showExtentTime;
|
|
|
|
App->solidPixelShader->SetColor(App->solidPixelShader->GetParameter(0), rectangleColor);
|
|
|
|
LoadVertexShader(App->solidVertexShader);
|
|
LoadPixelShader(App->solidPixelShader);
|
|
DrawBox(pos, extentVal);
|
|
|
|
LoadVertexShader(vShader);
|
|
LoadPixelShader(pShader);
|
|
}
|
|
|
|
if(!bWrap)
|
|
{
|
|
XRect rect = {int(pos.x), int(pos.y), int(extentVal.x), int(extentVal.y)};
|
|
SetScissorRect(&rect);
|
|
}
|
|
}
|
|
|
|
if(bUsePointFiltering) {
|
|
if (!sampler) {
|
|
SamplerInfo samplerinfo;
|
|
samplerinfo.filter = GS_FILTER_POINT;
|
|
std::unique_ptr<SamplerState> new_sampler(CreateSamplerState(samplerinfo));
|
|
sampler = std::move(new_sampler);
|
|
}
|
|
|
|
LoadSamplerState(sampler.get(), 0);
|
|
}
|
|
|
|
DWORD alpha = DWORD(double(globalOpacity)*2.55);
|
|
DWORD outputColor = (alpha << 24) | 0xFFFFFF;
|
|
|
|
if(scrollSpeed != 0)
|
|
{
|
|
UVCoord ul(0.0f, 0.0f);
|
|
UVCoord lr(1.0f, 1.0f);
|
|
|
|
if(bVertical)
|
|
{
|
|
/*float sizeVal = float(textureSize.cy);
|
|
float clampedVal = floorf(scrollValue*sizeVal)/sizeVal;*/
|
|
ul.y += scrollValue;
|
|
lr.y += scrollValue;
|
|
}
|
|
else
|
|
{
|
|
/*float sizeVal = float(textureSize.cx);
|
|
float clampedVal = floorf(scrollValue*sizeVal)/sizeVal;*/
|
|
ul.x += scrollValue;
|
|
lr.x += scrollValue;
|
|
}
|
|
|
|
LoadSamplerState(ss);
|
|
DrawSpriteEx(texture, outputColor, pos.x, pos.y, pos.x+newSize.x, pos.y+newSize.y, ul.x, ul.y, lr.x, lr.y);
|
|
}
|
|
else
|
|
DrawSprite(texture, outputColor, pos.x, pos.y, pos.x+newSize.x, pos.y+newSize.y);
|
|
|
|
if (bUsePointFiltering)
|
|
LoadSamplerState(NULL, 0);
|
|
|
|
if(bUseExtents && !bWrap)
|
|
SetScissorRect(NULL);
|
|
//EnableBlending(TRUE);
|
|
}
|
|
}
|
|
|
|
Vect2 GetSize() const
|
|
{
|
|
return baseSize;
|
|
}
|
|
|
|
void UpdateSettings()
|
|
{
|
|
strFont = data->GetString(TEXT("font"), TEXT("Arial"));
|
|
color = data->GetInt(TEXT("color"), 0xFFFFFFFF);
|
|
size = data->GetInt(TEXT("fontSize"), 48);
|
|
opacity = data->GetInt(TEXT("textOpacity"), 100);
|
|
scrollSpeed = data->GetInt(TEXT("scrollSpeed"), 0);
|
|
bBold = data->GetInt(TEXT("bold"), 0) != 0;
|
|
bItalic = data->GetInt(TEXT("italic"), 0) != 0;
|
|
bWrap = data->GetInt(TEXT("wrap"), 0) != 0;
|
|
bScrollMode = data->GetInt(TEXT("scrollMode"), 0) != 0;
|
|
bUnderline = data->GetInt(TEXT("underline"), 0) != 0;
|
|
bVertical = data->GetInt(TEXT("vertical"), 0) != 0;
|
|
bUseExtents = data->GetInt(TEXT("useTextExtents"), 0) != 0;
|
|
extentWidth = data->GetInt(TEXT("extentWidth"), 0);
|
|
extentHeight= data->GetInt(TEXT("extentHeight"), 0);
|
|
align = data->GetInt(TEXT("align"), 0);
|
|
strFile = data->GetString(TEXT("file"));
|
|
strText = data->GetString(TEXT("text"));
|
|
mode = data->GetInt(TEXT("mode"), 0);
|
|
bUsePointFiltering = data->GetInt(TEXT("pointFiltering"), 0) != 0;
|
|
|
|
baseSize.x = data->GetFloat(TEXT("baseSizeCX"), MIN_TEX_SIZE_W);
|
|
baseSize.y = data->GetFloat(TEXT("baseSizeCY"), MIN_TEX_SIZE_H);
|
|
|
|
bUseOutline = data->GetInt(TEXT("useOutline")) != 0;
|
|
outlineColor = data->GetInt(TEXT("outlineColor"), 0xFF000000);
|
|
outlineSize = data->GetFloat(TEXT("outlineSize"), 2);
|
|
outlineOpacity = data->GetInt(TEXT("outlineOpacity"), 100);
|
|
|
|
backgroundColor = data->GetInt(TEXT("backgroundColor"), 0xFF000000);
|
|
backgroundOpacity = data->GetInt(TEXT("backgroundOpacity"), 0);
|
|
|
|
bUpdateTexture = true;
|
|
}
|
|
|
|
void SetString(CTSTR lpName, CTSTR lpVal)
|
|
{
|
|
if(scmpi(lpName, TEXT("font")) == 0)
|
|
strFont = lpVal;
|
|
else if(scmpi(lpName, TEXT("text")) == 0)
|
|
strText = lpVal;
|
|
else if(scmpi(lpName, TEXT("file")) == 0)
|
|
strFile = lpVal;
|
|
|
|
bUpdateTexture = true;
|
|
}
|
|
|
|
void SetInt(CTSTR lpName, int iValue)
|
|
{
|
|
if(scmpi(lpName, TEXT("color")) == 0)
|
|
color = iValue;
|
|
else if(scmpi(lpName, TEXT("fontSize")) == 0)
|
|
size = iValue;
|
|
else if(scmpi(lpName, TEXT("textOpacity")) == 0)
|
|
opacity = iValue;
|
|
else if(scmpi(lpName, TEXT("scrollSpeed")) == 0)
|
|
{
|
|
if(scrollSpeed == 0)
|
|
scrollValue = 0.0f;
|
|
scrollSpeed = iValue;
|
|
}
|
|
else if(scmpi(lpName, TEXT("bold")) == 0)
|
|
bBold = iValue != 0;
|
|
else if(scmpi(lpName, TEXT("italic")) == 0)
|
|
bItalic = iValue != 0;
|
|
else if(scmpi(lpName, TEXT("wrap")) == 0)
|
|
bWrap = iValue != 0;
|
|
else if(scmpi(lpName, TEXT("scrollMode")) == 0)
|
|
bScrollMode = iValue != 0;
|
|
else if(scmpi(lpName, TEXT("underline")) == 0)
|
|
bUnderline = iValue != 0;
|
|
else if(scmpi(lpName, TEXT("vertical")) == 0)
|
|
bVertical = iValue != 0;
|
|
else if(scmpi(lpName, TEXT("useTextExtents")) == 0)
|
|
bUseExtents = iValue != 0;
|
|
else if(scmpi(lpName, TEXT("extentWidth")) == 0)
|
|
{
|
|
showExtentTime = 2.0f;
|
|
extentWidth = iValue;
|
|
}
|
|
else if(scmpi(lpName, TEXT("extentHeight")) == 0)
|
|
{
|
|
showExtentTime = 2.0f;
|
|
extentHeight = iValue;
|
|
}
|
|
else if(scmpi(lpName, TEXT("align")) == 0)
|
|
align = iValue;
|
|
else if(scmpi(lpName, TEXT("mode")) == 0)
|
|
mode = iValue;
|
|
else if(scmpi(lpName, TEXT("useOutline")) == 0)
|
|
bUseOutline = iValue != 0;
|
|
else if(scmpi(lpName, TEXT("outlineColor")) == 0)
|
|
outlineColor = iValue;
|
|
else if(scmpi(lpName, TEXT("outlineOpacity")) == 0)
|
|
outlineOpacity = iValue;
|
|
else if(scmpi(lpName, TEXT("backgroundColor")) == 0)
|
|
backgroundColor = iValue;
|
|
else if(scmpi(lpName, TEXT("backgroundOpacity")) == 0)
|
|
backgroundOpacity = iValue;
|
|
|
|
bUpdateTexture = true;
|
|
}
|
|
|
|
void SetFloat(CTSTR lpName, float fValue)
|
|
{
|
|
if(scmpi(lpName, TEXT("outlineSize")) == 0)
|
|
outlineSize = fValue;
|
|
|
|
bUpdateTexture = true;
|
|
}
|
|
|
|
inline void ResetExtentRect() {showExtentTime = 0.0f;}
|
|
};
|
|
|
|
struct ConfigTextSourceInfo
|
|
{
|
|
CTSTR lpName;
|
|
XElement *data;
|
|
float cx, cy;
|
|
|
|
StringList fontNames;
|
|
StringList fontFaces;
|
|
};
|
|
|
|
ImageSource* STDCALL CreateTextSource(XElement *data)
|
|
{
|
|
if(!data)
|
|
return NULL;
|
|
|
|
return new TextOutputSource(data);
|
|
}
|
|
|
|
int CALLBACK FontEnumProcThingy(ENUMLOGFONTEX *logicalData, NEWTEXTMETRICEX *physicalData, DWORD fontType, ConfigTextSourceInfo *configInfo)
|
|
{
|
|
if(fontType == TRUETYPE_FONTTYPE) //HomeWorld - GDI+ doesn't like anything other than truetype
|
|
{
|
|
configInfo->fontNames << logicalData->elfFullName;
|
|
configInfo->fontFaces << logicalData->elfLogFont.lfFaceName;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
void DoCancelStuff(HWND hwnd)
|
|
{
|
|
ConfigTextSourceInfo *configInfo = (ConfigTextSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
|
|
ImageSource *source = API->GetSceneImageSource(configInfo->lpName);
|
|
//XElement *data = configInfo->data;
|
|
|
|
if(source)
|
|
source->UpdateSettings();
|
|
}
|
|
|
|
UINT FindFontFace(ConfigTextSourceInfo *configInfo, HWND hwndFontList, CTSTR lpFontFace)
|
|
{
|
|
UINT id = configInfo->fontFaces.FindValueIndexI(lpFontFace);
|
|
if(id == INVALID)
|
|
return INVALID;
|
|
else
|
|
{
|
|
for(UINT i=0; i<configInfo->fontFaces.Num(); i++)
|
|
{
|
|
UINT targetID = (UINT)SendMessage(hwndFontList, CB_GETITEMDATA, i, 0);
|
|
if(targetID == id)
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return INVALID;
|
|
}
|
|
|
|
UINT FindFontName(ConfigTextSourceInfo *configInfo, HWND hwndFontList, CTSTR lpFontFace)
|
|
{
|
|
return configInfo->fontNames.FindValueIndexI(lpFontFace);
|
|
}
|
|
|
|
CTSTR GetFontFace(ConfigTextSourceInfo *configInfo, HWND hwndFontList)
|
|
{
|
|
UINT id = (UINT)SendMessage(hwndFontList, CB_GETCURSEL, 0, 0);
|
|
if(id == CB_ERR)
|
|
return NULL;
|
|
|
|
UINT actualID = (UINT)SendMessage(hwndFontList, CB_GETITEMDATA, id, 0);
|
|
return configInfo->fontFaces[actualID];
|
|
}
|
|
|
|
INT_PTR CALLBACK ConfigureTextProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
static bool bInitializedDialog = false;
|
|
|
|
switch(message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
ConfigTextSourceInfo *configInfo = (ConfigTextSourceInfo*)lParam;
|
|
SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)configInfo);
|
|
LocalizeWindow(hwnd);
|
|
|
|
XElement *data = configInfo->data;
|
|
|
|
//-----------------------------------------
|
|
|
|
HDC hDCtest = GetDC(hwnd);
|
|
|
|
LOGFONT lf;
|
|
zero(&lf, sizeof(lf));
|
|
EnumFontFamiliesEx(hDCtest, &lf, (FONTENUMPROC)FontEnumProcThingy, (LPARAM)configInfo, 0);
|
|
|
|
HWND hwndFonts = GetDlgItem(hwnd, IDC_FONT);
|
|
for(UINT i=0; i<configInfo->fontNames.Num(); i++)
|
|
{
|
|
int id = (int)SendMessage(hwndFonts, CB_ADDSTRING, 0, (LPARAM)configInfo->fontNames[i].Array());
|
|
SendMessage(hwndFonts, CB_SETITEMDATA, id, (LPARAM)i);
|
|
}
|
|
|
|
CTSTR lpFont = data->GetString(TEXT("font"));
|
|
UINT id = FindFontFace(configInfo, hwndFonts, lpFont);
|
|
if(id == INVALID)
|
|
id = (UINT)SendMessage(hwndFonts, CB_FINDSTRINGEXACT, -1, (LPARAM)TEXT("Arial"));
|
|
|
|
SendMessage(hwndFonts, CB_SETCURSEL, id, 0);
|
|
|
|
//-----------------------------------------
|
|
|
|
SendMessage(GetDlgItem(hwnd, IDC_TEXTSIZE), UDM_SETRANGE32, 5, MAX_TEX_SIZE_H);
|
|
SendMessage(GetDlgItem(hwnd, IDC_TEXTSIZE), UDM_SETPOS32, 0, data->GetInt(TEXT("fontSize"), 48));
|
|
|
|
//-----------------------------------------
|
|
|
|
CCSetColor(GetDlgItem(hwnd, IDC_COLOR), data->GetInt(TEXT("color"), 0xFFFFFFFF));
|
|
|
|
SendMessage(GetDlgItem(hwnd, IDC_TEXTOPACITY), UDM_SETRANGE32, 0, 100);
|
|
SendMessage(GetDlgItem(hwnd, IDC_TEXTOPACITY), UDM_SETPOS32, 0, data->GetInt(TEXT("textOpacity"), 100));
|
|
|
|
SendMessage(GetDlgItem(hwnd, IDC_SCROLLSPEED), UDM_SETRANGE32, -4095, 4095);
|
|
SendMessage(GetDlgItem(hwnd, IDC_SCROLLSPEED), UDM_SETPOS32, 0, data->GetInt(TEXT("scrollSpeed"), 0));
|
|
|
|
SendMessage(GetDlgItem(hwnd, IDC_BOLD), BM_SETCHECK, data->GetInt(TEXT("bold"), 0) ? BST_CHECKED : BST_UNCHECKED, 0);
|
|
SendMessage(GetDlgItem(hwnd, IDC_ITALIC), BM_SETCHECK, data->GetInt(TEXT("italic"), 0) ? BST_CHECKED : BST_UNCHECKED, 0);
|
|
SendMessage(GetDlgItem(hwnd, IDC_UNDERLINE), BM_SETCHECK, data->GetInt(TEXT("underline"), 0) ? BST_CHECKED : BST_UNCHECKED, 0);
|
|
|
|
SendMessage(GetDlgItem(hwnd, IDC_VERTICALSCRIPT), BM_SETCHECK, data->GetInt(TEXT("vertical"), 0) ? BST_CHECKED : BST_UNCHECKED, 0);
|
|
|
|
BOOL bUsePointFilter = data->GetInt(TEXT("pointFiltering"), 0) != 0;
|
|
SendMessage(GetDlgItem(hwnd, IDC_POINTFILTERING), BM_SETCHECK, bUsePointFilter ? BST_CHECKED : BST_UNCHECKED, 0);
|
|
|
|
//-----------------------------------------
|
|
|
|
CCSetColor(GetDlgItem(hwnd, IDC_BACKGROUNDCOLOR), data->GetInt(TEXT("backgroundColor"), 0xFF000000));
|
|
|
|
SendMessage(GetDlgItem(hwnd, IDC_BACKGROUNDOPACITY), UDM_SETRANGE32, 0, 100);
|
|
SendMessage(GetDlgItem(hwnd, IDC_BACKGROUNDOPACITY), UDM_SETPOS32, 0, data->GetInt(TEXT("backgroundOpacity"), 0));
|
|
|
|
//-----------------------------------------
|
|
|
|
bool bChecked = data->GetInt(TEXT("useOutline"), 0) != 0;
|
|
SendMessage(GetDlgItem(hwnd, IDC_USEOUTLINE), BM_SETCHECK, bChecked ? BST_CHECKED : BST_UNCHECKED, 0);
|
|
|
|
EnableWindow(GetDlgItem(hwnd, IDC_OUTLINETHICKNESS_EDIT), bChecked);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_OUTLINETHICKNESS), bChecked);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_OUTLINECOLOR), bChecked);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_OUTLINEOPACITY_EDIT), bChecked);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_OUTLINEOPACITY), bChecked);
|
|
|
|
SendMessage(GetDlgItem(hwnd, IDC_OUTLINETHICKNESS), UDM_SETRANGE32, 1, 20);
|
|
SendMessage(GetDlgItem(hwnd, IDC_OUTLINETHICKNESS), UDM_SETPOS32, 0, data->GetInt(TEXT("outlineSize"), 2));
|
|
|
|
CCSetColor(GetDlgItem(hwnd, IDC_OUTLINECOLOR), data->GetInt(TEXT("outlineColor"), 0xFF000000));
|
|
|
|
SendMessage(GetDlgItem(hwnd, IDC_OUTLINEOPACITY), UDM_SETRANGE32, 0, 100);
|
|
SendMessage(GetDlgItem(hwnd, IDC_OUTLINEOPACITY), UDM_SETPOS32, 0, data->GetInt(TEXT("outlineOpacity"), 100));
|
|
|
|
//-----------------------------------------
|
|
|
|
bChecked = data->GetInt(TEXT("useTextExtents"), 0) != 0;
|
|
SendMessage(GetDlgItem(hwnd, IDC_USETEXTEXTENTS), BM_SETCHECK, bChecked ? BST_CHECKED : BST_UNCHECKED, 0);
|
|
ConfigureTextProc(hwnd, WM_COMMAND, MAKEWPARAM(IDC_USETEXTEXTENTS, BN_CLICKED), (LPARAM)GetDlgItem(hwnd, IDC_USETEXTEXTENTS));
|
|
|
|
EnableWindow(GetDlgItem(hwnd, IDC_EXTENTWIDTH_EDIT), bChecked);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_EXTENTHEIGHT_EDIT), bChecked);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_EXTENTWIDTH), bChecked);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_EXTENTHEIGHT), bChecked);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_WRAP), bChecked);
|
|
|
|
bool bVertical = data->GetInt(TEXT("vertical"), 0) != 0;
|
|
|
|
SendMessage(GetDlgItem(hwnd, IDC_EXTENTWIDTH), UDM_SETRANGE32, MIN_TEX_SIZE_W, MAX_TEX_SIZE_W);
|
|
SendMessage(GetDlgItem(hwnd, IDC_EXTENTHEIGHT), UDM_SETRANGE32, MIN_TEX_SIZE_H, MAX_TEX_SIZE_H);
|
|
SendMessage(GetDlgItem(hwnd, IDC_EXTENTWIDTH), UDM_SETPOS32, 0, data->GetInt(TEXT("extentWidth"), MIN_TEX_SIZE_W));
|
|
SendMessage(GetDlgItem(hwnd, IDC_EXTENTHEIGHT), UDM_SETPOS32, 0, data->GetInt(TEXT("extentHeight"), MIN_TEX_SIZE_H));
|
|
|
|
bool bWrap = data->GetInt(TEXT("wrap"), 0) != 0;
|
|
SendMessage(GetDlgItem(hwnd, IDC_WRAP), BM_SETCHECK, bWrap ? BST_CHECKED : BST_UNCHECKED, 0);
|
|
|
|
bool bScrollMode = data->GetInt(TEXT("scrollMode"), 0) != 0;
|
|
SendMessage(GetDlgItem(hwnd, IDC_SCROLLMODE), BM_SETCHECK, bScrollMode ? BST_CHECKED : BST_UNCHECKED, 0);
|
|
|
|
EnableWindow(GetDlgItem(hwnd, IDC_ALIGN), bChecked && bWrap);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_SCROLLMODE), bChecked && bWrap && !bVertical);
|
|
|
|
HWND hwndAlign = GetDlgItem(hwnd, IDC_ALIGN);
|
|
SendMessage(hwndAlign, CB_ADDSTRING, 0, (LPARAM)Str("Sources.TextSource.Left"));
|
|
SendMessage(hwndAlign, CB_ADDSTRING, 0, (LPARAM)Str("Sources.TextSource.Center"));
|
|
SendMessage(hwndAlign, CB_ADDSTRING, 0, (LPARAM)Str("Sources.TextSource.Right"));
|
|
|
|
int align = data->GetInt(TEXT("align"), 0);
|
|
ClampVal(align, 0, 2);
|
|
SendMessage(hwndAlign, CB_SETCURSEL, align, 0);
|
|
|
|
//-----------------------------------------
|
|
|
|
BOOL bUseFile = data->GetInt(TEXT("mode"), 0) == 1;
|
|
SendMessage(GetDlgItem(hwnd, IDC_USEFILE), BM_SETCHECK, bUseFile ? BST_CHECKED : BST_UNCHECKED, 0);
|
|
SendMessage(GetDlgItem(hwnd, IDC_USETEXT), BM_SETCHECK, bUseFile ? BST_UNCHECKED : BST_CHECKED, 0);
|
|
|
|
SetWindowText(GetDlgItem(hwnd, IDC_TEXT), data->GetString(TEXT("text")));
|
|
SetWindowText(GetDlgItem(hwnd, IDC_FILE), data->GetString(TEXT("file")));
|
|
|
|
EnableWindow(GetDlgItem(hwnd, IDC_TEXT), !bUseFile);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_FILE), bUseFile);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_BROWSE), bUseFile);
|
|
|
|
bInitializedDialog = true;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
case WM_DESTROY:
|
|
bInitializedDialog = false;
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch(LOWORD(wParam))
|
|
{
|
|
case IDC_FONT:
|
|
if(bInitializedDialog)
|
|
{
|
|
if(HIWORD(wParam) == CBN_SELCHANGE || HIWORD(wParam) == CBN_EDITCHANGE)
|
|
{
|
|
ConfigTextSourceInfo *configInfo = (ConfigTextSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
|
|
if(!configInfo) break;
|
|
|
|
String strFont;
|
|
if(HIWORD(wParam) == CBN_SELCHANGE)
|
|
strFont = GetFontFace(configInfo, (HWND)lParam);
|
|
else
|
|
{
|
|
UINT id = FindFontName(configInfo, (HWND)lParam, GetEditText((HWND)lParam));
|
|
if(id != INVALID)
|
|
strFont = configInfo->fontFaces[id];
|
|
}
|
|
|
|
ImageSource *source = API->GetSceneImageSource(configInfo->lpName);
|
|
if(source && strFont.IsValid())
|
|
source->SetString(TEXT("font"), strFont);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IDC_OUTLINECOLOR:
|
|
case IDC_BACKGROUNDCOLOR:
|
|
case IDC_COLOR:
|
|
if(bInitializedDialog)
|
|
{
|
|
DWORD color = CCGetColor((HWND)lParam);
|
|
|
|
ConfigTextSourceInfo *configInfo = (ConfigTextSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
|
|
if(!configInfo) break;
|
|
ImageSource *source = API->GetSceneImageSource(configInfo->lpName);
|
|
if(source)
|
|
{
|
|
switch(LOWORD(wParam))
|
|
{
|
|
case IDC_OUTLINECOLOR: source->SetInt(TEXT("outlineColor"), color); break;
|
|
case IDC_BACKGROUNDCOLOR: source->SetInt(TEXT("backgroundColor"), color); break;
|
|
case IDC_COLOR: source->SetInt(TEXT("color"), color); break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IDC_TEXTSIZE_EDIT:
|
|
case IDC_EXTENTWIDTH_EDIT:
|
|
case IDC_EXTENTHEIGHT_EDIT:
|
|
case IDC_BACKGROUNDOPACITY_EDIT:
|
|
case IDC_TEXTOPACITY_EDIT:
|
|
case IDC_OUTLINEOPACITY_EDIT:
|
|
case IDC_OUTLINETHICKNESS_EDIT:
|
|
case IDC_SCROLLSPEED_EDIT:
|
|
if(HIWORD(wParam) == EN_CHANGE && bInitializedDialog)
|
|
{
|
|
int val = (int)SendMessage(GetWindow((HWND)lParam, GW_HWNDNEXT), UDM_GETPOS32, 0, 0);
|
|
|
|
ConfigTextSourceInfo *configInfo = (ConfigTextSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
|
|
if(!configInfo) break;
|
|
|
|
ImageSource *source = API->GetSceneImageSource(configInfo->lpName);
|
|
if(source)
|
|
{
|
|
switch(LOWORD(wParam))
|
|
{
|
|
case IDC_TEXTSIZE_EDIT: source->SetInt(TEXT("fontSize"), val); break;
|
|
case IDC_EXTENTWIDTH_EDIT: source->SetInt(TEXT("extentWidth"), val); break;
|
|
case IDC_EXTENTHEIGHT_EDIT: source->SetInt(TEXT("extentHeight"), val); break;
|
|
case IDC_TEXTOPACITY_EDIT: source->SetInt(TEXT("textOpacity"), val); break;
|
|
case IDC_OUTLINEOPACITY_EDIT: source->SetInt(TEXT("outlineOpacity"), val); break;
|
|
case IDC_BACKGROUNDOPACITY_EDIT: source->SetInt(TEXT("backgroundOpacity"), val); break;
|
|
case IDC_OUTLINETHICKNESS_EDIT: source->SetFloat(TEXT("outlineSize"), (float)val); break;
|
|
case IDC_SCROLLSPEED_EDIT: source->SetInt(TEXT("scrollSpeed"), val); break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IDC_BOLD:
|
|
case IDC_ITALIC:
|
|
case IDC_UNDERLINE:
|
|
case IDC_VERTICALSCRIPT:
|
|
case IDC_WRAP:
|
|
case IDC_SCROLLMODE:
|
|
case IDC_USEOUTLINE:
|
|
case IDC_USETEXTEXTENTS:
|
|
if(HIWORD(wParam) == BN_CLICKED && bInitializedDialog)
|
|
{
|
|
BOOL bChecked = SendMessage((HWND)lParam, BM_GETCHECK, 0, 0) == BST_CHECKED;
|
|
|
|
ConfigTextSourceInfo *configInfo = (ConfigTextSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
|
|
if(!configInfo) break;
|
|
ImageSource *source = API->GetSceneImageSource(configInfo->lpName);
|
|
if(source)
|
|
{
|
|
switch(LOWORD(wParam))
|
|
{
|
|
case IDC_BOLD: source->SetInt(TEXT("bold"), bChecked); break;
|
|
case IDC_ITALIC: source->SetInt(TEXT("italic"), bChecked); break;
|
|
case IDC_UNDERLINE: source->SetInt(TEXT("underline"), bChecked); break;
|
|
case IDC_VERTICALSCRIPT: source->SetInt(TEXT("vertical"), bChecked); break;
|
|
case IDC_WRAP: source->SetInt(TEXT("wrap"), bChecked); break;
|
|
case IDC_SCROLLMODE: source->SetInt(TEXT("scrollMode"), bChecked); break;
|
|
case IDC_USEOUTLINE: source->SetInt(TEXT("useOutline"), bChecked); break;
|
|
case IDC_USETEXTEXTENTS: source->SetInt(TEXT("useTextExtents"), bChecked); break;
|
|
}
|
|
}
|
|
|
|
if(LOWORD(wParam) == IDC_VERTICALSCRIPT)
|
|
{
|
|
bool bWrap = SendMessage(GetDlgItem(hwnd, IDC_WRAP), BM_GETCHECK, 0, 0) == BST_CHECKED;
|
|
bool bUseExtents = SendMessage(GetDlgItem(hwnd, IDC_USETEXTEXTENTS), BM_GETCHECK, 0, 0) == BST_CHECKED;
|
|
|
|
EnableWindow(GetDlgItem(hwnd, IDC_SCROLLMODE), bWrap && bUseExtents && !bChecked);
|
|
}
|
|
else if(LOWORD(wParam) == IDC_WRAP)
|
|
{
|
|
bool bVertical = SendMessage(GetDlgItem(hwnd, IDC_VERTICALSCRIPT), BM_GETCHECK, 0, 0) == BST_CHECKED;
|
|
|
|
EnableWindow(GetDlgItem(hwnd, IDC_ALIGN), bChecked);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_SCROLLMODE), bChecked && !bVertical);
|
|
}
|
|
else if(LOWORD(wParam) == IDC_USETEXTEXTENTS)
|
|
{
|
|
EnableWindow(GetDlgItem(hwnd, IDC_EXTENTWIDTH_EDIT), bChecked);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_EXTENTHEIGHT_EDIT), bChecked);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_EXTENTWIDTH), bChecked);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_EXTENTHEIGHT), bChecked);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_WRAP), bChecked);
|
|
|
|
bool bWrap = SendMessage(GetDlgItem(hwnd, IDC_WRAP), BM_GETCHECK, 0, 0) == BST_CHECKED;
|
|
bool bVertical = SendMessage(GetDlgItem(hwnd, IDC_VERTICALSCRIPT), BM_GETCHECK, 0, 0) == BST_CHECKED;
|
|
|
|
EnableWindow(GetDlgItem(hwnd, IDC_ALIGN), bChecked && bWrap);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_SCROLLMODE), bChecked && bWrap && !bVertical);
|
|
}
|
|
else if(LOWORD(wParam) == IDC_USEOUTLINE)
|
|
{
|
|
EnableWindow(GetDlgItem(hwnd, IDC_OUTLINETHICKNESS_EDIT), bChecked);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_OUTLINETHICKNESS), bChecked);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_OUTLINECOLOR), bChecked);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_OUTLINEOPACITY_EDIT), bChecked);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_OUTLINEOPACITY), bChecked);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IDC_ALIGN:
|
|
if(HIWORD(wParam) == CBN_SELCHANGE && bInitializedDialog)
|
|
{
|
|
int align = (int)SendMessage((HWND)lParam, CB_GETCURSEL, 0, 0);
|
|
if(align == CB_ERR)
|
|
break;
|
|
|
|
ConfigTextSourceInfo *configInfo = (ConfigTextSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
|
|
if(!configInfo) break;
|
|
ImageSource *source = API->GetSceneImageSource(configInfo->lpName);
|
|
if(source)
|
|
source->SetInt(TEXT("align"), align);
|
|
}
|
|
break;
|
|
|
|
case IDC_FILE:
|
|
case IDC_TEXT:
|
|
if(HIWORD(wParam) == EN_CHANGE && bInitializedDialog)
|
|
{
|
|
String strText = GetEditText((HWND)lParam);
|
|
|
|
ConfigTextSourceInfo *configInfo = (ConfigTextSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
|
|
if(!configInfo) break;
|
|
ImageSource *source = API->GetSceneImageSource(configInfo->lpName);
|
|
if(source)
|
|
{
|
|
switch(LOWORD(wParam))
|
|
{
|
|
case IDC_FILE: source->SetString(TEXT("file"), strText); break;
|
|
case IDC_TEXT: source->SetString(TEXT("text"), strText); break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IDC_USEFILE:
|
|
if(HIWORD(wParam) == BN_CLICKED && bInitializedDialog)
|
|
{
|
|
EnableWindow(GetDlgItem(hwnd, IDC_TEXT), FALSE);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_FILE), TRUE);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_BROWSE), TRUE);
|
|
|
|
ConfigTextSourceInfo *configInfo = (ConfigTextSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
|
|
ImageSource *source = API->GetSceneImageSource(configInfo->lpName);
|
|
if(source)
|
|
source->SetInt(TEXT("mode"), 1);
|
|
}
|
|
break;
|
|
|
|
case IDC_USETEXT:
|
|
if(HIWORD(wParam) == BN_CLICKED && bInitializedDialog)
|
|
{
|
|
EnableWindow(GetDlgItem(hwnd, IDC_TEXT), TRUE);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_FILE), FALSE);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_BROWSE), FALSE);
|
|
|
|
ConfigTextSourceInfo *configInfo = (ConfigTextSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
|
|
if(!configInfo) break;
|
|
ImageSource *source = API->GetSceneImageSource(configInfo->lpName);
|
|
if(source)
|
|
source->SetInt(TEXT("mode"), 0);
|
|
}
|
|
break;
|
|
|
|
case IDC_BROWSE:
|
|
{
|
|
TCHAR lpFile[MAX_PATH+1];
|
|
zero(lpFile, sizeof(lpFile));
|
|
|
|
OPENFILENAME ofn;
|
|
zero(&ofn, sizeof(ofn));
|
|
ofn.lStructSize = sizeof(ofn);
|
|
ofn.lpstrFile = lpFile;
|
|
ofn.hwndOwner = hwnd;
|
|
ofn.nMaxFile = MAX_PATH;
|
|
ofn.lpstrFilter = TEXT("Text Files (*.txt)\0*.txt\0");
|
|
ofn.nFilterIndex = 1;
|
|
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
|
|
|
|
TCHAR curDirectory[MAX_PATH+1];
|
|
GetCurrentDirectory(MAX_PATH, curDirectory);
|
|
|
|
BOOL bOpenFile = GetOpenFileName(&ofn);
|
|
SetCurrentDirectory(curDirectory);
|
|
|
|
if(bOpenFile)
|
|
{
|
|
SetWindowText(GetDlgItem(hwnd, IDC_FILE), lpFile);
|
|
|
|
ConfigTextSourceInfo *configInfo = (ConfigTextSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
|
|
ImageSource *source = API->GetSceneImageSource(configInfo->lpName);
|
|
if(source)
|
|
source->SetString(TEXT("file"), lpFile);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IDOK:
|
|
{
|
|
ConfigTextSourceInfo *configInfo = (ConfigTextSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
|
|
if(!configInfo) break;
|
|
XElement *data = configInfo->data;
|
|
|
|
BOOL bUseTextExtents = SendMessage(GetDlgItem(hwnd, IDC_USETEXTEXTENTS), BM_GETCHECK, 0, 0) == BST_CHECKED;
|
|
BOOL bUseOutline = SendMessage(GetDlgItem(hwnd, IDC_USEOUTLINE), BM_GETCHECK, 0, 0) == BST_CHECKED;
|
|
float outlineSize = (float)SendMessage(GetDlgItem(hwnd, IDC_OUTLINETHICKNESS), UDM_GETPOS32, 0, 0);
|
|
|
|
int mode = SendMessage(GetDlgItem(hwnd, IDC_USEFILE), BM_GETCHECK, 0, 0) == BST_CHECKED;
|
|
|
|
String strText = GetEditText(GetDlgItem(hwnd, IDC_TEXT));
|
|
String strFile = GetEditText(GetDlgItem(hwnd, IDC_FILE));
|
|
|
|
UINT extentWidth = (UINT)SendMessage(GetDlgItem(hwnd, IDC_EXTENTWIDTH), UDM_GETPOS32, 0, 0);
|
|
UINT extentHeight = (UINT)SendMessage(GetDlgItem(hwnd, IDC_EXTENTHEIGHT), UDM_GETPOS32, 0, 0);
|
|
|
|
String strFont = GetFontFace(configInfo, GetDlgItem(hwnd, IDC_FONT));
|
|
UINT fontSize = (UINT)SendMessage(GetDlgItem(hwnd, IDC_TEXTSIZE), UDM_GETPOS32, 0, 0);
|
|
|
|
BOOL bBold = SendMessage(GetDlgItem(hwnd, IDC_BOLD), BM_GETCHECK, 0, 0) == BST_CHECKED;
|
|
BOOL bItalic = SendMessage(GetDlgItem(hwnd, IDC_ITALIC), BM_GETCHECK, 0, 0) == BST_CHECKED;
|
|
BOOL bVertical = SendMessage(GetDlgItem(hwnd, IDC_VERTICALSCRIPT), BM_GETCHECK, 0, 0) == BST_CHECKED;
|
|
|
|
BOOL pointFiltering = SendMessage(GetDlgItem(hwnd, IDC_POINTFILTERING), BM_GETCHECK, 0, 0) == BST_CHECKED;
|
|
|
|
String strFontDisplayName = GetEditText(GetDlgItem(hwnd, IDC_FONT));
|
|
if(strFont.IsEmpty())
|
|
{
|
|
UINT id = FindFontName(configInfo, GetDlgItem(hwnd, IDC_FONT), strFontDisplayName);
|
|
if(id != INVALID)
|
|
strFont = configInfo->fontFaces[id];
|
|
}
|
|
|
|
if(strFont.IsEmpty())
|
|
{
|
|
String strError = Str("Sources.TextSource.FontNotFound");
|
|
strError.FindReplace(TEXT("$1"), strFontDisplayName);
|
|
OBSMessageBox(hwnd, strError, NULL, 0);
|
|
break;
|
|
}
|
|
|
|
if(bUseTextExtents)
|
|
{
|
|
configInfo->cx = float(extentWidth);
|
|
configInfo->cy = float(extentHeight);
|
|
}
|
|
else
|
|
{
|
|
String strOutputText;
|
|
if(mode == 0)
|
|
strOutputText = strText;
|
|
else if(mode == 1)
|
|
{
|
|
XFile textFile;
|
|
if(strFile.IsEmpty() || !textFile.Open(strFile, XFILE_READ | XFILE_SHARED, XFILE_OPENEXISTING))
|
|
{
|
|
String strError = Str("Sources.TextSource.FileNotFound");
|
|
strError.FindReplace(TEXT("$1"), strFile);
|
|
|
|
OBSMessageBox(hwnd, strError, NULL, 0);
|
|
break;
|
|
}
|
|
|
|
textFile.ReadFileToString(strOutputText);
|
|
}
|
|
|
|
LOGFONT lf;
|
|
zero(&lf, sizeof(lf));
|
|
lf.lfHeight = fontSize;
|
|
lf.lfWeight = bBold ? FW_BOLD : FW_DONTCARE;
|
|
lf.lfItalic = bItalic;
|
|
lf.lfQuality = ANTIALIASED_QUALITY;
|
|
if(strFont.IsValid())
|
|
scpy_n(lf.lfFaceName, strFont, 31);
|
|
else
|
|
scpy_n(lf.lfFaceName, TEXT("Arial"), 31);
|
|
|
|
HDC hDC = CreateCompatibleDC(NULL);
|
|
|
|
Gdiplus::Font font(hDC, &lf);
|
|
|
|
if(!font.IsAvailable())
|
|
{
|
|
String strError = Str("Sources.TextSource.FontNotFound");
|
|
strError.FindReplace(TEXT("$1"), strFontDisplayName);
|
|
OBSMessageBox(hwnd, strError, NULL, 0);
|
|
DeleteDC(hDC);
|
|
break;
|
|
}
|
|
|
|
{
|
|
Gdiplus::Graphics graphics(hDC);
|
|
Gdiplus::StringFormat format(Gdiplus::StringFormat::GenericTypographic());
|
|
|
|
UINT formatFlags;
|
|
|
|
formatFlags = Gdiplus::StringFormatFlagsNoFitBlackBox
|
|
| Gdiplus::StringFormatFlagsMeasureTrailingSpaces;
|
|
|
|
if(bVertical)
|
|
formatFlags |= Gdiplus::StringFormatFlagsDirectionVertical
|
|
| Gdiplus::StringFormatFlagsDirectionRightToLeft;
|
|
|
|
format.SetFormatFlags(formatFlags);
|
|
format.SetTrimming(Gdiplus::StringTrimmingWord);
|
|
|
|
Gdiplus::RectF rcf;
|
|
graphics.MeasureString(strOutputText, -1, &font, Gdiplus::PointF(0.0f, 0.0f), &format, &rcf);
|
|
|
|
if(bUseOutline)
|
|
{
|
|
rcf.Height += outlineSize;
|
|
rcf.Width += outlineSize;
|
|
}
|
|
|
|
if(bVertical)
|
|
{
|
|
if(rcf.Width<fontSize)
|
|
rcf.Width = (float)fontSize;
|
|
}
|
|
else
|
|
{
|
|
if(rcf.Height<fontSize)
|
|
rcf.Height = (float)fontSize;
|
|
}
|
|
configInfo->cx = MAX(rcf.Width, 32.0f);
|
|
configInfo->cy = MAX(rcf.Height, 32.0f);
|
|
}
|
|
|
|
DeleteDC(hDC);
|
|
}
|
|
|
|
data->SetFloat(TEXT("baseSizeCX"), configInfo->cx);
|
|
data->SetFloat(TEXT("baseSizeCY"), configInfo->cy);
|
|
|
|
data->SetString(TEXT("font"), strFont);
|
|
data->SetInt(TEXT("color"), CCGetColor(GetDlgItem(hwnd, IDC_COLOR)));
|
|
data->SetInt(TEXT("fontSize"), fontSize);
|
|
data->SetInt(TEXT("textOpacity"), (UINT)SendMessage(GetDlgItem(hwnd, IDC_TEXTOPACITY), UDM_GETPOS32, 0, 0));
|
|
data->SetInt(TEXT("scrollSpeed"), (int)SendMessage(GetDlgItem(hwnd, IDC_SCROLLSPEED), UDM_GETPOS32, 0, 0));
|
|
data->SetInt(TEXT("bold"), bBold);
|
|
data->SetInt(TEXT("italic"), bItalic);
|
|
data->SetInt(TEXT("vertical"), bVertical);
|
|
data->SetInt(TEXT("wrap"), SendMessage(GetDlgItem(hwnd, IDC_WRAP), BM_GETCHECK, 0, 0) == BST_CHECKED);
|
|
data->SetInt(TEXT("scrollMode"), SendMessage(GetDlgItem(hwnd, IDC_SCROLLMODE), BM_GETCHECK, 0, 0) == BST_CHECKED);
|
|
data->SetInt(TEXT("underline"), SendMessage(GetDlgItem(hwnd, IDC_UNDERLINE), BM_GETCHECK, 0, 0) == BST_CHECKED);
|
|
data->SetInt(TEXT("pointFiltering"), pointFiltering);
|
|
|
|
data->SetInt(TEXT("backgroundColor"), CCGetColor(GetDlgItem(hwnd, IDC_BACKGROUNDCOLOR)));
|
|
data->SetInt(TEXT("backgroundOpacity"), (UINT)SendMessage(GetDlgItem(hwnd, IDC_BACKGROUNDOPACITY), UDM_GETPOS32, 0, 0));
|
|
|
|
data->SetInt(TEXT("useOutline"), bUseOutline);
|
|
data->SetInt(TEXT("outlineColor"), CCGetColor(GetDlgItem(hwnd, IDC_OUTLINECOLOR)));
|
|
data->SetFloat(TEXT("outlineSize"), outlineSize);
|
|
data->SetInt(TEXT("outlineOpacity"), (UINT)SendMessage(GetDlgItem(hwnd, IDC_OUTLINEOPACITY), UDM_GETPOS32, 0, 0));
|
|
|
|
data->SetInt(TEXT("useTextExtents"), bUseTextExtents);
|
|
data->SetInt(TEXT("extentWidth"), extentWidth);
|
|
data->SetInt(TEXT("extentHeight"), extentHeight);
|
|
data->SetInt(TEXT("align"), (int)SendMessage(GetDlgItem(hwnd, IDC_ALIGN), CB_GETCURSEL, 0, 0));
|
|
data->SetString(TEXT("file"), strFile);
|
|
data->SetString(TEXT("text"), strText);
|
|
data->SetInt(TEXT("mode"), mode);
|
|
}
|
|
|
|
case IDCANCEL:
|
|
if(LOWORD(wParam) == IDCANCEL)
|
|
DoCancelStuff(hwnd);
|
|
|
|
EndDialog(hwnd, LOWORD(wParam));
|
|
}
|
|
break;
|
|
|
|
case WM_CLOSE:
|
|
DoCancelStuff(hwnd);
|
|
EndDialog(hwnd, IDCANCEL);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
bool STDCALL ConfigureTextSource(XElement *element, bool bCreating)
|
|
{
|
|
if(!element)
|
|
{
|
|
AppWarning(TEXT("ConfigureTextSource: NULL element"));
|
|
return false;
|
|
}
|
|
|
|
XElement *data = element->GetElement(TEXT("data"));
|
|
if(!data)
|
|
data = element->CreateElement(TEXT("data"));
|
|
|
|
ConfigTextSourceInfo configInfo;
|
|
configInfo.lpName = element->GetName();
|
|
configInfo.data = data;
|
|
|
|
if(OBSDialogBox(hinstMain, MAKEINTRESOURCE(IDD_CONFIGURETEXTSOURCE), hwndMain, ConfigureTextProc, (LPARAM)&configInfo) == IDOK)
|
|
{
|
|
element->SetFloat(TEXT("cx"), configInfo.cx);
|
|
element->SetFloat(TEXT("cy"), configInfo.cy);
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|