The MASM Forum Archive 2004 to 2012

General Forums => The Campus => Topic started by: Jimg on May 07, 2007, 04:53:49 PM

Title: Graphics, Coordinate systems, etc. questions
Post by: Jimg on May 07, 2007, 04:53:49 PM
Up to now, I have avoided graphics as much as possible, and if I needed to do anything, I copied it from sample code without understanding what was going on.

I now want to create a custom control, which is going to require understanding what is going on graphically.  I have read for several days but the more I read the more conflicting ideas I get so I thought I would ask some simple questions to get this straightened out.

Is it true that the default logical unit for graphics is the pixel?  It looks like I am going to need to use CreatePen, FillRect, Rectangle, MoveToEx, LineTo, DrawText, BitBlit, etc, and they all say they operate in "logical units".  It looks like the default mapping is MM_TEXT   which is one pixel per count, correct?  Is this the default logical unit?

Assuming I have that correct, what is the correct way to convert from the units that windows are specified in?  GetWindowRect, MoveWindow, etc. are specified in screen coordinates.  I want to draw the stuff in the control, so I need to convert to pixels.  It seems I should be able to get a conversion factor once and store it away somewhere for future use rather than calling some bloated api every time.  Is this a bad idea? What is this api that converts from screen coordinates to pixels?

Almost every sample of graphics code I can find repeatedly creates uses and destroys pens, brushes, fonts, etc.  Is there some reason for all this overhead?  Can I create them once at the start of the program and just use them as needed?  Is there some limit as the the number of brushes and pens I can create at one time?  When I close the program, will windows automatically delete them?  Or do they hang around somewhere in memory forever?  All the graphics api say to use DeleteObject when you are done with them, but Windows seems pretty good at cleaning up after a program.  Likewise, is it really necessary to delete all the objects in a device context before deleting the dc?  And doesn't exiting a program automatically delete any created device contexts?

That's enough for now, I just want to get on the right track from the beginning and not find out a week from now that I have to redo everything:)

Title: Re: Graphics, Coordinate systems, etc. questions
Post by: MichaelW on May 07, 2007, 08:56:38 PM
In answer to the first two questions, this article (http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/dnargdi/html/msdn_mapping.asp) is old, but I think still valid.

"The default mapping mode is MM_TEXT. One logical unit equals one pixel."
Title: Re: Graphics, Coordinate systems, etc. questions
Post by: u on May 07, 2007, 09:47:17 PM
The basics:
A bitmap is a 2D array (width * height). Each element of the array is a pixel. Usually it's 24-bit or 32-bit.
A Device context (DC) is just a small structure, containing handles to a bitmap (to draw on), and to draw with: color-info + handles of: a pen, a font, (and some advanced stuff),
Drawing on a DeviceContext actually means "drawing on the DC's bitmap, using the DC's brush/pen/color".
Drawing is done by setting elements in the array. Blitting is done by copying elements from one array (bitmap) to another.

You don't need to always create DCs, bitmaps and stuff always on WM_PAINT - you can have them as globals. Though, it can complicate things, because once you use SelectObject(), you have to manage the returned object too! And properly return it to its original DC.
So, it's a bit of a hassle ^^". But anyway, imagine if all software kept DCs... that have bitmaps in them... each app would use over 4MB just for that!

Maybe a bright day will come when I finally make my sDraw library more useful in any GUI app ^^" (by adding dynamic allocation...)
Title: Re: Graphics, Coordinate systems, etc. questions
Post by: Jimg on May 07, 2007, 11:31:24 PM
Thank you Michael and Ultrano.

If I'm understanding this properly, then I can do everything in pixels and ignore the other coordinate systems.  The exception being if I wanted to resize the control, for example, the user sends me a message to make it a certain height and or width, then I would have to do mapwindowpoints or some other conversion to get from what the user would normally put in for a width to convert it to pixels.  What units does a user usually expect such a width to be in?

