-
Content Count
2561 -
Joined
-
Last visited
-
Days Won
133
Everything posted by Anders Melander
-
Change "FadeOut" code to "FadeIn" code
Anders Melander replied to Willicious's topic in Delphi IDE and APIs
Yes. As I stated: Right now you only have one bitmap, which is black because you faded it out, so you only have one color. If you don't have a copy of the image you're supposed to be fading in to, you need to code a time machine that goes back in time and gets it - or maybe save a copy somewhere before you destroy the color information by fading it to black. -
Change "FadeOut" code to "FadeIn" code
Anders Melander replied to Willicious's topic in Delphi IDE and APIs
No. The Value specifies how far you are between fade-in and fade-out. In my example it's a float value between 0 and 1, inclusive, so 0.5 is halfway faded in/out. I would probably use integer math for performance instead of floats, but it's easier to explain with a float. The two code snippets I gave you should be ready to use for what you're trying: // "Fade" from blue to red for i := 0 to 100 do Color := ColorModulate(clBlue32, clRed32, i / 100); // "Fade" from green to black for i := 0 to 100 do Color := ColorModulate(clGreen32, clBlack32, i / 100); // or... for i := 0 to 100 do Color := FadeToBlack(clGreen32, i / 100); Actually, in my FadeToBlack example, I modulate the Alpha channel too. You probably should leave the Alpha alone in that case. Otherwise, the result will end up being transparent. -
Poor image quality with DrawBitmap when destination is smaller than source
Anders Melander replied to XylemFlow's topic in FMX
Confirmation bias, most likely. It's a common trap that I find myself in more often than I'd like to admit. Well, I guess I just did 🙂 I doubt it. Unless you're running this on a potato you shouldn't really need the GPU for something as simple as this. Of course, the GPU will be faster but the CPU should be fast enough. Rotation, translation, and scaling can be done in one go with a 3x3 (well, 2x3 actually) affine transformation. You "just" need to find a library that does that (or write it yourself). Graphics32 can do it but it doesn't support FMX. I'm guessing Image32 can too. -
Poor image quality with DrawBitmap when destination is smaller than source
Anders Melander replied to XylemFlow's topic in FMX
I think it's just a bug in their implementation. They appear to be AND'ing the pixels instead or OR'ing them. Even the GDI's COLORONCOLOR or STRETCH_DELETESCAN methods, which are just about the fastest methods there are, with the worst quality, would produce a better result. Possibly, but the examples on that page are cooked to show the result you want; They only really demonstrate the effect of a downsample followed by a cubic upsample followed by a linear downsample (you've let the browser shrink the final bitmap). A fair comparison would be to compare the unscaled, downsampled results. What the results would look like when upsampled again with a cubic resampler is not relevant to the downsample quality. Original Downsampled, box filter Downsampled, linear filter Downsampled, cubic filter -
Change "FadeOut" code to "FadeIn" code
Anders Melander replied to Willicious's topic in Delphi IDE and APIs
Yes. For the "fade in" you need two bitmaps, giving you three color values: 1) the source color (black), 2) the target color (your original bitmap), and 3) the current color (the display bitmap). For the "fade out", the way you've implemented it, you only need one bitmap because the source and the current color are the same (the display bitmap) and the target color value is implicit (black). You can modulate/mix linearly between two colors, ColorFrom and ColorTo, by a value going from 0 to 1 with this formula: Color := ColorFrom * (1 - Value) + ColorTo * Value or in other words: // Value = 0: ColorFrom // Value = 1: ColorTo function ColorModulate(ColorFrom, ColorTo: TColor32Entry; Value: Single): TColor32Entry; begin Result.A := Round(ColorFrom.A * (1 - Value)) + Round(ColorTo.A * Value); Result.R := Round(ColorFrom.R * (1 - Value)) + Round(ColorTo.R * Value); Result.G := Round(ColorFrom.G * (1 - Value)) + Round(ColorTo.G * Value); Result.B := Round(ColorFrom.B * (1 - Value)) + Round(ColorTo.B * Value); end; This can both be used to fade in and fade out. When you're fading to black it follows that you are actually just doing this: // Value = 0: Color // Value = 1: Black function FadeToBlack(Color: TColor32Entry; Value: Single): TColor32Entry; begin Result.A := Round(Color.A * (1 - Value)); Result.R := Round(Color.R * (1 - Value)); Result.G := Round(Color.G * (1 - Value)); Result.B := Round(Color.B * (1 - Value)); end; -
Interesting article: Branchless binary search
Anders Melander replied to Tommi Prami's topic in Algorithms, Data Structures and Class Design
Nice! To bad that there's no chance in hell that the Delphi compiler can compile it branchless. It could be hand-coded in asm but then the call to the comparer can't be inlined, making the whole thing pointless. -
Lightweight Multicast Events
Anders Melander replied to Erik@Grijjy's topic in Tips / Blogs / Tutorials / Videos
Fair enough, but I'm guessing that if you made the consequences of their choice clear to them they might reconsider. Remember to offer more than two choices: The bad choice, the right choice, and the super deluxe, over-the-top, choice. That way they can feel that they have a say in the matter 🙂 -
Lightweight Multicast Events
Anders Melander replied to Erik@Grijjy's topic in Tips / Blogs / Tutorials / Videos
Yeah, but nobody ever asked me to implement the easy solution. For some reason, they all want the hard stuff. -
Lightweight Multicast Events
Anders Melander replied to Erik@Grijjy's topic in Tips / Blogs / Tutorials / Videos
Any classes that need to know what's going on with other classes, state changes, etc. I basically only implement classic events if I have a component that needs design-time event hookup via the object inspector. For everything else, it's notifications via interfaces (i.e. multicast). It has a higher cost up-front in terms of writing the code but down the line, it saves me when inevitably I need more than one notification receiver. @dummzeuch gave a real-world example. Yes, it can be solved in multiple ways. He solved it with a delegate chain (very fragile). You solved it by having the event source not use the event slot, but that still leaves you with a single-cast event. What if you have a form with multiple frames that all need to know when the state changes? With multi-cast you don't need to worry about if you will ever need to have more than one event consumer. With interfaces there's the added benefit of separation and, if you design things for it, no dependencies between the different parts. -
Lightweight Multicast Events
Anders Melander replied to Erik@Grijjy's topic in Tips / Blogs / Tutorials / Videos
The solution seems obvious... Don't use the OnClose event. Have the form broadcast a notification that it is closing and have the frames subscribe to this notification. eAsY. -
Lightweight Multicast Events
Anders Melander replied to Erik@Grijjy's topic in Tips / Blogs / Tutorials / Videos
Are you sure? It's the observer pattern. I use it literally all the time, like daily, but I must admit that even though it would be much easier to implement as delegates, so far I have always implemented it via interfaces: type IMyNotification = interface [...GUID...] procedure MyNotification(...params...); end; TSomeClass = class private FSubscriptions: TList<IMyNotification>; protected procedure Notify(...params...); public destructor Destroy; override; procedure Subscribe(const Subscriber: IMyNotification); procedure Unsubscribe(const Subscriber: IMyNotification); end; destructor TSomeClass.Destroy; begin FSubscriptions.Free; inherited; end; procedure TSomeClass.Notify(...params...); begin if (FSubscriptions <> nil) then for var Subscriber in FSubscriptions do Subscriber.MyNotification(...params...); end; procedure TSomeClass.Subscribe(const Subscriber: IMyNotification); begin if (FSubscriptions = nil) then FSubscriptions := TList<IMyNotification>.Create; FSubscriptions.Add(Subscriber); end; procedure TSomeClass.Unsubscribe(const Subscriber: IMyNotification); begin if (FSubscriptions <> nil) then FSubscriptions.Remove(Subscriber); end; versus type TMyNotification = procedure(...params...); TSomeClass = class private FMyEvent: TDelegate<TMyNotification>; protected procedure Notify(...params...); public property MyEvent: IDelegate<TMyNotification> read GetMyEvent; end; function TSomeClass.GetMyEvent: IDelegate<TMyNotification>; begin Result := FMyEvent; end; procedure TSomeClass.Notify(...params...); begin for var Delegate in FMyEvent do Delegate(...params...); end; -
Lightweight Multicast Events
Anders Melander replied to Erik@Grijjy's topic in Tips / Blogs / Tutorials / Videos
For older versions there's always this one: Multicast Delegates - An amazingly simple and elegant solution and, as far as I can tell, even more versatile. -
No. It shows that there's some problem. It doesn't show that the bug is still there. Btw, I guess it's this one: RSP-27825 (status: Closed, resolution: Fixed, fixed version: 10.4.1). Or they could step on yours. 🙂
-
I don't think it is, but... ...since the TWICImage constructor calls CoCreateInstance you need to have COM initialized before that happens. As you've observed CoInitialize/CoInitializeEx does that. Remember though to check the result of CoInitialize(Ex); It will return an error code (it's not an error as such) if COM has already been initialized (on the calling thread). You should only call CoUninitialize if the call to CoInitialize(Ex) succeeded. If you search here I'm guessing the how and why has been explained many times.
-
Yes, div 2^n is compiled to an arithmetic shift (sar instruction) while shr n is compiled to a logical shift (shr instruction). Even if that would have been possible it wouldn't magically have become faster. The calculation of the index into the table is a (implicit) multiplication too so you would just be trading one integer multiplication for another - and adding a memory access.
-
I wish they would just deprecate AlphaFormat. It's an abomination that was supposed to make it easy to draw a 32-bit TBitmap with alpha. I guess it did that but what it also did was make it almost impossible to do anything beyond the single use case they could think of.
-
What about it? So it used to be shareware. That doesn't mean that it still is. As far as I have been able to determine the author, Graham Knight, has either vanished from the internet or he is the owner of that Github repository.
-
Drag and Drop Component Suite: Outlook embedded images
Anders Melander replied to haentschman's topic in VCL
I suggest you install the components and run the Source Analyzer example. Then you can see exactly what information an Outlook drop contains. I would be very surprised if Outlook didn't offer the image as a file with a name (real or synthesized). -
Only empty, published methods are removed. Are you saying that you manually add published event handlers?
-
Drag and Drop Component Suite: Outlook embedded images
Anders Melander replied to haentschman's topic in VCL
I can't see why not. You haven't stated if your application is the drop source or the drop target, but if you can drop to/from Outlook from/to the desktop, then you can do the same from/to your own application. -
It's always been this way. It would actually annoy me if they spent time fixing this instead of some of the more important stuff. Defeatism, I know.
-
procedure TFormFooBar.FormClick(Sender: TObject); begin end; { this comment prevents FormClick from being automatically removed } procedure TFormFooBar.FormCreate(Sender: TObject); begin // Blah end;
-
Applying hue change to font graphic on the fly
Anders Melander replied to Willicious's topic in Delphi IDE and APIs
Don't sweat it. Take your time. Look at some code and try to understand what it does and how it does it. Don't rush it and eventually, it'll come to you. -
Applying hue change to font graphic on the fly
Anders Melander replied to Willicious's topic in Delphi IDE and APIs
Apart from this line... Result := TColor32(Integer(Result) + (aDiff.RAdj * $10000) + (aDiff.GAdj * $100) + (aDiff.BAdj)); ...it looks ok. The above doesn't take overflow in the individual color components into account so I'm guessing that what's happening is that the overflow causes the alpha to overflow from 255 to 0 (or some very small value). Do this instead: Result := HSVToRGB(H, S, V, TColor32Entry(aBase).A); TColor32Entry(Result).R := Max(255, TColor32Entry(Result).R + aDiff.RAdj); TColor32Entry(Result).G := Max(255, TColor32Entry(Result).G + aDiff.GAdj); TColor32Entry(Result).B := Max(255, TColor32Entry(Result).B + aDiff.BAdj); -
Applying hue change to font graphic on the fly
Anders Melander replied to Willicious's topic in Delphi IDE and APIs
Can you show us what ApplyColorShift looks like?