/******************************************************************************** Copyright (C) 2012 Hugh Bailey 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 #define ClampVal(val, minVal, maxVal) \ if(val < minVal) val = minVal; \ else if(val > maxVal) val = maxVal; 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; bool bUseExtents; UINT extentWidth, extentHeight; bool bWrap; int align; Vect2 baseSize; SIZE textureSize; bool bMonitoringFileChanges; OSFileChangeData *fileChangeMonitor; 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(); // Stuff to make things look pretty graphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); graphics.SetInterpolationMode(Gdiplus::InterpolationModeHighQualityBicubic); graphics.SetCompositingMode(Gdiplus::CompositingModeSourceOver); // Outline color and size Gdiplus::Pen pen(Gdiplus::Color(GetAlphaVal(opacity) | (outlineColor&0xFFFFFF)), outlineSize); pen.SetLineJoin(Gdiplus::LineJoinRound); // Widen the outline outlinePath->Widen(&pen); // Draw the outline graphics.DrawPath(&pen, outlinePath); // Draw the text graphics.FillPath(brush, &path); delete outlinePath; } void UpdateTexture() { Gdiplus::Status stat; if(bMonitoringFileChanges) { OSMonitorFileDestroy(fileChangeMonitor); fileChangeMonitor = NULL; bMonitoringFileChanges = false; } if(mode == 0) strCurrentText = strText; else if(mode == 1) { XFile textFile; if(strFile.IsValid() && 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; } 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); } if(!hFont) return; SIZE textSize; SIZE actualTextSize; { HDC hDC = CreateCompatibleDC(NULL); { Gdiplus::Font font(hDC, hFont); Gdiplus::Graphics graphics(hDC); Gdiplus::StringFormat format(Gdiplus::StringFormat::GenericTypographic()); stat = graphics.SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAlias); if(stat != Gdiplus::Ok) AppWarning(TEXT("graphics.SetTextRenderingHint failed: %u"), (int)stat); if(bVertical) format.SetFormatFlags(Gdiplus::StringFormatFlagsDirectionVertical|Gdiplus::StringFormatFlagsDirectionRightToLeft|Gdiplus::StringFormatFlagsMeasureTrailingSpaces); else format.SetFormatFlags(Gdiplus::StringFormatFlagsMeasureTrailingSpaces); Gdiplus::RectF rcf; if(!strCurrentText.IsEmpty()) { stat = graphics.MeasureString(strCurrentText, -1, &font, Gdiplus::PointF(0.0f, 0.0f), &format, &rcf); if(stat != Gdiplus::Ok) AppWarning(TEXT("graphics.MeasureString failed: %u"), (int)stat); textSize.cx = long(rcf.Width+EPSILON); textSize.cy = long(rcf.Height+EPSILON); } else { textSize.cx = 32; textSize.cy = 32; } if(!textSize.cx || !textSize.cy) { AppWarning(TEXT("TextSource::UpdateTexture: bad texture sizes apparently, very strange")); DeleteObject(hFont); return; } } DeleteDC(hDC); } mcpy(&actualTextSize, &textSize, sizeof(actualTextSize)); 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; ClampVal(textSize.cx, 32, 4096); ClampVal(textSize.cy, 32, 4096); if(textureSize.cx != textSize.cx || textureSize.cy != textSize.cy) { if(texture) { delete texture; texture = NULL; } mcpy(&textureSize, &textSize, sizeof(textureSize)); texture = CreateGDITexture(textSize.cx, textSize.cy); } if(!texture) { AppWarning(TEXT("TextSource::UpdateTexture: could not create texture")); DeleteObject(hFont); return; } HDC hDC; if(texture->GetDC(hDC)) { 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 = textureSize.cx; bih.biHeight = textureSize.cy; bih.biPlanes = 1; HBITMAP hBitmap = CreateDIBSection(hTempDC, &bi, DIB_RGB_COLORS, &lpBits, NULL, 0); { Gdiplus::Bitmap bmp(textureSize.cx, textureSize.cy, 4*textureSize.cx, PixelFormat32bppARGB, (BYTE*)lpBits); Gdiplus::Graphics graphics(&bmp); Gdiplus::SolidBrush *brush = new Gdiplus::SolidBrush(Gdiplus::Color(GetAlphaVal(opacity)|(color&0x00FFFFFF))); Gdiplus::Font font(hTempDC, hFont); stat = graphics.SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAlias); if(stat != Gdiplus::Ok) AppWarning(TEXT("graphics.SetTextRenderingHint failed: %u"), (int)stat); if((textureSize.cx > actualTextSize.cx || textureSize.cy > actualTextSize.cy) && !bUseExtents) { stat = graphics.Clear(Gdiplus::Color( 0x00000000)); if(stat != Gdiplus::Ok) AppWarning(TEXT("graphics.Clear failed: %u"), (int)stat); Gdiplus::SolidBrush *bkBrush = new Gdiplus::SolidBrush(Gdiplus::Color( ((strCurrentText.IsValid() || bUseExtents) ? GetAlphaVal(backgroundOpacity) : GetAlphaVal(0)) | (backgroundColor&0x00FFFFFF))); Gdiplus::RectF bkClearRect(bVertical ? float(textureSize.cx - actualTextSize.cx) * 0.5f : 0.0f, bVertical ? 0.0f : float(textureSize.cy - actualTextSize.cy) * 0.5f, float(actualTextSize.cx) , bVertical ? float(textureSize.cy) : float(actualTextSize.cy)); graphics.FillRectangle(bkBrush, bkClearRect); } else { stat = graphics.Clear(Gdiplus::Color( ((strCurrentText.IsValid() || bUseExtents) ? GetAlphaVal(backgroundOpacity) : GetAlphaVal(0)) | (backgroundColor&0x00FFFFFF) )); if(stat != Gdiplus::Ok) AppWarning(TEXT("graphics.Clear failed: %u"), (int)stat); } float tx = 0.0f, ty = 0.0f; if(bVertical) if(textureSize.cx > size) tx = float(textureSize.cx) - float(textureSize.cx - size) * 0.5f; else tx = float(textureSize.cx); else if(textureSize.cy > size) ty = float(textureSize.cy - size) * 0.5f; if(bUseExtents && bWrap && strCurrentText.IsValid()) { Gdiplus::StringFormat format(Gdiplus::StringFormat::GenericTypographic()); Gdiplus::PointF pos(0.0f, 0.0f); 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); pos.X = float(textSize.cx/2); break; case 2: if(bVertical) format.SetLineAlignment(Gdiplus::StringAlignmentNear); else format.SetAlignment(Gdiplus::StringAlignmentFar); pos.X = float(textSize.cx); break; } if(bVertical) format.SetFormatFlags(Gdiplus::StringFormatFlagsDirectionVertical|Gdiplus::StringFormatFlagsDirectionRightToLeft); Gdiplus::RectF rcf(tx, ty, float(textureSize.cx), float(textureSize.cy)); if(bUseOutline) { Gdiplus::FontFamily fontFamily; font.GetFamily(&fontFamily); Gdiplus::GraphicsPath path; path.AddString(strCurrentText, -1, &fontFamily, font.GetStyle(), font.GetSize(), rcf, &format); DrawOutlineText(graphics, font, path, format, brush); } else { stat = graphics.DrawString(strCurrentText, -1, &font, rcf, &format, brush); if(stat != Gdiplus::Ok) AppWarning(TEXT("Hmm, DrawString failed: %u"), (int)stat); } } else if(strCurrentText.IsValid()) { Gdiplus::StringFormat format(Gdiplus::StringFormat::GenericTypographic()); if(bVertical) format.SetFormatFlags(Gdiplus::StringFormatFlagsDirectionVertical|Gdiplus::StringFormatFlagsDirectionRightToLeft); if(bUseOutline) { Gdiplus::FontFamily fontFamily; font.GetFamily(&fontFamily); Gdiplus::GraphicsPath path; path.AddString(strCurrentText, -1, &fontFamily, font.GetStyle(), font.GetSize(), Gdiplus::PointF(tx, ty), &format); DrawOutlineText(graphics, font, path, format, brush); } else { stat = graphics.DrawString(strCurrentText, -1, &font, Gdiplus::PointF(tx, ty), &format, brush); if(stat != Gdiplus::Ok) AppWarning(TEXT("Hmm, DrawString failed: %u"), (int)stat); } } delete brush; } HBITMAP hbmpOld = (HBITMAP)SelectObject(hTempDC, hBitmap); BitBlt(hDC, 0, 0, textureSize.cx, textureSize.cy, hTempDC, 0, 0, SRCCOPY); SelectObject(hTempDC, hbmpOld); DeleteDC(hTempDC); DeleteObject(hBitmap); texture->ReleaseDC(); } DeleteObject(hFont); } 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); } } 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+newSize.y, pos.x+newSize.x, pos.y, ul.x, ul.y, lr.x, lr.y); } else DrawSprite(texture, outputColor, pos.x, pos.y+newSize.y, pos.x+newSize.x, pos.y); 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"), 0xFF000000); size = data->GetInt(TEXT("fontSize"), 12); 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; 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); baseSize.x = data->GetFloat(TEXT("baseSizeCX"), 100); baseSize.y = data->GetFloat(TEXT("baseSizeCY"), 100); bUseOutline = data->GetInt(TEXT("useOutline")) != 0; outlineColor= data->GetInt(TEXT("outlineColor"), 0xFFFFFF); outlineSize = data->GetFloat(TEXT("outlineSize"), 2); 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("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("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; ifontFaces.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; ifontNames.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, 2048); SendMessage(GetDlgItem(hwnd, IDC_TEXTSIZE), UDM_SETPOS32, 0, data->GetInt(TEXT("fontSize"), 12)); //----------------------------------------- CCSetColor(GetDlgItem(hwnd, IDC_COLOR), data->GetInt(TEXT("color"), 0xFF000000)); 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); //----------------------------------------- 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); 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"), 0xFFFFFFFF)); //----------------------------------------- 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); EnableWindow(GetDlgItem(hwnd, IDC_ALIGN), bChecked); SendMessage(GetDlgItem(hwnd, IDC_EXTENTWIDTH), UDM_SETRANGE32, 32, 2048); SendMessage(GetDlgItem(hwnd, IDC_EXTENTHEIGHT), UDM_SETRANGE32, 32, 2048); SendMessage(GetDlgItem(hwnd, IDC_EXTENTWIDTH), UDM_SETPOS32, 0, data->GetInt(TEXT("extentWidth"), 100)); SendMessage(GetDlgItem(hwnd, IDC_EXTENTHEIGHT), UDM_SETPOS32, 0, data->GetInt(TEXT("extentHeight"), 100)); bool bWrap = data->GetInt(TEXT("wrap"), 0) != 0; SendMessage(GetDlgItem(hwnd, IDC_WRAP), BM_SETCHECK, bWrap ? BST_CHECKED : BST_UNCHECKED, 0); if(bChecked) EnableWindow(GetDlgItem(hwnd, IDC_ALIGN), bWrap); 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_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_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_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_USEOUTLINE: source->SetInt(TEXT("useOutline"), bChecked); break; case IDC_USETEXTEXTENTS: source->SetInt(TEXT("useTextExtents"), bChecked); break; } } if(LOWORD(wParam) == IDC_WRAP) EnableWindow(GetDlgItem(hwnd, IDC_ALIGN), bChecked); 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; EnableWindow(GetDlgItem(hwnd, IDC_ALIGN), bChecked); if(bChecked) EnableWindow(GetDlgItem(hwnd, IDC_ALIGN), bWrap); } 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); } } 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; 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; 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); MessageBox(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); MessageBox(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); MessageBox(hwnd, strError, NULL, 0); DeleteDC(hDC); break; } { Gdiplus::Graphics graphics(hDC); Gdiplus::StringFormat format(Gdiplus::StringFormat::GenericTypographic()); if(bVertical) format.SetFormatFlags(Gdiplus::StringFormatFlagsDirectionVertical|Gdiplus::StringFormatFlagsDirectionRightToLeft|Gdiplus::StringFormatFlagsMeasureTrailingSpaces); else format.SetFormatFlags(Gdiplus::StringFormatFlagsMeasureTrailingSpaces); Gdiplus::RectF rcf; graphics.MeasureString(strOutputText, -1, &font, Gdiplus::PointF(0.0f, 0.0f), &format, &rcf); 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("underline"), SendMessage(GetDlgItem(hwnd, IDC_UNDERLINE), BM_GETCHECK, 0, 0) == BST_CHECKED); 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"), SendMessage(GetDlgItem(hwnd, IDC_USEOUTLINE), BM_GETCHECK, 0, 0) == BST_CHECKED); data->SetInt(TEXT("outlineColor"), CCGetColor(GetDlgItem(hwnd, IDC_OUTLINECOLOR))); data->SetFloat(TEXT("outlineSize"), (float)SendMessage(GetDlgItem(hwnd, IDC_OUTLINETHICKNESS), 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(DialogBoxParam(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; }