SDL : blitting on background instead of screen? - c++

Hi i'm working on an SDL/C game , i've made a camera scrolling with a
big background (6000*1024) and (1024*768) screen,
game.screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE );
so if i want to blit something on the screen as a destenation :
apply_surface( xxx, yyy, map.BALL, game.screen, NULL );
it will follow the camera when moving, wich it's not the case for ennemies they should move on the background and not the screen !
so if i blit something on the background as destination i have a problèmeas following,
apply_surface( xxx, yyy, map.BALL, map.background, NULL );
the old images stays on the background when moving as the folowing pictures :

First I have to say that your way of implementing camera scrolling is quite heavy. I would recommend that you would just draw the objects directly to the screen surface taking the camera position into account.
If you want stick with your plan, you should clear your background before redrawing it. This can be done using command SDL_FillRect.
// Replace 101, 102, 103 with the background color you want
SDL_FillRect(map.background, NULL, SDL_MapRGB(map.background->format, 101, 102, 103));

Related

X11 window cuts off bottom 30 pixels of drawing (C++)

This is a homework assignment. Basically, we were given some code and had to run it through Bresenham's line drawing algorithm.
Everything works fine except that the lines are cut off at the bottom (about 30 pixels). The window is big enough, but it just displays white space at the bottom.
(If I make the window 30 pixels higher, all the lines are complete so the algorithm implementation is good.)
window = XCreateSimpleWindow(display, DefaultRootWindow(display), 0,
0, 512, 512, 5, black, white);
gc = XCreateGC(display, window, 0,0);
XClearWindow(display, window);
XMapRaised(display, window);
Am I guessing the error is somewhere in one of these lines?

Draw semitransparently in invisible layered window

My goal is to have a fullscreen overlaying invisible "canvas" on which I can draw using win32's various drawing functions.
The way I am currently attempting it is this:
WNDCLASSA myclass = { 0 };
myclass.lpfnWndProc = WindowProc3;
myclass.hInstance = GetModuleHandle(0);
myclass.lpszClassName = "MyCanvas";
myclass.hbrBackground = CreateSolidBrush(0xFEEDBEEF);
myclass.hCursor = LoadCursor(0, IDC_ARROW);
RegisterClassA(&myclass);
...
HWND wnd = CreateWindowExA(WS_EX_TOPMOST | WS_EX_LAYERED | WS_EX_TRANSPARENT, "MyCanvas", 0, WS_POPUP | WS_VISIBLE, 0, 0, screen_width, screen_height, 0, 0, GetModuleHandle(0), 0);
SetLayeredWindowAttributes(wnd, 0xFEEDBEEF, 0, LWA_COLORKEY);
Although this serves as a canvas, hours of googling later, I am still unable to draw on it semitransparently.
I have added a screenshot of what my program is currently displaying as I am writing this. What I would like to be able to do is, for example, make the black box in the top right corner (drawn with Rectangle) semitransparent so as to reveal the stackoverflow page content below it.
This is a question I found that I was hopeful about, but the resulting text is just a blended combination of the background color ((COLORREF)0xFEEDBEEF) and text color. Other things I have found have either just made the element fully invisible, done nothing at all, or required some library like MFC. I want to only use win32 functions if at all possible, as I would like to be able to achieve the highest FPS possible.
I do not care if this doesn't work on all Windows versions as long as it does on 7 up to 10.
If you only need transparency for a rectangular area where all pixels either have the same transparency (aka alpha) value or are completely transparent, you can use SetLayeredWindowAttributes() with a combination of alpha value and/or color key.
UpdateLayeredWindow() is the way to go if you need to be able to define transparency per-pixel.
For that you have to create memory DC and select a 32bpp bitmap into it. You may use the buffered paint API to ease the task. Raymond Chen has a blog post with a code sample about that.
You can draw into the memory DC, but you can't use most of GDI API for that, because GDI ignores the alpha channel (transparency). I suggest using GDI+ which allows you to specify the alpha values.
After you have completed drawing into the memory DC, you would call UpdateLayeredWindow() and pass that memory DC as the argument for the hdcSrc parameter to make the result visible on screen.
Illustration of possible effects:
SetLayeredWindowAttributes( hwnd, 0, 176, LWA_ALPHA );
SetLayeredWindowAttributes( hwnd, colorkey, 0, LWA_COLORKEY );
SetLayeredWindowAttributes( hwnd, colorkey, 176, LWA_ALPHA|LWA_COLORKEY );
UpdateLayeredWindow( ... )
Note the antialiased edge of the shape and the transparency gradient in the last example. Things like that are only possible with UpdateLayeredWindow().