Ultrano-  Since you brought up the next level of complexity -
(and anyone else that want's to answer)
I plan on doing my drawing on a "hidden" bitmap/DC and blitting to the UserControl the user defined.  Is this the correct way, or should I skip the usercontrol completely and blit directly to the parent DC?  It would make sense to me to go straight to the parent, but I'm sure there is some reason not to.
QuoteYou don't need to always create DCs, bitmaps and stuff always on WM_PAINT - you can have them as globals. Though, it can complicate things, because once you use SelectObject(), you have to manage the returned object too! And properly return it to its original DC.
So you are saying, if the DC is destroyed, the objects selected into it still exist and is creating a "memory leak"?
What about creating all the pens and brushes I need at startup and keeping them to use.  Does this use a lot of memory also?

Title: Re: Graphics, Coordinate systems, etc. questions
Post by: u on May 08, 2007, 12:40:49 AM
About the resizing - I don't see any problem... almost all functions take and return width/height/position in pixels. Except for some rarely used API. You'll probably never have to use MapWindowPoints.

The PlatformSDK iirc says/hints that a DC won't be released correctly until you return its original hBitmap, hPen, hBrush and hFont to it. Though, I think that because in Win2k/XP and above, reference-counting is used, we can avoid leaks even if we don't return the original handles to a DC. I haven't inspected this. (ProcessExplorer could help you keep track of # of GDI objects allocated )
One thing is for sure: only hBitmaps can use a lot of memory, the other objects are probably around 100 bytes in size.

Yes, it's good to use a backbuffer. Furthermore, it's absolutely necessary if your window is big. Just don't let DefWindowProc process the WM_ERASEBKGND message, as it will introduce flicker even in back-buffered drawing. Back-buffering is necessary, because at any time of your drawing on the window, the OS can decide to send this intermediate visual result onscreen (the sole reason for flicker).
Title: Re: Graphics, Coordinate systems, etc. questions
Post by: raymond on May 08, 2007, 02:56:48 AM
Another good reason to use a backbuffer is to be able to easily refresh the window whenever it may be moved, resized, minimized and later restored, etc. In most if not all such cases, Windows sends the WM_PAINT message where all you would have to do is BitBlt the backbuffer instead of redrawing everything.

Raymond
Title: Re: Graphics, Coordinate systems, etc. questions
Post by: u on May 08, 2007, 10:40:29 AM
raymond, correction: set the hbrBackground of your window's class to null, and watch Windows actually being smart at keeping already-drawn areas :). This won't work if you've set the CS_HREDRAW/CS_VREDRAW or the hbrBackground.
But in cases when your GUI takes ages to compute , it's good, because during resizing/moving you might get the WM_PAINT msg 100 times per second.
Title: Re: Graphics, Coordinate systems, etc. questions
Post by: Jimg on May 08, 2007, 01:40:46 PM
OK, I'll keep the backbuffer between WM_PAINT messages.

I'll only need to remake the backbuffer if the size of the actual control is increased in width or height.
   (Remake the backbuffer when I receive the WM_SIZE message and it's an increase)
   (Do not set CS_HREDRAW or CS_VREDRAW)

Set hbrBackground for the class to null.

When I get the WM_ERASEBKGND message, ignore it (return non-zero?)

When I get the WM_PAINT message,
    Do a BeginPaint to get the DC
    blit the backbuffer to the DC.
     

Title: Re: Graphics, Coordinate systems, etc. questions
Post by: hutch-- on May 08, 2007, 01:47:21 PM
Jim,

Make the back buffer the size of the screen 1st time so that you don't have to mess around with destroying it then recreating it over and over again. Just size what you draw on the backbuffer to match the client area of your display window and it works fine.
Title: Re: Graphics, Coordinate systems, etc. questions
Post by: u on May 08, 2007, 01:58:02 PM
Quote from: Jimg on May 08, 2007, 01:40:46 PM
When I get the WM_ERASEBKGND message, ignore it (return non-zero?)
Return zero. Actually, either you set the window-class' hbrBackground to null, or you don't let DefWindowProc process WM_ERASEBKGND. Because DefWindowProc returns immediately on that message if hbrBackground is null.

Quote from: Jimg on May 08, 2007, 01:40:46 PM
When I get the WM_PAINT message,
    Do a BeginPaint to get the DC
    blit the backbuffer to the DC.     
Don't forget the EndPaint() too :)


The problem I mentioned with my sDraw lib (that makes GDI drawing much easier and powerful) is that it usually makes a whole 1024x768 bitmap (or of the given screen-size), a DWORD per pixel... and keeps that 4MB buffer all the time. So, it's not rather elegant for small apps. Though, you can create a 400x100 bitmap if you'll be using just that much space - yet, this is not flexible enough.
[same "problem" plagues Hutch's advised method of using GDI]
Title: Re: Graphics, Coordinate systems, etc. questions
Post by: Jimg on May 08, 2007, 02:07:49 PM
Ok, thanks.  One thing I'm worried about is if the user has several instances of my control on his app, I would have to keep several 5+ megabyte backbuffers around (1280*1024*4byte/pixel).  Maybe not too bad for 3 or 4, but if more than that we're talking about a lot of memory.  But it would certainly be easier.
Would it be possible to just create a new backbuffer of the appropriate size and blit the current backbuffer to the new one and just recompute the pixels for the added part rather than the whole thing?  Or is there an api I can't find that lets you resize a bitmap?
Title: Re: Graphics, Coordinate systems, etc. questions
Post by: u on May 08, 2007, 03:03:41 PM
If your Ctl is in static .lib or .dll , you can (will) share the backbuffer for all instances of the control. After all, it's only one thread that draws.
There's no API to resize a bitmap.
Title: Re: Graphics, Coordinate systems, etc. questions
Post by: Jimg on May 08, 2007, 05:01:45 PM
If I only use one backbuffer for all instances of the control, then whenever the the users program does something to change the contents of one of the instances of the control, I would have to recreate the entire contents of the backbuffer.  As always, a compromise between speed and memory and overhead :(
Yes, it will be a static lib.  Each instance will have it's own chunk of the heap to keep track of all it's settings and data, including I was thinking, the handle of it's bitmap.
Title: Re: Graphics, Coordinate systems, etc. questions
Post by: u on May 08, 2007, 05:29:47 PM
Are the graphics in your Ctl very hard to compute/draw? I.e taking 200+ ms. If not, then you needn't keep the precomputed bitmap-data into your backbuffer.
Actually, what is your Ctl about?
Title: Re: Graphics, Coordinate systems, etc. questions
Post by: Jimg on May 08, 2007, 07:36:26 PM
Well, ultimately it's going to be graphing control to allow me to drop multiple graphs on a form with many options and types, and update them in realtime. 
For right now, just to learn how to write a control, I'm doing a grid with features I can't find on any existing grids (plus it's nice to be able to add features if and when I want).  I'm trying to gather all the basic information on how to do all this stuff, so even if I don't need to keep the bitmaps now, I thought I would do it just to see how to do the process, and to keep cycles to a minimum.
Title: Re: Graphics, Coordinate systems, etc. questions
Post by: Jimg on May 12, 2007, 06:46:14 PM
Ok, dumb question #436-

I'm confused as to what I am supposed to do when I get a WM_DRAWITEM as opposed to getting a WM_PAINT message.  What parts are supposed to be done where, or can I do it all in one or the other?

I understand I also have to do redrawing on WM_RESIZE.  What other messages require redrawing of some kind?
Title: Re: Graphics, Coordinate systems, etc. questions
Post by: Jimg on May 13, 2007, 05:21:03 PM
So I wrote a simple logger (prtmsg2) to write out the value of every message I get in my lpfnWndProc that handles all the message to my control.
I wrote an app that has one instance of the control and nothing else.
I ran the app to see what message the control was getting.
The lpfnWndProc looks like this-
GridUProc Proc hCtrl:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
inv prtmsg2,uMsg,0 ;   this prints out the message to a log file
mov eax,uMsg
.if eax==WM_CREATE
.elseif eax==WM_DRAWITEM
.elseif eax==WM_PAINT
.elseif eax==WM_ERASEBKGND
.elseif eax==WM_SIZE
.elseif eax==WM_GETDLGCODE
.elseif eax==WM_DESTROY
.elseif eax==WM_SETFOCUS
.elseif eax==WM_VSCROLL
.elseif eax==WM_HSCROLL
.elseif eax==WM_MOUSEWHEEL
.else
Invoke DefWindowProc,hCtrl,uMsg,wParam,lParam
jmp GridURet
.endIf
GridUProcExit:
xor eax,eax
GridURet:
ret

GridUProc EndP

I started the test app and immediately closed it.
This is what I got-
WM_NCCREATE=129
WM_NCCALCSIZE=131
WM_CREATE=1
WM_SIZE=5
WM_MOVE=3
WM_SHOWWINDOW=24
WM_SETFONT=48
WM_GETDLGCODE=135
unknown=1025
WM_GETDLGCODE=135
WM_SETFOCUS=7
WM_PAINT=15
WM_NCPAINT=133
WM_ERASEBKGND=20
WM_PAINT=15
WM_PAINT=15
WM_PAINT=15
WM_PAINT=15
.
.
.
.        over 300 thousand more WM_PAINT messages
.
.
WM_PAINT=15
WM_KILLFOCUS=8
WM_DESTROY=2
WM_NCDESTROY=130

I never saw a WM_DRAWITEM message.
What's with all these paint messages?
edit:  ugly test program upload deleted
Title: Re: Graphics, Coordinate systems, etc. questions
Post by: ramguru on May 13, 2007, 07:32:26 PM
Hi, Jimg
WM_DRAWITEM is only used for sub-classed owner drawn controls. I guess you're writing your grid control from scratch, so everything should be painted during WM_PAINT message. Now regarding a wave of WM_PAINT message, set WS_CLIBSIBLINGS+WS_CLIPCHILDREN to your GridU control and see the difference. Even scintilla should be created using these styles...
Title: Re: Graphics, Coordinate systems, etc. questions
Post by: Jimg on May 14, 2007, 01:20:23 AM
Thanks for the response.
I tried add the style WS_CLIBSIBLINGS+WS_CLIPCHILDREN to the usercontrol in the test program and got the exact same thing.  And even if it had worked, I wouldn't want to count on the user to set these properly.  There is nothing similar to set in the WNDCLASSEX structure, and I don't know where else I could make these settings.
Clearly I still do not have a grasp on all these windows messages.
And I'm rather surprised about WM_DRAWITEM.


Title: Re: Graphics, Coordinate systems, etc. questions
Post by: MichaelW on May 14, 2007, 02:26:37 AM
Quote from: ramguru on May 13, 2007, 07:32:26 PM
Now regarding a wave of WM_PAINT message, set WS_CLIBSIBLINGS+WS_CLIPCHILDREN to your GridU control and see the difference. Even scintilla should be created using these styles...
I'm sure that you meant WS_CLIPSIBLINGS, and thanks for this information. I knew about WS_CLIPCHILDREN, but adding WS_CLIPSIBLINGS cured a problem I had been having with a Scintilla control flashing intermittently when it was resized. I had given up on solving the problem.
Title: Re: Graphics, Coordinate systems, etc. questions
Post by: ramguru on May 14, 2007, 03:45:23 AM
OK maybe it's not related with those styles, it's very unusuall and hard to reproduce. But final investigation shows that the wave of WM_PAINT messages was to do with the same WM_PAINT implementation:
instead of
   .elseif eax==WM_PAINT
write
   .elseif eax==WM_PAINT
      invoke BeginPaint, hCtrl, ADDR pt
      
      invoke EndPaint, hCtrl, ADDR pt
And it's cured
Title: Re: Graphics, Coordinate systems, etc. questions
Post by: Jimg on May 14, 2007, 01:08:16 PM
Excellent.  Thank you very much.

So much to learn.... :boohoo:
Title: Re: Graphics, Coordinate systems, etc. questions
Post by: Jimg on May 23, 2007, 06:12:33 PM
After a great deal of getting other code out of the way, I'm finally at a point where I can start testing some of this graphics stuff.

Before I go to a lot of trouble saving the stuff in every CreateCompatibleDC I create, just so I can put them back before deleting the DC I created, is it possible to just delete the old bitmap, brush, etc when I select a new one into the DC and let the system delete the new selected objects when I do a DeleteDC? I mean, I know I can do it, but memory leaks are such an arcane subject when it come to graphics for me, I thought I had better ask.
Title: Re: Graphics, Coordinate systems, etc. questions
Post by: Tedd on May 23, 2007, 06:31:09 PM
If the brush/pen/bitmap isn't selected into any DC then you can safely delete it. The defaults are usually stock-objects, but you can safely delete these too (it actually has no effect.)
However, anything you create and select into a DC, you should equally select 'out' and delete once you've finished. (DeleteDC may be good and delete its current state objects - on newer windows version - but I wouldn't rely on it.)
Title: Re: Graphics, Coordinate systems, etc. questions
Post by: Jimg on May 23, 2007, 06:42:21 PM
Thank you Tedd-

The only confusing part is  "you should equally select 'out' and delete once you've finished"

How do I select out a bitmap or brush or pen from a DC without selecting a new one into it?  I can't seem to find that API.  Or is this the real and only reason for keeping the originals?  I could see selecting in a stock object for the pen and brush, but what about the bitmap?  Or does it matter?

And what really happens when a program closes.  Surely Windows keeps track of all this stuff and cleans up, no?
Title: Re: Graphics, Coordinate systems, etc. questions
Post by: Jimg on May 23, 2007, 07:19:13 PM
Another confusing part---

I create a bitmap and select it into the DC.

But then I never reference the handle of the bitmap.  All the drawing functions that require handles want the handle of the DC, not the bitmap, right?  Including bitblt?  Do I ever use the handle of the bitmap for anything other than selecting into the DC and deleting the bitmap later?
Title: Re: Graphics, Coordinate systems, etc. questions
Post by: u on May 23, 2007, 07:38:32 PM
Quote from: Jimg on May 23, 2007, 07:19:13 PM
Do I ever use the handle of the bitmap for anything other than selecting into the DC and deleting the bitmap later?
Not really.
Title: Re: Graphics, Coordinate systems, etc. questions
Post by: Tedd on May 23, 2007, 07:48:59 PM
Actually, for bitmaps it's best to delete the DC and then the bitmap (in that order.)
And yeah, that's generally the reason for keeping the old ones (the comments for SelectObject say to select back in what you got out after you're done.) It is a bit of a hassle ::)
Yes, windows 'should' keep track of it, and I think it's generally done, but there were situations in past versions where gdi objects weren't kept track of properely. Just as with file handles, it's more about safety and good practice. (What 'should' happen, and what actually does happen aren't always the same.)
Title: Re: Graphics, Coordinate systems, etc. questions
Post by: Jimg on May 23, 2007, 08:33:05 PM
Ok, let's see if I got all the straight----


.if uMsg==WM_CREATE
    mov eax,hCurGrid  ; handle to the current control
    inv GetDC,eax     ; get the DC of the control
    mov mctrlhDC,eax  ; save the current DC handle forever, it will never change
    inv CreateCompatibleDC,mctrlhDC   ; create a DC compatible with the controls DC
    mov mhDC,eax                      ; save the dc forever, it will never change
   
    inv GetClientRect,hCurGrid,addr tRect       ; get the size needed for the bitmap
    m2m mctrlWidth,tRect.right
    m2m mctrlHeight,tRect.bottom

    inv CreateCompatibleBitmap,mctrlhDC, mctrlWidth, mctrlHeight
    mov mhBmp,eax
    inv SelectObject, mhDC, mhBmp
    mov mhBmpOld,eax    ;  ?? to put back when the program is closing before DeleteDC ???
   
    inv SelectObject,mhDC,mhPen   ; the pen I want
    mov hPenOld,eax
    inv SelectObject,mhDC,mhBrush  ; the brush I want
    mov mhBrushOld,eax

.elseif uMsg==WM_SIZE       ; this shouldn't be happening very often, I hope

    movzx eax,word ptr lParam       ; get the new size of the control to make a new bitmap
    mov mctrlWidth,eax
    movzx eax,word ptr [lParam+2]
    mov mctrlHeight,eax
    inv SelectObject,mhDC,mhBmpOld  ; put the old one back
    inv DeleteObject,mhBmp          ; delete the current one
    inv CreateCompatibleBitmap,mctrlhDC, mctrlWidth, mctrlHeight    ; make a new one of the appropriate size
    mov mhBmp,eax                   ; and associate it with the hidden buffer
    inv SelectObject, mhDC, mhBmp
    mov mhBmpOld,eax

.elseif uMsg==WM_DESTROY
    inv SelectObject,mhDC,mhBmpOld     
    inv SelectObject,mhDC,hPenOld
    inv SelectObject,mhDC,mhBrushOld
    inv DeleteDC,mhDC                       ; should this be DeleteObject instead???
       
    inv DeleteObject,mhPen
    inv DeleteObject,mhBrush
    inv DeleteObject,mhBmp
.endif 
   
;.
;.
;.
    ; in drawing routne  e.g.

    inv DrawText, mhDC, sText, SLen,addr rectClipping, TextAlignment
    inv MoveToEx,mhDC, X1, Y1,addr lpPoint
    inv LineTo,mhDC,X2,Y2
    inv FillRect,mhDC,addr lpRect,mhBrush
    inv DrawFrameControl,mhDC,addr lpRect,DFC_SCROLL,DFCS_SCROLLLEFT
    inv BitBlt,mctrlhDC, X1, Y1, mctrlWidth, mctrlHeight, mhDC, 0, 0, SRCCOPY  ; copy directly to parent screen

Title: Re: Graphics, Coordinate systems, etc. questions
Post by: Tedd on May 24, 2007, 12:13:20 PM
my changes/comments as ;**


.if uMsg==WM_CREATE
    mov eax,hCurGrid  ; handle to the current control
    inv GetDC,eax     ; get the DC of the control
    mov mctrlhDC,eax  ;** you should release a DC you didn't create once you've finished with it - they can change!
    inv CreateCompatibleDC,mctrlhDC   ; create a DC compatible with the controls DC
    mov mhDC,eax                      ; save the dc forever, it will never change
   
    inv GetClientRect,hCurGrid,addr tRect       ; get the size needed for the bitmap
    m2m mctrlWidth,tRect.right
    m2m mctrlHeight,tRect.bottom

    inv CreateCompatibleBitmap,mctrlhDC, mctrlWidth, mctrlHeight
    mov mhBmp,eax
    inv SelectObject, mhDC, mhBmp
    ;** there isn't initially a bitmap associated with a DC, not that it ever 'owns' a bitmap anyway
    ;** it just uses it to size itself (which is why it's your responsibility to delete it)
    ;mov mhBmpOld,eax    ;  ?? to put back when the program is closing before DeleteDC ???

    inv ReleaseDC, hCurGrid,mctrlhDC   ;** release that DC
   
    ;** if 'mhPen' and 'mhBrush' are stock objects then you don't need to worry about saving the old ones
    ;** (or deleting them) - otherwise, yes, you do
    inv SelectObject,mhDC,mhPen   ; the pen I want
    mov hPenOld,eax
    inv SelectObject,mhDC,mhBrush  ; the brush I want
    mov mhBrushOld,eax

.elseif uMsg==WM_SIZE       ; this shouldn't be happening very often, I hope

    ;** this happens first when your window is shown (after wm_create)
    ;** might be a better opportunity for creating the bitmap?
    ;** (deleting the 'old' inital one, when there wasn't one, shouldn't do any harm)

    mov eax,lParam  ;**
    mov edx,eax     ;**
    and eax,0ffffh  ;** width
    shr edx,16      ;** height
    ;movzx eax,word ptr lParam       ; get the new size of the control to make a new bitmap
    mov mctrlWidth,eax
    ;movzx eax,word ptr [lParam+2]
    mov mctrlHeight,edx ;*

    ;** seems like a long way to do it - create the new one, select it in, then delete the old one that's returned
    ;inv SelectObject,mhDC,mhBmpOld  ; put the old one back
    ;inv DeleteObject,mhBmp          ; delete the current one
    inv GetDC,hCurGrid  ;**
    mov mctrlhDC,eax    ;**
    inv CreateCompatibleBitmap, mctrlhDC,mctrlWidth,mctrlHeight    ; make a new one of the appropriate size
    mov mhBmp,eax
    inv SelectObject, mhDC, mhBmp    ; and associate it with the hidden buffer
    ;mov mhBmpOld,eax
    invoke DeleteObject, eax    ;** delete the old bitmap (as returned from selecting the new one in)

    inv ReleaseDC, hCurGrid,mctrlhDC     ;**

.elseif uMsg==WM_DESTROY
    ;inv SelectObject,mhDC,mhBmpOld     ;** no need (and we don't have it)
    inv SelectObject,mhDC,hPenOld
    inv SelectObject,mhDC,mhBrushOld
    inv DeleteDC,mhDC                       ; should this be DeleteObject instead??? ** no, DeleteDC is right **
       
    inv DeleteObject,mhPen
    inv DeleteObject,mhBrush
    inv DeleteObject,mhBmp
.endif
   
;.
;.
;.
    ; in drawing routne  e.g.

    inv DrawText, mhDC, sText, SLen,addr rectClipping, TextAlignment
    inv MoveToEx,mhDC, X1, Y1,addr lpPoint
    inv LineTo,mhDC,X2,Y2
    inv FillRect,mhDC,addr lpRect,mhBrush
    inv DrawFrameControl,mhDC,addr lpRect,DFC_SCROLL,DFCS_SCROLLLEFT
    ;** it's our good friend GetDC again ;)
    ;** unless this is in wm_paint, and then BeginPaint returns the correct one anyway
    ;** (either way, you shouldn't be using mctrlhDC)
    inv BitBlt,mctrlhDC, X1, Y1, mctrlWidth, mctrlHeight, mhDC, 0, 0, SRCCOPY  ; copy directly to parent screen
Title: Re: Graphics, Coordinate systems, etc. questions
Post by: Jimg on May 24, 2007, 02:55:09 PM
Thank you for your time and patience, Tedd, that helped a lot.


"mov mctrlhDC,eax  ;** you should release a DC you didn't create once you've finished with it - they can change!"

Well, I certainly misread that one.  The first line of the description of GetDC says -
"The GetDC function retrieves a handle of a display device context (DC) for the client area of the specified window."
Which I took to mean I was just getting the handle of THE existing DC, not creating one.
So, can I create one CompatibleDC that will be valid throughout the lifetime of the control, or is this compatibility going to change also?

"
    mov eax,lParam  ;**
    mov edx,eax     ;**
    and eax,0ffffh  ;** width
    shr edx,16      ;** height
    ;movzx eax,word ptr lParam       ; get the new size of the control to make a new bitmap
    mov mctrlWidth,eax
    ;movzx eax,word ptr [lParam+2]
    mov mctrlHeight,edx ;**
"
Gee, when I realized I could access these word values directly this way, I thought it was really "neat".


"    ;** seems like a long way to do it - create the new one, select it in, then delete the old one that's returned"
yeah, I was just trying to avoid having both in existence at once.


Got it for the bitblt-
        inv GetDC,hCurGrid     ; get the DC of the control
        mov mctrlhDC,eax       ; get temp handle to control
        inv BitBlt,mctrlhDC, X1, Y1, eax, edx, mhDC, X1, Y1, SRCCOPY  ; copy directly to parent screen
          inv ReleaseDC,hCurGrid,mctrlhDC

Anyway, once I see that the handle to the control dc is transitory, everything else is obvious.  Thanks again Tedd--



Title: Re: Graphics, Coordinate systems, etc. questions
Post by: Tedd on May 24, 2007, 03:20:41 PM
Quote from: Jimg on May 24, 2007, 02:55:09 PM
Thank you for your time and patience, Tedd, that helped a lot.
No problem, that's what we're here for :bg

Quote
"mov mctrlhDC,eax  ;** you should release a DC you didn't create once you've finished with it - they can change!"

Well, I certainly misread that one.  The first line of the description of GetDC says -
"The GetDC function retrieves a handle of a display device context (DC) for the client area of the specified window."
Which I took to mean I was just getting the handle of THE existing DC, not creating one.
So, can I create one CompatibleDC that will be valid throughout the lifetime of the control, or is this compatibility going to change also?
Nooo, you had it right - GetDC does return the DC of the window you asked for. "you should release a DC you didn't create, once you've finished with it"
But the point is: it's not your DC, you don't have control of it, so you shouldn't assume anything about it - including how long it will last, and therefore how long you can hold onto it. So you should release it once you're finished with it (because it's not yours to 'keep.') Window DCs do appear to change for some reason, probably as part of the GDI managing its resources.
On the other hand, the Compatible-DC that you actually create is yours to do with as you wish (it's a 'memory DC' not a 'window DC') - keep it as long as you like (the 'compatible' part just means it has the same colour-depth and attributes as the other one, but apart from that you don't really need the other one.) So yes, you create your own DC (that's compatible with that window's one - so it looks okay when you bitblt to it) and just keep it as a block of memory, until you throw it away at the end of your program.

Quote
"    mov eax,lParam  ;**
    mov edx,eax     ;**
    and eax,0ffffh  ;** width
    shr edx,16      ;** height
    ;movzx eax,word ptr lParam       ; get the new size of the control to make a new bitmap
    mov mctrlWidth,eax
    ;movzx eax,word ptr [lParam+2]
    mov mctrlHeight,edx ;**
"
Gee, when I realized I could access these word values directly this way, I thought it was really "neat".
Well yes, it is :wink But a 32-bit machine treats 16-bit operations as awkward - it actually has to get the dword twice and then mask off the bits you don't want (behind the scenes) - so it's best to just get the whole thing in one go and separate them yourself.
Title: Re: Graphics, Coordinate systems, etc. questions
Post by: Jimg on May 24, 2007, 10:29:31 PM
QuoteBut a 32-bit machine treats 16-bit operations as awkward - it actually has to get the dword twice and then mask off the bits you don't want (behind the scenes) - so it's best to just get the whole thing in one go and separate them yourself.
Yeah, 4 and a half times slower on my computer---

And I'm amazed at how much faster it is to use fillrect with a brush rather than drawing with a pen.  And using fillrect, you don't need to keep doing selectobjects.  So if you only need simple vertical or horizontal lines like I do, it's much better to use fillrect!



[attachment deleted by admin]