SDL2 OpengGL Anti-aliasing has no effect - c++

I want to draw smooth fill elipse with SDL2.
I have following code
#include <iostream>
#include <SDL2/SDL.h>
#include <SDL2/SDL2_gfxPrimitives.h>
#include <GL/gl.h>
void init()
{
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 2);
glEnable(GL_MULTISAMPLE);
}
int main()
{
SDL_Init(SDL_INIT_EVERYTHING);
init();
SDL_Window* window = SDL_CreateWindow("Anti-aliasing test",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
100, 100,
SDL_WINDOW_RESIZABLE);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
int Buffers, Samples;
SDL_GL_GetAttribute( SDL_GL_MULTISAMPLEBUFFERS, &Buffers );
SDL_GL_GetAttribute( SDL_GL_MULTISAMPLESAMPLES, &Samples );
std::cout << "buf = " << Buffers << ", samples = " << Samples;
std::cout.flush();
SDL_Event e;
int x, y;
while(true)
{
SDL_WaitEvent(&e);
if (e.type == SDL_QUIT)
break;
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderClear(renderer);
SDL_GetWindowSize(window, &x, &y);
filledEllipseRGBA(renderer, x / 2, y / 2, 50, 50, 255, 0, 0, 255);
SDL_RenderPresent(renderer);
}
}
I expected to draw with anti-aliasing, but actually I have no effect from OpenGL.
We can see that my circle don't use alpha channel, which is necessary for AA. But console output is "buffer = 0, samples = 4".
Any idea about how can I activate(of fix) AA in SDL2 (with or without OpenGL).
Next screenshot demonstrate what I have and what I want. Bottom picture drawed in Pinta software.

You are trying to use OpenGL window hints for anti-aliasing but this only works when you create a window with a OpenGL context, which would disable all SDL renderering.
The SDL2/SDL2_gfxPrimitives.h library you are using to draw a filled ellipse has several anti-aliasing functions but not for a filled eclipse, a work around could be to draw a not filled anti-aliased ellipse with a filled eclipse inside everytime you draw an anti-aliased ellipse.
void aafilledEllipseRGBA(...) {
aaellipseRGBA(...);
filledEllipseRGBA(...);
}
or to write your own anti-aliased filled ellipse rendering code. You could base this on the code of the open-source library you are using by peeking at their code here.

Related

Rectangle in sdl2 sets colour for entire screen

