Windows API CRect Inverting so works like graph paper - c++

I guess i am old school when it comes to doing graphics (graphs) etc.
My Brain = Bottom/Left is 0,0, Top is Size y, Right is Size x
DC Rect = Top/Left is 0,0, Bottom is Size y, Right is Size x
Hence I find drawing in Windows DC Rect a pain as Y is inverted and I have to flip my brain for each drawing function.
Is there a way to draw in Rect or DC in graph mode and/or flip/mirror it into the Windows dc rect?

You can move the viewport origin anywhere you like. This is done using either SetViewportOrgEx (GDI) or CDC::SetViewportOrg in MFC.
The fundamentals are explained in Microsoft's documentation under Coordinate Spaces and Transformations.
While this moves the viewport origin to an arbitrary position, it doesn't flip the orientation along the y-axis. There are several ways to accomplish that, though the easiest is probably to take advantage of adjustable viewport scaling (ScaleViewportExtEx, or CDC::ScaleViewportExt). The following OnPaint implementation draws a line from (0, 0) to (height, width). With the viewport adjustments in place, this line goes from the bottom left to the top right.
void CSampleDlg::OnPaint()
{
CPaintDC dc{ this };
CRect rc{};
GetClientRect(&rc);
auto const width{ rc.right - rc.left };
auto const height{ rc.bottom - rc.top };
dc.SetMapMode(MM_ANISOTROPIC);
dc.SetViewportOrg(0, height);
dc.ScaleViewportExt(1, 1, -1, 1);
dc.MoveTo(0, 0);
dc.LineTo(width, height);
}

Related

C++ Winapi - How to draw a fill shape rectangle and set the border thickness?

I'm trying to draw a rectangle with a border.
RECT rect;
GetClientRect(hwnd, &rect);
FillRect((HDC)wParam, &rect, CreateSolidBrush(RGB(0,0,0))); //black fill
FrameRect((HDC)wParam, &rect, CreateSolidBrush(RGB(255,0,0))); //red border
The above code works, though I'm not actually sure if that's the proper way to do it.
Anyway, I would like to set the thickness of the border. But I'm having a hard time figuring how. Can anyone can point me in the right direction or much better give a working example?
If GDI+ is allowed then this is how I'll do it
int width = 100; //set the width.
int height = 100; //set the height.
int borderSize = 5; //set border size.
HDC hdc = GetDC(hwnd); //don't forget to release later when done.
Graphics g(hdc);
SolidBrush brush((Color(255, 241, 103, 210))); //Set the fill color.
Pen pen(Color(255,255, 0, 0), borderSize); //Set the border color and border size.
width = width-borderSize; //deduct the border size to width to get the same point we wanted, for border only.
height = height-borderSize; //deduct the border size to height to get the same point we wanted, for border only
g.DrawRectangle(&pen, (borderSize / 2), (borderSize / 2), width, height); //draw the border
g.FillRectangle(&brush, borderSize, borderSize, width-borderSize, height - borderSize); //draw the fill shape, and again deduct the border size to the width and height to get the same point we wanted.
DeleteObject(&brush); //always delete object
DeleteObject(&pen); //always delete object
ReleaseDC(hwnd, hdc); //always release hdc
It's a little tricky, refer to the comments for the explanation.
FrameRect documentation says
The width and height of the border are always one logical unit.
So, one option is to change the mapping between logical units and physical units. If you don't want to mess up subsequent drawing operations, you'll have to save the old mapping and restore it after drawing your rectangle and frame. And the rectangle dimensions will need to change when the mapping changes. What a mess!
A better and simpler option is to stop using FrameRect. Simply use FillRect and the border brush, then DeflateRect to obtain a rectangle representing the interior, and FillRect that rectangle with your fill brush. The parameters to DeflateRect will determine the border thickness.
This doesn't work for creating hollow borders the way that FrameRect does, but for a border on a filled rectangle it is an elegant solution.

Drawing an OpenGL overlay using SwapBuffers interception

I'm trying to make a library that would allow me to draw my overlay on top of the content of a game window that uses OpenGL by intercepting the call to the SwapBuffers function. For interception i use Microsoft Detours.
BOOL WINAPI __SwapBuffers(HDC hDC)
{
HGLRC oldContext = wglGetCurrentContext();
if (!context) // Global variable
{
context = wglCreateContext(hDC);
}
wglMakeCurrent(hDC, context);
// Drawing
glRectf(0.1F, 0.5F, 0.2F, 0.6F);
wglMakeCurrent(hDC, oldContext);
return _SwapBuffers(hDC); // Call the original SwapBuffers
}
This code works, but occasionally, when I move my mouse, my overlay blinks. Why? Some forums have said that such an implementation can significantly reduce FPS. Is there any better alternative? How do I correctly translate a normal position to an OpenGL position? For example, width = 1366. It turns out 1366 = 1, and 0 = -1. How to get the value for example for 738? What about height?
To translate a screen coordinate to normal coordinate you need to know the screen width and screen height, linear mapping from [0, screenwidth] to [-1, 1] / [0, screenheight] to [-1, 1]. It is as simple as follows:
int screenwidth, screenheight;
//...
screenwidth = 1366;
screenheight = 738;
//...
float screenx, screeny;
float x = (screenx/(float)screenwidth)*2-1;
float y = (screeny/(float)screenheight)*2-1;
Problem z=0:
glRect renders to z=0, it is a problem because the plane would be infinitely near. Because opengl considers rendering to world space still. Screen space lies at (x, y, 1) in non transformed world space. OpenGL almost always works with 3D coordinates.
There are two ways to tackle this problem:
You should prefer using functions with a z component, because opengl does not render correctly at z=0. z=1 corresponds to the normalized screen space
or you add a glTranslatef(0,0,1); to get to the normalized screen space
Remember to disable depth testing when rendering 2D on the screen space and resetting the modelview matrix.

