Related
im trying to show two different animations made with two functions, one render and two threads.
Im getting different kind of error each time i run the code.
Such as: segmentation default in the refresh function (line SDL_RenderPresent(w1.renderer);) and other strange errors too. Everytime is different.
I know its about using the render in both different threads. But i dont know how to solve this problem.
When i run with just one of the threads everything its ok. But not with the two of them.
I just want to show different graphics playing around the window. (always using sdl2).
Here is my code:
window.h:
class Window
{
public:
SDL_Window *window1;
int background,windowWidth,windowHeight,windowXcoord,windowYcoord;
SDL_Renderer * renderer;
SDL_Renderer * renderer2;
Window();
};
void refresh();
extern Window w1;
window.cpp:
Window w1;
Window::Window()
{
window1=nullptr;
background = 0xffffff;
windowWidth=700; windowHeight=500;
windowXcoord = 650; windowYcoord = 0;
this->window1 =
SDL_CreateWindow("Window",windowXcoord,windowYcoord,
windowWidth,windowHeight, SDL_WINDOW_SHOWN);
this->renderer = SDL_CreateRenderer( this->window1, -1 ,
SDL_RENDERER_ACCELERATED);
SDL_SetRenderDrawColor( this->renderer, 255, 255, 255, 255 );
SDL_RenderClear( this->renderer );
SDL_RenderPresent(this->renderer);
}
// this function is called everytime an object or function want to "refresh" the window.
void refresh(){
// clearing the window
SDL_SetRenderDrawColor( w1.renderer, 255, 255, 255,0 );
SDL_RenderClear( w1.renderer );
// r1, the first Rects object to animate.
SDL_SetRenderDrawColor( w1.renderer,255,0,0,255);
SDL_RenderFillRect( w1.renderer, &r1.rect );
// r2, the second Rects.
SDL_SetRenderDrawColor( w1.renderer,255,0,255,255);
SDL_RenderFillRect( w1.renderer, &r2.rect );
SDL_RenderPresent(w1.renderer);
}
rects.h:
class Rects
{
public:
SDL_Rect rect;
Rects();
};
extern Rects r1, r2;
void moveR1();
void moveR2();
rects.cpp:
Rects::Rects()
{ }
Rects r1,r2;
// moveR1 and moveR2, (just some dumm animations-example)
void moveR1(){
r1.rect.x=400; r1.rect.y=100;
r1.rect.w =40; r1.rect.h =10;
SDL_SetRenderDrawColor( w1.renderer,255,0,0,255);
SDL_RenderFillRect( w1.renderer, &r1.rect );
{
for (int u = 1; u<=5;u++){
r1.rect.x=200; r1.rect.y=100;
r1.rect.w =50; r1.rect.h =50;
refresh();
for (int i = 1; i <=200; i++){
r1.rect.x-=1;
usleep (7000);
refresh();
}
}
}
}
void moveR2(){
r2.rect.x=200; r2.rect.y=100;
r2.rect.w =40; r2.rect.h =10;
SDL_SetRenderDrawColor( w1.renderer,255,255,0,255);
SDL_RenderFillRect( w1.renderer, &r2.rect );
{
for (int u = 1; u<=5;u++){
check
r2.rect.x=200; r2.rect.y=100;
r2.rect.w =50; r2.rect.h =50;
refresh();
for (int i = 1; i <=200; i++){
r2.rect.x+=1; r2.rect.y+=1;
usleep (7000);
refresh();
}
}
}
}
and the main:
int main()
{
thread t1(moveR1);
t1.detach();
thread t2(moveR2);
t2.detach();
// sleep instead of showing a loop.
sleep (10);
return 0;
}
any polite help is welcome, im here to learn.
When i run with just one of the threads everything its ok. But not with the two of them.
According to the documentation for 2D accelerated rendering (also known as SDL_render.h, in other terms the place where SDL_RenderPresent lives):
This API is not designed to be used from multiple threads, see SDL bug #1995 for details.
You won't be able to do that any time soon. By looking at the description of the error, it looks like an UB and the link to the bug gives you all the details probably.
I just want to show different graphics playing around the window.
You don't need to use two threads to do that.
You can just update positions, animations and whatever is needed for your graphics and show them from the same thread. Nothing prevents you from calling the same function (as an example SDL_RenderCopy) more than once before to invoke SDL_RenderPresent.
If you needed a thread per graphic, what about a game with thousands of polygons on video?
// thanks to skypjack, i am able to solve the problem
// HOW TO PRESENT TWO (OR MORE) GRAPHICS WITH SDL_RENDERER WITHOUT USING THREADS.
// The two rectangle animation are just and example.
// It could be whatever we want to show.
// In this case, just two rectangles moving around.
#include <unistd.h>
#include <SDL.h>
using namespace std;
SDL_Window *window1;
int background, windowWidth, windowHeight,windowXcoord,
windowYcoord;
SDL_Rect rectangle1;
SDL_Rect rectangle2;
SDL_Renderer *renderer;
int sequence1;
int sequence2;
void moveRectangle1(), moveRectangle2();
int main()
{
window1=nullptr;
background = 0xffffff;
windowWidth=700; windowHeight=500;
windowXcoord = 650; windowYcoord = 0;
window1 = SDL_CreateWindow("Main
Window",windowXcoord,windowYcoord, windowWidth,windowHeight,
SDL_WINDOW_SHOWN);
renderer = SDL_CreateRenderer( window1, -1 ,
SDL_RENDERER_ACCELERATED);
SDL_SetRenderDrawColor( renderer, 255, 255, 255, 255 );
SDL_RenderClear( renderer );
SDL_RenderPresent(renderer);
rectangle1.x = 100; rectangle1.y = 100; rectangle1.h = 40;
rectangle1.w = 40;
rectangle2.x = 100; rectangle2.y = 100; rectangle2.h = 40;
rectangle2.w = 40;
for (int i = 1;i<500;i++){
SDL_SetRenderDrawColor( renderer, 255, 255, 255,0 );
SDL_RenderClear( renderer );
// chequear return (cerrar programa)
moveRectangle1();
moveRectangle2();
SDL_RenderPresent(renderer);
usleep (12000);
}
return 0;
}
void moveRectangle1(){
sequence1++;
if (sequence1 <= 50){ rectangle1.x++; }
else if (sequence1 <= 100){ rectangle1.x--; }
else { sequence1 = 0; }
SDL_SetRenderDrawColor(renderer,255,0,0,255);
SDL_RenderFillRect(renderer, &rectangle1 );
}
void moveRectangle2(){
sequence2++;
if (sequence2 <= 100){ rectangle2.y++; }
else if (sequence2 <= 200){ rectangle2.y--; }
else { sequence2 = 0; }
SDL_SetRenderDrawColor(renderer,0,200,0,255);
SDL_RenderFillRect( renderer, &rectangle2 );
}
I'm following this tutorial that teaches how to use SDL2 with the final goal of learning C++ in a more fun and interactive way.
For this, I only need to be able to draw lines, polygons and circles.
So, after reading part 1 that explains how to create a window on the screen and part 3 that introduces event handling, I headed torward part 7 and 8 that explain, respectively, how to create a renderer and how to draw a rectangle on the screen. This is the code I've got so far (it isn't exactly the same as the code on the tutorial: I've introduced a struct to pass SDL objects around and removed all the error handling which was confusing):
#include <SDL2/SDL.h>
//screen dimensions costants
#define SCREEN_WIDTH 540
#define SCREEN_HEIGHT 960
//data structure holding the objects needed to create a window and draw on it
struct interface {
SDL_Window * window = NULL;
SDL_Surface * surface = NULL;
SDL_Renderer * renderer = NULL;
};
//function which inits the sdl and creates an interface object
interface init() {
interface screen;
SDL_Init(SDL_INIT_VIDEO);
screen.window = SDL_CreateWindow("", 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
screen.surface = SDL_GetWindowSurface(screen.window);
screen.renderer = SDL_CreateRenderer(screen.window, -1, SDL_RENDERER_ACCELERATED);
return screen;
}
//function to free the memory and close the sdl application
void close(interface screen) {
SDL_DestroyRenderer(screen.renderer);
SDL_DestroyWindow(screen.window);
screen.renderer = NULL;
screen.window = NULL;
SDL_Quit();
}
int main(int argc, char* args[]) {
//start the application
interface screen = init();
//setup for event handling
bool quit = false;
SDL_Event event;
//the shape to render
SDL_Rect fillRect = { SCREEN_WIDTH / 4, SCREEN_HEIGHT / 4, SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2 };
//main loop which first handles events
while (!quit) {
while (SDL_PollEvent(&event) != 0) {
if (event.type == SDL_QUIT)
quit = true;
}
//should draw a red rectangle on the screen
SDL_SetRenderDrawColor(screen.renderer, 0xFF, 0xFF, 0xFF, 0xFF);
SDL_RenderClear(screen.renderer);
SDL_SetRenderDrawColor(screen.renderer, 0xFF, 0x00, 0x00, 0xFF);
SDL_RenderFillRect(screen.renderer, &fillRect);
}
//End the application
close(screen);
return 0;
}
The problem is that, as it is, the program draws nothing to the screen (which remains black), and if I remove the line screen.surface = SDL_GetWindowSurface(screen.window); it also begins lagging a lot in a manner I even find difficult to exit the application.
Note that I'm programming on Android using C4droid and the SDL Plugin for C4droid.
Why is that happening? What am I doing wrong?
EDIT Problem solved by renaming close to end and by including a call to SDL_RenderPresent(screen.renderer); at the end of the main loop. With this setup the screen surface has to be deleted or the program won't draw anything.
Thanks to #keltar and #Wutipong Wongsakuldej for answering the question in the comments
First of all I tested the code in Windows (MSYS2) rather than on Android as I don't have AIDE installed at the moment.
Basically I added 2 lines of code into the main loop :
//main loop which first handles events
while (!quit) {
while (SDL_PollEvent(&event) != 0) {
if (event.type == SDL_QUIT)
quit = true;
}
//should draw a red rectangle on the screen
SDL_SetRenderDrawColor(screen.renderer, 0xFF, 0xFF, 0xFF, 0xFF);
SDL_RenderClear(screen.renderer);
SDL_SetRenderDrawColor(screen.renderer, 0xFF, 0x00, 0x00, 0xFF);
SDL_RenderFillRect(screen.renderer, &fillRect);
/** below lines are added **/
SDL_RenderPresent(screen.renderer);
SDL_Delay(0);
}
SDL_RenderPresent draw whatever you've renderred so far to the screen. This make the output shows up.
SDL_Delay() this is added to give the cpu time back to the os. Without this your app might become unresponsive and the cpu utilization will be 100% (at one core) in some operating system (especially the very old one). I don't know if this is needed in Android or not anyway. Give it a try.
My board game is using a matrix. I created a board using rectangles. gimprimir() takes the matrix and translates it creating different types of rectangles.
I need to insert an image on a part of the screen. This tutorial teaches how to put an image on screen, but not how to load it in a part of the screen. Whenever I try to modify it, I get a segmentation fault. I want to keep it simple. The image format is .bmp.
My code:
bool loadMedia();
void close();
SDL_Texture* loadTexture( std::string path );
SDL_Window* gWindow = NULL;
SDL_Renderer* gRenderer = NULL;
const int SCREEN_WIDTH = 1200;
const int SCREEN_HEIGHT = 680;
int main(int argc, char* args[]){
nodo a;
if( !init() ){
cout << "Failed to initialize!\n" ;
}
else{
if(!loadMedia()){
cout << "Failed to load media!\n";
}
else{
bool quit = false; // flag ciclo principal
SDL_Event e; // variables manejo de eventos
SDL_Event t;
gimprimir(a);
}
}
}
Function gimprimir() prints a board using struct a:
struct nodo {
array<array<int,19>,19> tablero; // Estado tablero
array<int,2> p1,p2; // Posiciones
int d1,d2; // Distancias mínimas
int paredes1;
int paredes2;
} a;
gimprimir() uses empty and filled rectangles:
void gimprimir(nodo aa){
//Clear screen
SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF );
SDL_RenderClear( gRenderer );
int i,j;
for (i=1; i<=17; i++){
if (i%2==1){
for (j=1; j<=17 ; j++){
if (j%2==1){
if (aa.p1[0]==i && aa.p1[1]==j){ // FICHA 1
SDL_Rect fillRect = {(50+SCREEN_WIDTH/11)+(SCREEN_WIDTH/11)*(j-1)/2+34, (SCREEN_HEIGHT/11)+(SCREEN_HEIGHT/11)*(i-1)/2+34, SCREEN_WIDTH/12, SCREEN_HEIGHT/12};
SDL_SetRenderDrawColor( gRenderer, 0xff, 0xcc, 0x66, 0xFF );
SDL_RenderFillRect( gRenderer, &fillRect );
}
else{
if (aa.p2[0]==i && aa.p2[1]==j){ // FICHA 2
SDL_Rect fillRect = {(50+SCREEN_WIDTH/11)+(SCREEN_WIDTH/11)*(j-1)/2+34, (SCREEN_HEIGHT/11)+(SCREEN_HEIGHT/11)*(i-1)/2+34, SCREEN_WIDTH/12, SCREEN_HEIGHT/12};
SDL_SetRenderDrawColor( gRenderer, 0x6E, 0x2C, 0x67, 0xFF );
SDL_RenderFillRect( gRenderer, &fillRect );
}
else{ // CASILLA VACÍA
SDL_Rect fillRect = {(50+SCREEN_WIDTH/11)+(SCREEN_WIDTH/11)*(j-1)/2+34, (SCREEN_HEIGHT/11)+(SCREEN_HEIGHT/11)*(i-1)/2+34, SCREEN_WIDTH/12, SCREEN_HEIGHT/12};
SDL_SetRenderDrawColor( gRenderer, 0x8B, 0x45, 0x13, 0xFF);
SDL_RenderFillRect( gRenderer, &fillRect );
}
}
}
}
}
}
SDL_RenderPresent( gRenderer );
}
loadMedia():
bool loadMedia()
{
//Loading success flag
bool success = true;
//Nothing to load
return success;
}
I want to have both on screen. To load the image to be left in a part of the screen forever and then update the rectangles generated with gimprimir().
SDL_BlitSurface is the SDL function used to blit (copy) from a surface to another, it takes two SDL_Rect arguments, srcrect for source and dstrect for destination.
SDL_BlitSurface isn't changed much from SDL1.2 to SDL2, so, old examples which use it should still work.
In the getting_an_image_on_the_screen example you propose a NULL pointer is used for both src and dst rect, a NULL rect mean copy the whole src surface into the destination at top, left = 0, 0 with a maximum size equal to the destination size (if the source is bigger should be cropped).
To blit a partial image just specify src and dst rect:
SDL_Rect srcrect = { 0, 0, 100, 100 };
SDL_Rect dstrect = { 50, 50, 100, 100 };
//Apply the image
SDL_BlitSurface( gHelloWorld, &srcrect, gScreenSurface, &dstrect );
In this case top, left = 0, 0 with width, height = 100, 100 from source surface (gHelloWorld) is blit to top, left = 50, 50 of dest surface (gScreenSurface).
how to load it with other types of objects
Sorry but is not clear to me what you mean by other types of objects
SDL_BlitSurface() will work, but since you're using SDL2 you're probably working mostly with SDL_Textures and not SDL_Surfaces. If this is the case the easiest way to copy one texture onto another texture or onto the screen is using SDL_RenderCopy() as keltar mentioned. The advantages of using SDL_Texture are explained here: http://wiki.libsdl.org/MigrationGuide#Video
As documented here, SDL_RenderCopy() takes four arguments: a pointer to the SDL_Renderer, a pointer to your source texture, a pointer to the source rectangle, and a pointer to the destination rectangle. By default the texture will be copied onto the screen but you can copy onto other textures by setting a target texture with SDL_SetRenderTarget().
Everything about source and destination rectangles carries over from SDL_BlitSurface.
I have learnt how to draw a line on an image in OpenCV using line( frame, Point( 15, 20 ), Point( 70, 50), 'r', 2, 8 );
I have also learnt how to draw a line on image using mouse clicks. For example the following code draws a line connecting two points user clicks on an image:
using namespace cv;
using namespace std;
void onMouse(int evt, int x, int y, int flags, void* param) {
if(evt == CV_EVENT_LBUTTONDOWN) {
std::vector<cv::Point>* ptPtr = (std::vector<cv::Point>*)param;
ptPtr->push_back(cv::Point(x,y));
}
}
int main()
{
std::vector<Point> points;
cv::namedWindow("Output Window");
Mat frame = cv::imread("chhha.png");
cv::setMouseCallback("Output Window", onMouse, (void*)&points);
int X1=0, Y1=0, X2=0, Y2=0;
while(1)
{
cv::imshow("Output Window", frame);
if (points.size() > 1) //we have 2 points
{
for (auto it = points.begin(); it != points.end(); ++it)
{
}
break;
}
waitKey(10);
}
// Now let us draw a line on the image
line( frame, points[0], points[1], 'r', 2, 8 );
cv::imshow("Output Window", frame);
waitKey( 10 );
getch();
return 0;
}
Now basically what I want is to keep drawing the lines until I right click or may be some character is entered.
What I have tried so far is using do-while loop:
char m;
do{
while(1)
{
cv::imshow("Output Window", frame);
if (points.size() > 1) //we have 2 points
{
for (auto it = points.begin(); it != points.end(); ++it)
{
}
break;
}
waitKey(10);
}
// Draw a line
line( frame, points[0], points[1], 'r', 2, 8 );
cv::imshow("Output Window", frame);
cout<<"do you want more lines, if so , press 'y'"<<endl;
cin>>m;
// instead of this a right click check would be much better
if(m!='y')
{
break;
}
}while(m=='y');
But the problem is this way not even one line would be drawn, and after few clicks and entering 'y', the application won't respond.
Please help me solve this issue.
There are probably several issues with your code that prevent it from doing what you want. The first thing that comes to mind is that you're not clearing the vector used for capturing the coordinates. After drawing a line
line( frame, points[0], points[1], 'r', 2, 8 );
you should reset the vector like this
points.clear();
so that the next mouse click's coordinate goes to points[0]. Otherwise it would append to the vector and you would keep drawing lines between the first two mouse coordinates over and over again.
Me and my friend needs to create a reaction time game.
Something like this.
Right now we just managed to show an image of the red button, but we need help how to make a hitbox, where if you click the red button, it becomes green.
Would someone could show us how?
We are using SDL, I guess that's important to mention.
Here is our code so far:
#include <SDL/SDL.h>
void Plot(SDL_Surface *sur, int x, int y, SDL_Surface *dest)
{
SDL_Rect rect = {x, y};
SDL_BlitSurface(sur, NULL, dest, &rect);
}
SDL_Surface *LoadImage(const char *filename)
{
SDL_Surface *sur = NULL;
sur = SDL_LoadBMP(filename);
if(sur == NULL)
{
printf("Img not found");
}
SDL_Surface *opsur = NULL;
if(sur != NULL)
{
opsur = SDL_DisplayFormat(sur);
SDL_SetColorKey(opsur, SDL_SRCCOLORKEY, 0xFFFFFF);
if(opsur != NULL)
SDL_FreeSurface(sur);
}
return opsur;
}
int main(int argc, char **argv)
{
SDL_Init(SDL_INIT_EVERYTHING);
SDL_Surface *screen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE);
SDL_WM_SetCaption("Eksamensprojekt", NULL);
SDL_Event Event;
bool Running = true;
SDL_Surface *sur = LoadImage("Red.bmp");
while(Running)
{
while(SDL_PollEvent(&Event))
{
if(Event.type == SDL_QUIT)
Running = false;
}
SDL_FillRect(screen, &screen->clip_rect, 0x000000);
Plot(sur, 215, 140, screen);
SDL_Flip(screen);
}
}
You can use SDL_Rect as a hit box. You can use SDL's own event handling system for checking when mouse button is clicked and the position of it. Then you just need to check if the mouse position is within the SDL_Rect.
You can read more about SDL here.
So... a little help on the way. You have a main loop and you pull events.
if ( event.type == SDL_MOUSEBUTTONDOWN ){
//Get mouse coordinates
int x = event.motion.x;
int y = event.motion.y;
//If the mouse is over the button
if( checkSpriteCollision( x, y ) ){
// Yay, you hit the button
doThings();
}
else
{
// D'oh I missed
}
}
Add this to the while, that will at least get you started.
Like this?
while(Running)
{
while(SDL_PollEvent(&Event))
{
if(Event.type == SDL_QUIT)
Running = false;
if ( event.type == SDL_MOUSEBUTTONDOWN ){
//Get mouse coordinates
int x = event.motion.x;
int y = event.motion.y;
//If the mouse is over the button
if( checkSpriteCollision( x, y ) ){
// Yay, you hit the button
doThings();
}
else {
// D'oh I missed
}
}
}
SDL_FillRect(screen, &screen->clip_rect, 0x000000);
Plot(sur, 215, 140, screen);
SDL_Flip(screen);
}
}