WARNING: massive commit! PD 7.0 is going to provide a single master Fill class (brush in GDI/GDI+) and Stroke class (pen in GDI/GDI+) as the back-end for anything that can be filled and/or outlined, eg. text, shapes, arrows, whatever. My goal is to make these classes support every fill/outline setting under the sun, and because the resulting settings are just stored as strings, all new tools will automatically support every fill/outline setting under the sun without any extra work on my part. This commit is the first step toward making that possible. The Typography tool already exposed a lot of these features manually, but now, I've reworked the fill-specific settings into a single, standalone UC with a custom dialog and corresponding render class (pdGraphicsBrush). From here on out, any feature added to the user control + rendering class will be automatically available to all other tools, which is great! There is still a *ton* to implement in the dialog, and textures in particular are going to be weird and messy, but this is an important first step. Note that this commit *IS NOT BACKWARDS COMPATIBLE WITH TEXT IN EXISTING PDI FILES*. PDI text layers will still save/load just fine, but any previous fill settings will be lost, as they are now stored in a totally different format. I will likely be modifying this format further in the coming weeks, so as with any developer build, don't save PDI files you can't afford to lose (just in case). Note that text background region fill settings are also lost; however, text backgrounds now support 100% of the features available when filling the text, so you now have way more options available for text backgrounds. The outline/pen UC is still TBD, but now that the bulk of the infrastructure for the Brush UC + rendering class is done (all that's left is feature implementation), I may turn to the outline/pen tool so I can call the Typography tool more or less done. Then I can move onto implementing other on-canvas tools while still plugging away at fill/outline features. We'll see.
Not glyph-level. With this change, an outlined underline/strikeout looks like one contiguous line, instead of a bunch of tiny glyph-width lines placed next to each other. Trailing whitespace chars are also ignored when calculating underline/strikeout width and placement.
Some path transforms can fail unpredictably; if this happens, the typography tool will now try to be smarter about restoring an unmodified version of the glyph (as a "better than nothing" last resort).
The font's specified positioning and sizing is used in both cases, woohoo! (I'll probably end up moving the actual rendering to a different position in the text engine so that outlining doesn't show the lines between characters, and trailing spaces are ignored, but that's easily done now that I've cracked how to pull the relevant information out of WAPI.)
… behavior GetOutlineTextMetrics is a neat WAPI function that provides a ton of useful data, but man, struct alignment for the return is a disaster, and MSDN isn't helpful because VB silently performs its own word alignment, negating the need for some of the dummy padding bytes. I think I've sorted everything out, since I'm getting proper returns on the underline and strikeout entries on both XP and Win 8. Fingers crossed that more testing bears this out.
…perties Always good to have a failsafe with performance-sensitive features.
Language-specific font properties are no longer cached at program startup (because it was killing performance; see fcfeb0f). Instead, the round-robin cache used by the font dropdown UC caches those properties on-demand. Testing on a 2001-era PC shows no trouble with this approach, so I'm content to make it permanent.
(Well, maybe not the *absolute last* as I still need to fix underline and strikethrough... sigh) Anyway, after this commit, it's time to shift gears and start working on dedicated UCs for pen and brush selection. This will not only let me clean up the Typography tool's various "visual" panels, but will also save me a ton of work on eventual Shape tools (which make use of the same fill and stroke features).
Lots of fun per-character options
This will be an ongoing WIP, seeing as there are so many random system-interaction bits throughout the project, but moving one of the bigger modules into a class is a good start.
Fixes #162. Everything in the original issue report has been handled, save the creation of a matching UC. That's outside the scope of what I need right now, but I'll revisit if/when it becomes relevant.
Yep, PD's that awesome. ;) To keep the on-canvas UI simple, shear can only be controlled from the move/size tool panel. I've seen other software try to cram shear controls onto the canvas (e.g. Inkscape) but this gets unruly pretty quickly. Also, I've temporarily suspended on-canvas arc prediction if shearing is active, because I haven't solved the math necessary to draw a sheared arc without it warping to strange new locations.
I can't promise that these will actually work, but since I've gone to the trouble of implementing matrix-based affine transforms, it should theoretically be trivial to add non-destructive shearing too. If my theory proves incorrect, this commit "causes no harm" so it won't need to be rolled back (and perhaps I can revisit in the future).
If the user initiates a merge operation on an image with text/vector layers, rasterization prompts will now be displayed ONLY if a text/vector layer is actually involved in the current merge operation. Said another way, merging 2+ raster layers will never raise a rasterization prompt.
Cropping to a rectangular selection can be handled instantaneously by simply adjusting layer offsets and canvas size. This effectively makes it a non-destructive operation, as no image data is lost - but even better, it avoids the need for rasterizing text and vector layers!
Resize, rotate, etc now process rotated layers correctly. Since I was here, I also optimized various functions related to these transforms to cut down on memory churn. Overall performance should be much better, especially on systems where RAM is tight.
Rotation is now considered when figuring out which layer lies under the cursor
This commit uses a shortcut calculation so there is *slight* potential for subpixel shifting when merging, but I'll fix this in the coming days. (Right now I just wanted to get the function working at all so I can test a number of merge-related behaviors.) Since I was here, I also rewrote the bulk of the merge function to take advantage of recent compositor enhancements. Merging should now be significantly faster under all conditions, but *especially* when non-standard blend modes or non-destructive FX are active. (Most importantly, this hugely improves the speed of flattening the entire image, since flattening is just a loop of "merge layer" calls.) I've also fixed a number of annoying old merge bugs, like merging two layers with variable opacity and having the end result be wonky because the merged layer retains its original opacity setting. Merging should now be 100% accurate regardless of layer opacity, blend mode, and/or non-destructive effects for both top and bottom layers.
Rotated *top* layers are still broken, but I'm close to a fix
Lots going on here, but the end result should be a significantly better UI for all on-canvas layer interactions. - I've reworked the viewport so that an active POI can be marked, and its ID forwarded to the viewport. From there, the viewport simply forwards the value onto other rendering functions. (This system is great because it means we can implement any UI behavior for POIs without touching viewport code.) - Layer interaction nodes are now highlighted on mouse-over. - Layer corner nodes are now rendered as squares, to differentiate their behavior from rotation nodes. - Rotation nodes (circles) are now provided along each image edge, so the user can freely rotate the image using any visible boundary. - On mouseover, rotation nodes now display a center line and rotation arc, to give some helpful feedback on how the node behaves. A number of other misc layer and canvas fixes/improvements are also part of this commit, to make viewport interactions a bit more fluid.
- Layer opacity now works - Custom blend modes now work - Mad optimizations are now active. PD's extensive viewport caching mechanism is now compatible with affine-transformed layers, so the viewport should be back to excellent performance, even on images with many rotated layers. Huge win here. - I've added rudimentary antialiasing along rotated borders. There's not really a good way to do this without murdering performance, so for extremely high rotation quality, a destructive transform is inevitable. But the current solution is still way more than other software offers, so I'm content to compromise for now. - Program-wide viewport performance settings are now respected by the affine transform rendering path. This should make non-destructive rotation usable even on terrible hardware, at some (inevitable) cost to viewport rendering quality.
…ing paths Opacity and blend modes are broken, and no optimizations have been applied, but the core rotation math is all functional! This means you can now rotate and resize layers non-destructively using 100% on-canvas controls. Next up is myriad optimizations and restoring blend mode and opacity support.
- On-canvas layer transforms (by click-dragging layer corners) now work for all corners, even while layer rotation is active. - To simplify transformations, on-canvas transforms are now handled relative to a layer's center. So click-dragging any corner applies an identical transformation, by sizing/moving the layer without changing its current position. I've seen this in other software and while it's a little jarring relative to PD's past behavior, I think it's ultimately more intuitive, especially given the way image interactions work on mobile devices (which the average user is probably *more* familiar with at this point). - Obviously, you can still move a layer by clicking anywhere inside its bounds and dragging it around. - Shift key behavior is better. I still need to fix its behavior if you release the shift key before releasing the mouse, but while moving the mouse, the use of Shift (to lock aspect ratio) behaves a lot more naturally. - New text layers created via click (and no subsequent drag) are now sized to the union rect of the current viewport and the image itself. This is much better than forcing new text layers to the size of the image, especially if the user is currently zoomed-in. (Note that you can still click-drag to set your own text layer size at creation-time.) - On-canvas nodes and layer boundaries have received some clean-up, so line junctions and endings are now rendered as continuous shapes instead of discrete lines. - A new on-canvas node has been added for rotation. It is rendered and hit-detected correctly, but you can't otherwise interact with it just yet. (That's coming!) Still WIP: - Auto-detecting the layer under the mouse is still broken, but I've finally reworked the tool code to a point where I can fix this (soon). - The default viewport pipeline is still broken, so only the UI nodes will rotate, not the image, unless you manually set the viewport performance setting to "best quality". I'll be fixing this soon as well.
Also, get top-left layer transformations working. Now that it's complete, and all support code is in place, the other transforms are going to be cake! The old move/size tool code performed a ton of redundant calculations, since it was created at a time when PD's canvas UC was just a thin wrapper for image display. Now that the canvas is much more capable, it handles a lot of calculations so the caller doesn't have to - and the move/size tool finally takes advantage of that. A bunch of other tool rework was done to prep for paint tools, and the canvas UC is slowly getting toward an acceptable state (although there's a lot of refactoring still to do).
Layer resizing is still a disaster. Hope to have a solution in the coming days.
Rotated layers now have their boundaries and corner nodes rendered to the correct location. Still to-do is fixing mouse interactions to account for the rotated positions.
I've now cracked the math for restricting the transform to a relevant destination sub-region, which was the main missing piece for adding rotation support to PD's performance-optimized viewport pipeline. Also in this commit, I've defaulted the layer non-destructive resize quality to bilinear scaling. While bicubic is actually faster for rescaling *only*, complex transforms see a huge performance boost from bilinear (or nearest-neighbor, obviously). This means the GDI+ team did some custom bicubic optimizations for rescaling alone, which is great - kudos to them!
This reduces duplicate code in the compositor, without harming optimization. (In fact, it opens up some new routes for optimizing, since the layer maintains most the crucial data, saving us from transferring it externally!)