How to draw on just a portion of the screen with SpriteBatch in libgdx?

When I do this:
SpriteBatch spriteBatch = new SpriteBatch();
spriteBatch.setProjectionMatrix(new Matrix4().setToOrtho(0, 320, 0, 240, -1, 1));
spriteBatch.begin();
spriteBatch.draw(textureRegion, 0, 0);
spriteBatch.end();
SpriteBatch will draw the textureRegion onto the coordinate system 320-240 that I have specified to the whole screen. Say I want to draw with the same coordinate system 320 240 but only on the left half of the screen (which means everything will be scaled down horizontally in the left side, leaving the right half of the screen black), how can I do?
You're going to want to use the ScissorStack. Effectively, you define a rectangle that you want to draw in. All drawing will be in the rectangle that you defined.
Rectangle scissors = new Rectangle();
Rectangle clipBounds = new Rectangle(x,y,w,h);
ScissorStack.calculateScissors(camera, spriteBatch.getTransformMatrix(), clipBounds, scissors);
ScissorStack.pushScissors(scissors);
spriteBatch.draw(...);
spriteBatch.flush();
ScissorStack.popScissors();
This will limit rendering to within the bounds of the rectangle "clipBounds".
It is also possible push multiple rectangles. Only the pixels of the sprites that are within all of the rectangles will be rendered.
From http://code.google.com/p/libgdx/wiki/GraphicsScissors
Before rendering the batch, you can set the viewport to draw on a specific screen area. The important line is:
Gdx.gl.glViewport(x, y, w, h);
The viewport usually starts at x = 0 and y = 0 and extends to the full width and height of the screen. If we want to see only a part of that original viewport, we need to change both the size and the starting position. To draw only on the left half of the screen, use:
x = 0;
y = 0;
w = Gdx.graphics.getWidth()/2;
h = Gdx.graphics.getWidth();
I found the solution here and originally answered this question to a slightly more complicated problem, but the technique is the same.
To focus on any different portion of the viewport, simply choose x, y, w, and h accordingly. If you're going to do any more rendering in the normal fashion, make sure to reset the viewport with the original x, y, w, and h values.
Perhaps I am misunderstanding the question, but could you not just double the viewport width, setting it to 640 instead of 320?
SpriteBatch spriteBatch = new SpriteBatch;
spriteBatch.setProjectionMatrix(new Matrix4().setToOrtho(0, 640, 0, 240, -1, 1));
spriteBatch.begin();
spriteBatch.draw(textureRegion, 0, 0);
spriteBatch.end();
You could either
double the viewport width of the SpriteBatch
use a Sprite and set its width scale to 0.5f (be careful about the origin) and use its draw(SpriteBatch) method to draw it.

How do we get the border size of a window?

I am drawing a rectangle (in OpenGL) and the corner are based on the cursor position. I modify the pixel position to a float position, but i need the width and height (Which is save somewhere).
So i did some test and on a 1024x512 window, the upper left corner is indeed (0,0) but the bottom corner is (1007,473) or something near.
Now it works ok, but if the window get resize, then it obviously won't work anymore, so here is my question:
How can i get the border size?
That way i think i can subtract it from the window size and get the right position for my cursor to draw the rectangle.
On windows you can use GetWindowRect and GetClientRect
RECT windowRect;
GetWindowRect(hwnd, &windowRect);
RECT clientRect;
GetClientRect(hwnd, &clientRect);
int borderWidth = ((windowRect.right - windowRect.left) - (clientRect.right -clientRect.left))/2;
Though GetClientRect should give you the inner width of the window and that should be enough for you.
int innerWidth = clientRect.right - clientRect.left;

Huge framerate drop when drawing surface on screen

I just started to make another small game in SDL, i made my 2 players - represented by the top half of a circle. So far, i draw a background, and the two players on top.
if (SDL_Init(SDL_INIT_VIDEO) < 0 ) return 1;
if (!(screen = SDL_SetVideoMode(WIDTH, HEIGHT, DEPTH,SDL_HWSURFACE| SDL_DOUBLEBUF)))
{
SDL_Quit();
return 1;
}
SDL_Surface* surface2 = SDL_CreateRGBSurface(SDL_HWSURFACE, WIDTH, HEIGHT, 32,
rmask, gmask, bmask, amask);
SDL_FillRect(surface2, 0, SDL_MapRGBA(surface2->format,0,0xAA,0,0xFF));
//in the while loop
SDL_BlitSurface(surface2,0,screen,0);
When i move the player, it moves 10px per movement. I have implemented smooth movement, with timers, so that is not the case. The intersting part is, that when i choose to leave the surface2 black - without a fillrect at the start, then everything works smooth.
I now fill the screen surface with a color, and it also runs smoothely. So what might be the problem?