Why might the scaling of SetWindowExtEx be just wrong? - windows

I am trying to scale images/text etc using MM_ANISTROPIC and what I've done is the following (by the way if the syntax is a little weird, it's originally from delphi so treat the following as pseudocode)
I would expect the following code to produce a rectangle that is 70% of the width of the PaintBox and 30% of the height, yet it doesn't, instead it it noticeably too small.
SetMapMode(hdc,MM_ANISOTROPIC);
SetWindowExtEx(hdc,100,100,0);
SetViewportExtEx(hdc,70,30,0);
Rectangle(hdc, 0,0,PaintBox.width-1,PaintBox.Height-1);
if, on the other hand I change the code so that the SetWindowExtEx has 91 instead of 100 as its parameters (as shown below) then it works, which makes no sense to me at all...
SetMapMode(hdc,MM_ANISOTROPIC);
SetWindowExtEx(hdc,91,91,0);
SetViewportExtEx(hdc,70,30,0);
Rectangle(hdc, 0,0,PaintBox.width-1,PaintBox.Height-1);
My sanity test case was to add the following pseudocode
SetMapMode(hdc,MM_TEXT);
DrawLine(hdc,Round(PaintBox.width*0.7),0,Round(PaintBox.width*0.7),PaintBox.Height-1);
DrawLine(hdc,0,Round(PaintBox.height*0.3),PaintBox.width-1,Round(PaintBox.height*0.3));
I would have expected this to overwrite the lower / bottom edges of my original Rectangle but it does not unless I uses that 91,91 SetWindowExtEx.
Can anyone duplicate this?
FURTHER EDIT: Here is my exact original code I had given pseudo code before to make the question more accessible to non-delphi users but one of my commenters wanted full code to see if my contention that it was a delphi quirk was true or not.
The entire project consisted of a VCL form with a rectangular paintbox dropped on it centered so there was space all around it, and its onPaint event was set to the code below resulting in this image::
procedure TForm11.PaintBox2Paint(Sender: TObject);
var
hdc:THandle;
res:TPoint;
procedure SetupMapMode;
begin
SetMapMode(hdc,MM_ANISOTROPIC);
SetWindowExtEx(hdc,100,100,0);
SetViewportExtEx(hdc,70,30,0);
// These lines are required when we're painting to a TPaintBox but can't be used
// if we're paiting to a TPanel and they were NOT in my original question but only
// got added as part of the answer
// SetViewportOrgEx(hdc,PaintBox2.Left,PaintBox2.Top,#ZeroPoint);
// SetWindowOrgEx(hdc,0,0,#ZeroPoint);
end;
begin
//draw a rectangle to frame the Paintbox Surface
PaintBox2.Canvas.Pen.Style:=psSolid;
PaintBox2.Canvas.Pen.width:=2;
PaintBox2.Canvas.Pen.Color:=clGreen;
PaintBox2.Canvas.Brush.Style:=bsClear;
PaintBox2.Canvas.Rectangle(0,0,PaintBox2.Width-1,PaintBox2.Height-1);
PaintBox2.Canvas.Brush.Style:=bsSolid;
//initialize convenience variable
hdc:=PaintBox2.Canvas.Handle;
SetTextAlign(hdc,TA_LEFT);
//as doing things to the PaintBox2.Canvas via Delphi's interface tends to reset
//everything, I'm ensuring the map mode gets set **immediately** before
//each drawing call
SetupMapMode;
/// Draw Text at the bottom of the PaintBox2.Canvas (though as it's mapped it
/// SHOULD be 1/3 of the way down and much smaller instead)
TextOut(hdc,200,PaintBox2.Height-PaintBox2.Canvas.TextHeight('Ap'),'Hello, World!',13);
PaintBox2.Canvas.Pen.Color:=clblue;
PaintBox2.Canvas.Brush.Style:=bsClear;
//ensure it's set before doing the rectangle
SetupMapMode;
// Redraw the same rectangle as before but in the mapped mode
Rectangle(hdc, 0,0,PaintBox2.Width-1,PaintBox2.Height-1);
PaintBox2.Canvas.Brush.Style:=bsSolid;
//reset the map mode to normal
SetMapMode(hdc,MM_Text);
//draw text at the "same" position as before but unmapped...
TextOut(hdc,200,PaintBox2.Height-PaintBox2.Canvas.TextHeight('Ap'),'Goodbye, World!',15);
//Draw lines exactly at 70% of the way across and 30% of the way down
//if this works as expected they should overwrite the right and bottom
//borders of the rectangle drawn in the mapped mode
PaintBox2.Canvas.Pen.Color:=RGB(0,255,255);
PaintBox2.Canvas.MoveTo(Round(PaintBox2.Width*0.7),0);
PaintBox2.Canvas.LineTo(Round(PaintBox2.Width*0.7),PaintBox2.Height);
PaintBox2.Canvas.MoveTo(0,Round(PaintBox2.Height*0.3));
PaintBox2.Canvas.LineTo(PaintBox2.Width,Round(PaintBox2.Height*0.3));
end;