Explanation of SDL2 windows/surfaces?

I made a short program to test out SDL2, though there are some things I don't understand how they work.
So I have created a window and a surface:
SDL_Window *window = nullptr;
SDL_Surface *windowSurface = nullptr;
Now I have this (the part I don't get):
window = SDL_CreateWindow("Window name", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_SHOWN);
windowSurface = SDL_GetWindowSurface(window);
So the first line: I use the SDL_createWindow() function to create a window called window I assume. The second line, I got no idea whats going on - explanation?
Finally I have this:
SDL_BlitSurface(currentImage, NULL, windowSurface, NULL);
SDL_UpdateWindowSurface(window);
followed by some clean up code to set the pointers back to nullptr and exit the program/destroy windows etc.
The code you have pasted does the following things: Creates a SDL window called "Window name", sets its horizontal and vertical positions to center, sets the window size to 640 x 480 and marks it as shown.
The second line acquires the SDL surface bind to this window.
What this means is: Create Window , actually sets up and openGL window and a GPU texture (the Surface, althou SDL2 has seperate class for Textures), to which it is going to draw. Modifying the surface acquired with GetWindowSurface will modify the pixel on the window you have just created.
Bliting is applying a array of pixel to a target texture, in the meaning : hey i got this image/prerendered frame etc.. and I want to apply it to this surface so i can show it. Blit it.
I hope this is helpful : >
You can find more information for SDL here
Official SDL wiki
LazyFoo
LazyFoo provides a full tutorial and explanations of everything for the old SDL, but a lot of the things are the same in SDL2

SDL2 OpenGL window shrinking and changing mouse coordinates

After shrinking my applications to window size mouse coordinates won't change. Graphics work fine, just mouse coordinates are problem.
My applications native size is 1920x1080. But I wan't to shrink app to 1280x720.
Here is what I'm doing right now:
Create window with 1280x720 w/h
appWindow = SDL_CreateWindow(GAME_TITLE, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1280, 720, SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOWPOS_CENTERED);
I set glViewport to match with window
glViewport(0,0,1280,720);
I make set glOrtho with native size 1920x1080
glOrtho(0, 1920, 1080, 0, -1, 1);
Like I already said, by doing this graphics do scale on new window size but mouse coordinates don't change and i need to know how to change them.
I am not sure i understand your question, but i think here is problem: glOrtho() is opengl comand not sdl, so it affects opengl graphics only. Mouse and windowing is controlled by SDL in your case.
I dont understand what you are trying to do by saying "My applications native size is 1920x1080. But I wan't to shrink app to 1280x720." if you want to resize window use SDL_SetWindowSize. And then adjust opengl viewport and projection with glViewport and glOrtho, so your opengl view and sdl window size is in sync.
Edit 1: If you want to render as it is now, by using larger view than windows, then you need to calculate mouse position by your self. sdl gives you mouse relative to window size not opengl view and projection. Math should be quite simple if you are just scaling the view.
Edit 2: in your case glOrtho(0, 1920, 1080, 0, -1, 1) projects 1920x1080 image to glViewport(0,0, 1280 ,720) view. So it scales down if i am not mistaken. So you need to scale mouse pos down to relative to scale ratio:
untested code:
mouseX= 1920.0/1280.0 * winMouse.x
mouseY= 1080.0/720.0 * winMouse.y;
I ussually experiment alot, so just try to understand what opengl does and experiment.

Painting Text above OpenGL context in MFC

I work on an MFC app containing OpenGL context.I am new to MFC that is why I am asking it.OpenGL works fine ,but when I want to draw a text above the 3D window using this code inside WindowProc:
case WM_PAINT:
hDC=BeginPaint(window,&paintStr);
GetClientRect(window,&aRect);
SetBkMode(hDC,TRANSPARENT);
DrawText(hDC,L"He He I am a text on top of OpenGL",-1,&aRect,DT_SINGLELINE|DT_CENTER|DT_VCENTER);
EndPaint(window,&paintStr);
return 0;
it is shown beneath the OpenGL context.I can see it only when resizing the window as the OpenGL rendering pauses than.
What you're doing is wrong and also harder than doing it all in OpenGL. To solve the problem of adding text to an OpenGL-drawn window, it's better to just make OpenGL draw the text. You can even use the exact same font you were using in MFC by creating a CFont instance when you handle WM_CREATE, selecting the font into the DC, and calling wglUseFontBitmaps, which will make a series of rasterized bitmaps that you can use with glCallLists. (While you're at it, call GetCharABCWidths and GetTextMetrics to determine the width and height of each glyph, respectively.)
ABC glyphInfo[256]; // for font widths
TEXTMETRIC tm; // for font heights
// create a bitmap font
CFont myFont;
myFont.CreateFont(
16, // nHeight
0, // nWidth
0, // nEscapement
0, // nOrientation
FW_NORMAL, // nWeight
FALSE, // bItalic
FALSE, // bUnderline
0, // cStrikeOut
ANSI_CHARSET, // nCharSet
OUT_DEFAULT_PRECIS, // nOutPrecision
CLIP_DEFAULT_PRECIS, // nClipPrecision
DEFAULT_QUALITY, // nQuality
DEFAULT_PITCH | FF_SWISS, // nPitchAndFamily
_T("Arial") // lpszFacename
);
// change the current font in the DC
CDC* pDC = CDC::FromHandle(hdc);
// make the system font the device context's selected font
CFont *pOldFont = (CFont *)pDC->SelectObject (&myFont);
// the display list numbering starts at 1000, an arbitrary choice
wglUseFontBitmaps (hdc, 0, 255, 1000);
VERIFY( GetCharABCWidths (hdc, 0, 255, &glyphInfo[0]) );
pDC->GetTextMetrics(&tm);
if(pOldFont)
pDC->SelectObject(pOldFont);
myFont.DeleteObject();
Then when you handle WM_PAINT, reset your matrices and use glRasterPos2d to put the text where you need it to go. I suggest calculating the exact width of your string using code similar to the one below if you want it to be horizontally centered.
// indicate start of glyph display lists
glListBase (1000);
CRect r;
GetWindowRect(r);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(0, r.Width(), 0, r.Height());
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
CString formattedString;
formattedString.Format("Pi is about %1.2f", 3.1415);
int stringWidth=0; // pixels
for(int j=0; j < formattedString.GetLength(); ++j)
stringWidth += glyphInfo[ formattedString.GetAt(j) ].abcA + glyphInfo[ formattedString.GetAt(j) ].abcB + glyphInfo[ formattedString.GetAt(j) ].abcC;
double textXPosition, textYPosition;
textXPosition = r.Width()/2-stringWidth/2; // horizontally centered
textYPosition = r.Height()/2-tm.tmHeight/2; // vertically centered
glRasterPos2d(textXPosition,textYPosition);
// this is what actually draws the text (as a series of rasterized bitmaps)
glCallLists (formattedString.GetLength(), GL_UNSIGNED_BYTE, (LPCSTR)formattedString);
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
While the setup is annoying, you only have to do it once, and I think it's less frustrating than dealing with GDI. Mixing GDI and OpenGL is really asking for trouble, and OpenGL does a very good job of displaying text -- you get sub-pixel accuracy for free, among other benefits.
Edit: In response to your request for including GUI elements, I will assume that you meant that you want to have both OpenGL-drawn windows and also standard Windows controls (edit boxes, check boxes, buttons, list controls, etc.) inside the same parent window. I will also assume that you intend OpenGL to draw only part of the window, not the background of the window.
Since you said you're using MFC, I suggest that you create a dialog window, add all of your standard Windows controls to it, and then add in a CWnd-derived class where you handle WM_PAINT. Use the resource editor to move the control to where you want it. Effectively, you're making an owner-draw custom control where OpenGL is doing the drawing. So OpenGL will draw that window, and the standard MFC classes (CEdit, CButton, etc.) will draw themselves. This works well in my experience, and it's really not much different from what GDI does in an owner-draw control.
What if instead you want OpenGL to draw the background of the window, and you want standard Windows controls to appear on top of it? I don't think this is a great idea, but you can handle WM_PAINT and WM_ERASE for your CDialog-derived class. In WM_ERASE, call OpenGL to draw your 3D content, which will be overwritten by the standard Windows controls when WM_PAINT is called. Alternatively in WM_PAINT you could call OpenGL before calling CDialog::OnDraw, which would be similar.
Please clarify your statement "I want to add some 2s graphics overlay (like labels ,gui elements)" if you want me to write more.
Looking at your code I assume the OpenGL rendering is called from a timer or as idel loop action. Naturally OpenGL execution will probably contain some clearing, thus taking anything else drawn with it.
Mixing GDI text drawing with OpenGL is not recommended, but can be done. But of course you then need to include that code into the OpenGL drawing function, too, placing all GDI operations after the buffer swap.