I know there are already questions like this on SO but I am new to SDL2 and I have had a look at some tutorials to draw a rectangle and I have had a look at some questions here as well. With the current code below I cannot draw a rectanlge onto the window as it doesn't appear I have also tried to clear the window after the rectangle is meant to be drawn this just sets the entire window to that colour.
#include <iostream>
#include <SDL2\SDL.h>
int main(int argc, char** argv){
SDL_Window* window;
window = SDL_CreateWindow("Test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_SHOWN);
SDL_Renderer* render;
render = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
bool close = false;
SDL_Event event;
while (close == false){
while (SDL_PollEvent(&event)){
if (event.type == SDL_QUIT){
close = true;
}
}
//set colour
SDL_SetRenderDrawColor(render, 255, 0, 0, 255);
SDL_RenderClear(render);
SDL_Rect rect;
rect.x, rect.y, rect.h, rect.w = 50, 50, 50, 50;
SDL_SetRenderDrawColor(render, 0, 0, 255, 255);
SDL_RenderFillRect(render, &rect);
//SDL_RenderClear(render); <-- If this is uncommented it clears the screen to blue.
SDL_RenderPresent(render);
}
SDL_DestroyWindow(window);
SDL_DestroyRenderer(render);
SDL_Quit();
}
This is mean't to draw a blue rectangle onto a red window but I only get the red window and clearing the renderer only set's the window blue. Why does this rectangle not draw? If it is drawing then how come the colour of it ahsnt changed so it doesn't blend in with the background.
I have used these questions to help me get this far:
How to draw a rectangle in SDL 2 and what exactly is a renderer
SDL2 Wont draw Rectangles Correctly
https://dev.to/noah11012/using-sdl2-drawing-rectangles-3hc2
Your issue seems to be with the rect.x, rect.y, rect.h, rect.w = 50, 50, 50, 50;
When I changed it to
rect.x = 50;
rect.y = 50;
rect.h = 50;
rect.w = 50;
The program worked

SDL: How to set size of pixel (stretch) of a window

I'm making a retro pixel game so I want to make my window a very low resolution (256x256). However when I try to make it fullscreen, the whole window was just rendered top left, while leaving all other areas black.
I want to know a way of globally setting the size of each pixel in a window, in order to let it fit the fullscreen, or, a way of stretching the whole window (or a renderer?) to a specified size(and full screen) while having the (w, h) unchanged in parameter 2 and 3 in SDL_CreateWindow, and also whilst having the sizes proportional (so, if it was a square window, it should be a square window after stretched, not a rect after stretched into a rect displayer).
First, render your game to a 256x256 texture. This gist has an example, I will inline it below.
Next, figure out the correct size and position of your game texture on your actual window, and render the texture there. That will require modifications to the SDL_RenderCopyEx call, as the gist simply renders it stretched to the screen.
#include <iostream>
#ifdef __linux__
#include <SDL2/SDL.h>
#elif defined(_WIN32)
#include <SDL.h>
#endif
const int WIN_WIDTH = 640;
const int WIN_HEIGHT = 480;
int main(int argc, char **argv){
if (SDL_Init(SDL_INIT_EVERYTHING) != 0){
std::cerr << "SDL_Init failed: " << SDL_GetError() << "\n";
return 1;
}
SDL_Window *win = SDL_CreateWindow("Rendering to a texture!", SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, WIN_WIDTH, WIN_HEIGHT, 0);
SDL_Renderer *renderer = SDL_CreateRenderer(win, -1,
SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
//Put your own bmp image here
SDL_Surface *bmpSurf = SDL_LoadBMP("../res/image.bmp");
SDL_Texture *bmpTex = SDL_CreateTextureFromSurface(renderer, bmpSurf);
SDL_FreeSurface(bmpSurf);
//Make a target texture to render too
SDL_Texture *texTarget = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888,
SDL_TEXTUREACCESS_TARGET, WIN_WIDTH, WIN_HEIGHT);
//Now render to the texture
SDL_SetRenderTarget(renderer, texTarget);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, bmpTex, NULL, NULL);
//Detach the texture
SDL_SetRenderTarget(renderer, NULL);
//Now render the texture target to our screen, but upside down
SDL_RenderClear(renderer);
SDL_RenderCopyEx(renderer, texTarget, NULL, NULL, 0, NULL, SDL_FLIP_VERTICAL);
SDL_RenderPresent(renderer);
SDL_Delay(1000);
SDL_DestroyTexture(texTarget);
SDL_DestroyTexture(bmpTex);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
}

Change background of SDL2 window?

