| @@ -33,7 +33,7 @@ | |||
| <PackageName Value="LCL"/> | |||
| </Item1> | |||
| </RequiredPackages> | |||
| <Units Count="10"> | |||
| <Units Count="15"> | |||
| <Unit0> | |||
| <Filename Value="TextSuiteTest.lpr"/> | |||
| <IsPartOfProject Value="True"/> | |||
| @@ -59,6 +59,7 @@ | |||
| <Unit4> | |||
| <Filename Value="old\TextSuiteImports.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="TextSuiteImports"/> | |||
| </Unit4> | |||
| <Unit5> | |||
| <Filename Value="old\TextSuiteWideUtils.pas"/> | |||
| @@ -77,11 +78,34 @@ | |||
| <Unit8> | |||
| <Filename Value="old\TextSuiteTTFUtils.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="TextSuiteTTFUtils"/> | |||
| </Unit8> | |||
| <Unit9> | |||
| <Filename Value="old\TextSuiteVersion.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| </Unit9> | |||
| <Unit10> | |||
| <Filename Value="new\utsFontCreatorGDI.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="utsFontCreatorGDI"/> | |||
| </Unit10> | |||
| <Unit11> | |||
| <Filename Value="new\utsTtfUtils.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| </Unit11> | |||
| <Unit12> | |||
| <Filename Value="new\utsTypes.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| </Unit12> | |||
| <Unit13> | |||
| <Filename Value="new\utsUtils.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| </Unit13> | |||
| <Unit14> | |||
| <Filename Value="new\utsRendererOpenGL.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="utsRendererOpenGL"/> | |||
| </Unit14> | |||
| </Units> | |||
| </ProjectOptions> | |||
| <CompilerOptions> | |||
| @@ -92,10 +116,13 @@ | |||
| </Target> | |||
| <SearchPaths> | |||
| <IncludeFiles Value="$(ProjOutDir);old"/> | |||
| <OtherUnitFiles Value="old;..\bitSpace\_projects\MassiveUniverseOnline\bitSpaceEngine\src\OpenGLCore;new"/> | |||
| <OtherUnitFiles Value="old;new;..\bitSpace\_projects\MassiveUniverseOnline\bitSpaceEngine\src\OpenGLCore"/> | |||
| <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> | |||
| </SearchPaths> | |||
| <Linking> | |||
| <Debugging> | |||
| <UseHeaptrc Value="True"/> | |||
| </Debugging> | |||
| <Options> | |||
| <Win32> | |||
| <GraphicApplication Value="True"/> | |||
| @@ -7,8 +7,9 @@ uses | |||
| cthreads, | |||
| {$ENDIF}{$ENDIF} | |||
| Interfaces, // this includes the LCL widgetset | |||
| Forms, uMainForm, TextSuite, TextSuiteClasses, TextSuiteImports, TextSuitePostProcess, | |||
| TextSuiteTTFUtils, TextSuiteVersion, TextSuiteWideUtils, utsTextSuite; | |||
| Forms, uMainForm, TextSuite, TextSuiteClasses, TextSuiteImports, TextSuitePostProcess, TextSuiteTTFUtils, | |||
| TextSuiteVersion, TextSuiteWideUtils, utsTextSuite, utsFontCreatorGDI, utsTtfUtils, utsTypes, utsUtils, | |||
| utsRendererOpenGL; | |||
| {$R *.res} | |||
| @@ -4,13 +4,13 @@ | |||
| <PathDelim Value="\"/> | |||
| <Version Value="9"/> | |||
| <BuildModes Active="Default"/> | |||
| <Units Count="19"> | |||
| <Units Count="42"> | |||
| <Unit0> | |||
| <Filename Value="TextSuiteTest.lpr"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <EditorIndex Value="-1"/> | |||
| <CursorPos X="45" Y="17"/> | |||
| <UsageCount Value="60"/> | |||
| <UsageCount Value="92"/> | |||
| </Unit0> | |||
| <Unit1> | |||
| <Filename Value="uMainForm.pas"/> | |||
| @@ -19,9 +19,9 @@ | |||
| <HasResources Value="True"/> | |||
| <ResourceBaseClass Value="Form"/> | |||
| <UnitName Value="uMainForm"/> | |||
| <TopLine Value="79"/> | |||
| <CursorPos Y="97"/> | |||
| <UsageCount Value="60"/> | |||
| <IsVisibleTab Value="True"/> | |||
| <CursorPos X="3" Y="5"/> | |||
| <UsageCount Value="92"/> | |||
| <Loaded Value="True"/> | |||
| <LoadedDesigner Value="True"/> | |||
| </Unit1> | |||
| @@ -29,58 +29,59 @@ | |||
| <Filename Value="new\utsTextSuite.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="utsTextSuite"/> | |||
| <IsVisibleTab Value="True"/> | |||
| <EditorIndex Value="2"/> | |||
| <TopLine Value="1988"/> | |||
| <CursorPos X="22" Y="2002"/> | |||
| <UsageCount Value="59"/> | |||
| <TopLine Value="1886"/> | |||
| <CursorPos X="33" Y="1904"/> | |||
| <UsageCount Value="91"/> | |||
| <Loaded Value="True"/> | |||
| </Unit2> | |||
| <Unit3> | |||
| <Filename Value="old\TextSuite.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="TextSuite"/> | |||
| <EditorIndex Value="1"/> | |||
| <EditorIndex Value="6"/> | |||
| <WindowIndex Value="1"/> | |||
| <TopLine Value="207"/> | |||
| <CursorPos X="3" Y="223"/> | |||
| <TopLine Value="391"/> | |||
| <CursorPos X="13" Y="408"/> | |||
| <ExtraEditorCount Value="1"/> | |||
| <ExtraEditor1> | |||
| <EditorIndex Value="-1"/> | |||
| <TopLine Value="232"/> | |||
| <CursorPos X="3" Y="302"/> | |||
| </ExtraEditor1> | |||
| <UsageCount Value="54"/> | |||
| <UsageCount Value="86"/> | |||
| <Loaded Value="True"/> | |||
| </Unit3> | |||
| <Unit4> | |||
| <Filename Value="old\TextSuiteImports.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <EditorIndex Value="-1"/> | |||
| <TopLine Value="662"/> | |||
| <CursorPos X="3" Y="664"/> | |||
| <UsageCount Value="54"/> | |||
| <UnitName Value="TextSuiteImports"/> | |||
| <EditorIndex Value="5"/> | |||
| <WindowIndex Value="1"/> | |||
| <TopLine Value="656"/> | |||
| <CursorPos X="20" Y="635"/> | |||
| <UsageCount Value="86"/> | |||
| <Loaded Value="True"/> | |||
| </Unit4> | |||
| <Unit5> | |||
| <Filename Value="old\TextSuiteWideUtils.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="TextSuiteWideUtils"/> | |||
| <EditorIndex Value="2"/> | |||
| <EditorIndex Value="7"/> | |||
| <WindowIndex Value="1"/> | |||
| <TopLine Value="1243"/> | |||
| <CursorPos X="18" Y="1257"/> | |||
| <UsageCount Value="54"/> | |||
| <UsageCount Value="86"/> | |||
| <Loaded Value="True"/> | |||
| </Unit5> | |||
| <Unit6> | |||
| <Filename Value="old\TextSuiteClasses.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="TextSuiteClasses"/> | |||
| <IsVisibleTab Value="True"/> | |||
| <WindowIndex Value="1"/> | |||
| <TopLine Value="4487"/> | |||
| <CursorPos X="28" Y="4439"/> | |||
| <UsageCount Value="54"/> | |||
| <TopLine Value="654"/> | |||
| <CursorPos X="25" Y="673"/> | |||
| <UsageCount Value="86"/> | |||
| <Loaded Value="True"/> | |||
| </Unit6> | |||
| <Unit7> | |||
| @@ -90,16 +91,18 @@ | |||
| <WindowIndex Value="1"/> | |||
| <TopLine Value="163"/> | |||
| <CursorPos X="61" Y="141"/> | |||
| <UsageCount Value="54"/> | |||
| <UsageCount Value="86"/> | |||
| </Unit7> | |||
| <Unit8> | |||
| <Filename Value="old\TextSuiteTTFUtils.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <EditorIndex Value="-1"/> | |||
| <WindowIndex Value="-1"/> | |||
| <TopLine Value="-1"/> | |||
| <CursorPos X="-1" Y="-1"/> | |||
| <UsageCount Value="54"/> | |||
| <UnitName Value="TextSuiteTTFUtils"/> | |||
| <EditorIndex Value="4"/> | |||
| <WindowIndex Value="1"/> | |||
| <TopLine Value="83"/> | |||
| <CursorPos X="3" Y="91"/> | |||
| <UsageCount Value="86"/> | |||
| <Loaded Value="True"/> | |||
| </Unit8> | |||
| <Unit9> | |||
| <Filename Value="old\TextSuiteVersion.pas"/> | |||
| @@ -108,243 +111,386 @@ | |||
| <WindowIndex Value="-1"/> | |||
| <TopLine Value="-1"/> | |||
| <CursorPos X="-1" Y="-1"/> | |||
| <UsageCount Value="54"/> | |||
| <UsageCount Value="86"/> | |||
| </Unit9> | |||
| <Unit10> | |||
| <Filename Value="..\bitSpace\_projects\MassiveUniverseOnline\bitSpaceEngine\src\OpenGLCore\uglcTypes.pas"/> | |||
| <UnitName Value="uglcTypes"/> | |||
| <EditorIndex Value="1"/> | |||
| <TopLine Value="264"/> | |||
| <CursorPos X="3" Y="273"/> | |||
| <UsageCount Value="30"/> | |||
| <Filename Value="new\utsFontCreatorGDI.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="utsFontCreatorGDI"/> | |||
| <EditorIndex Value="4"/> | |||
| <TopLine Value="655"/> | |||
| <CursorPos X="53" Y="662"/> | |||
| <UsageCount Value="50"/> | |||
| <Loaded Value="True"/> | |||
| </Unit10> | |||
| <Unit11> | |||
| <Filename Value="..\bitSpace\_projects\MassiveUniverseOnline\bitSpaceEngine\src\OpenGLCore\dglOpenGL.pas"/> | |||
| <UnitName Value="dglOpenGL"/> | |||
| <EditorIndex Value="5"/> | |||
| <TopLine Value="11398"/> | |||
| <CursorPos X="3" Y="11232"/> | |||
| <UsageCount Value="30"/> | |||
| <Loaded Value="True"/> | |||
| <Filename Value="new\utsTtfUtils.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <EditorIndex Value="-1"/> | |||
| <TopLine Value="128"/> | |||
| <CursorPos X="17" Y="144"/> | |||
| <UsageCount Value="42"/> | |||
| </Unit11> | |||
| <Unit12> | |||
| <Filename Value="new\uglctextsuite.pas"/> | |||
| <Filename Value="new\utsTypes.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <EditorIndex Value="-1"/> | |||
| <CursorPos X="3" Y="13"/> | |||
| <UsageCount Value="15"/> | |||
| <TopLine Value="152"/> | |||
| <CursorPos X="5" Y="168"/> | |||
| <UsageCount Value="42"/> | |||
| </Unit12> | |||
| <Unit13> | |||
| <Filename Value="new\utsUtils.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <EditorIndex Value="-1"/> | |||
| <CursorPos Y="20"/> | |||
| <UsageCount Value="42"/> | |||
| </Unit13> | |||
| <Unit14> | |||
| <Filename Value="new\utsRendererOpenGL.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="utsRendererOpenGL"/> | |||
| <EditorIndex Value="3"/> | |||
| <TopLine Value="356"/> | |||
| <CursorPos X="20" Y="376"/> | |||
| <UsageCount Value="39"/> | |||
| <Loaded Value="True"/> | |||
| </Unit14> | |||
| <Unit15> | |||
| <Filename Value="..\bitSpace\_projects\MassiveUniverseOnline\bitSpaceEngine\src\OpenGLCore\uglcTypes.pas"/> | |||
| <EditorIndex Value="-1"/> | |||
| <WindowIndex Value="1"/> | |||
| <TopLine Value="261"/> | |||
| <CursorPos X="3" Y="277"/> | |||
| <UsageCount Value="37"/> | |||
| </Unit15> | |||
| <Unit16> | |||
| <Filename Value="..\bitSpace\_projects\MassiveUniverseOnline\bitSpaceEngine\src\OpenGLCore\dglOpenGL.pas"/> | |||
| <EditorIndex Value="-1"/> | |||
| <TopLine Value="1066"/> | |||
| <CursorPos X="27" Y="1082"/> | |||
| <UsageCount Value="32"/> | |||
| </Unit16> | |||
| <Unit17> | |||
| <Filename Value="new\uglctextsuite.pas"/> | |||
| <EditorIndex Value="-1"/> | |||
| <CursorPos X="3" Y="13"/> | |||
| <UsageCount Value="13"/> | |||
| </Unit17> | |||
| <Unit18> | |||
| <Filename Value="C:\Zusatzprogramme\Lazarus\fpc\2.7.1\source\rtl\inc\ustringh.inc"/> | |||
| <EditorIndex Value="4"/> | |||
| <EditorIndex Value="-1"/> | |||
| <TopLine Value="110"/> | |||
| <CursorPos X="10" Y="126"/> | |||
| <UsageCount Value="28"/> | |||
| <Loaded Value="True"/> | |||
| </Unit13> | |||
| <Unit14> | |||
| <UsageCount Value="27"/> | |||
| </Unit18> | |||
| <Unit19> | |||
| <Filename Value="C:\Zusatzprogramme\Lazarus\fpc\2.7.1\source\rtl\inc\ustrings.inc"/> | |||
| <EditorIndex Value="-1"/> | |||
| <TopLine Value="1819"/> | |||
| <CursorPos X="37" Y="2066"/> | |||
| <UsageCount Value="6"/> | |||
| </Unit14> | |||
| <Unit15> | |||
| <UsageCount Value="4"/> | |||
| </Unit19> | |||
| <Unit20> | |||
| <Filename Value="C:\Zusatzprogramme\Lazarus\fpc\2.7.1\source\rtl\inc\systemh.inc"/> | |||
| <EditorIndex Value="-1"/> | |||
| <TopLine Value="756"/> | |||
| <CursorPos X="32" Y="774"/> | |||
| <UsageCount Value="27"/> | |||
| </Unit15> | |||
| <Unit16> | |||
| <UsageCount Value="25"/> | |||
| </Unit20> | |||
| <Unit21> | |||
| <Filename Value="C:\Zusatzprogramme\Lazarus\fpc\2.7.1\source\rtl\inc\heaph.inc"/> | |||
| <EditorIndex Value="3"/> | |||
| <TopLine Value="69"/> | |||
| <CursorPos X="10" Y="94"/> | |||
| <UsageCount Value="27"/> | |||
| <Loaded Value="True"/> | |||
| </Unit16> | |||
| <Unit17> | |||
| <EditorIndex Value="-1"/> | |||
| <TopLine Value="71"/> | |||
| <CursorPos X="10" Y="95"/> | |||
| <UsageCount Value="26"/> | |||
| </Unit21> | |||
| <Unit22> | |||
| <Filename Value="old\TextSuiteCPUUtils.pas"/> | |||
| <EditorIndex Value="-1"/> | |||
| <WindowIndex Value="1"/> | |||
| <CursorPos X="23" Y="20"/> | |||
| <UsageCount Value="18"/> | |||
| </Unit17> | |||
| <Unit18> | |||
| <UsageCount Value="16"/> | |||
| </Unit22> | |||
| <Unit23> | |||
| <Filename Value="..\glBitmap\glBitmap\glBitmap.pas"/> | |||
| <EditorIndex Value="-1"/> | |||
| <CursorPos X="14" Y="14"/> | |||
| <UsageCount Value="6"/> | |||
| </Unit18> | |||
| <UsageCount Value="4"/> | |||
| </Unit23> | |||
| <Unit24> | |||
| <Filename Value="C:\Zusatzprogramme\Lazarus\fpc\2.7.1\source\rtl\objpas\math.pp"/> | |||
| <EditorIndex Value="-1"/> | |||
| <TopLine Value="1011"/> | |||
| <CursorPos X="47" Y="1015"/> | |||
| <UsageCount Value="8"/> | |||
| </Unit24> | |||
| <Unit25> | |||
| <Filename Value="C:\Zusatzprogramme\Lazarus\fpc\2.7.1\source\rtl\inc\mathh.inc"/> | |||
| <EditorIndex Value="-1"/> | |||
| <TopLine Value="84"/> | |||
| <CursorPos X="14" Y="101"/> | |||
| <UsageCount Value="8"/> | |||
| </Unit25> | |||
| <Unit26> | |||
| <Filename Value="C:\Zusatzprogramme\Lazarus\fpc\2.7.1\source\rtl\inc\genmath.inc"/> | |||
| <EditorIndex Value="-1"/> | |||
| <TopLine Value="152"/> | |||
| <CursorPos X="10" Y="155"/> | |||
| <UsageCount Value="8"/> | |||
| </Unit26> | |||
| <Unit27> | |||
| <Filename Value="C:\Zusatzprogramme\Lazarus\fpc\2.7.1\source\rtl\inc\dynlibs.pas"/> | |||
| <EditorIndex Value="-1"/> | |||
| <TopLine Value="41"/> | |||
| <CursorPos X="10" Y="58"/> | |||
| <UsageCount Value="13"/> | |||
| </Unit27> | |||
| <Unit28> | |||
| <Filename Value="C:\Zusatzprogramme\Lazarus\fpc\2.7.1\source\rtl\win\dynlibs.inc"/> | |||
| <EditorIndex Value="-1"/> | |||
| <TopLine Value="9"/> | |||
| <CursorPos X="3" Y="26"/> | |||
| <UsageCount Value="13"/> | |||
| </Unit28> | |||
| <Unit29> | |||
| <Filename Value="C:\Zusatzprogramme\Lazarus\fpc\2.7.1\source\rtl\win\sysosh.inc"/> | |||
| <EditorIndex Value="-1"/> | |||
| <TopLine Value="11"/> | |||
| <CursorPos X="3" Y="19"/> | |||
| <UsageCount Value="13"/> | |||
| </Unit29> | |||
| <Unit30> | |||
| <Filename Value="C:\Zusatzprogramme\Lazarus\fpc\2.7.1\source\rtl\inc\objpash.inc"/> | |||
| <EditorIndex Value="-1"/> | |||
| <TopLine Value="177"/> | |||
| <CursorPos X="22" Y="195"/> | |||
| <UsageCount Value="17"/> | |||
| </Unit30> | |||
| <Unit31> | |||
| <Filename Value="C:\Zusatzprogramme\Lazarus\fpc\2.7.1\source\rtl\objpas\sysutils\sysunih.inc"/> | |||
| <EditorIndex Value="3"/> | |||
| <WindowIndex Value="1"/> | |||
| <TopLine Value="25"/> | |||
| <CursorPos X="34" Y="43"/> | |||
| <UsageCount Value="21"/> | |||
| <Loaded Value="True"/> | |||
| </Unit31> | |||
| <Unit32> | |||
| <Filename Value="C:\Zusatzprogramme\Lazarus\fpc\2.7.1\source\packages\fcl-base\src\syncobjs.pp"/> | |||
| <EditorIndex Value="-1"/> | |||
| <TopLine Value="113"/> | |||
| <CursorPos X="25" Y="115"/> | |||
| <UsageCount Value="18"/> | |||
| </Unit32> | |||
| <Unit33> | |||
| <Filename Value="C:\Zusatzprogramme\Lazarus\fpc\2.7.1\source\rtl\objpas\classes\classesh.inc"/> | |||
| <EditorIndex Value="1"/> | |||
| <WindowIndex Value="1"/> | |||
| <TopLine Value="311"/> | |||
| <CursorPos X="14" Y="327"/> | |||
| <UsageCount Value="18"/> | |||
| <Loaded Value="True"/> | |||
| </Unit33> | |||
| <Unit34> | |||
| <Filename Value="C:\Zusatzprogramme\Lazarus\fpc\2.7.1\source\rtl\inc\objpas.inc"/> | |||
| <EditorIndex Value="-1"/> | |||
| <TopLine Value="516"/> | |||
| <CursorPos X="9" Y="525"/> | |||
| <UsageCount Value="16"/> | |||
| </Unit34> | |||
| <Unit35> | |||
| <Filename Value="C:\Zusatzprogramme\Lazarus\lcl\include\control.inc"/> | |||
| <EditorIndex Value="-1"/> | |||
| <TopLine Value="2843"/> | |||
| <CursorPos Y="2858"/> | |||
| <UsageCount Value="15"/> | |||
| </Unit35> | |||
| <Unit36> | |||
| <Filename Value="C:\Users\Erik\Desktop\RectPacking\unit1.pas"/> | |||
| <UnitName Value="Unit1"/> | |||
| <IsVisibleTab Value="True"/> | |||
| <EditorIndex Value="2"/> | |||
| <WindowIndex Value="1"/> | |||
| <TopLine Value="376"/> | |||
| <CursorPos X="7" Y="390"/> | |||
| <UsageCount Value="16"/> | |||
| <Loaded Value="True"/> | |||
| </Unit36> | |||
| <Unit37> | |||
| <Filename Value="..\bitSpace\_projects\MassiveUniverseOnline\bitSpaceEngine\src\OpenGLCore\uglcArrayBuffer.pas"/> | |||
| <EditorIndex Value="-1"/> | |||
| <WindowIndex Value="1"/> | |||
| <TopLine Value="102"/> | |||
| <CursorPos X="37" Y="112"/> | |||
| <UsageCount Value="12"/> | |||
| </Unit37> | |||
| <Unit38> | |||
| <Filename Value="..\bitSpace\_projects\MassiveUniverseOnline\bitSpaceEngine\src\OpenGLCore\uglcBitmap.pas"/> | |||
| <EditorIndex Value="-1"/> | |||
| <WindowIndex Value="1"/> | |||
| <TopLine Value="1047"/> | |||
| <CursorPos X="15" Y="1043"/> | |||
| <UsageCount Value="10"/> | |||
| </Unit38> | |||
| <Unit39> | |||
| <Filename Value="C:\Zusatzprogramme\Lazarus\fpc\2.7.1\source\rtl\objpas\objpas.pp"/> | |||
| <EditorIndex Value="-1"/> | |||
| <TopLine Value="19"/> | |||
| <CursorPos X="8" Y="35"/> | |||
| <UsageCount Value="10"/> | |||
| </Unit39> | |||
| <Unit40> | |||
| <Filename Value="C:\Zusatzprogramme\Lazarus\lcl\include\application.inc"/> | |||
| <EditorIndex Value="-1"/> | |||
| <TopLine Value="966"/> | |||
| <CursorPos Y="981"/> | |||
| <UsageCount Value="10"/> | |||
| </Unit40> | |||
| <Unit41> | |||
| <Filename Value="..\bitSpace\_projects\MassiveUniverseOnline\bitSpaceEngine\src\SpaceEngine\uengFrameLimiter.pas"/> | |||
| <UnitName Value="uengFrameLimiter"/> | |||
| <EditorIndex Value="1"/> | |||
| <TopLine Value="14"/> | |||
| <CursorPos X="13" Y="14"/> | |||
| <UsageCount Value="10"/> | |||
| <Loaded Value="True"/> | |||
| </Unit41> | |||
| </Units> | |||
| <JumpHistory Count="30" HistoryIndex="29"> | |||
| <JumpHistory Count="30" HistoryIndex="28"> | |||
| <Position1> | |||
| <Filename Value="new\utsTextSuite.pas"/> | |||
| <Caret Line="1979" TopLine="1967"/> | |||
| <Caret Line="1797" TopLine="1781"/> | |||
| </Position1> | |||
| <Position2> | |||
| <Filename Value="new\utsTextSuite.pas"/> | |||
| <Caret Line="1980" TopLine="1967"/> | |||
| <Caret Line="1683" TopLine="1657"/> | |||
| </Position2> | |||
| <Position3> | |||
| <Filename Value="new\utsTextSuite.pas"/> | |||
| <Caret Line="1981" TopLine="1967"/> | |||
| <Caret Line="1679" TopLine="1657"/> | |||
| </Position3> | |||
| <Position4> | |||
| <Filename Value="new\utsTextSuite.pas"/> | |||
| <Caret Line="1982" TopLine="1967"/> | |||
| <Caret Line="1680" TopLine="1657"/> | |||
| </Position4> | |||
| <Position5> | |||
| <Filename Value="new\utsTextSuite.pas"/> | |||
| <Caret Line="1983" TopLine="1967"/> | |||
| <Caret Line="1681" TopLine="1657"/> | |||
| </Position5> | |||
| <Position6> | |||
| <Filename Value="new\utsTextSuite.pas"/> | |||
| <Caret Line="1984" TopLine="1967"/> | |||
| <Caret Line="1683" TopLine="1658"/> | |||
| </Position6> | |||
| <Position7> | |||
| <Filename Value="new\utsTextSuite.pas"/> | |||
| <Caret Line="1987" TopLine="1967"/> | |||
| <Caret Line="1797" TopLine="1781"/> | |||
| </Position7> | |||
| <Position8> | |||
| <Filename Value="new\utsTextSuite.pas"/> | |||
| <Caret Line="2032" TopLine="2015"/> | |||
| <Caret Line="1799" TopLine="1781"/> | |||
| </Position8> | |||
| <Position9> | |||
| <Filename Value="new\utsTextSuite.pas"/> | |||
| <Caret Line="2037" TopLine="2015"/> | |||
| <Caret Line="1800" TopLine="1781"/> | |||
| </Position9> | |||
| <Position10> | |||
| <Filename Value="new\utsTextSuite.pas"/> | |||
| <Caret Line="1970" TopLine="1954"/> | |||
| <Caret Line="1801" TopLine="1781"/> | |||
| </Position10> | |||
| <Position11> | |||
| <Filename Value="new\utsTextSuite.pas"/> | |||
| <Caret Line="1973" TopLine="1954"/> | |||
| <Caret Line="1803" TopLine="1781"/> | |||
| </Position11> | |||
| <Position12> | |||
| <Filename Value="new\utsTextSuite.pas"/> | |||
| <Caret Line="1974" TopLine="1954"/> | |||
| <Caret Line="1804" TopLine="1781"/> | |||
| </Position12> | |||
| <Position13> | |||
| <Filename Value="new\utsTextSuite.pas"/> | |||
| <Caret Line="1975" TopLine="1967"/> | |||
| <Caret Line="1805" TopLine="1781"/> | |||
| </Position13> | |||
| <Position14> | |||
| <Filename Value="new\utsTextSuite.pas"/> | |||
| <Caret Line="1977" TopLine="1967"/> | |||
| <Caret Line="1679" TopLine="1663"/> | |||
| </Position14> | |||
| <Position15> | |||
| <Filename Value="new\utsTextSuite.pas"/> | |||
| <Caret Line="1991" TopLine="1967"/> | |||
| <Caret Line="1465" Column="3" TopLine="1460"/> | |||
| </Position15> | |||
| <Position16> | |||
| <Filename Value="new\utsTextSuite.pas"/> | |||
| <Caret Line="1995" TopLine="2008"/> | |||
| <Caret Line="288" Column="101" TopLine="274"/> | |||
| </Position16> | |||
| <Position17> | |||
| <Filename Value="new\utsTextSuite.pas"/> | |||
| <Caret Line="1997" TopLine="1982"/> | |||
| <Caret Line="1470" Column="28" TopLine="1459"/> | |||
| </Position17> | |||
| <Position18> | |||
| <Filename Value="new\utsTextSuite.pas"/> | |||
| <Caret Line="2008" TopLine="1982"/> | |||
| <Caret Line="1471" Column="73" TopLine="1459"/> | |||
| </Position18> | |||
| <Position19> | |||
| <Filename Value="new\utsTextSuite.pas"/> | |||
| <Caret Line="2054" TopLine="2037"/> | |||
| <Caret Line="1723" Column="29" TopLine="1713"/> | |||
| </Position19> | |||
| <Position20> | |||
| <Filename Value="new\utsTextSuite.pas"/> | |||
| <Caret Line="2032" TopLine="2016"/> | |||
| <Caret Line="1685" TopLine="1670"/> | |||
| </Position20> | |||
| <Position21> | |||
| <Filename Value="new\utsTextSuite.pas"/> | |||
| <Caret Line="2037" Column="36" TopLine="2013"/> | |||
| <Caret Line="1686" TopLine="1670"/> | |||
| </Position21> | |||
| <Position22> | |||
| <Filename Value="new\utsTextSuite.pas"/> | |||
| <Caret Line="2011" TopLine="1995"/> | |||
| <Caret Line="1687" TopLine="1670"/> | |||
| </Position22> | |||
| <Position23> | |||
| <Filename Value="new\utsTextSuite.pas"/> | |||
| <Caret Line="2032" TopLine="2016"/> | |||
| <Caret Line="1689" TopLine="1670"/> | |||
| </Position23> | |||
| <Position24> | |||
| <Filename Value="new\utsTextSuite.pas"/> | |||
| <Caret Line="1991" Column="51" TopLine="2005"/> | |||
| <Caret Line="1686" Column="20" TopLine="1670"/> | |||
| </Position24> | |||
| <Position25> | |||
| <Filename Value="new\utsTextSuite.pas"/> | |||
| <Caret Line="2011" TopLine="2006"/> | |||
| <Caret Line="290" Column="52" TopLine="281"/> | |||
| </Position25> | |||
| <Position26> | |||
| <Filename Value="new\utsTextSuite.pas"/> | |||
| <Caret Line="2034" TopLine="2012"/> | |||
| <Caret Line="1761" Column="23" TopLine="1742"/> | |||
| </Position26> | |||
| <Position27> | |||
| <Filename Value="new\utsTextSuite.pas"/> | |||
| <Caret Line="2035" TopLine="2012"/> | |||
| <Filename Value="uMainForm.pas"/> | |||
| <Caret Line="5" Column="2"/> | |||
| </Position27> | |||
| <Position28> | |||
| <Filename Value="new\utsTextSuite.pas"/> | |||
| <Caret Line="2051" TopLine="2035"/> | |||
| <Filename Value="uMainForm.pas"/> | |||
| <Caret Line="21" Column="18" TopLine="5"/> | |||
| </Position28> | |||
| <Position29> | |||
| <Filename Value="new\utsTextSuite.pas"/> | |||
| <Caret Line="1993" Column="28" TopLine="1991"/> | |||
| <Filename Value="uMainForm.pas"/> | |||
| <Caret Line="57" Column="40" TopLine="50"/> | |||
| </Position29> | |||
| <Position30> | |||
| <Filename Value="new\utsTextSuite.pas"/> | |||
| <Caret Line="2011" TopLine="1990"/> | |||
| <Filename Value="uMainForm.pas"/> | |||
| <Caret Line="23" Column="21" TopLine="22"/> | |||
| </Position30> | |||
| </JumpHistory> | |||
| </ProjectSession> | |||
| <Debugging> | |||
| <BreakPoints Count="4"> | |||
| <Item1> | |||
| <Kind Value="bpkSource"/> | |||
| <WatchScope Value="wpsLocal"/> | |||
| <WatchKind Value="wpkWrite"/> | |||
| <Source Value="new\utsTextSuite.pas"/> | |||
| <Line Value="2011"/> | |||
| </Item1> | |||
| <Item2> | |||
| <Kind Value="bpkSource"/> | |||
| <WatchScope Value="wpsLocal"/> | |||
| <WatchKind Value="wpkWrite"/> | |||
| <Source Value="new\utsTextSuite.pas"/> | |||
| <Line Value="2058"/> | |||
| </Item2> | |||
| <Item3> | |||
| <Kind Value="bpkSource"/> | |||
| <WatchScope Value="wpsLocal"/> | |||
| <WatchKind Value="wpkWrite"/> | |||
| <Source Value="new\utsTextSuite.pas"/> | |||
| <Line Value="2037"/> | |||
| </Item3> | |||
| <Item4> | |||
| <Kind Value="bpkSource"/> | |||
| <WatchScope Value="wpsLocal"/> | |||
| <WatchKind Value="wpkWrite"/> | |||
| <Source Value="new\utsTextSuite.pas"/> | |||
| <Line Value="1991"/> | |||
| </Item4> | |||
| </BreakPoints> | |||
| <Watches Count="4"> | |||
| <Watches Count="3"> | |||
| <Item1> | |||
| <Expression Value="Text"/> | |||
| <Expression Value="aItem"/> | |||
| </Item1> | |||
| <Item2> | |||
| <Expression Value="p^.Text"/> | |||
| <Expression Value="aItem^.children[0]"/> | |||
| </Item2> | |||
| <Item3> | |||
| <Expression Value="TextBegin"/> | |||
| <Expression Value="aItem^.children[1]"/> | |||
| </Item3> | |||
| <Item4> | |||
| <Expression Value="aText"/> | |||
| </Item4> | |||
| </Watches> | |||
| </Debugging> | |||
| </CONFIG> | |||
| @@ -0,0 +1,918 @@ | |||
| unit utsFontCreatorGDI; | |||
| {$mode objfpc}{$H+} | |||
| interface | |||
| uses | |||
| Classes, SysUtils, syncobjs, dynlibs, | |||
| utsTextSuite, utsTypes; | |||
| type | |||
| HDC = Cardinal; | |||
| TFixed = packed record | |||
| fract: Word; | |||
| value: Smallint; | |||
| end; | |||
| TMat2 = packed record | |||
| eM11: TFixed; | |||
| eM12: TFixed; | |||
| eM21: TFixed; | |||
| eM22: TFixed; | |||
| end; | |||
| PMat2 = ^TMat2; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| TtsFontGDI = class(TtsFont) | |||
| private | |||
| fHandle: THandle; | |||
| fMat2: TMat2; | |||
| protected | |||
| constructor Create(const aRenderer: TtsRenderer; const aCreator: TtsFontGenerator; const aProperties: TtsFontProperties; const aHandle: THandle); | |||
| public | |||
| destructor Destroy; override; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| TtsFontRegistration = class(TObject) | |||
| protected | |||
| fIsRegistered: Boolean; | |||
| fFontname: String; | |||
| procedure UnregisterFont; virtual; abstract; | |||
| public | |||
| property IsRegistered: Boolean read fIsRegistered; | |||
| property Fontname: String read fFontname; | |||
| destructor Destroy; override; | |||
| end; | |||
| TtsFontRegistrationFile = class(TtsFontRegistration) | |||
| private | |||
| fFilename: String; | |||
| protected | |||
| procedure UnregisterFont; override; | |||
| public | |||
| constructor Create(const aFilename: String); | |||
| end; | |||
| TtsFontRegistrationStream = class(TtsFontRegistration) | |||
| private | |||
| fHandle: THandle; | |||
| protected | |||
| procedure UnregisterFont; override; | |||
| public | |||
| constructor Create(const aStream: TStream); | |||
| end; | |||
| TtsRegistredFontGDI = class(TtsFontGDI) | |||
| private | |||
| fRegistration: TtsFontRegistration; | |||
| public | |||
| constructor Create(const aRenderer: TtsRenderer; const aCreator: TtsFontGenerator; | |||
| const aRegistration: TtsFontRegistration; const aProperties: TtsFontProperties; const aHandle: THandle); | |||
| destructor Destroy; override; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| TtsFontGeneratorGDI = class(TtsFontGenerator) | |||
| private | |||
| function ConvertFont(const aFont: TtsFont): TtsFontGDI; | |||
| function GetGlyphIndex(const aFont: TtsFontGDI; const aCharCode: WideChar): Integer; | |||
| procedure GetCharImageAANone(const aDC: HDC; const aFont: TtsFontGDI; const aCharCode: WideChar; const aImage: TtsImage); | |||
| procedure GetCharImageAANormal(const aDC: HDC; const aFont: TtsFontGDI; const aCharCode: WideChar; const aImage: TtsImage); | |||
| function CreateFont(const aFontname: String; const aSize: Integer; const aStyle: TtsFontStyles; const aAntiAliasing: TtsAntiAliasing; out aProperties: TtsFontProperties): THandle; | |||
| protected | |||
| function GetGlyphMetrics(const aFont: TtsFont; const aCharCode: WideChar; out aGlyphOrigin, aGlyphSize: TtsPosition; out aAdvance: Integer): Boolean; override; | |||
| procedure GetCharImage(const aFont: TtsFont; const aCharCode: WideChar; const aCharImage: TtsImage); override; | |||
| public | |||
| function GetFontByName(const aFontname: String; const aRenderer: TtsRenderer; const aSize: Integer; const aStyle: TtsFontStyles; const aAntiAliasing: TtsAntiAliasing): TtsFont; overload; | |||
| function GetFontByFile(const aFilename: String; const aRenderer: TtsRenderer; const aSize: Integer; const aStyle: TtsFontStyles; const aAntiAliasing: TtsAntiAliasing): TtsFont; overload; | |||
| function GetFontByStream(const aStream: TStream; const aRenderer: TtsRenderer; const aSize: Integer; const aStyle: TtsFontStyles; const aAntiAliasing: TtsAntiAliasing): TtsFont; overload; | |||
| constructor Create; | |||
| destructor Destroy; override; | |||
| end; | |||
| implementation | |||
| uses | |||
| math, utsTtfUtils; | |||
| const | |||
| LIB_GDI32 = 'gdi32.dll'; | |||
| LIB_KERNEL32 = 'kernel32.dll'; | |||
| GDI_ERROR = DWORD($FFFFFFFF); | |||
| FW_NORMAL = 400; | |||
| FW_BOLD = 700; | |||
| DEFAULT_CHARSET = 1; | |||
| NONANTIALIASED_QUALITY = 3; | |||
| ANTIALIASED_QUALITY = 4; | |||
| GGO_METRICS = 0; | |||
| GGO_BITMAP = 1; | |||
| GGO_GRAY8_BITMAP = 6; | |||
| GGO_GLYPH_INDEX = $80; | |||
| FR_PRIVATE = $10; | |||
| FR_NOT_ENUM = $20; | |||
| LOCALE_USER_DEFAULT = $0400; | |||
| LOCALE_ILANGUAGE = $1; | |||
| GCP_MAXEXTENT = $100000; | |||
| TMPF_FIXED_PITCH = 1; | |||
| type | |||
| HFONT = Cardinal; | |||
| HGDIOBJ = Cardinal; | |||
| TLogFontA = record | |||
| lfHeight: Longint; | |||
| lfWidth: Longint; | |||
| lfEscapement: Longint; | |||
| lfOrientation: Longint; | |||
| lfWeight: Longint; | |||
| lfItalic: Byte; | |||
| lfUnderline: Byte; | |||
| lfStrikeOut: Byte; | |||
| lfCharSet: Byte; | |||
| lfOutPrecision: Byte; | |||
| lfClipPrecision: Byte; | |||
| lfQuality: Byte; | |||
| lfPitchAndFamily: Byte; | |||
| lfFaceName: array[0..31] of AnsiChar; | |||
| end; | |||
| PLogFontA = ^TLogFontA; | |||
| TTextMetricW = record | |||
| tmHeight: Longint; | |||
| tmAscent: Longint; | |||
| tmDescent: Longint; | |||
| tmInternalLeading: Longint; | |||
| tmExternalLeading: Longint; | |||
| tmAveCharWidth: Longint; | |||
| tmMaxCharWidth: Longint; | |||
| tmWeight: Longint; | |||
| tmOverhang: Longint; | |||
| tmDigitizedAspectX: Longint; | |||
| tmDigitizedAspectY: Longint; | |||
| tmFirstChar: WideChar; | |||
| tmLastChar: WideChar; | |||
| tmDefaultChar: WideChar; | |||
| tmBreakChar: WideChar; | |||
| tmItalic: Byte; | |||
| tmUnderlined: Byte; | |||
| tmStruckOut: Byte; | |||
| tmPitchAndFamily: Byte; | |||
| tmCharSet: Byte; | |||
| end; | |||
| PTextMetricW = ^TTextMetricW; | |||
| TGlyphMetrics = record | |||
| gmBlackBoxX: Cardinal; | |||
| gmBlackBoxY: Cardinal; | |||
| gmptGlyphOrigin: TtsPosition; | |||
| gmCellIncX: Smallint; | |||
| gmCellIncY: Smallint; | |||
| end; | |||
| PGlyphMetrics = ^TGlyphMetrics; | |||
| TGCPResultsW = record | |||
| lStructSize: DWORD; | |||
| lpOutString: PWideChar; | |||
| lpOrder: PDWORD; | |||
| lpDx: PInteger; | |||
| lpCaretPos: PInteger; | |||
| lpClass: PChar; | |||
| lpGlyphs: PCardinal; | |||
| nGlyphs: Cardinal; | |||
| nMaxFit: Cardinal; | |||
| end; | |||
| PGCPResultsW = ^TGCPResultsW; | |||
| TPanose = record | |||
| bFamilyType: Byte; | |||
| bSerifStyle: Byte; | |||
| bWeight: Byte; | |||
| bProportion: Byte; | |||
| bContrast: Byte; | |||
| bStrokeVariation: Byte; | |||
| bArmStyle: Byte; | |||
| bLetterform: Byte; | |||
| bMidline: Byte; | |||
| bXHeight: Byte; | |||
| end; | |||
| PPanose = ^TPanose; | |||
| TOutlineTextmetricW = record | |||
| otmSize: LongWord; | |||
| otmTextMetrics: TTextMetricW; | |||
| otmFiller: Byte; | |||
| otmPanoseNumber: TPanose; | |||
| otmfsSelection: LongWord; | |||
| otmfsType: LongWord; | |||
| otmsCharSlopeRise: Integer; | |||
| otmsCharSlopeRun: Integer; | |||
| otmItalicAngle: Integer; | |||
| otmEMSquare: LongWord; | |||
| otmAscent: Integer; | |||
| otmDescent: Integer; | |||
| otmLineGap: LongWord; | |||
| otmsCapEmHeight: LongWord; | |||
| otmsXHeight: LongWord; | |||
| otmrcFontBox: TtsRect; | |||
| otmMacAscent: Integer; | |||
| otmMacDescent: Integer; | |||
| otmMacLineGap: LongWord; | |||
| otmusMinimumPPEM: LongWord; | |||
| otmptSubscriptSize: TtsPosition; | |||
| otmptSubscriptOffset: TtsPosition; | |||
| otmptSuperscriptSize: TtsPosition; | |||
| otmptSuperscriptOffset: TtsPosition; | |||
| otmsStrikeoutSize: LongWord; | |||
| otmsStrikeoutPosition: Integer; | |||
| otmsUnderscoreSize: Integer; | |||
| otmsUnderscorePosition: Integer; | |||
| otmpFamilyName: PWideChar; | |||
| otmpFaceName: PWideChar; | |||
| otmpStyleName: PWideChar; | |||
| otmpFullName: PWideChar; | |||
| end; | |||
| POutlineTextmetricW = ^TOutlineTextmetricW; | |||
| TCreateFontIndirectA = function (const p1: TLogFontA): HFONT; stdcall; | |||
| TAddFontResourceA = function(Filename: PAnsiChar): Integer; stdcall; | |||
| TAddFontResourceExA = function(Filename: PAnsiChar; Flag: DWORD; pdv: Pointer): Integer; stdcall; | |||
| TAddFontMemResourceEx = function(pbFont: Pointer; cbFont: DWORD; pdv: Pointer; pcFonts: PDWORD): THandle; stdcall; | |||
| TRemoveFontResourceA = function(Filename: PAnsiChar): Boolean; stdcall; | |||
| TRemoveFontResourceExA = function(filename: PAnsiChar; Flag: DWORD; pdv: Pointer): Boolean; stdcall; | |||
| TRemoveFontMemResourceEx = function(fh: THandle): Boolean; stdcall; | |||
| TGetTextMetricsW = function(DC: HDC; var TM: TTextMetricW): Boolean; stdcall; | |||
| TGetGlyphOutlineA = function(DC: HDC; uChar, uFormat: Cardinal; lpgm: PGlyphMetrics; cbBuffer: DWORD; lpvBuffer: Pointer; lpmat2: PMat2): DWORD; stdcall; | |||
| TGetCharacterPlacementW = function(DC: HDC; Str: PWideChar; Count, MaxExtent: Integer; Result: PGCPResultsW; Flags: DWORD): DWORD; stdcall; | |||
| TGetFontData = function(DC: HDC; TableName, Offset: DWORD; Buffer: Pointer; Data: DWORD): DWORD; stdcall; | |||
| TCreateCompatibleDC = function(DC: HDC): HDC; stdcall; | |||
| TDeleteDC = function(DC: HDC): Boolean; stdcall; | |||
| TSelectObject = function(DC: HDC; p2: HGDIOBJ): HGDIOBJ; stdcall; | |||
| TDeleteObject = function(p1: HGDIOBJ): Boolean; stdcall; | |||
| TGetOutlineTextMetricsW = function(DC: HDC; p2: LongWord; var OTMetricStructs: TOutlineTextmetricW): LongWord; stdcall; | |||
| TGetLocaleInfoA = function(Locale: DWORD; LCType: DWORD; lpLCData: pAnsiChar; cchData: Integer): Integer; stdcall; | |||
| var | |||
| gdiRefCount: Integer; | |||
| gdiCritSec: TCriticalSection; | |||
| gdiInitialized: Boolean; | |||
| gdiLibHandle: TLibHandle = 0; | |||
| kernel32LibHandle: TLibHandle = 0; | |||
| CreateFontIndirectA: TCreateFontIndirectA; | |||
| AddFontResourceA: TAddFontResourceA; | |||
| AddFontResourceExA: TAddFontResourceExA; | |||
| AddFontMemResourceEx: TAddFontMemResourceEx; | |||
| RemoveFontResourceA: TRemoveFontResourceA; | |||
| RemoveFontResourceExA: TRemoveFontResourceExA; | |||
| RemoveFontMemResourceEx: TRemoveFontMemResourceEx; | |||
| GetTextMetricsW: TGetTextMetricsW; | |||
| GetGlyphOutlineA: TGetGlyphOutlineA; | |||
| GetCharacterPlacementW: TGetCharacterPlacementW; | |||
| GetFontData: TGetFontData; | |||
| CreateCompatibleDC: TCreateCompatibleDC; | |||
| DeleteDC: TDeleteDC; | |||
| SelectObject: TSelectObject; | |||
| DeleteObject: TDeleteObject; | |||
| GetOutlineTextMetricsW: TGetOutlineTextMetricsW; | |||
| GetLocaleInfoA: TGetLocaleInfoA; | |||
| procedure InitGDI; | |||
| function GetProcAddr(const aLibHandle: TLibHandle; const aName: String): Pointer; | |||
| begin | |||
| result := GetProcAddress(aLibHandle, aName); | |||
| if not Assigned(result) then | |||
| raise EtsException.Create('unable to load procedure from library: ' + aName); | |||
| end; | |||
| begin | |||
| try | |||
| if (gdiLibHandle = 0) then begin | |||
| gdiLibHandle := LoadLibrary(LIB_GDI32); | |||
| if (gdiLibHandle = 0) then | |||
| raise EtsException.Create('unable to load gdi lib: ' + LIB_GDI32); | |||
| end; | |||
| if (kernel32LibHandle = 0) then begin | |||
| kernel32LibHandle := LoadLibrary(LIB_KERNEL32); | |||
| if (kernel32LibHandle = 0) then | |||
| raise EtsException.Create('unable to load kernel lib: ' + LIB_KERNEL32); | |||
| end; | |||
| CreateFontIndirectA := TCreateFontIndirectA( GetProcAddr(gdiLibHandle, 'CreateFontIndirectA')); | |||
| AddFontResourceA := TAddFontResourceA( GetProcAddr(gdiLibHandle, 'AddFontResourceA')); | |||
| AddFontResourceExA := TAddFontResourceExA( GetProcAddr(gdiLibHandle, 'AddFontResourceExA')); | |||
| AddFontMemResourceEx := TAddFontMemResourceEx( GetProcAddr(gdiLibHandle, 'AddFontMemResourceEx')); | |||
| RemoveFontResourceA := TRemoveFontResourceA( GetProcAddr(gdiLibHandle, 'RemoveFontResourceA')); | |||
| RemoveFontResourceExA := TRemoveFontResourceExA( GetProcAddr(gdiLibHandle, 'RemoveFontResourceExA')); | |||
| RemoveFontMemResourceEx := TRemoveFontMemResourceEx(GetProcAddr(gdiLibHandle, 'RemoveFontMemResourceEx')); | |||
| GetTextMetricsW := TGetTextMetricsW( GetProcAddr(gdiLibHandle, 'GetTextMetricsW')); | |||
| GetGlyphOutlineA := TGetGlyphOutlineA( GetProcAddr(gdiLibHandle, 'GetGlyphOutlineA')); | |||
| GetCharacterPlacementW := TGetCharacterPlacementW( GetProcAddr(gdiLibHandle, 'GetCharacterPlacementW')); | |||
| GetFontData := TGetFontData( GetProcAddr(gdiLibHandle, 'GetFontData')); | |||
| CreateCompatibleDC := TCreateCompatibleDC( GetProcAddr(gdiLibHandle, 'CreateCompatibleDC')); | |||
| DeleteDC := TDeleteDC( GetProcAddr(gdiLibHandle, 'DeleteDC')); | |||
| SelectObject := TSelectObject( GetProcAddr(gdiLibHandle, 'SelectObject')); | |||
| DeleteObject := TDeleteObject( GetProcAddr(gdiLibHandle, 'DeleteObject')); | |||
| GetOutlineTextMetricsW := TGetOutlineTextMetricsW( GetProcAddr(gdiLibHandle, 'GetOutlineTextMetricsW')); | |||
| GetLocaleInfoA := TGetLocaleInfoA(GetProcAddr(kernel32LibHandle, 'GetLocaleInfoA')); | |||
| gdiInitialized := true; | |||
| except | |||
| gdiInitialized := false; | |||
| FreeLibrary(gdiLibHandle); | |||
| FreeLibrary(kernel32LibHandle); | |||
| end; | |||
| end; | |||
| procedure QuitGDI; | |||
| begin | |||
| CreateFontIndirectA := nil; | |||
| AddFontResourceA := nil; | |||
| AddFontResourceExA := nil; | |||
| RemoveFontResourceA := nil; | |||
| RemoveFontResourceExA := nil; | |||
| GetTextMetricsW := nil; | |||
| GetGlyphOutlineA := nil; | |||
| GetCharacterPlacementW := nil; | |||
| GetFontData := nil; | |||
| CreateCompatibleDC := nil; | |||
| DeleteDC := nil; | |||
| SelectObject := nil; | |||
| DeleteObject := nil; | |||
| GetLocaleInfoA := nil; | |||
| if (gdiLibHandle <> 0) then begin | |||
| FreeLibrary(gdiLibHandle); | |||
| gdiLibHandle := 0; | |||
| end; | |||
| if (kernel32LibHandle <> 0) then begin | |||
| FreeLibrary(kernel32LibHandle); | |||
| kernel32LibHandle := 0; | |||
| end; | |||
| gdiInitialized := false; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| //TtsFontGDI//////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| constructor TtsFontGDI.Create(const aRenderer: TtsRenderer; const aCreator: TtsFontGenerator; const aProperties: TtsFontProperties; const aHandle: THandle); | |||
| begin | |||
| inherited Create(aRenderer, aCreator, aProperties); | |||
| FillByte(fMat2, SizeOf(fMat2), 0); | |||
| fMat2.eM11.value := 1; | |||
| fMat2.eM22.value := 1; | |||
| fHandle := aHandle; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| destructor TtsFontGDI.Destroy; | |||
| begin | |||
| DeleteObject(fHandle); | |||
| inherited Destroy; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| //TtsFontRegistration/////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| destructor TtsFontRegistration.Destroy; | |||
| begin | |||
| if fIsRegistered then | |||
| UnregisterFont; | |||
| inherited Destroy; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| //TtsFontRegistrationFile/////////////////////////////////////////////////////////////////////////////////////////////// | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| procedure TtsFontRegistrationFile.UnregisterFont; | |||
| begin | |||
| if Assigned(RemoveFontResourceExA) then | |||
| RemoveFontResourceExA(PAnsiChar(fFilename), 0, nil) | |||
| else if Assigned(RemoveFontResourceA) then | |||
| RemoveFontResourceA(PAnsiChar(fFilename)); | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| constructor TtsFontRegistrationFile.Create(const aFilename: String); | |||
| var | |||
| lang: AnsiString; | |||
| begin | |||
| inherited Create; | |||
| fFilename := aFilename; | |||
| // get Fontname | |||
| SetLength(lang, 4); | |||
| GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_ILANGUAGE, @lang[1], 4); | |||
| fFontname := GetTTFontFullNameFromFile(aFilename, StrToInt('$' + String(lang))); | |||
| // register font | |||
| if Assigned(AddFontResourceExA) then | |||
| fIsRegistered := (AddFontResourceExA(PAnsiChar(fFilename), 0, nil) > 0) | |||
| else if Assigned(AddFontResourceA) then | |||
| fIsRegistered := (AddFontResourceA(PAnsiChar(fFilename)) > 0) | |||
| else | |||
| fIsRegistered := false; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| //TtsFontRegistrationStream///////////////////////////////////////////////////////////////////////////////////////////// | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| procedure TtsFontRegistrationStream.UnregisterFont; | |||
| begin | |||
| if Assigned(RemoveFontMemResourceEx) then | |||
| RemoveFontMemResourceEx(fHandle); | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| constructor TtsFontRegistrationStream.Create(const aStream: TStream); | |||
| var | |||
| lang: AnsiString; | |||
| ms: TMemoryStream; | |||
| cnt: DWORD; | |||
| begin | |||
| inherited Create; | |||
| fHandle := 0; | |||
| fIsRegistered := false; | |||
| // get Fontname | |||
| SetLength(Lang, 4); | |||
| GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_ILANGUAGE, @lang[1], 4); | |||
| fFontname := GetTTFontFullNameFromStream(aStream, StrToInt('$' + String(Lang))); | |||
| // register font | |||
| ms := TMemoryStream.Create; | |||
| try | |||
| ms.CopyFrom(aStream, 0); | |||
| if Assigned(AddFontMemResourceEx) then | |||
| fHandle := AddFontMemResourceEx(ms.Memory, ms.Size, nil, @cnt); | |||
| fIsRegistered := (fHandle > 0); | |||
| finally | |||
| FreeAndNil(ms); | |||
| end; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| //TtsRegistredFontGDI/////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| constructor TtsRegistredFontGDI.Create(const aRenderer: TtsRenderer; const aCreator: TtsFontGenerator; | |||
| const aRegistration: TtsFontRegistration; const aProperties: TtsFontProperties; const aHandle: THandle); | |||
| begin | |||
| inherited Create(aRenderer, aCreator, aProperties, aHandle); | |||
| fRegistration := aRegistration; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| destructor TtsRegistredFontGDI.Destroy; | |||
| begin | |||
| FreeAndNil(fRegistration); | |||
| inherited Destroy; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| //TtsFontCreatorGDIFontFace///////////////////////////////////////////////////////////////////////////////////////////// | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| function TtsFontGeneratorGDI.ConvertFont(const aFont: TtsFont): TtsFontGDI; | |||
| begin | |||
| if not (aFont is TtsFontGDI) then | |||
| raise EtsException.Create('aFont need to be a TtsFontGDI object'); | |||
| result := (aFont as TtsFontGDI); | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| function TtsFontGeneratorGDI.GetGlyphIndex(const aFont: TtsFontGDI; const aCharCode: WideChar): Integer; | |||
| var | |||
| DC: HDC; | |||
| GCPRes: TGCPResultsW; | |||
| begin | |||
| result := -1; | |||
| DC := CreateCompatibleDC(0); | |||
| try | |||
| SelectObject(DC, aFont.fHandle); | |||
| if Assigned(GetCharacterPlacementW) then begin | |||
| FillByte(GCPRes, SizeOf(GCPRes), 0); | |||
| GetMem(GCPRes.lpGlyphs, SizeOf(Cardinal)); | |||
| try | |||
| GCPRes.lStructSize := SizeOf(GCPRes); | |||
| GCPRes.lpGlyphs^ := 0; | |||
| GCPRes.nGlyphs := 1; | |||
| if (GetCharacterPlacementW(DC, @aCharCode, 1, GCP_MAXEXTENT, @GCPRes, 0) <> GDI_ERROR) and | |||
| (GCPRes.nGlyphs = 1) and | |||
| (GCPRes.lpGlyphs <> nil) then | |||
| begin | |||
| result := GCPRes.lpGlyphs^; | |||
| end; | |||
| finally | |||
| FreeMem(GCPRes.lpGlyphs); | |||
| end; | |||
| end; | |||
| finally | |||
| DeleteDC(DC); | |||
| end; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| procedure TtsFontGeneratorGDI.GetCharImageAANone(const aDC: HDC; const aFont: TtsFontGDI; const aCharCode: WideChar; const aImage: TtsImage); | |||
| var | |||
| Metric: TGlyphMetrics; | |||
| GlyphIndex, srcW, srcX, w, h, x, y: Integer; | |||
| Size, OutlineRes: Cardinal; | |||
| Buffer, pSrc, pDst: PByte; | |||
| procedure ExpandByte; | |||
| var | |||
| i, cnt, srcCnt: Integer; | |||
| c: TtsColor4f; | |||
| begin | |||
| srcCnt := min(8, srcX); | |||
| cnt := min(8, x); | |||
| for i := 1 to cnt do begin | |||
| c := tsColor4f(1, 1, 1, 1); | |||
| if ((pSrc^ and $80) > 0) then | |||
| c.a := 1 | |||
| else | |||
| c.a := 0; | |||
| pSrc^ := (pSrc^ and not $80) shl 1; | |||
| tsFormatMap(aFont.Renderer.Format, pDst, c); | |||
| end; | |||
| dec(srcX, srcCnt); | |||
| dec(x, cnt); | |||
| inc(pSrc); | |||
| end; | |||
| begin | |||
| if (aFont.fMat2.eM11.value <> 1) then | |||
| raise EtsException.Create('invalid value'); | |||
| FillByte(Metric, SizeOf(Metric), 0); | |||
| GlyphIndex := GetGlyphIndex(aFont, aCharCode); | |||
| if (GlyphIndex < 0) then | |||
| exit; | |||
| Size := GetGlyphOutlineA(aDC, GlyphIndex, GGO_BITMAP or GGO_GLYPH_INDEX, @Metric, 0, nil, @aFont.fMat2); | |||
| if (Size = GDI_ERROR) or (Size = 0) then | |||
| exit; | |||
| GetMem(Buffer, Size); | |||
| try | |||
| OutlineRes := GetGlyphOutlineA(aDC, GlyphIndex, GGO_BITMAP or GGO_GLYPH_INDEX, @Metric, Size, Buffer, @aFont.fMat2); | |||
| if (OutlineRes = GDI_ERROR) then | |||
| exit; | |||
| w := Metric.gmBlackBoxX; | |||
| h := Metric.gmBlackBoxY; | |||
| srcW := (Size div h) * 8; | |||
| if (w <= 0) or (h <= 0) then | |||
| exit; | |||
| aImage.CreateEmpty(aFont.Renderer.Format, w, h); | |||
| pSrc := Buffer; | |||
| for y := 0 to h-1 do begin | |||
| pDst := aImage.Scanline[y]; | |||
| srcX := srcW; | |||
| while (srcX > 0) do | |||
| ExpandByte; | |||
| end; | |||
| finally | |||
| Freemem(Buffer); | |||
| end; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| procedure TtsFontGeneratorGDI.GetCharImageAANormal(const aDC: HDC; const aFont: TtsFontGDI; const aCharCode: WideChar; const aImage: TtsImage); | |||
| var | |||
| Metric: TGlyphMetrics; | |||
| GlyphIndex, OutlineRes, tmp, Spacer, x, y, w, h: Integer; | |||
| Size: Cardinal; | |||
| Buffer, pSrc, pDst: PByte; | |||
| procedure CopyPixel; | |||
| var | |||
| i: Integer; | |||
| tmp, cnt: Cardinal; | |||
| c: TtsColor4f; | |||
| begin | |||
| cnt := min(x, aFont.fMat2.eM11.value); | |||
| tmp := 0; | |||
| for i := 0 to cnt-1 do begin | |||
| tmp := tmp + pSrc^; | |||
| inc(pSrc, 1); | |||
| end; | |||
| dec(x, cnt); | |||
| c := tsColor4f(1, 1, 1, tmp / ($40 * Cardinal(aFont.fMat2.eM11.value))); | |||
| tsFormatMap(aFont.Renderer.Format, pDst, c); | |||
| end; | |||
| begin | |||
| FillByte(Metric, SizeOf(Metric), 0); | |||
| GlyphIndex := GetGlyphIndex(aFont, aCharCode); | |||
| if (GlyphIndex < 0) then | |||
| exit; | |||
| Size := GetGlyphOutlineA(aDC, GlyphIndex, GGO_GRAY8_BITMAP or GGO_GLYPH_INDEX, @Metric, 0, nil, @aFont.fMat2); | |||
| if (Size = GDI_ERROR) or (Size = 0) then | |||
| exit; | |||
| GetMem(Buffer, Size); | |||
| try | |||
| OutlineRes := GetGlyphOutlineA(aDC, GlyphIndex, GGO_GRAY8_BITMAP or GGO_GLYPH_INDEX, @Metric, Size, Buffer, @aFont.fMat2); | |||
| if (OutlineRes = GDI_ERROR) then | |||
| exit; | |||
| w := Integer(Metric.gmBlackBoxX) div aFont.fMat2.eM11.value; | |||
| h := Metric.gmBlackBoxY; | |||
| tmp := Integer(Metric.gmBlackBoxX) mod aFont.fMat2.eM11.value; | |||
| if (tmp <> 0) then | |||
| w := w + aFont.fMat2.eM11.value - tmp; | |||
| if (w <= 0) or (h <= 0) then | |||
| exit; | |||
| // spacer | |||
| Spacer := Metric.gmBlackBoxX mod 4; | |||
| if (Spacer <> 0) then | |||
| Spacer := 4 - Spacer; | |||
| // copy image | |||
| aImage.CreateEmpty(aFont.Renderer.Format, w, h); | |||
| pSrc := Buffer; | |||
| for y := 0 to h-1 do begin | |||
| pDst := aImage.Scanline[y]; | |||
| x := Metric.gmBlackBoxX; | |||
| while (x > 0) do | |||
| CopyPixel; | |||
| inc(pSrc, Spacer); | |||
| end; | |||
| finally | |||
| FreeMem(Buffer); | |||
| end; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| function TtsFontGeneratorGDI.CreateFont(const aFontname: String; const aSize: Integer; const aStyle: TtsFontStyles; | |||
| const aAntiAliasing: TtsAntiAliasing; out aProperties: TtsFontProperties): THandle; | |||
| var | |||
| LogFont: TLogFontA; | |||
| i: Integer; | |||
| DC: HDC; | |||
| TableName, BufSize: Cardinal; | |||
| Buffer: PByte; | |||
| Lang: AnsiString; | |||
| TextMetric: TTextMetricW; | |||
| OutlineMetric: TOutlineTextmetricW; | |||
| function _(e: Boolean; a, b: Integer): Integer; | |||
| begin | |||
| if e then | |||
| result := a | |||
| else | |||
| result := b; | |||
| end; | |||
| begin | |||
| result := 0; | |||
| FillByte(aProperties, SizeOf(aProperties), 0); | |||
| aProperties.Size := aSize; | |||
| aProperties.Style := aStyle; | |||
| aProperties.AntiAliasing := aAntiAliasing; | |||
| aProperties.Fontname := aFontname; | |||
| // prepare font attribs | |||
| FillByte(LogFont, SizeOf(LogFont), 0); | |||
| for i := 1 to min(Length(aFontname), Length(LogFont.lfFaceName)) do | |||
| LogFont.lfFaceName[i-1] := aFontname[i]; | |||
| LogFont.lfCharSet := DEFAULT_CHARSET; | |||
| LogFont.lfHeight := -aSize; | |||
| LogFont.lfWeight := _(tsStyleBold in aStyle, FW_BOLD, FW_NORMAL); | |||
| LogFont.lfItalic := _(tsStyleItalic in aStyle, 1, 0); | |||
| LogFont.lfUnderline := _(tsStyleUnderline in aStyle, 1, 0); | |||
| LogFont.lfQuality := _(aAntiAliasing = tsAANormal, ANTIALIASED_QUALITY, NONANTIALIASED_QUALITY); | |||
| result := CreateFontIndirectA(LogFont); | |||
| DC := CreateCompatibleDC(0); | |||
| try try | |||
| SelectObject(DC, result); | |||
| TableName := MakeTTTableName('n', 'a', 'm', 'e'); | |||
| BufSize := GetFontData(DC, TableName, 0, nil, 0); | |||
| if (BufSize <> GDI_ERROR) then begin | |||
| GetMem(Buffer, BufSize); | |||
| try | |||
| if (GetFontData(DC, TableName, 0, Buffer, BufSize) <> GDI_ERROR) then begin | |||
| SetLength(Lang, 4); | |||
| GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_ILANGUAGE, @Lang[1], 4); | |||
| GetTTString(Buffer, BufSize, NAME_ID_COPYRIGHT, StrToInt('$' + String(Lang)), aProperties.Copyright); | |||
| GetTTString(Buffer, BufSize, NAME_ID_FACE_NAME, StrToInt('$' + String(Lang)), aProperties.FaceName); | |||
| GetTTString(Buffer, BufSize, NAME_ID_STYLE_NAME, StrToInt('$' + String(Lang)), aProperties.StyleName); | |||
| GetTTString(Buffer, BufSize, NAME_ID_FULL_NAME, StrToInt('$' + String(Lang)), aProperties.FullName); | |||
| end; | |||
| finally | |||
| FreeMem(Buffer); | |||
| end; | |||
| end; | |||
| if GetTextMetricsW(DC, TextMetric) then begin | |||
| aProperties.Ascent := TextMetric.tmAscent; | |||
| aProperties.Descent := TextMetric.tmDescent; | |||
| aProperties.ExternalLeading := TextMetric.tmExternalLeading; | |||
| aProperties.DefaultChar := TextMetric.tmDefaultChar; | |||
| end; | |||
| if (GetOutlineTextMetricsW(DC, SizeOf(OutlineMetric), OutlineMetric) > 0) then begin | |||
| aProperties.UnderlinePos := OutlineMetric.otmsUnderscorePosition; | |||
| aProperties.UnderlineSize := Min(1, OutlineMetric.otmsUnderscoreSize); | |||
| aProperties.StrikeoutPos := OutlineMetric.otmsStrikeoutPosition; | |||
| aProperties.StrikeoutSize := Min(1, OutlineMetric.otmsStrikeoutSize); | |||
| end; | |||
| except | |||
| DeleteObject(result); | |||
| result := 0; | |||
| end; | |||
| finally | |||
| DeleteDC(DC); | |||
| end; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| function TtsFontGeneratorGDI.GetGlyphMetrics(const aFont: TtsFont; const aCharCode: WideChar; out aGlyphOrigin, aGlyphSize: TtsPosition; out aAdvance: Integer): Boolean; | |||
| var | |||
| GlyphIndex: Integer; | |||
| font: TtsFontGDI; | |||
| DC: HDC; | |||
| Metric: TGlyphMetrics; | |||
| Size: Cardinal; | |||
| begin | |||
| result := false; | |||
| aGlyphOrigin.x := 0; | |||
| aGlyphOrigin.x := 0; | |||
| aGlyphSize.x := 0; | |||
| aGlyphSize.y := 0; | |||
| aAdvance := 0; | |||
| font := ConvertFont(aFont); | |||
| GlyphIndex := GetGlyphIndex(font, aCharCode); | |||
| if (GlyphIndex < 0) then | |||
| exit; | |||
| DC := CreateCompatibleDC(0); | |||
| try | |||
| SelectObject(DC, font.fHandle); | |||
| case font.Properties.AntiAliasing of | |||
| tsAANone: begin | |||
| Size := GetGlyphOutlineA(DC, GlyphIndex, GGO_BITMAP or GGO_GLYPH_INDEX, @Metric, 0, nil, @font.fMat2); | |||
| end; | |||
| tsAANormal: begin | |||
| Size := GetGlyphOutlineA(DC, GlyphIndex, GGO_GRAY8_BITMAP or GGO_GLYPH_INDEX, @Metric, 0, nil, @font.fMat2); | |||
| end; | |||
| else | |||
| Size := GDI_ERROR; | |||
| end; | |||
| if (Size = GDI_ERROR) then | |||
| Size := GetGlyphOutlineA(DC, GlyphIndex, GGO_METRICS or GGO_GLYPH_INDEX, @Metric, 0, nil, @font.fMat2); | |||
| if (Size <> GDI_ERROR) then begin | |||
| aGlyphOrigin.x := Round(Metric.gmptGlyphOrigin.x / font.fMat2.eM11.value); | |||
| aGlyphOrigin.y := Metric.gmptGlyphOrigin.y; | |||
| aGlyphSize.x := Round(Metric.gmBlackBoxX / font.fMat2.eM11.value); | |||
| aGlyphSize.y := Metric.gmBlackBoxY; | |||
| aAdvance := Round(Metric.gmCellIncX / font.fMat2.eM11.value); | |||
| result := true; | |||
| end; | |||
| finally | |||
| DeleteDC(DC); | |||
| end; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| procedure TtsFontGeneratorGDI.GetCharImage(const aFont: TtsFont; const aCharCode: WideChar; const aCharImage: TtsImage); | |||
| var | |||
| DC: HDC; | |||
| font: TtsFontGDI; | |||
| begin | |||
| font := ConvertFont(aFont); | |||
| DC := CreateCompatibleDC(0); | |||
| try | |||
| SelectObject(DC, font.fHandle); | |||
| case font.Properties.AntiAliasing of | |||
| tsAANone: | |||
| GetCharImageAANone(DC, font, aCharCode, aCharImage); | |||
| tsAANormal: | |||
| GetCharImageAANormal(DC, font, aCharCode, aCharImage); | |||
| end; | |||
| finally | |||
| DeleteDC(DC); | |||
| end; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| function TtsFontGeneratorGDI.GetFontByName(const aFontname: String; const aRenderer: TtsRenderer; | |||
| const aSize: Integer; const aStyle: TtsFontStyles; const aAntiAliasing: TtsAntiAliasing): TtsFont; | |||
| var | |||
| handle: THandle; | |||
| prop: TtsFontProperties; | |||
| begin | |||
| handle := CreateFont(aFontname, aSize, aStyle, aAntiAliasing, prop); | |||
| if (handle = 0) then | |||
| raise EtsException.Create('unable to create font from name: ' + aFontname); | |||
| result := TtsFontGDI.Create(aRenderer, self, prop, handle); | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| function TtsFontGeneratorGDI.GetFontByFile(const aFilename: String; const aRenderer: TtsRenderer; | |||
| const aSize: Integer; const aStyle: TtsFontStyles; const aAntiAliasing: TtsAntiAliasing): TtsFont; | |||
| var | |||
| reg: TtsFontRegistrationFile; | |||
| handle: THandle; | |||
| prop: TtsFontProperties; | |||
| begin | |||
| reg := TtsFontRegistrationFile.Create(aFilename); | |||
| if not reg.IsRegistered then | |||
| raise EtsException.Create('unable to register font file: ' + aFilename); | |||
| handle := CreateFont(reg.Fontname, aSize, aStyle, aAntiAliasing, prop); | |||
| if (handle = 0) then | |||
| raise EtsException.Create('unable to create font from file: ' + aFilename); | |||
| result := TtsRegistredFontGDI.Create(aRenderer, self, reg, prop, handle); | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| function TtsFontGeneratorGDI.GetFontByStream(const aStream: TStream; const aRenderer: TtsRenderer; | |||
| const aSize: Integer; const aStyle: TtsFontStyles; const aAntiAliasing: TtsAntiAliasing): TtsFont; | |||
| var | |||
| reg: TtsFontRegistrationStream; | |||
| handle: THandle; | |||
| prop: TtsFontProperties; | |||
| begin | |||
| reg := TtsFontRegistrationStream.Create(aStream); | |||
| if not reg.IsRegistered then | |||
| raise EtsException.Create('unable to register font from stream'); | |||
| handle := CreateFont(reg.Fontname, aSize, aStyle, aAntiAliasing, prop); | |||
| if (handle = 0) then | |||
| raise EtsException.Create('unable to create font from stream: ' + reg.Fontname); | |||
| result := TtsRegistredFontGDI.Create(aRenderer, self, reg, prop, handle); | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| constructor TtsFontGeneratorGDI.Create; | |||
| begin | |||
| inherited Create; | |||
| gdiCritSec.Enter; | |||
| try | |||
| inc(gdiRefCount, 1); | |||
| if not gdiInitialized then | |||
| InitGDI; | |||
| finally | |||
| gdiCritSec.Leave; | |||
| end; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| destructor TtsFontGeneratorGDI.Destroy; | |||
| begin | |||
| gdiCritSec.Enter; | |||
| try | |||
| dec(gdiRefCount, 1); | |||
| if (gdiRefCount <= 0) then | |||
| QuitGDI; | |||
| finally | |||
| gdiCritSec.Leave; | |||
| end; | |||
| inherited Destroy; | |||
| end; | |||
| initialization | |||
| gdiRefCount := 0; | |||
| gdiInitialized := false; | |||
| gdiCritSec := TCriticalSection.Create; | |||
| finalization | |||
| if gdiInitialized then | |||
| QuitGDI; | |||
| FreeAndNil(gdiCritSec); | |||
| end. | |||
| @@ -0,0 +1,521 @@ | |||
| unit utsRendererOpenGL; | |||
| {$mode objfpc}{$H+} | |||
| interface | |||
| uses | |||
| Classes, SysUtils, syncobjs, dglOpenGL, | |||
| utsTextSuite, utsTypes; | |||
| type | |||
| TtsQuadPosF = array[0..3] of TtsPositionF; | |||
| TtsCharRenderRefOpenGL = class(TtsCharRenderRef) | |||
| private | |||
| TextureID: GLint; // ID of OpenGL texture where the char is stored in | |||
| TexCoordSize: TtsPositionF; // size of the char in texture coords (0.0 - 1.0) | |||
| TexCoordPos: TtsPositionF; // position of the char in texture coords (0.0 - 1.0) | |||
| VertexSize: TtsPositionF; // size of the char in world coords | |||
| VertexPos: TtsPositionF; // size of the char in world coords | |||
| public | |||
| constructor Create; | |||
| end; | |||
| PtsTextureUsageItem = ^TtsTextureUsageItem; | |||
| TtsTextureUsageItem = packed record | |||
| children: array[0..3] of PtsTextureUsageItem; | |||
| end; | |||
| PtsTextureTreeItem = ^TtsTextureTreeItem; | |||
| TtsTextureTreeItem = packed record | |||
| value: SmallInt; | |||
| children: array[0..1] of PtsTextureTreeItem; | |||
| ref: TtsCharRenderRefOpenGL; | |||
| end; | |||
| PtsFontTexture = ^TtsFontTexture; | |||
| TtsFontTexture = packed record | |||
| ID: GLint; // OpenGL texture ID | |||
| Usage: PtsTextureTreeItem ; // tree of used texture space | |||
| Next: PtsFontTexture; // next texture in list | |||
| Prev: PtsFontTexture; // previouse texture in list | |||
| Size: Integer; // size of this texture | |||
| Count: Integer; // number of chars stored in this texture | |||
| end; | |||
| TtsRendererOpenGL = class(TtsRenderer) | |||
| private | |||
| fVBO: GLuint; | |||
| fTextureSize: Integer; | |||
| fColor: TtsColor4f; | |||
| fRenderPos: TtsPosition; | |||
| fIsRendering: Boolean; | |||
| fFirstTexture: PtsFontTexture; | |||
| fLastTexture: PtsFontTexture; | |||
| function CreateNewTexture: PtsFontTexture; | |||
| procedure FreeTexture(var aTexture: PtsFontTexture); | |||
| procedure FreeTextures(var aTexture: PtsFontTexture); | |||
| procedure FreeTextureTreeItem(var aItem: PtsTextureTreeItem); | |||
| protected | |||
| function CreateRenderRef(const aChar: TtsChar; const aCharImage: TtsImage): TtsCharRenderRef; override; | |||
| procedure FreeRenderRef(const aCharRef: TtsCharRenderRef); override; | |||
| procedure BeginRender; override; | |||
| procedure EndRender; override; | |||
| procedure SetDrawPos(const X, Y: Integer); override; | |||
| function GetDrawPos: TtsPosition; override; | |||
| procedure MoveDrawPos(const X, Y: Integer); override; | |||
| procedure SetColor(const aColor: TtsColor4f); override; | |||
| procedure Render(const aCharRef: TtsCharRenderRef); override; | |||
| public | |||
| property TextureSize: Integer read fTextureSize write fTextureSize; | |||
| constructor Create(const aContext: TtsContext; const aFormat: TtsFormat); | |||
| destructor Destroy; override; | |||
| end; | |||
| EtsRendererOpenGL = class(EtsRenderer); | |||
| implementation | |||
| type | |||
| TVertex = packed record | |||
| pos: array[0..1] of GLfloat; | |||
| tex: array[0..1] of GLfloat; | |||
| end; | |||
| const | |||
| FORMAT_TYPES: array[TtsFormat] of packed record | |||
| InternalFormat: GLenum; | |||
| Format: GLenum; | |||
| DataFormat: GLenum; | |||
| end = ( | |||
| ( //tsFormatEmpty | |||
| InternalFormat: 0; | |||
| Format: 0; | |||
| DataFormat: 0), | |||
| ( //tsFormatRGBA8 | |||
| InternalFormat: GL_RGBA8; | |||
| Format: GL_RGBA; | |||
| DataFormat: GL_UNSIGNED_BYTE), | |||
| ( //tsFormatLumAlpha8 | |||
| InternalFormat: GL_LUMINANCE8_ALPHA8; | |||
| Format: GL_LUMINANCE_ALPHA; | |||
| DataFormat: GL_UNSIGNED_BYTE), | |||
| ( //tsFormatAlpha8 | |||
| InternalFormat: GL_ALPHA8; | |||
| Format: GL_ALPHA; | |||
| DataFormat: GL_UNSIGNED_BYTE) | |||
| ); | |||
| VBO_DATA: array[0..3] of TVertex = ( | |||
| (pos: (0.0, 0.0); tex: (0.0, 0.0)), | |||
| (pos: (0.0, 1.0); tex: (0.0, 1.0)), | |||
| (pos: (1.0, 1.0); tex: (1.0, 1.0)), | |||
| (pos: (1.0, 0.0); tex: (1.0, 0.0)) | |||
| ); | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| //TtsCharRenderRefOpenGL//////////////////////////////////////////////////////////////////////////////////////////////// | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| constructor TtsCharRenderRefOpenGL.Create; | |||
| begin | |||
| inherited Create; | |||
| TextureID := 0; | |||
| FillByte(TexCoordPos, SizeOf(TexCoordPos), 0); | |||
| FillByte(TexCoordSize, SizeOf(TexCoordSize), 0); | |||
| FillByte(VertexPos, SizeOf(VertexPos), 0); | |||
| FillByte(VertexSize, SizeOf(VertexSize), 0); | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| //TtsRendererOpenGL///////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| function TtsRendererOpenGL.CreateNewTexture: PtsFontTexture; | |||
| begin | |||
| new(result); | |||
| try | |||
| FillByte(result^, SizeOf(result^), 0); | |||
| new(result^.Usage); | |||
| FillByte(result^.Usage^, SizeOf(result^.Usage^), 0); | |||
| result^.Size := TextureSize; | |||
| glGenTextures(1, @result^.ID); | |||
| glBindTexture(GL_TEXTURE_2D, result^.ID); | |||
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |||
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |||
| glTexImage2D( | |||
| GL_TEXTURE_2D, | |||
| 0, | |||
| FORMAT_TYPES[Format].InternalFormat, | |||
| result^.Size, | |||
| result^.Size, | |||
| 0, | |||
| FORMAT_TYPES[Format].Format, | |||
| FORMAT_TYPES[Format].DataFormat, | |||
| nil); | |||
| result^.Prev := fLastTexture; | |||
| if Assigned(fLastTexture) then | |||
| fLastTexture^.Next := result | |||
| else | |||
| fFirstTexture := result; | |||
| fLastTexture := result; | |||
| except | |||
| if Assigned(result^.Usage) then | |||
| Dispose(result^.Usage); | |||
| Dispose(result); | |||
| end; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| procedure TtsRendererOpenGL.FreeTexture(var aTexture: PtsFontTexture); | |||
| begin | |||
| if not Assigned(aTexture) then | |||
| exit; | |||
| glDeleteTextures(1, @aTexture^.ID); | |||
| FreeTextureTreeItem(aTexture^.Usage); | |||
| if Assigned(aTexture^.Prev) then | |||
| aTexture^.Prev^.Next := aTexture^.Next; | |||
| if Assigned(aTexture^.Next) then | |||
| aTexture^.Next^.Prev := aTexture^.Prev; | |||
| Dispose(aTexture); | |||
| aTexture := nil; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| procedure TtsRendererOpenGL.FreeTextures(var aTexture: PtsFontTexture); | |||
| begin | |||
| if not Assigned(aTexture) then | |||
| exit; | |||
| FreeTextures(aTexture^.Next); | |||
| FreeTexture(aTexture); | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| procedure TtsRendererOpenGL.FreeTextureTreeItem(var aItem: PtsTextureTreeItem); | |||
| begin | |||
| if not Assigned(aItem) then | |||
| exit; | |||
| FreeTextureTreeItem(aItem^.children[0]); | |||
| FreeTextureTreeItem(aItem^.children[1]); | |||
| Dispose(aItem); | |||
| aItem := nil; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| function TtsRendererOpenGL.CreateRenderRef(const aChar: TtsChar; const aCharImage: TtsImage): TtsCharRenderRef; | |||
| var | |||
| GlyphWidth, GlyphHeight: Integer; | |||
| function InsertToTree(const aItem: PtsTextureTreeItem; const X1, Y1, X2, Y2: SmallInt; out X, Y: Integer): PtsTextureTreeItem; | |||
| var | |||
| w, h: Integer; | |||
| begin | |||
| result := nil; | |||
| w := X2 - X1; | |||
| h := Y2 - Y1; | |||
| if not Assigned(aItem) or | |||
| Assigned(aItem^.ref) or | |||
| (w < GlyphWidth) or | |||
| (h < GlyphHeight) then | |||
| exit; | |||
| if (aItem^.value > 0) then begin | |||
| result := InsertToTree(aItem^.children[0], X1, Y1, X2, aItem^.value, X, Y); | |||
| if not Assigned(result) then | |||
| result := InsertToTree(aItem^.children[1], X1, aItem^.value, X2, Y2, X, Y); | |||
| end else if (aItem^.value < 0) then begin | |||
| result := InsertToTree(aItem^.children[0], X1, Y1, -aItem^.value, Y2, X, Y); | |||
| if not Assigned(result) then | |||
| result := InsertToTree(aItem^.children[1], -aItem^.value, Y1, X2, Y2, X, Y); | |||
| end else if (w = GlyphWidth) and (h = GlyphHeight) then begin | |||
| X := X1; | |||
| Y := Y1; | |||
| result := aItem; | |||
| end else begin | |||
| new(aItem^.children[0]); | |||
| new(aItem^.children[1]); | |||
| FillByte(aItem^.children[0]^, SizeOf(aItem^.children[0]^), 0); | |||
| FillByte(aItem^.children[1]^, SizeOf(aItem^.children[1]^), 0); | |||
| if (w - GlyphWidth) < (h - GlyphHeight) then begin | |||
| aItem^.value := Y1 + GlyphHeight; | |||
| result := InsertToTree(aItem^.children[0], X1, Y1, X2, aItem^.value, X, Y); | |||
| end else begin | |||
| aItem^.value := -(X1 + GlyphWidth); | |||
| result := InsertToTree(aItem^.children[0], X1, Y1, -aItem^.value, Y2, X, Y) | |||
| end; | |||
| end; | |||
| end; | |||
| function AddToTexture(const aTexture: PtsFontTexture): TtsCharRenderRefOpenGL; | |||
| var | |||
| x, y: Integer; | |||
| item: PtsTextureTreeItem; | |||
| begin | |||
| item := InsertToTree(aTexture^.Usage, 0, 0, aTexture^.Size, aTexture^.Size, x, y); | |||
| if not Assigned(item) then | |||
| raise EtsRendererOpenGL.Create('unable to add glyph to texture'); | |||
| item^.ref := TtsCharRenderRefOpenGL.Create; | |||
| result := item^.ref; | |||
| // Text Coords | |||
| result.TextureID := aTexture^.ID; | |||
| result.TexCoordPos.x := x / aTexture^.Size; | |||
| result.TexCoordPos.y := y / aTexture^.Size; | |||
| result.TexCoordSize.x := aCharImage.Width / aTexture^.Size; | |||
| result.TexCoordSize.y := aCharImage.Height / aTexture^.Size; | |||
| // Vertex Coords | |||
| result.VertexPos.x := -aChar.GlyphRect.Left; | |||
| result.VertexPos.y := -aChar.GlyphRect.Top - aChar.GlyphOrigin.y; | |||
| result.VertexSize.x := aCharImage.Width; | |||
| result.VertexSize.y := aCharImage.Height; | |||
| glBindTexture(GL_TEXTURE_2D, result.TextureID); | |||
| glTexSubImage2D(GL_TEXTURE_2D, 0, | |||
| x, y, aCharImage.Width, aCharImage.Height, | |||
| FORMAT_TYPES[aCharImage.Format].Format, | |||
| FORMAT_TYPES[aCharImage.Format].DataFormat, | |||
| aCharImage.Data); | |||
| end; | |||
| var | |||
| tex: PtsFontTexture; | |||
| begin | |||
| result := nil; | |||
| if aCharImage.IsEmpty then | |||
| exit; | |||
| GlyphWidth := aCharImage.Width + 1; | |||
| GlyphHeight := aCharImage.Height + 1; | |||
| // try to add to existing texture | |||
| tex := fFirstTexture; | |||
| while Assigned(tex) and not Assigned(result) do begin | |||
| result := AddToTexture(tex); | |||
| tex := tex^.Next; | |||
| end; | |||
| // create new texture | |||
| if not Assigned(result) then begin | |||
| if (aCharImage.Width > TextureSize) or (aCharImage.Height > TextureSize) then | |||
| raise EtsRendererOpenGL.Create('char is to large to fit into a texture: ' + aChar.CharCode + ' (0x' + IntToHex(Ord(aChar.CharCode), 4) + ')'); | |||
| tex := CreateNewTexture; | |||
| result := AddToTexture(tex); | |||
| end; | |||
| if not Assigned(result) then | |||
| raise EtsRendererOpenGL.Create('unable to creat render reference for char: ' + aChar.CharCode + ' (0x' + IntToHex(Ord(aChar.CharCode), 4) + ')'); | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| procedure TtsRendererOpenGL.FreeRenderRef(const aCharRef: TtsCharRenderRef); | |||
| var | |||
| ref: TtsCharRenderRefOpenGL; | |||
| tex: PtsFontTexture; | |||
| function IsEmtpy(const aItem: PtsTextureTreeItem): Boolean; | |||
| begin | |||
| result := | |||
| Assigned(aItem) and | |||
| not Assigned(aItem^.children[0]) and | |||
| not Assigned(aItem^.children[1]) and | |||
| not Assigned(aItem^.ref); | |||
| end; | |||
| function RemoveFromTree(const aItem: PtsTextureTreeItem; const X1, Y1, X2, Y2: Integer): Boolean; | |||
| var | |||
| w, h: Integer; | |||
| begin | |||
| w := X2 - X1; | |||
| h := Y2 - Y1; | |||
| if not Assigned(aItem) or | |||
| (w < ref.VertexSize.x) or | |||
| (h < ref.VertexSize.y) then | |||
| exit; | |||
| result := (aItem^.ref = ref); | |||
| if not result then begin | |||
| if (aItem^.value > 0) then begin | |||
| result := result or RemoveFromTree(aItem^.children[0], X1, Y1, X2, aItem^.value); | |||
| result := result or RemoveFromTree(aItem^.children[1], X1, aItem^.value, X2, Y2); | |||
| end else if (aItem^.value < 0) then begin | |||
| result := result or RemoveFromTree(aItem^.children[0], X1, Y1, -aItem^.value, Y2); | |||
| result := result or RemoveFromTree(aItem^.children[1], -aItem^.value, Y1, X2, Y2); | |||
| end; | |||
| end else | |||
| aItem^.ref := nil; | |||
| if result and | |||
| IsEmtpy(aItem^.children[0]) and | |||
| IsEmtpy(aItem^.children[1]) then | |||
| begin | |||
| FreeTextureTreeItem(aItem^.children[0]); | |||
| FreeTextureTreeItem(aItem^.children[1]); | |||
| FillByte(aItem^, SizeOf(aItem^), 0); | |||
| end; | |||
| end; | |||
| begin | |||
| try | |||
| if not Assigned(aCharRef) or not (aCharRef is TtsCharRenderRefOpenGL) then | |||
| exit; | |||
| ref := (aCharRef as TtsCharRenderRefOpenGL); | |||
| tex := fFirstTexture; | |||
| while Assigned(tex) do begin | |||
| if (tex^.ID = ref.TextureID) then begin | |||
| if not RemoveFromTree(tex^.Usage, 0, 0, tex^.Size, tex^.Size) then | |||
| raise EtsRendererOpenGL.Create('unable to remove render ref from texture'); | |||
| if IsEmtpy(tex^.Usage) then begin | |||
| if (tex = fFirstTexture) then | |||
| fFirstTexture := nil; | |||
| FreeTexture(tex); | |||
| end; | |||
| tex := nil; | |||
| end else | |||
| tex := tex^.Next; | |||
| end; | |||
| finally | |||
| if Assigned(aCharRef) then | |||
| aCharRef.Free; | |||
| end; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| procedure TtsRendererOpenGL.BeginRender; | |||
| begin | |||
| inherited BeginRender; | |||
| fIsRendering := true; | |||
| fRenderPos.x := 0; | |||
| fRenderPos.y := 0; | |||
| glPushMatrix; | |||
| glColor4fv(@fColor.arr[0]); | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| procedure TtsRendererOpenGL.EndRender; | |||
| begin | |||
| if fIsRendering then begin | |||
| glPopMatrix; | |||
| fIsRendering := false; | |||
| end; | |||
| inherited EndRender; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| procedure TtsRendererOpenGL.SetDrawPos(const X, Y: Integer); | |||
| begin | |||
| fRenderPos.x := X; | |||
| fRenderPos.y := Y; | |||
| glPopMatrix; | |||
| glPushMatrix; | |||
| glTranslatef(X, Y, 0); | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| function TtsRendererOpenGL.GetDrawPos: TtsPosition; | |||
| begin | |||
| result := fRenderPos; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| procedure TtsRendererOpenGL.MoveDrawPos(const X, Y: Integer); | |||
| begin | |||
| fRenderPos.x := fRenderPos.x + X; | |||
| fRenderPos.y := fRenderPos.y + Y; | |||
| glTranslatef(X, Y, 0); | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| procedure TtsRendererOpenGL.SetColor(const aColor: TtsColor4f); | |||
| begin | |||
| fColor := aColor; | |||
| glColor4fv(@fColor.arr[0]); | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| procedure TtsRendererOpenGL.Render(const aCharRef: TtsCharRenderRef); | |||
| var | |||
| ref: TtsCharRenderRefOpenGL; | |||
| procedure RenderTreeItem(const aItem: PtsTextureTreeItem; const X1, Y1, X2, Y2: Integer); | |||
| begin | |||
| glBegin(GL_LINE_LOOP); | |||
| glVertex2f(X1, Y1); | |||
| glVertex2f(X2, Y1); | |||
| glVertex2f(X2, Y2); | |||
| glVertex2f(X1, Y2); | |||
| glEnd; | |||
| if (aItem^.value > 0) then begin | |||
| RenderTreeItem(aItem^.children[0], X1, Y1, X2, aItem^.value); | |||
| RenderTreeItem(aItem^.children[1], X1, aItem^.value, X2, Y2); | |||
| end else if (aItem^.value < 0) then begin | |||
| RenderTreeItem(aItem^.children[0], X1, Y1, -aItem^.value, Y2); | |||
| RenderTreeItem(aItem^.children[1], -aItem^.value, Y1, X2, Y2); | |||
| end; | |||
| end; | |||
| begin | |||
| if Assigned(aCharRef) and (aCharRef is TtsCharRenderRefOpenGL) then begin | |||
| ref := (aCharRef as TtsCharRenderRefOpenGL); | |||
| glEnable(GL_TEXTURE_2D); | |||
| glBindTexture(GL_TEXTURE_2D, ref.TextureID); | |||
| glMatrixMode(GL_TEXTURE); | |||
| glPushMatrix; | |||
| glLoadIdentity; | |||
| glTranslatef(ref.TexCoordPos.x, ref.TexCoordPos.y, 0); | |||
| glScalef(ref.TexCoordSize.x, ref.TexCoordSize.y, 1); | |||
| glMatrixMode(GL_MODELVIEW); | |||
| glPushMatrix; | |||
| glTranslatef(ref.VertexPos.x, ref.VertexPos.y, 0); | |||
| glScalef(ref.VertexSize.x, ref.VertexSize.y, 1); | |||
| glBindBuffer(GL_ARRAY_BUFFER, fVBO); | |||
| glEnableClientState(GL_VERTEX_ARRAY); | |||
| glVertexPointer(2, GL_FLOAT, SizeOf(TVertex), Pointer(0)); | |||
| glEnableClientState(GL_TEXTURE_COORD_ARRAY); | |||
| glTexCoordPointer(2, GL_FLOAT, SizeOf(TVertex), Pointer(8)); | |||
| glDrawArrays(GL_QUADS, 0, 4); | |||
| glDisableClientState(GL_TEXTURE_COORD_ARRAY); | |||
| glDisableClientState(GL_VERTEX_ARRAY); | |||
| glMatrixMode(GL_TEXTURE); | |||
| glPopMatrix; | |||
| glMatrixMode(GL_MODELVIEW); | |||
| glPopMatrix; | |||
| end; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| constructor TtsRendererOpenGL.Create(const aContext: TtsContext; const aFormat: TtsFormat); | |||
| begin | |||
| inherited Create(aContext, aFormat); | |||
| fIsRendering := false; | |||
| fFirstTexture := nil; | |||
| fLastTexture := nil; | |||
| fTextureSize := 2048; | |||
| fColor := tsColor4f(1, 1, 1, 1); | |||
| fRenderPos := tsPosition(0, 0); | |||
| glGenBuffers(1, @fVBO); | |||
| glBindBuffer(GL_ARRAY_BUFFER, fVBO); | |||
| glBufferData(GL_ARRAY_BUFFER, SizeOf(TVertex) * Length(VBO_DATA), @VBO_DATA[0].pos[0], GL_STATIC_DRAW); | |||
| glBindBuffer(GL_ARRAY_BUFFER, 0); | |||
| end; | |||
| destructor TtsRendererOpenGL.Destroy; | |||
| begin | |||
| glDeleteBuffers(1, @fVBO); | |||
| FreeTextures(fFirstTexture); | |||
| inherited Destroy; | |||
| end; | |||
| end. | |||
| @@ -0,0 +1,323 @@ | |||
| unit utsTtfUtils; | |||
| {$mode objfpc}{$H+} | |||
| interface | |||
| uses | |||
| Classes, SysUtils; | |||
| const | |||
| NAME_ID_COPYRIGHT = 0; | |||
| NAME_ID_FACE_NAME = 1; | |||
| NAME_ID_STYLE_NAME = 2; | |||
| NAME_ID_FULL_NAME = 4; | |||
| function MakeTTTableName(const ch1, ch2, ch3, ch4: Char): Cardinal; | |||
| function GetTTString(pBuffer: Pointer; BufferSize: Integer; NameID, LanguageID: Cardinal; var Text: AnsiString): Boolean; | |||
| function GetTTFontFullNameFromStream(Stream: TStream; LanguageID: Cardinal): AnsiString; | |||
| function GetTTFontFullNameFromFile(Filename: AnsiString; LanguageID: Cardinal): AnsiString; | |||
| implementation | |||
| uses | |||
| utsUtils; | |||
| type | |||
| TT_OFFSET_TABLE = packed record | |||
| uMajorVersion: Word; | |||
| uMinorVersion: Word; | |||
| uNumOfTables: Word; | |||
| uSearchRange: Word; | |||
| uEntrySelector: Word; | |||
| uRangeShift: Word; | |||
| end; | |||
| TT_TABLE_DIRECTORY = packed record | |||
| TableName: Cardinal; // table name | |||
| uCheckSum: Cardinal; // Check sum | |||
| uOffset: Cardinal; // Offset from beginning of file | |||
| uLength: Cardinal; // length of the table in bytes | |||
| end; | |||
| TT_NAME_TABLE_HEADER = packed record | |||
| uFSelector: Word; //format selector. Always 0 | |||
| uNRCount: Word; //Name Records count | |||
| uStorageOffset: Word; //Offset for strings storage, from start of the table | |||
| end; | |||
| TT_NAME_RECORD = packed record | |||
| uPlatformID: Word; | |||
| uEncodingID: Word; | |||
| uLanguageID: Word; | |||
| uNameID: Word; | |||
| uStringLength: Word; | |||
| uStringOffset: Word; //from start of storage area | |||
| end; | |||
| const | |||
| PLATFORM_ID_APPLE_UNICODE = 0; | |||
| PLATFORM_ID_MACINTOSH = 1; | |||
| PLATFORM_ID_MICROSOFT = 3; | |||
| function SWAPWORD(x: Word): Word; | |||
| begin | |||
| Result := x and $FF; | |||
| Result := Result shl 8; | |||
| Result := Result or (x shr 8); | |||
| end; | |||
| function SWAPLONG(x: Cardinal): Cardinal; | |||
| begin | |||
| Result := (x and $FF) shl 24; | |||
| x := x shr 8; | |||
| Result := Result or ((x and $FF) shl 16); | |||
| x := x shr 8; | |||
| Result := Result or ((x and $FF) shl 8); | |||
| x := x shr 8; | |||
| Result := Result or x; | |||
| end; | |||
| function GetTTTableData(Stream: TStream; TableName: Cardinal; pBuff: Pointer; var Size: Integer): Boolean; | |||
| var | |||
| Pos: Int64; | |||
| OffsetTable: TT_OFFSET_TABLE; | |||
| TableDir: TT_TABLE_DIRECTORY; | |||
| Idx: Integer; | |||
| begin | |||
| Result := False; | |||
| Pos := Stream.Position; | |||
| // Reading table header | |||
| Stream.Read(OffsetTable, sizeof(TT_OFFSET_TABLE)); | |||
| OffsetTable.uNumOfTables := SWAPWORD(OffsetTable.uNumOfTables); | |||
| OffsetTable.uMajorVersion := SWAPWORD(OffsetTable.uMajorVersion); | |||
| OffsetTable.uMinorVersion := SWAPWORD(OffsetTable.uMinorVersion); | |||
| //check is this is a true type font and the version is 1.0 | |||
| if (OffsetTable.uMajorVersion <> 1) or (OffsetTable.uMinorVersion <> 0) then | |||
| Exit; | |||
| // seaching table with name | |||
| for Idx := 0 to OffsetTable.uNumOfTables -1 do begin | |||
| Stream.Read(TableDir, sizeof(TT_TABLE_DIRECTORY)); | |||
| if (TableName = TableDir.TableName) then begin | |||
| TableDir.uOffset := SWAPLONG(TableDir.uOffset); | |||
| TableDir.uLength := SWAPLONG(TableDir.uLength); | |||
| // copying tabledata | |||
| if (pBuff <> nil) and (Size >= Integer(TableDir.uLength)) then begin | |||
| Stream.Seek(TableDir.uOffset, soBeginning); | |||
| Size := Stream.Read(pBuff^, TableDir.uLength); | |||
| Result := Size = Integer(TableDir.uLength); | |||
| end else | |||
| begin | |||
| // restoring streamposition | |||
| Stream.Position := Pos; | |||
| Size := TableDir.uLength; | |||
| Result := True; | |||
| end; | |||
| break; | |||
| end; | |||
| end; | |||
| end; | |||
| function MakeTTTableName(const ch1, ch2, ch3, ch4: Char): Cardinal; | |||
| begin | |||
| Result := ord(ch4) shl 24 or ord(ch3) shl 16 or ord(ch2) shl 8 or ord(ch1); | |||
| end; | |||
| function GetTTString(pBuffer: Pointer; BufferSize: Integer; NameID, LanguageID: Cardinal; var Text: AnsiString): Boolean; | |||
| var | |||
| pActBuffer: pByte; | |||
| ttNTHeader: TT_NAME_TABLE_HEADER; | |||
| ttRecord: TT_NAME_RECORD; | |||
| Idx: Integer; | |||
| Prio: Integer; | |||
| procedure ExtractName; | |||
| var | |||
| pTempBuffer: pByte; | |||
| pTemp: pWideChar; | |||
| uStringLengthH2: Word; | |||
| procedure SwapText(pText: pWideChar; Length: Word); | |||
| begin | |||
| while Length > 0 do begin | |||
| pWord(pText)^ := SWAPWORD(pWord(pText)^); | |||
| Inc(pText); | |||
| Dec(Length); | |||
| end; | |||
| end; | |||
| begin | |||
| Result := True; | |||
| ttRecord.uStringLength := SWAPWORD(ttRecord.uStringLength); | |||
| ttRecord.uStringOffset := SWAPWORD(ttRecord.uStringOffset); | |||
| uStringLengthH2 := ttRecord.uStringLength shr 1; | |||
| pTempBuffer := pBuffer; | |||
| Inc(pTempBuffer, ttNTHeader.uStorageOffset + ttRecord.uStringOffset); | |||
| // Unicode | |||
| if ((ttRecord.uPlatformID = PLATFORM_ID_MICROSOFT) and (ttRecord.uEncodingID in [0, 1])) or | |||
| ((ttRecord.uPlatformID = PLATFORM_ID_APPLE_UNICODE) and (ttRecord.uEncodingID > 0)) then begin | |||
| pTemp := tsStrAlloc(uStringLengthH2); | |||
| try | |||
| // uStringLengthH2 * 2 because possible buffer overrun | |||
| Move(pTempBuffer^, pTemp^, uStringLengthH2 * 2); | |||
| SwapText(pTemp, uStringLengthH2); | |||
| WideCharLenToStrVar(pTemp, uStringLengthH2, Text); | |||
| finally | |||
| tsStrDispose(pTemp); | |||
| end; | |||
| end else | |||
| // none unicode | |||
| begin | |||
| SetLength(Text, ttRecord.uStringLength); | |||
| Move(pTempBuffer^, Text[1], ttRecord.uStringLength); | |||
| end; | |||
| end; | |||
| begin | |||
| Result := False; | |||
| pActBuffer := pBuffer; | |||
| Move(pActBuffer^, ttNTHeader, sizeof(TT_NAME_TABLE_HEADER)); | |||
| inc(pActBuffer, sizeof(TT_NAME_TABLE_HEADER)); | |||
| ttNTHeader.uNRCount := SWAPWORD(ttNTHeader.uNRCount); | |||
| ttNTHeader.uStorageOffset := SWAPWORD(ttNTHeader.uStorageOffset); | |||
| Prio := -1; | |||
| for Idx := 0 to ttNTHeader.uNRCount -1 do begin | |||
| Move(pActBuffer^, ttRecord, sizeof(TT_NAME_RECORD)); | |||
| Inc(pActBuffer, sizeof(TT_NAME_RECORD)); | |||
| ttRecord.uNameID := SWAPWORD(ttRecord.uNameID); | |||
| if ttRecord.uNameID = NameID then begin | |||
| ttRecord.uPlatformID := SWAPWORD(ttRecord.uPlatformID); | |||
| ttRecord.uEncodingID := SWAPWORD(ttRecord.uEncodingID); | |||
| ttRecord.uLanguageID := SWAPWORD(ttRecord.uLanguageID); | |||
| // highest priority | |||
| if (ttRecord.uPlatformID = PLATFORM_ID_MICROSOFT) then begin | |||
| // system language | |||
| if (ttRecord.uLanguageID = languageID) then begin | |||
| if Prio <= 7 then begin | |||
| ExtractName; | |||
| Prio := 7; | |||
| end; | |||
| end else | |||
| // english | |||
| if (ttRecord.uLanguageID = 1033) then begin | |||
| if Prio <= 6 then begin | |||
| ExtractName; | |||
| Prio := 6; | |||
| end; | |||
| end else | |||
| // all else | |||
| if Prio <= 5 then begin | |||
| ExtractName; | |||
| Prio := 5; | |||
| end; | |||
| end else | |||
| // apple unicode | |||
| if (ttRecord.uPlatformID = PLATFORM_ID_APPLE_UNICODE) then begin | |||
| ExtractName; | |||
| Prio := 4; | |||
| end else | |||
| // macintosh | |||
| if (ttRecord.uPlatformID = PLATFORM_ID_MACINTOSH) then begin | |||
| // english | |||
| if (ttRecord.uLanguageID = 0) then begin | |||
| if Prio <= 3 then begin | |||
| ExtractName; | |||
| Prio := 3; | |||
| end; | |||
| end else | |||
| // all other | |||
| begin | |||
| ExtractName; | |||
| Prio := 2; | |||
| end; | |||
| end else | |||
| begin | |||
| if Prio <= 1 then begin | |||
| ExtractName; | |||
| Prio := 1; | |||
| end; | |||
| end; | |||
| end; | |||
| end; | |||
| end; | |||
| function GetTTFontFullNameFromStream(Stream: TStream; LanguageID: Cardinal): AnsiString; | |||
| var | |||
| TableName: Cardinal; | |||
| Buffer: Pointer; | |||
| BufferSize: Integer; | |||
| begin | |||
| TableName := MakeTTTableName('n', 'a', 'm', 'e'); | |||
| if GetTTTableData(Stream, TableName, nil, BufferSize) then begin | |||
| GetMem(Buffer, BufferSize); | |||
| try | |||
| if GetTTTableData(Stream, TableName, Buffer, BufferSize) then begin | |||
| if not GetTTString(Buffer, BufferSize, NAME_ID_FULL_NAME, LanguageID, Result) then | |||
| if not GetTTString(Buffer, BufferSize, NAME_ID_FACE_NAME, LanguageID, Result) then | |||
| Result := ''; | |||
| end; | |||
| finally | |||
| FreeMem(Buffer); | |||
| end; | |||
| end; | |||
| end; | |||
| function GetTTFontFullNameFromFile(Filename: AnsiString; LanguageID: Cardinal): AnsiString; | |||
| var | |||
| fs: TFileStream; | |||
| begin | |||
| fs := TFileStream.Create(String(Filename), fmOpenRead or fmShareDenyWrite); | |||
| try | |||
| result := GetTTFontFullNameFromStream(fs, LanguageID); | |||
| finally | |||
| fs.Free; | |||
| end; | |||
| end; | |||
| end. | |||
| @@ -0,0 +1,304 @@ | |||
| unit utsTypes; | |||
| {$mode objfpc}{$H+} | |||
| interface | |||
| uses | |||
| Classes, SysUtils; | |||
| type | |||
| TtsCodePage = ( | |||
| tsUTF8, | |||
| tsISO_8859_1, | |||
| tsISO_8859_2, | |||
| tsISO_8859_3, | |||
| tsISO_8859_4, | |||
| tsISO_8859_5, | |||
| tsISO_8859_6, | |||
| tsISO_8859_7, | |||
| tsISO_8859_8, | |||
| tsISO_8859_9, | |||
| tsISO_8859_10, | |||
| tsISO_8859_11, | |||
| tsISO_8859_13, | |||
| tsISO_8859_14, | |||
| tsISO_8859_15, | |||
| tsISO_8859_16, | |||
| tsISO_037, | |||
| tsISO_437, | |||
| tsISO_500, | |||
| tsISO_737, | |||
| tsISO_775, | |||
| tsISO_850, | |||
| tsISO_852, | |||
| tsISO_855, | |||
| tsISO_857, | |||
| tsISO_860, | |||
| tsISO_861, | |||
| tsISO_862, | |||
| tsISO_863, | |||
| tsISO_864, | |||
| tsISO_865, | |||
| tsISO_866, | |||
| tsISO_869, | |||
| tsISO_874, | |||
| tsISO_875, | |||
| tsISO_1026, | |||
| tsISO_1250, | |||
| tsISO_1251, | |||
| tsISO_1252, | |||
| tsISO_1253, | |||
| tsISO_1254, | |||
| tsISO_1255, | |||
| tsISO_1256, | |||
| tsISO_1257, | |||
| tsISO_1258); | |||
| TtsFontStyle = ( | |||
| tsStyleBold, | |||
| tsStyleItalic, | |||
| tsStyleUnderline, | |||
| tsStyleStrikeout); | |||
| TtsFontStyles = set of TtsFontStyle; | |||
| TtsVertAlignment = ( | |||
| tsVertAlignTop, | |||
| tsVertAlignCenter, | |||
| tsVertAlignBottom); | |||
| TtsHorzAlignment = ( | |||
| tsHorzAlignLeft, | |||
| tsHorzAlignCenter, | |||
| tsHorzAlignRight, | |||
| tsHorzAlignJustify); | |||
| TtsFormat = ( | |||
| tsFormatEmpty, | |||
| tsFormatRGBA8, | |||
| tsFormatLumAlpha8, | |||
| tsFormatAlpha8); | |||
| TtsAntiAliasing = ( | |||
| tsAANone, | |||
| tsAANormal); | |||
| TtsColorChannel = ( | |||
| tsChannelRed, | |||
| tsChannelGreen, | |||
| tsChannelBlue, | |||
| tsChannelAlpha); | |||
| TtsColorChannels = set of TtsColorChannel; | |||
| TtsImageMode = ( | |||
| tsModeIgnore, | |||
| tsModeReplace, | |||
| tsModeModulate); | |||
| TtsImageModes = array[TtsColorChannel] of TtsImageMode; | |||
| TtsImageModeFunc = function(const aSource, aDest: Single): Single; | |||
| TtsFontProperties = packed record | |||
| Fontname: String; | |||
| Copyright: String; | |||
| FaceName: String; | |||
| StyleName: String; | |||
| FullName: String; | |||
| Size: Integer; | |||
| Style: TtsFontStyles; | |||
| AntiAliasing: TtsAntiAliasing; | |||
| DefaultChar: WideChar; | |||
| Ascent: Integer; | |||
| Descent: Integer; | |||
| ExternalLeading: Integer; | |||
| BaseLineOffset: Integer; | |||
| UnderlinePos: Integer; | |||
| UnderlineSize: Integer; | |||
| StrikeoutPos: Integer; | |||
| StrikeoutSize: Integer; | |||
| end; | |||
| TtsPosition = packed record | |||
| x, y: Integer; | |||
| end; | |||
| PtsPosition = ^TtsPosition; | |||
| TtsPositionF = packed record | |||
| x, y: Single; | |||
| end; | |||
| PtsPositionF = ^TtsPositionF; | |||
| TtsRect = packed record | |||
| case Byte of | |||
| 0: (TopLeft: TtsPosition; BottomRight: TtsPosition); | |||
| 1: (Left, Top, Right, Bottom: Integer); | |||
| end; | |||
| PtsRect = ^TtsRect; | |||
| TtsRectF = packed record | |||
| case Byte of | |||
| 0: (TopLeft: TtsPositionF; BottomRight: TtsPositionF); | |||
| 1: (Left, Top, Right, Bottom: Single); | |||
| end; | |||
| PtsRectF = ^TtsRectF; | |||
| TtsColor4f = packed record | |||
| case Boolean of | |||
| true: (r, g, b, a: Single); | |||
| false: (arr: array[0..3] of Single); | |||
| end; | |||
| PtsColor4f = ^TtsColor4f; | |||
| TtsColor4ub = packed record | |||
| case Boolean of | |||
| true: (r, g, b, a: Byte); | |||
| false: (arr: array[0..3] of Byte); | |||
| end; | |||
| PtsColor4ub = ^TtsColor4ub; | |||
| TtsTextMetric = packed record | |||
| Ascent: Integer; | |||
| Descent: Integer; | |||
| ExternalLeading: Integer; | |||
| BaseLineOffset: Integer; | |||
| CharSpacing: Integer; | |||
| LineHeight: Integer; | |||
| LineSpacing: Integer; | |||
| end; | |||
| TtsAnsiToWideCharFunc = procedure(aDst: PWideChar; const aSize: Integer; aSource: PAnsiChar; const aCodePage: TtsCodePage; const aDefaultChar: WideChar); | |||
| function tsColor4f(r, g, b, a: Single): TtsColor4f; | |||
| function tsRect(const l, t, r, b: Integer): TtsRect; | |||
| function tsPosition(const x, y: Integer): TtsPosition; | |||
| function tsFormatSize(const aFormat: TtsFormat): Integer; | |||
| procedure tsFormatMap(const aFormat: TtsFormat; var aData: PByte; const aColor: TtsColor4f); | |||
| procedure tsFormatUnmap(const aFormat: TtsFormat; var aData: PByte; out aColor: TtsColor4f); | |||
| function tsImageModeFuncIgnore(const aSource, aDest: Single): Single; | |||
| function tsImageModeFuncReplace(const aSource, aDest: Single): Single; | |||
| function tsImageModeFuncModulate(const aSource, aDest: Single): Single; | |||
| implementation | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| function tsColor4f(r, g, b, a: Single): TtsColor4f; | |||
| begin | |||
| result.r := r; | |||
| result.g := g; | |||
| result.b := b; | |||
| result.a := a; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| function tsRect(const l, t, r, b: Integer): TtsRect; | |||
| begin | |||
| result.Left := l; | |||
| result.Top := t; | |||
| result.Right := r; | |||
| result.Bottom := b; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| function tsPosition(const x, y: Integer): TtsPosition; | |||
| begin | |||
| result.x := x; | |||
| result.y := y; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| function tsFormatSize(const aFormat: TtsFormat): Integer; | |||
| begin | |||
| case aFormat of | |||
| tsFormatRGBA8: result := 4; | |||
| tsFormatLumAlpha8: result := 2; | |||
| tsFormatAlpha8: result := 1; | |||
| else | |||
| result := 0; | |||
| end; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| procedure tsFormatMap(const aFormat: TtsFormat; var aData: PByte; const aColor: TtsColor4f); | |||
| var | |||
| i: Integer; | |||
| s: Single; | |||
| begin | |||
| case aFormat of | |||
| tsFormatRGBA8: begin | |||
| for i := 0 to 3 do begin | |||
| aData^ := Trunc($FF * aColor.arr[i]); | |||
| inc(aData); | |||
| end; | |||
| end; | |||
| tsFormatLumAlpha8: begin | |||
| s := 0.30 * aColor.r + 0.59 * aColor.g + 0.11 * aColor.b; | |||
| aData^ := Trunc($FF * s); inc(aData); | |||
| aData^ := Trunc($FF * s); inc(aData); | |||
| aData^ := Trunc($FF * s); inc(aData); | |||
| aData^ := Trunc($FF * aColor.a); inc(aData); | |||
| end; | |||
| tsFormatAlpha8: begin | |||
| aData^ := Trunc($FF * aColor.a); | |||
| inc(aData); | |||
| end; | |||
| end; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| procedure tsFormatUnmap(const aFormat: TtsFormat; var aData: PByte; out aColor: TtsColor4f); | |||
| var | |||
| i: Integer; | |||
| begin | |||
| case aFormat of | |||
| tsFormatRGBA8: begin | |||
| for i := 0 to 3 do begin | |||
| aColor.arr[i] := aData^ / $FF; | |||
| inc(aData); | |||
| end; | |||
| end; | |||
| tsFormatLumAlpha8: begin | |||
| aColor.r := aData^ / $FF; | |||
| aColor.g := aData^ / $FF; | |||
| aColor.b := aData^ / $FF; | |||
| inc(aData); | |||
| aColor.a := aData^ / $FF; | |||
| inc(aData); | |||
| end; | |||
| tsFormatAlpha8: begin | |||
| aColor.r := 1.0; | |||
| aColor.g := 1.0; | |||
| aColor.b := 1.0; | |||
| aColor.a := aData^ / $FF; | |||
| inc(aData); | |||
| end; | |||
| end; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| function tsImageModeFuncIgnore(const aSource, aDest: Single): Single; | |||
| begin | |||
| result := aDest; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| function tsImageModeFuncReplace(const aSource, aDest: Single): Single; | |||
| begin | |||
| result := aSource; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| function tsImageModeFuncModulate(const aSource, aDest: Single): Single; | |||
| begin | |||
| result := aSource * aDest; | |||
| end; | |||
| end. | |||
| @@ -0,0 +1,144 @@ | |||
| unit utsUtils; | |||
| {$mode objfpc}{$H+} | |||
| interface | |||
| uses | |||
| Classes, SysUtils; | |||
| function tsStrAlloc(aSize: Cardinal): PWideChar; | |||
| function tsStrNew(const aText: PWideChar): PWideChar; | |||
| procedure tsStrDispose(const aText: PWideChar); | |||
| function tsStrLength(aText: PWideChar): Cardinal; | |||
| function tsStrCopy(aDst, aSrc: PWideChar): PWideChar; | |||
| function tsISO_8859_1ToWide(aDst: PWideChar; const aSize: Integer; aSrc: PAnsiChar): Integer; | |||
| function tsUTF8ToWide(aDst: PWideChar; const aSize: Integer; const aSrc: PAnsiChar; const aDefaultChar: WideChar): Integer; | |||
| implementation | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| function tsStrAlloc(aSize: Cardinal): PWideChar; | |||
| begin | |||
| aSize := (aSize + 1) shl 1; | |||
| GetMem(result, aSize); | |||
| FillChar(result^, aSize, 0); | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| function tsStrNew(const aText: PWideChar): PWideChar; | |||
| begin | |||
| result := tsStrAlloc(tsStrLength(aText)); | |||
| tsStrCopy(result, aText); | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| procedure tsStrDispose(const aText: PWideChar); | |||
| begin | |||
| FreeMem(aText); | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| function tsStrLength(aText: PWideChar): Cardinal; | |||
| begin | |||
| result := 0; | |||
| if Assigned(aText) then | |||
| while (ord(aText^) <> 0) do begin | |||
| inc(result); | |||
| inc(aText); | |||
| end; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| function tsStrCopy(aDst, aSrc: PWideChar): PWideChar; | |||
| begin | |||
| result := aDst; | |||
| if Assigned(aDst) and Assigned(aSrc) then | |||
| while ord(aSrc^) <> 0 do begin | |||
| aDst^ := aSrc^; | |||
| inc(aDst); | |||
| inc(aSrc); | |||
| end; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| function tsISO_8859_1ToWide(aDst: PWideChar; const aSize: Integer; aSrc: PAnsiChar): Integer; | |||
| begin | |||
| result := 0; | |||
| if Assigned(aDst) and Assigned(aSrc) then | |||
| while (ord(aSrc^) <> 0) do begin | |||
| aDst^ := WideChar(aSrc^); | |||
| inc(aDst); | |||
| inc(aSrc); | |||
| inc(result); | |||
| end; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| function tsUTF8ToWide(aDst: PWideChar; const aSize: Integer; const aSrc: PAnsiChar; const aDefaultChar: WideChar): Integer; | |||
| procedure AddToDest(aCharCode: UInt64); | |||
| begin | |||
| if (aCharCode > $FFFF) then | |||
| aCharCode := ord(aDefaultChar); | |||
| PWord(aDst)^ := aCharCode; | |||
| inc(aDst); | |||
| result := result + 1; | |||
| end; | |||
| const | |||
| STATE_STARTBYTE = 0; | |||
| STATE_FOLLOWBYTE = 1; | |||
| var | |||
| cc: QWord; | |||
| len, state, c: Integer; | |||
| p: PByte; | |||
| tmp: Byte; | |||
| begin | |||
| result := 0; | |||
| if not Assigned(aDst) or not Assigned(aSrc) or (aSize <= 0) then | |||
| exit; | |||
| p := PByte(aSrc); | |||
| len := Length(aSrc); | |||
| state := STATE_STARTBYTE; | |||
| while (len > 0) do begin | |||
| case state of | |||
| STATE_STARTBYTE: begin | |||
| if (p^ and %10000000 = 0) then begin | |||
| AddToDest(p^); | |||
| end else if (p^ and %01000000 > 0) then begin | |||
| tmp := p^; | |||
| c := 0; | |||
| while (tmp and %10000000) > 0 do begin | |||
| inc(c); | |||
| tmp := tmp shl 1; | |||
| end; | |||
| cc := p^ and ((1 shl (7 - c)) - 1); | |||
| state := STATE_FOLLOWBYTE; | |||
| c := c - 1; | |||
| end; | |||
| end; | |||
| STATE_FOLLOWBYTE: begin | |||
| if ((p^ and %11000000) = %10000000) then begin | |||
| cc := (cc shl 6) or (p^ and %00111111); | |||
| c := c - 1; | |||
| if (c = 0) then begin | |||
| AddToDest(cc); | |||
| state := STATE_STARTBYTE; | |||
| end; | |||
| end else | |||
| state := STATE_STARTBYTE; | |||
| end; | |||
| end; | |||
| if (result >= aSize) then | |||
| exit; | |||
| inc(p); | |||
| end; | |||
| end; | |||
| end. | |||
| @@ -3082,7 +3082,7 @@ begin | |||
| // name | |||
| fFontname := Fontname; | |||
| for Idx := 1 to Min(Length(Fontname), Length(LogFont.lfFaceName)) do | |||
| for Idx := 1 to min(Length(Fontname), Length(LogFont.lfFaceName)) do | |||
| LogFont.lfFaceName[Idx -1] := Fontname[Idx]; | |||
| // char set | |||
| @@ -4,6 +4,7 @@ object MainForm: TMainForm | |||
| Top = 255 | |||
| Width = 682 | |||
| OnCreate = FormCreate | |||
| OnDestroy = FormDestroy | |||
| OnPaint = FormPaint | |||
| LCLVersion = '1.3' | |||
| object ApplicationProperties: TApplicationProperties | |||
| @@ -2,27 +2,36 @@ unit uMainForm; | |||
| {$mode objfpc}{$H+} | |||
| {.$DEFINE USE_OLD_TS} | |||
| interface | |||
| uses | |||
| Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, uglcContext, TextSuite, uglcTypes, utsTextSuite; | |||
| Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, uglcContext, TextSuite, uglcTypes, | |||
| utsTextSuite, utsTypes, utsFontCreatorGDI, utsRendererOpenGL; | |||
| type | |||
| TMainForm = class(TForm) | |||
| ApplicationProperties: TApplicationProperties; | |||
| procedure ApplicationPropertiesIdle(Sender: TObject; var Done: Boolean); | |||
| procedure FormCreate(Sender: TObject); | |||
| procedure FormDestroy(Sender: TObject); | |||
| procedure FormPaint(Sender: TObject); | |||
| private | |||
| fFrameTime: QWord; | |||
| fFrameCount: Integer; | |||
| fSecTime: QWord; | |||
| fContext: TglcContext; | |||
| {$IFDEF USE_OLD_TS} | |||
| fTextSuiteContext: tsContextID; | |||
| fFontID: tsFontID; | |||
| ftsContext: TtsContext; | |||
| ftsRenderer: TtsRenderer; | |||
| ftsCreator: TtsFontCreator; | |||
| ftsFont: TtsFont; | |||
| {$ELSE} | |||
| ftsContext: TtsContext; | |||
| ftsRenderer: TtsRendererOpenGL; | |||
| ftsGenerator: TtsFontGeneratorGDI; | |||
| ftsFont: TtsFont; | |||
| {$ENDIF} | |||
| procedure Render; | |||
| public | |||
| { public declarations } | |||
| @@ -48,19 +57,31 @@ begin | |||
| pf := TglcContext.MakePF(); | |||
| fContext := TglcContext.GetPlatformClass.Create(self, pf); | |||
| fContext.BuildContext; | |||
| {$IFDEF USE_OLD_TS} | |||
| tsInit(TS_INIT_TEXTSUITE or TS_INIT_OPENGL or TS_INIT_GDI); | |||
| tsContextCreate(@fTextSuiteContext); | |||
| tsSetParameteri(TS_RENDERER, TS_RENDERER_OPENGL); | |||
| tsSetParameteri(TS_CREATOR, TS_CREATOR_GDI); | |||
| tsSetParameteri(TS_CREATOR, TS_CREATOR_GDI_FACENAME); | |||
| tsContextBind(fTextSuiteContext); | |||
| tsFontCreateCreatorA('ttf/calibri.ttf', 24, 0, TS_ANTIALIASING_NORMAL, TS_DEFAULT, @fFontID); | |||
| tsFontCreateCreatorA('Calibri', 25, 0, TS_ANTIALIASING_NORMAL, TS_DEFAULT, @fFontID); | |||
| tsFontBind(fFontID); | |||
| {$ELSE} | |||
| ftsContext := TtsContext.Create; | |||
| ftsRenderer := TtsRendererOpenGL.Create(ftsContext, tsFormatRGBA8); | |||
| ftsGenerator := TtsFontGeneratorGDI.Create; | |||
| ftsFont := ftsGenerator.GetFontByName('Calibri', ftsRenderer, 25, [], tsAANormal); | |||
| ftsFont.LineSpacing := 0; | |||
| {$ENDIF} | |||
| end; | |||
| ftsContext := TtsContext.Create; | |||
| ftsRenderer := TtsRenderer.Create(ftsContext, tsFormatRGBA8); | |||
| ftsCreator := TtsFontCreator.Create; | |||
| ftsFont := TtsFont.Create(ftsRenderer, ftsCreator, '', '', '', '', 12, 0, 0, [], tsAANormal); | |||
| procedure TMainForm.FormDestroy(Sender: TObject); | |||
| begin | |||
| {$IFNDEF USE_OLD_TS} | |||
| FreeAndNil(ftsFont); | |||
| FreeAndNil(ftsGenerator); | |||
| FreeAndNil(ftsRenderer); | |||
| FreeAndNil(ftsContext); | |||
| {$ENDIF} | |||
| end; | |||
| procedure TMainForm.FormPaint(Sender: TObject); | |||
| @@ -71,7 +92,22 @@ end; | |||
| procedure TMainForm.Render; | |||
| var | |||
| block: TtsTextBlock; | |||
| t: QWord; | |||
| dif: Integer; | |||
| begin | |||
| t := GetTickCount64; | |||
| if (fFrameTime <> 0) then begin | |||
| dif := t - fFrameTime; | |||
| inc(fFrameCount, 1); | |||
| inc(fSecTime, dif); | |||
| if (fSecTime > 1000) then begin | |||
| Caption := IntToStr(fFrameCount) + ' FPS'; | |||
| fFrameCount := 0; | |||
| dec(fSecTime, 1000); | |||
| end; | |||
| end; | |||
| fFrameTime := t; | |||
| glViewport(0, 0, ClientWidth, ClientHeight); | |||
| glClearColor(0, 0, 0, 0); | |||
| glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); | |||
| @@ -82,23 +118,22 @@ begin | |||
| glMatrixMode(GL_MODELVIEW); | |||
| glLoadIdentity; | |||
| glDisable(GL_CULL_FACE); | |||
| glDisable(GL_DEPTH_TEST); | |||
| glEnable(GL_BLEND); | |||
| glcBlendFunc(TglcBlendMode.bmAdditiveAlphaBlend); | |||
| //tsTextBeginBlock(10, 10, ClientWidth-10, ClientHeight-10, TS_ALIGN_BLOCK); | |||
| //tsTextOutA(TEST_STRING); | |||
| //tsTextEndBlock; | |||
| block := ftsRenderer.BeginBlock(10, 10, ClientWidth-10, ClientHeight-10, [tsBlockFlagWordWrap]); | |||
| {$IFDEF USE_OLD_TS} | |||
| tsTextBeginBlock(0, 0, ClientWidth, ClientHeight, TS_ALIGN_BLOCK); | |||
| tsTextOutA(TEST_STRING); | |||
| tsTextEndBlock; | |||
| {$ELSE} | |||
| block := ftsRenderer.BeginBlock(0, 0, ClientWidth, ClientHeight, [tsBlockFlagWordWrap]); | |||
| try | |||
| block.ChangeFont(ftsFont); | |||
| block.TextOutW('test'#13#10#13#10'test'#13#13'test'#10#10'test'#13#10#10'test'#13#13#10); | |||
| block.TextOutW(TEST_STRING); | |||
| finally | |||
| ftsRenderer.EndBlock(block); | |||
| end; | |||
| {$ENDIF} | |||
| fContext.SwapBuffers; | |||
| end; | |||