-
Content Count
2771 -
Joined
-
Last visited
-
Days Won
147
Everything posted by Anders Melander
-
MAP2PDB - Profiling with VTune
Anders Melander replied to Anders Melander's topic in Delphi Third-Party
Please elaborate -
MAP2PDB - Profiling with VTune
Anders Melander replied to Anders Melander's topic in Delphi Third-Party
This might help: https://www.intel.com/content/www/us/en/developer/articles/troubleshooting/older-version-product.html Please create an issue at the repository: https://bitbucket.org/anders_melander/map2pdb/issues/new The problem is most likely caused by msdia140.dll; The library VTune uses to read pdb files. You can try replacing the one that VTune installs with an older version. See: -
There are many ways. What have you tried so far?
-
Change "FadeOut" code to "FadeIn" code
Anders Melander replied to Willicious's topic in Delphi IDE and APIs
It doesn't matter. You are still not blending anything. Look, please forget about the alpha and just set it to 255. Even if alpha was somehow involved in what you are doing you are really not ready to deal with that part yet. Yes, but the code you posted does nothing in itself. It may very well be that you removed some parts that actually do something before you posted it, but I'm not a psychic and I can't guess what it originally did. Anyhow, moving on... Yes, it does. You are using the TImage32 control from the Graphics32 library to display the bitmaps. One approach would be to keep a copy of the bitmap you are fading from or to and then construct the bitmap to be displayed from that. However, I think we have by now established that you can't figure out how to do that. So I suggest you simply do this instead: // Set these values somewhere. // For example the place where you create the TImage32. // Make the background black fScreenImg.Color := clBlack; // Have the bitmap blend with the background color fScreenImg.Bitmap.DrawMode := dmBlend; ... // Fade out for var i := 255 downto 0 do begin fScreenImg.Bitmap.MasterAlpha := i; fScreenImg.Update; Sleep(50); end; // Load the new bitmap here fScreenImg.Bitmap.LoadFromFile(...); // or whatever... // Fade in for var i := 0 to 255 do begin fScreenImg.Bitmap.MasterAlpha := i; fScreenImg.Update; Sleep(50); end; -
Change "FadeOut" code to "FadeIn" code
Anders Melander replied to Willicious's topic in Delphi IDE and APIs
You don't need the alpha channel. The alpha is only needed when you later have to blend stuff together and that is not what you are doing. You are just "removing color" until only black is left. You haven't shown how exactly you draw stuff onto the screen so that is hard to answer. Generally, I would say that you need a temporary bitmap since it's dead slow to draw individual pixels one at a time. I don't know what this is supposed to illustrate since it doesn't do anything but once again: TColor32 is a DWORD (4 bytes) which is meant to contain the R, G, B and A channels simultaneously. You seem to think it represents a single channel. -
Poor image quality with DrawBitmap when destination is smaller than source
Anders Melander replied to XylemFlow's topic in FMX
Btw, I don't know if the following is relevant to what you're doing: https://blog.grijjy.com/2021/01/14/shader-programming/ -
Poor image quality with DrawBitmap when destination is smaller than source
Anders Melander replied to XylemFlow's topic in FMX
GDI+ is generally not a fast library... Okay. I guess I'll take your word on that since you've actually tried it and I'm only speculating, but I would really expect a significantly higher FPS (on a "reasonably" sized screen) to be possible without hardware assist. I mean, what did we do before we got access to the GPU? Again, I'm not arguing that the GPU isn't the faster solution. I'm just surprised that it's necessary. Can you remember what bitmap size and resampler type you used when you tried this with Graphics32 (if that was what you used)? Now that I think of it, that was a brain fart on my part; It's OR-ing. I was thinking that since it's dropping black pixels it must be AND-ing but of course, since black isn't a color but rather the absence of color, it's the other way round. It's OR-ing so white $xxFFFFFF is replacing black $xx000000. -
Change "FadeOut" code to "FadeIn" code
Anders Melander replied to Willicious's topic in Delphi IDE and APIs
A, R, G and B are bytes. TColor32 is a dword (i.e. 4 bytes). It can be cast to a TColor32Entry, which is a record containing the 4 ARGB bytes. Value needs to be a "floating point" type. E.g. Single or Double. And the you cannot use Inc() on it. If you want to iterate using an integer value then you need to do a division somewhere so you get a value between 0 and 1 that you can multiply the RGB values with. Like I did here: This doesn't do anything. What did you expect it to do? -
Change "FadeOut" code to "FadeIn" code
Anders Melander replied to Willicious's topic in Delphi IDE and APIs
That's the ColorModulate function; It "fades" from any color to any color. In your case, you would fade each pixel from black to the color of your new image. Or if you absolutely must have a FadeFromBlack function: // Value = 0: Black // Value = 1: Color function FadeFromBlack(Color: TColor32Entry; Value: Single): TColor32Entry; begin Result.A := Color.A; // Probably 255 Result.R := Round(Color.R * Value); Result.G := Round(Color.G * Value); Result.B := Round(Color.B * Value); end; Apply this to each pixel of your "to" bitmap and draw the resulting bitmap on top of whatever you have on the screen. -
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.