I've implemented these inside the Font_Management module, and will eventually look at cleaning up pdFont to simply wrap these improved creation functions. As for pdTextRenderer, it will now create a fallback GDI font object if GDI+ fails for whatever reason. (The potential list of failure reasons is longer than I can write in a single commit message... ha ha) My next commit may take awhile, as my next task is new fontGlyphCollection and fontGlyph classes, which manage raw path data for individual character glyphs. A ton of code has to be written before I can test these functions, so I don't know that intermediate commits will be very helpful.
The existing pure-GDI+ code path is still completely functional, so the debug text tool implementation will still work. However, it's now trivial for the class to switch paths if/when GDI+ fails on a font. Now to start work on the GDI path.
This is going to be a hideously ugly project, but it's theoretically doable. GDI supports OpenType fonts (and has for years), so I should be able to parse GDI glyphs, convert them from quadratic splines to GDI+ compatible Bezier curves, then import them to GDI+ as a GraphicsPath. This would allow me to use GDI+ to render OpenType fonts, enabling all the nice GDI+ features we have for TrueType fonts. Fingers crossed that it works. This commit is mostly a bunch of refactoring to make the new behavior easier to implement.
I thought about working this functionality directly into pdComboBox, but it's not worth the trouble, IMO. A font selection dropdown is a really odd duck for a couple reasons: 1) Its list contents are managed 100% internally, so it shouldn't expose any add/remove/clear type functionality. 2) It has some incredibly specific rendering requirements, as we have to create hundreds (possibly thousands) of fonts on-the-fly. That kind of messy work would just clutter up a normal combo box. 3) It requires a lot of interop with the separate Font_Management module, as this class doesn't do things like query the system for fonts; instead, it relies on the module to do that. 4) For saving/loading presets in a "portable app friendly" manner, this class needs to store the text contents of the combo box rather than the .ListIndex (as the availability of fonts will vary from system to system). Anyway, those are a few of the reasons that this is its own control. I'll be cracking away at this over the next few weeks amidst other UI work.
Performance should be excellent. On my old Win 7 PC, a system with ~250 fonts averages 12-13 ms to retrieve and sort the list of installed fonts. (Sorting is required because Windows returns fonts in an arbitrary order, and we need to mirror the output to various drop-downs throughout the program.) (Also, this makes me wonder why GIMP's startup font detection is so horrifically slow.)
Like the new font caching operation, lol - glad I caught this
Many thanks to Ellis Dee for his original "Snake Sort" algorithm, shared here in 2007: http://www.vbforums.com/showthread.php?473677-VB6-Sorting-algorithms-%28sort-array-sorting-arrays%29&p=2933240#post2933240 "Snake Sort" works especially well on lists that are comprised of individually sorted sub-lists. Windows returns fonts in exactly this fashion (strange blocks of 5-10 fonts, sorted alphabetically, before starting over again), so this is an ideal sort function for my current use case.
You can now click to create a text box at default size, or drag-release to set a specific size. (This was worth fixing now as I'm creating a *lot* of text layers during testing.)
Text hinting and clarity are worth testing, given Microsoft's general inability to write a coherent graphics library. As expected, ClearType is broken on 32-bpp rendering targets, but even more odd is that Non-AA + hinting (TextRenderingHintSingleBitPerPixelGridFit) is also inexplicably broken. For some reason, this setting forcibly sets target alpha values to zero *only where the font is displayed*, effectively making text transparent regardless of existing alpha. WTF. (Only tested on Win 7 so far, but since GDI+ is deprecated I expect similar behavior elsewhere) At this rate, I may look at implementing a Pango text backend sooner rather than later.
While there are (obviously) a ton more font options to expose, this is a decent start for testing. I'm going to take a detour now, and start overhauling the way the tool options panel works (specifically issue #166). This will simplify further work on the text tool UI, especially as I start to implement multiple text option panels. While the text tool works pretty well already, note that things like converting text layers to image layers, or merging text and image layers, have not been implemented yet. There are also some on-canvas UI quirks (like ugly pauses when a text layer is first created) that need to be addressed. These are all on my to-do list.
Text, font, and font size can now be set. Typing out text results in an immediate preview at quite good performance(YYYEEEEAAAAHHHHH). This commit also fixes a severe compositor bug where modified layers sometimes weren't being reflected on-screen. Oops! Tons of UI changes and improvements are coming, but I needed a bare minimum of text features so I can debug things like the new pdTextRenderer class.
…tion Only partially implemented at present, so I can't guarantee the program won't crash when selecting the text tool. Use at your own risk!
Important now that we have more than just raster layers
We need these to fill strings
Still more to do, but this is a good start
A class instance can now be properly serialized to/from XML, which is the main functionality required for PDI storage and Undo/Redo functionality. GDI+ objects are also cached and cleaned when relevant, and font caching has been implemented to minimize churn. Next, it's time to work on the actual rendering bits.
Unfortunately, GDI+ is only compatible with TrueType fonts (sigh). But at least it makes it straightforward to retrieve Unicode-compatible font names.
For size and performance reasons, text and vector layers do not store a raster copy of their contents. The raster copy is created on-the-fly at run-time. Thanks to careful planning, vector layers should not require any special handling in the Undo engine (which uses a variety of PDI file types to read/write Undo data efficiently), or even the generic PDI load/save functions, aside from this commit which involves retrieving layer-specific data as a generic byte stream or Unicode text block. The PDI read/write functions simply lean on pdLayer to properly generate or parse layer-specific XML data on a per-layer-type basis. As such, future vector layers should not require commits like this; only pdLayer itself will need to be updated.
The text tool is going to be a massive project, since text is PD's first true vector tool. As such, the pdLayer object is going to require many updates. (Obviously, once this project is done, adding future vector tools - shapes, pen, etc - will be much easier thanks to having a functional vector management pipeline.) Text tool is also a UI nightmare since a lot of user-facing options are relevant, and PD will need a dedicated edit box for text entry. (I do not plan to implement on-canvas editing - sorry! Blame WAPI for this.) Special user controls like a font-specific combo box are also important, not just here but elsewhere in the project, so that's another big component of this work. At first, I'm hoping to simply implement a "bare bones" version of a text tool, to make sure my vector engine design is sound. (I also need to write a new GDI+ font manager, which is going to take some time.) Once a bare bones implementation is functional and the new vector pipeline is in place, I can dedicate a lot more time to cleaning up the text tool UI and expanding available features.
...would cause the layer to seemingly "shift" its on-screen appearance while zoomed out.
I'm sure there will be more to optimize in the future, but as of now (build 70), PD's viewport pipeline is in a great place. Everything is more fluid and better organized, and the viewport pipeline and compositor will only need a few lines of code to handle paint tools. As an added bonus, paint operations will automatically receive all layer features for free (opacity, blend modes, subpixel positioning, etc) without any work on the part of the brush engine. Very exciting.
Oooohhh boy, this is exciting. With this commit, I believe PD now has the most fluid viewport of any open-source photo editor. Regardless of layer count, size, blend mode, or opacity, PD can now render interactive viewport actions (e.g. moving layers) with excellent responsiveness. There's none of the ridiculous chunky choppiness of other photo editors (*cough* GIMP *cough* Paint.NET) or the sluggishness of old PD versions. As an added bonus, sub-pixel positioning is actually displayed *more accurately* after this update! This is all possible with minimal impact to memory usage as well, so I consider this a pretty sweet win. I'm also feeling a lot better about implementing paint tools, as choppiness is murder when trying to do accurate painting work.
This greatly reduces the viewport render penalty for non-destructive effects and/or custom blend modes on the default pipeline. The current viewport chunk of each layer is now cached AFTER non-destructive effects are applied, so we only need to regenerate it after changes are made. Similarly, the temp copy of each layer required for custom blend-mode compositing is also cached, so when doing something like moving a layer around, all other layers with custom blend modes will render much faster. This was a prerequisite to paint tools. I may also look at caching resized versions of each layer when zoomed-out, to further improve render performance.