Jump to content

Anders Melander

Members
  • Content Count

    2312
  • Joined

  • Last visited

  • Days Won

    119

Everything posted by Anders Melander

  1. You're right. I need to flush my long term memory of obsolete information 🙂. In Delphi 5 the tread was started immediately in the TThread constructor. Since Delphi 6 it is started in AfterConstruction.
  2. Create the thread suspended and then start it once the constructor returns. It is generally a bad idea to construct a thread with CreateSuspended=False. I.e. instead of: constructor TEventChannel.TEvtLoadThread.Create(parent: TEventChannel); begin fParent := parent; inherited Create(False); end; do this: constructor TEventChannel.TEvtLoadThread.Create(parent: TEventChannel); begin inherited Create(True); fParent := parent; end; ... TheThread := TEvtLoadThread.Create(Something); TheThread.Start; ...
  3. Anders Melander

    Parnassus Bookmarks for Delphi 11 Alexandria?

    I've heard that it's a special integration operation and that everything is going according to plan. Nothing to see here. Move along.
  4. Anders Melander

    Set focus on dialog box button

    Replace this: if fChooseResult.showModal=mrOK then did:=dm.qStockNum.fieldbyname('design_id').asstring; with: if fChooseResult.Execute then did := dm.qStockNum.FieldByName('design_id').AsString; and then modify the TfChooseResult form like this: const MSG_AFTERSHOW = WM_USER; type TfChooseResult = class(TForm) ... protected procedure MsgAfterShow(var Msg: TMessage); message MSG_AFTERSHOW; public function Execute: boolean; end; implementation {$R *.dfm} procedure TfChooseResult.MsgAfterShow(var Msg: TMessage); begin BitBtn1.SetFocus; end; function TfChooseResult.Execute: boolean; begin PostMessage(Handle, MSG_AFTERSHOW, 0, 0); Result := (ShowModal = mrOK); end; Edit: Maybe I should explain what's going on. The PostMessage puts a custom message into the form's message queue. When ShowModal is called the form is displayed and the modal loop pumps the message queue [*]. The message pump grabs the custom message from the queue and calls the form's message handler (the MsgAfterShow method). MsgAfterShow focuses the button. [*] Pumping the message queue means that the code loops, reading one message at a time from the message queue and dispatching these messages to the "message handlers". It's "a bit" more complicated than that but hopefully you get the overall picture.
  5. Anders Melander

    Set focus on dialog box button

    Yes You can use Search->Find in files (Ctrl+Shift+F) to locate the place. Search for " fChooseResult .Show". No problem. Happy to help.
  6. Anders Melander

    Set focus on dialog box button

    @Pat Foley That example was really confusing - and contains so many bad practices.
  7. Anders Melander

    Set focus on dialog box button

    By the way, do yourself a favor and stop using TBitBtn. They were cute in the nineties. Not anymore.
  8. Anders Melander

    Set focus on dialog box button

    Nope. He's not calling the event handler. He's calling the Click method on the button - which emulates a click on the button.
  9. Anders Melander

    Set focus on dialog box button

    Assuming that you're showing this form modally from somewhere else I would do it like this: type TfChooseResult = class(TForm) wwDBGrid1: TwwDBGrid; Panel1: TPanel; dsResult: TDataSource; BitBtn1: TBitBtn; BitBtn2: TBitBtn; procedure wwDBGrid1DblClick(Sender: TObject); private public function Execute: boolean; end; var fChooseResult: TfChooseResult; implementation {$R *.dfm} procedure TfChooseResult.wwDBGrid1DblClick(Sender: TObject); begin BitBtn1.click; end; function TfChooseResult.Execute: boolean; begin BitBtn1.SetFocus; Result := (ShowModal = mrOK); end; and then display the form like this: begin ...do other stuff here... if (fChooseResult.Execute) then begin // User pressed OK end else begin // User closed dialog some other way end; end; And like Peter suggested, set the ModalResult property of the OK button to mrOK and the Default property of the same to True. If you add a Cancel button, set its ModalResult property to mrCancel and the Cancel property to True. If you're not displaying the form modally, then you'll need to call SetFocus in the forms OnShow event handler instead. This of course assumes that the form isn't visible all the time.
  10. Anders Melander

    Set focus on dialog box button

    Set it in code: ButtonOK.SetFocus; The ActiveControl property is a property of the form but that is only applied when the form is first created and it sounds like you are only doing that once.
  11. Anders Melander

    FireDAC, New OLE DB Driver, and SQL Server

    Um... you aren't using ODBC data sources via FireDAC, are you? ODBC is just the API FireDAC uses to talk to the driver. From your perspective there's nothing ODBC about it - the API could be anything. Maybe they did 🙂 We've just completed replacing MSSQL via ADO with FireDAC and for us it works fine. We had to update the client library to a newer version on a couple of clients but apart from that it's faster, better. I think the oldest SQL server version we connect to is 2014/v12.
  12. Anders Melander

    palette for 8 bit greyscale bitmap

    What you're dealing with is an unavavoidable rounding problem and a misunderstanding of what's going on mathematically. The two versions are equally bad. They just distribute the rounding error differently. You want the first palette entry to have a grey-level value of 0 and the last one to have a value of 255 - not 256. Level = 255 * (Index / (Levels-1)) or Grey := i * 255 div (_NumColors-1)
  13. Anders Melander

    Google WebP Image Format

    https://letmegooglethat.com/?q=delphi+webp Seems Bing has hijacked that service so here's a link without the sarcasm: https://www.google.com/search?q=delphi+webp
  14. Anders Melander

    Parallel Resampling of (VCL-) Bitmaps

    I had to reread the source 3 times before I spotted the place it occurs. "with" strikes again: ClusterWeight := ClusterX[X].Weight; with HorzBuffer[ClusterX[X].Pos - MapXLoPos] do begin Inc(Cb, B * ClusterWeight); // Note: Fixed precision multiplication done here Inc(Cg, G * ClusterWeight); Inc(Cr, R * ClusterWeight); Inc(Ca, A * ClusterWeight); end; As you can see I have now added a comment to make it obvious 🙂 Anyway, your changes has now been committed. Please verify that the comments I've added in the source are correct. I will continue working on correcting the alpha handling (i.e. do premultiplication).
  15. Anders Melander

    Parallel Resampling of (VCL-) Bitmaps

    Yes, you're right. I understand the midpoint rule but I just can't make your code fit it. Let me have a look again... Ah, now I get it. It was your comments that confused me. For example: // old weight: Filter(x0*Oldscale)*Oldscale If I just read the code and ignore the comments it makes much more sense. That's a new one 🙂 I mean that when you operate on 32-bit integer values which has been multiplied by $800 (= 1 shl 11) it means that the upper 21 bits will contain the integer part and the lower 11 bits the fractional part. In other words [21:11] fixed precision. When applying the weight values you do a shr 22 (= $800*$800) to convert from [10:22] fixed precision back to integer. The [10:22] must mean that you have multiplied two [21:11] values at some point but I can't really spot where that happens. FWIW much of Graphics32 supports the TFixed [16:16] fixed precision type. For example many methods allow you to specify coordinates in either integer, TFixed or floating point format. I don't understand what this refers to.
  16. Anders Melander

    Parallel Resampling of (VCL-) Bitmaps

    Duh! Yes of course. I've just checked and the value was correct in my original resampler source so it appears to be a copy/paste bug introduced when the code was integrated in GR32. As far as I can tell the bug has been there from the start 😕 Regarding this: x0 := J - Center; // old weight: Filter(x0*Oldscale)*Oldscale x1 := max(x0 - 0.5, -FilterWidth); x2 := min(x0 + 0.5, FilterWidth); // intersect symmetric interval of length 1 about x0 with support of scaled filter x3 := 0.5 * (x2 + x1); // new center Weight := Round(Prec * Filter(x3 * OldScale) * OldScale * (x2 - x1)); // intersection with support entered into the weight You say that you're "computing the integral for the convolution with the filter using the midpoint-rule" so I would have expected to see the averaging of two filter values in order to find the midpoint but I can't really match that with the above. Can you explain what's going on, please? Once I understand it I'll comment the code so it's maintainable. Also, am I correct in assuming that you're doing calculation in [21:11] fixed precision and storing the weights in [10:22] instead of the old [24:8] and [16:16]?
  17. Anders Melander

    Parallel Resampling of (VCL-) Bitmaps

    Very, very nice. The performance has suffered a bit but the result is much better. It actually seems that the quality of the Graphics32 resampler now surpasses your original algorithm for most kernels (there's still artifacts with the GR32 box filter). I've integrated your changes locally and will commit once I've done a bit more testing. One thing that almost gave me brain cancer was the abysmal ASM generated by this code (not your fault): C.B := min((max(Cb, 0) + $1FFFFF) shr 22, 255) It goes something like this cmp dword ptr [Cb],$00 jle A mov eax,[Cb] jmp B A: xor eax,eax B: lea edx,[eax+$001fffff] shr edx,$16 cmp edx,$000000ff jnl C add eax,$001fffff shr eax,$16 jmp D C: mov eax,$000000ff D: mov [C.B],al Luckily the path with that code isn't taken in your example.
  18. Anders Melander

    Parallel Resampling of (VCL-) Bitmaps

    Take a bath. Always works for me 🙂
  19. Anders Melander

    Parallel Resampling of (VCL-) Bitmaps

    I was surprised that this was necessary at all as I really thought that the compiler already made this optimization. Anyway, basically a "for" loop like this (the loop value isn't used inside the loop): for i := LowValue to HighValue do begin ..stuff here end; is compiled to this pseudo code: var i := LowValue; var test := HighValue - i; if (test = 0) then goto end_loop; :start_loop ..stuff here Inc(i); var test := HighValue - i; if (test <> 0) then goto start_loop; :end_loop while this equivalent while loop: i := HighValue - LowValue; while (i >= 0) do begin ..stuff here Dec(i); end; is compiled to: var i := HighValue - LowValue; if (test = 0) then goto end_loop; :start_loop ..stuff here Dec(i); if (test <> 0) then goto start_loop; :end_loop Exact same code if iterating from zero in case you wondered. Similarly a for loop where the loop variable is used inside the loop is also slightly faster when implemented as a while loop.
  20. Anders Melander

    Parallel Resampling of (VCL-) Bitmaps

    I've now merged your changes into the main Graphics32 branch. In addition I also included the following (very minor) optimizations of the Resample() function: Replaced for loops with while loops where possible. The channels are processed in their physical order: B, G, R, A instead of R, G, B, A. I've replaced the RGB bit-twiddling with regular record field access (32-bit compiler only). For example instead of: with BufferEntry^ do begin B := Integer(SourceColor.ARGB and $000000FF) * ClusterWeight; G := Integer(SourceColor.ARGB and $0000FF00) shr 8 * ClusterWeight; R := Integer(SourceColor.ARGB and $00FF0000) shr 16 * ClusterWeight; A := Integer(SourceColor.ARGB shr 24) * ClusterWeight; end; I now do this: BufferEntry.B := SourceColor.B * ClusterWeight; BufferEntry.G := SourceColor.G * ClusterWeight; BufferEntry.R := SourceColor.R * ClusterWeight; BufferEntry.A := SourceColor.A * ClusterWeight; I'm pretty sure the old method used to be faster but apparently not anymore. Maybe the compiler has gotten better or maybe it's the hardware (I have a pretty old CPU so I doubt it's that). I have only profiled the changes with optimization enabled so it's possible that I've made the unoptimized code slower. With optimization enabled, the performance of Resample() now matches, and in some cases even exceed, your algorithm. However since yours is also alpha-aware I still consider yours faster. There are a few additional things that could be done to make the code faster but I'm not really inclined to go there as it would also make it pretty unreadable. The performance of Resample() with the 64-bit compiler is horrible. For some reason your code is much faster there. I've not done anything to improve that.
  21. Anders Melander

    Parallel Resampling of (VCL-) Bitmaps

    That's excellent. I'm a bit surprised about the presence of the XY iteration order problem as that's a bit of a rookie mistake. It probably wasn't caught because the outer loop does iterate Y (and then iterates XY in the inner). Anyway, good catch. Would you mind either creating a pull request or posting a patched version of GR32_Resamplers.pas (without the reformat as that makes it hard to spot the actual changes - not that I disagree about the need to reformat). Your algorithm seems to be consistently 5-15% faster than GR32 on my system (tested with your latest changes). The quality is almost identical. For some kernels yours is marginally better, for some GR32 is marginally better. For the box filter GR32 wins in quality of details, but loses on fidelity (artifacts). WIC wins on both quality and speed. I think these results are as expected; GR32 is paying the price of the overhead a generalized framework. The quality could probably be improved to match WIC but the question is if it's worth the trouble or if the current quality is "good enough"...? I haven't had time to investigate why the Resample function doesn't use the alpha-aware methods. I'm knee deep in a quantization/dithering extension for GR32. P.S. "const StopWatch: TStopWatch" really should be "var StopWatch: TStopWatch". The only reason it works with const is Delphi doesn't know/care that the methods are modifying the TStopWatch record.
  22. No. It's empty. I don't know who "we" are but there's nothing unsafe about the code you posted. It's just fundamental string handling.
  23. Anders Melander

    Parallel Resampling of (VCL-) Bitmaps

    Apparently the GetSampleX methods are only used when sampling via a rasterizer or a transformation (e.g. rotate/skev/etc).
×