I can create a SDL2 window but I don't know how to change background color of this window.
My code:
#include "SDL.h"
SDL_Window *window;
void main()
{
window = SDL_CreateWindow("TEST", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_SHOWN);
SDL_Delay(3000);
}
How can I change background color of this window to black?
You should set drawing colour with SDL_SetRenderDrawColor and then use SDL_RenderClear:
(code comes directly from SDL wiki)
int main(int argc, char* argv[])
{
SDL_Window* window;
SDL_Renderer* renderer;
// Initialize SDL.
if (SDL_Init(SDL_INIT_VIDEO) < 0)
return 1;
// Create the window where we will draw.
window = SDL_CreateWindow("SDL_RenderClear",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
512, 512,
0);
// We must call SDL_CreateRenderer in order for draw calls to affect this window.
renderer = SDL_CreateRenderer(window, -1, 0);
// Select the color for drawing. It is set to red here.
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
// Clear the entire screen to our selected color.
SDL_RenderClear(renderer);
// Up until now everything was drawn behind the scenes.
// This will show the new, red contents of the window.
SDL_RenderPresent(renderer);
// Give us time to see the window.
SDL_Delay(5000);
// Always be sure to clean up
SDL_Quit();
return 0;
}
If you do not use SDL2 renderer you can do this:
Just call:
SDL_GL_SwapWindow(window);
After :
SDL_GL_MakeCurrent(window, context);
That's all! Now you have a black screen.
#include <SDL2/SDL.h>
#include <iostream>
using namespace std;
int main(){
int width=512, height=512;
SDL_Window *window=SDL_CreateWindow("Window", SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_RESIZABLE);
if(window==NULL)
cout << "There was an error while initializing the window" << endl << SDL_GetError << endl;
SDL_Event event;
bool running=true;
while(running){
while(SDL_PollEvent(&event)){
if(event.type==SDL_QUIT){
running=false;
break;
}
}
SDL_GetWindowSize(window, &width, &height);
SDL_Surface *surface=SDL_GetWindowSurface(window);
Uint32 skyblue=SDL_MapRGB(surface->format, 65,193,193);
SDL_FillRect(surface, NULL, skyblue);
SDL_UpdateWindowSurface(window);
}
SDL_DestroyWindow(window);
SDL_Quit();
}
Note, none of these solutions work properly with OpenGL. The question was how to init the window with predefined color, not how to paint the first frame. There's still a blink of white color before the first frame is painted.
Try this one :
SDL_Window *wind;
SDL_Surface *windSurface = NULL
void main()
{
wind = SDL_CreateWindow("TEST", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_SHOWN);
windSurface = SDL_GetWindowSurface(wind);
SDL_FillRect(windSurface, NULL, SDL_MapRGB(windSurface->format, 240, 200, 112));
SDL_UpdateWindowSurface(wind);
SDL_Delay(3000);
}

What exactly is a renderer in SDL2?

I dont exactly understand what renderer is. Can I have multiple renderers or is there always just one?
For example, how can I draw a rectangle with a certain color on a background with a different color using a renderer?
I believe the answer lies in the functions SDL_RenderDrawRect() and SDL_RenderFillRect(). Am I right?
I know how surfaces and bliting works but I dont know what exactly the renderer symbolizes.
If someone could show me how to draw a rectangle, I think i will understand how renderers work.
So far I have this:
#include <SDL.h>
int main(int argc, char* argv[]) {
//Initialization
SDL_Init(SDL_INIT_EVERYTHING);
//Window
SDL_Window *MainWindow = SDL_CreateWindow("My Game Window",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
640, 480,
SDL_WINDOW_SHOWN
);
//Renderer
SDL_Renderer *Background = SDL_CreateRenderer(MainWindow, -1, 0);
SDL_SetRenderDrawColor(Background, 255, 255, 255, 255);
SDL_RenderClear(Background);
SDL_Delay(3000);
//Clean up
SDL_DestroyWindow(MainWindow);
SDL_Quit();
return 0;
}
for the first part of your question see this SO question.
as to why your code doesnt do much:
you are correct that you need to use either SDL_RenderDrawRect(), or SDL_RenderFillRect().
SDL_RenderDrawRect will draw an unfilled rectangle. SDL_RenderFillRect will be filled (hopefully that is obvious).
With SDL_renderer you need to call SDL_RenderPresent to copy the "scene" to the screen.
...
//Renderer
SDL_Renderer* renderer = SDL_CreateRenderer(MainWindow, -1, 0);
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderClear(renderer); // fill the scene with white
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); // the rect color (solid red)
SDL_Rect rect(0, 0, 100, 50); // the rectangle
SDL_RenderFillRect(renderer, &rect);
SDL_RenderPresent(renderer); // copy to screen
SDL_Delay(3000);
...

SDL: Fullscreen translucent background