Okay, I don't know WHY the following is necessary -- it may be a Delphi quirk, the fact that I'm using a TPaintBox with is a TGraphicControl rather than a Component, or if I'm missing out on some fundamental concept on how this whole mapping mode works, BUT if I add the following code:
ZeroPoint:=TPoint.Zero;
SetViewportOrgEx(hdc,PaintBox1.Left,PaintBox1.Top,#ZeroPoint);
SetWindowOrgEx(hdc,0,0,#ZeroPoint);
Then it all displays as expected. Anyone have any explanations as to why this is necessary?
EDIT: Okay, I've got a PARTIAL explanation. It has to do with the control I was painting on being a TPaintBox, which is a TGraphic control rather than a TWinControl. To wit:
TGraphicControl is the base class for all lightweight controls.
TGraphicControl supports simple lightweight controls that do not need the ability to accept keyboard input or contain other controls. Since lightweight controls do not wrap Windows screen objects, they are faster and user fewer resources than controls based on TWinControl.
As such, although they APPEAR to have a separate canvas, I have this sneaking feeling that they are really sharing the form's canvas which is why, when I switched to a TWinControl descendant, which DOES own its own Windows DC, then the display worked as expected without setting the ViewpointOrg.
So it was a Delphi quirk after all...!

Related

DirectWrite + Direct2D custom text rendering is hairy

I'm evaluating Direct2D for research purposes, and while I was at it, I decided to render my usual help text with a DirectWrite custom text renderer, which converts the text to a path geometry in order to add outline (as demonstrated in the DWriteHelloWorld sample on MSDN).
However, some letters have weird "hairs" or "horns" on them (picture: stroke width of 3 and 5).
Also tried with other fonts (f.e. Consolas), the effect is the same.
Source code (VS 2015):
https://www.dropbox.com/s/v3204h0ww2cp0yk/FOR_STACKOVERFLOW_12.zip?dl=0
The solution is as easy as I hoped. The "hairs" are actually caused by the line joints which D2D generates. Therefore the solution is to create an ID2D1StrokeStyle object as the following:
ID2D1StrokeStyle* strokestyle = nullptr;
D2D1_STROKE_STYLE_PROPERTIES strokeprops = D2D1::StrokeStyleProperties();
strokeprops.lineJoin = D2D1_LINE_JOIN_ROUND;
d2dfactory->CreateStrokeStyle(strokeprops, NULL, 0, &strokestyle);
// draw
rendertarget->DrawGeometry(transformedgeometry, blackbrush, 3.0f, strokestyle);
With this solution, the text is rendered as expected (perhaps a little more roundish at the joints).
I would suspect the reason for that is that default flattening tolerance in D2D does not work well for the purpose of rendering glyph outlines, at small enough sizes. Normally you'd use bitmap rendering for small sizes and outlines for larger ones, according to GetRecommendedRenderingMode(). Do you have same artifacts if you increase font size let's say 10 times?

Winapi How do I draw a rectangle to a specific Window handle?

I'm Using a Wrapper Library in GMS2 That was made back in GM6 Days (gamemaker) Someone was able to wrap majority of the win32API to use in GM6-8. There is only 1 odd instance in where the WinAPI system seems to mess up when drawing the controls to the Main Application Window.
The desired goal is to draw an image to an Child window and draw a grid defining it's splitting according to the user input EX: 16x16 and having the user select squares VIA Mouse Click + Dragging over the boxes.
Unfortunately I have little to no experience in win32API so i'm a bit lost as to where to start.
Looking over the documentation it looks like he left majority of the script names of the DLL to mimic the format of that when calling in C++ or C (just my assumptions).
From His Documentation he has things like "Drawing System" Which Contains things like "Move Item","Add Line","Add Graphic Buffer" etc... and then other Graphic Buffer functions. But then theres the "Draw" functions which has things like "Draw Fill Rect , DrawSelectObj" etc... he doesn't really provide examples so i'm unsure as to how to use these things together to get my desired results. What is the difference between a drawing system and a draw function? Do I have to use them in conjunction, along with the Graphics Buffer?
Can Someone point in the right direction of the necessary steps to get it done? An Example without code and just the function equivalent will suffice, I just need to know out of which functions to use and then later bind it to the Child Window.
An Example Code from his demo is something like this
GbGradient2 = API_GB_Create (105,105); //Graphics Buffer
DcGradient2 = API_GB_GetDC (GbGradient2);
API_Draw_Gradient (DcGradient2,0,0,105,105,0,c_yellow,c_lime);
BrGradient2 = API_Draw_CreatePatternBrush (API_GB_GetBitmap (GbGradient2));
API_Draw_Gradient (DcGradient2,0,0,105,105,0,c_red,65535);
BrGradient3 = API_Draw_CreatePatternBrush (API_GB_GetBitmap (GbGradient2));
hRectangle = API_DS_AddRectangle (2,5,5,105,105); // Adds a rectangle(Drawing System)
hEllipse = API_DS_AddEllipse (2,5,5,105,105);
hNoPen = API_Draw_CreatePen (PS_NULL,0,0);
API_DS_SetItemBrush (hRectangle,BrGradient2); // Sets the brush
API_DS_SetItemBrush (hEllipse,BrGradient3);
API_DS_SetItemPen (hRectangle,hNoPen); // Sets the pen
API_DS_SetItemPen (hEllipse,hNoPen);
API_Draw_Gradient (GbGradient2,0,0,16,16,0,c_yellow,c_lime);
Lookin at it a little more it looks like the draw functions are linked to GDI somehow.
since GMS2 is a cross platform tool , its windows-only functionality gas been removed.
you can make a nice GUI for that porpose by using GMS2 objects , as you have a little Xp
about Win32 API,this will be easier than that big stuffy coding
here are some tips ,
creating a window object with a rectangle sprite
creating ui objects at the create event of above object
adding some code to the global mouse event

Calling TransparentBlt in MASM

I'm trying to make a game in Masm (my teacher said so) and I'm experiencing some problems with the TransparentBlt() function.
I made a base for my game and I was using BitBlt, like this:
invoke SelectObject,memDC,hPerson ;// selecting the Handler of my bitmap
mov hFImage, eax ;// putting the result in hFImage(using in other locals)
invoke BitBlt,hDC,0,0,500,478,memDC,coordX,coordY,SRCCOPY ;// drawing
Where coordX and coordY represents the coordinates os the principal character and the default values(500, 478) are the size of my window.
It's was working really nice, but some day I was searching and I found the TransparentBlt, I was fascinated with it's demonstrating results. Then I tryied to put it on my project and just VUSH! What's going on? My character just disappeared...
invoke SelectObject,memDC,hPerson ;// same
mov hFImage, eax ;// same
RGB_b 0,160,192 ;// it puts the RGB of background on ebx
invoke TransparentBlt,hDC,0,0,500,478,memDC,coordX,coordY, 59, 30, ebx
In case you're wondering, 59 and 30 are the width and height of my bitmap.
Could some one tell me how to use TransparentBlt (more than just MSDN)? I'm really excited with this almost PNG function...
You are probably passing the wrong dimensions.
Conceptually, BitBlt is a very simple function. You can think of it as simply "blitting" (copying) a block of pixels from one device context to another. So, it needs the following parameters:
The source device context
The destination device context
The origin (upper-left corner) of the source rectangle.
The origin (upper-left corner) of the destination rectangle.
The dimensions (width and height).
It also takes a raster-operation code, but you're passing SRCCOPY, which means exactly what I described above: copy a block of pixels from one device context to another. You can do fancier stuff with BitBlt, but we'll ignore that.
The thing to notice here is that BitBlt never does any resizing. The source and destination rectangles can have different origins (i.e., they can start at different coordinates), they they always have the same sizes (i.e., the source and destination always have the same width and height).
If you want to do resizing (stretching or compressing) of the bitmap when you blit it, there is a function that can do that: StretchBlt. StretchBlt is basically just a version of BitBlt that is capable of stretching. It can scale the source image up or down in size, so it takes separate dimensions for the source and the destination.
What does this have to do with TransparentBlt? Well, TransparentBlt also supports resizing. It is basically an extended version of StretchBlt that supports a limited form of transparency.*
So the progression is basically this:
BitBlt is the basic function.
StretchBlt builds on this by adding the ability to resize the source image as it is drawn onto the destination.
TransparentBlt builds on this by adding the ability to make a particular color in the source image transparent as it is drawn onto the destination.
I think this conceptual understanding is important, because it helps you keep straight how the functions should be used.
It also helps answer your question. If you want to use TransparentBlt as a transparent equivalent to BitBlt, then you don't want any stretching, and you therefore need to pass exactly the same dimensions for the source as for the destination.
In other words, call TransparentBlt as follows:
invoke TransparentBlt, hDC, 0, 0, 500, 478, memDC, coordX, coordY, 500, 478, ebx
One final note: you really need to be checking the return values of Windows API functions, otherwise you won't know whether they are failing. Generally, they will return FALSE (== 0) on failure. Sometimes (check the MSDN documentation to see if this is true), the GetLastError function can be called immediately after another function has returned FALSE to get additional information about why the function failed. Your code doesn't check any of the return values, so you have no idea if the functions failed or not, and therefore no good way of knowing where to start debugging.
__
* Technically, everything that you can do with TransparentBlt can be done with StretchBlt using that last parameter, the raster-operation code. And, in fact, this is how it had to be done prior to Windows 98/2000, before the TransparentBlt function existed. And even on Windows 98, you often wanted to do it the old-fashioned way, avoiding TransparentBlt, because TransparentBlt had a leak in it. Now that those days are well behind us, everyone just uses TransparentBlt because it is much simpler.

NSWindow Flip Animation - Like iWork

I'm attempting to implement window-flipping identical to that in iWork -
https://dl.dropbox.com/u/2338382/Window%20Flipping.mov
However, I can't quite seem to find a straightforward way of doing this. Some tutorials suggest sticking snapshot-images of both sides of the window in a bigger, transparent window and animate those. This might work, but seems a bit hacky, and the sample code is always bloated. Some tutorials suggest using private APIs, and since this app may be MAS-bound, I'd like to avoid that.
How should I go about implementing this? Does anyone have any hints?
NSWindow+Flipping
I've rewritten the ancient code linked below into NSWindow+Flipping. You can grab these source files from my misc. Cocoa collection on GitHub, PCSnippets.
You can achieve this using CoreGraphics framework. Take a look at this:
- (void) flipWithDuration: (float) duration forwards: (BOOL) forwards
{
CGSTransitionSpec spec;
CGSTransitionHandle transitionHandle;
CGSConnection cid = CGSDefaultConnection;
spec.type = CGSFlip;
spec.option = 0x80 | (forwards ? 2 : 1);
spec.wid = [self windowNumber];
spec.backColor = nil;
transitionHandle = -1;
CGSNewTransition (cid, &spec, &transitionHandle);
CGSInvokeTransition (cid, transitionHandle, duration);
[[NSRunLoop currentRunLoop] runUntilDate:
[NSDate dateWithTimeIntervalSinceNow: duration]];
CGSReleaseTransition (cid, transitionHandle);
}
You can download sample project: here. More info here.
UPDATE:
Take a look at this project. It's actually what You need.
About this project:
This category on NSWindow allows you to switch one window for
another, using the "flip" animation popularized by Dashboard widgets.
This was a nice excuse to learn something about CoreImage and how to
use it in Cocoa. The demo app shows how to use it. Scroll to the end
to see what's new in this version!
Basically, all you need to do is something like:
[someWindow flipToShowWindow:someOtherWindow forward:YES];
However, this code makes some assumptions: — someWindow (the initial
window) is already visible on-screen. — someOtherWindow (the final
window) is not already visible on-screen. — Both windows can be
resized to the same size, and aren't too large or complicated — the
latter conditions being less important the faster your CPU/video card
is. — The windows won't go away while the animation is running. — The
user won't try to click on the animated window or do something while
the animation is running.
The implementation is quite straightforward. I move the final to the
same position and size as the initial window. I then position a larger
transparent window so it covers that frame. I render both window
contents into CIImages, hide both windows, and start the animation.
Each frame of the animation renders a perspective-distorted image into
the transparent window. When the animation is done, I show the final
window. Some tricks are used to make this faster; the flipping window
is setup only once; the final window is hidden by setting its alpha to
0.0, not by ordering it out and later ordering it back in again, for instance.
The main bottleneck is the CoreImage filter, and the first frame
always takes much longer to render — 4 or 6 times what it takes for
the remaining frames. I suppose this time is spent with setup and
downloading to the video card. So I calculate the time this takes and
draw a second frame at a stage where the rotation begins to show. The
animation begins at this point, but, if those first two frames took
too long, I stretch the duration to make sure that at least 5 more
frames will get rendered. This will happen with slow hardware or large
windows. At the end, I don't render the last frame at all and swap the
final window in instead.

Calculate actual size needed for a MATLAB uicontrol

I'm trying to calculate the actual size needed for uicontrols in a GUI so the GUI can resize itself appropriately. My problem is that the Extent property of a uicontrol is only the text area, and I can't find a way to determine the size of the surrounding control (such as the down arrow in a popup or the margin of an edit control). Is there a way to get the size of the decorations on a control?
I saw this related question on MATLAB Answers, which looked like it ended with no solution as well.
Edit:
For example, I want to calculate how big this popup should be to avoid cutting off the contents:
uicontrol('style', 'popup', 'string', {'a long string'})
Extent only tells me how big "a long string" is, and I still don't know how big to make the popup. I want a way to determine how much extra space is needed on the user's display (without assuming which OS or font sizes they use).
You can use get(hObject,'extent') to find out how much space the string contained in the uicontrol takes up. You can see if this is larger than the uicontrol's position.
The uicontrol Position property gives you the height and width of the bounding rectangle for the control. This has always worked for me. Is there a control where this property does not provide enough information?
If the GUI you're building can be assembled exclusively from Java components, you can use MATLAB's Java integration to create and drive a window using Java Swing components (all from M-code). That sidesteps the problem entirely, since the Java layout managers can do UI layout properly.

Resources