I'm trying to write a program that has a translucent background covering the whole screen. After some research it appeared that SDL would be the way to go.
I've written the code to create a full screen window with a background whose alpha is equal to 100 (out of 255), but for some reason it just draws the solid colour. What have I done wrong?
// Initialise SDL
if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {
this->throwSDLError("SDL_Init Error");
}
// Create the window and renderer
if (SDL_CreateWindowAndRenderer(0, 0, SDL_WINDOW_FULLSCREEN_DESKTOP, &(this->window), &(this->renderer)) != 0) {
this->throwSDLError("Could not create the window and renderer");
}
// Set the blend mode to specify how the alpha channel is used
if (SDL_SetRenderDrawBlendMode(this->renderer, SDL_BLENDMODE_BLEND) != 0) {
this->throwSDLError("Could not set render draw blend mode");
}
// Set the colour to draw
if (SDL_SetRenderDrawColor(this->renderer, 200, 200, 200, 100) != 0) {
this->throwSDLError("Could not set the drawing colour");
}
// Clear the screen using the colour
if (SDL_RenderClear(this->renderer) != 0) {
this->throwSDLError("Could not render the screen");
}
// Present the rendered screen
SDL_RenderPresent(this->renderer);
On Windows, you can create a transparent window by using SetLayeredWindowAttributes to chroma-key the background color from a borderless SDL window.
Code:
// SDL window with transparent background v1.2
#include <SDL.h>
#include <SDL_syswm.h>
#include <Windows.h>
// Makes a window transparent by setting a transparency color.
bool MakeWindowTransparent(SDL_Window* window, COLORREF colorKey) {
// Get window handle (https://stackoverflow.com/a/24118145/3357935)
SDL_SysWMinfo wmInfo;
SDL_VERSION(&wmInfo.version); // Initialize wmInfo
SDL_GetWindowWMInfo(window, &wmInfo);
HWND hWnd = wmInfo.info.win.window;
// Change window type to layered (https://stackoverflow.com/a/3970218/3357935)
SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);
// Set transparency color
return SetLayeredWindowAttributes(hWnd, colorKey, 0, LWA_COLORKEY);
}
int main(int argc, char** argv) {
// Get resolution of primary monitor
int desktopWidth = GetSystemMetrics(SM_CXSCREEN);
int desktopHeight = GetSystemMetrics(SM_CYSCREEN);
SDL_Window* window = SDL_CreateWindow("SDL Transparent Window",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
desktopWidth, desktopHeight, SDL_WINDOW_BORDERLESS);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
// Set background color to magenta and clear screen
SDL_SetRenderDrawColor(renderer, 255, 0, 255, 255);
SDL_RenderClear(renderer);
// Draw blue square in top-left corner
SDL_Rect rect1 = {0, 0, 100, 100};
SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255);
SDL_RenderFillRect(renderer, &rect1);
// Draw red square in center of the screen
SDL_Rect rect2 = {(desktopWidth-100)/2, (desktopHeight-100)/2, 100, 100};
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
SDL_RenderFillRect(renderer, &rect2);
// Add window transparency (Magenta will be see-through)
MakeWindowTransparent(window, RGB(255, 0, 255));
// Render the square to the screen
SDL_RenderPresent(renderer);
// Loop until user quits
bool quit = false;
SDL_Event event;
while (!quit) {
while (SDL_PollEvent(&event) != 0) {
if (event.type == SDL_QUIT) {
quit = true;
}
}
}
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
Result:
Explanation:
First, create a borderless window with that covers the entire desktop. Choose a solid masking color and use it as your background. (In my case, I used magenta). You can then key-out your masking color with the Win32 API function SetLayeredWindowAttributes.
Any part of the window with this color will be completely see-through. Other windows behind your program can be interacted with as normal. By default, other applications can be moved on top of your borderless window.
If you want your SDL window to always be on top of other windows, you can set the SDL_WINDOW_ALWAYS_ON_TOP flag when creating your window.
See Also
Stack Overflow: Creating a transparent window in C++ Win32
Stack Overflow: How detect current screen resolution?
Microsoft: Layered Windows