SDL/C++ MORPG engine

Multithreading and drawing to the screen

Page 1 of 1

7 Replies - 2560 Views - Last Post: 07 June 2009 - 11:09 AM Rate Topic: -----

#1 gabehabe  Icon User is offline

  • GabehabeSwamp
  • member icon




Reputation: 1382
  • View blog
  • Posts: 10,962
  • Joined: 06-February 08

SDL/C++ MORPG engine

Posted 30 May 2009 - 08:23 AM

So yeah, I'm kinda contradicting myself here, but I decided to have a go at making a small multiplayer online rpg engine.

So far, it's not going too bad. I've got it all sussed, map loading, objects & collision detection, and even released a small demo with online functionality (seeing other players walk around on the same map as you)

BUT~ now I've hit a bit of a brick wall. See, the demo I released was too slow: It loaded and drew the other characters in the main game loop. This was never gonna be the final method of doing it, more just a test. Now, I've come to multithreading it. Been racking my brain every few days for about an hour each time and getting nowhere, so now I'm seeking the wisdom of you guys, oh wise gurus. :pimp:

See, I now have one additional thread to the main program for it.

The main game loop redraws the map and redraws the player according to their location. Simple stuff, right?

The thread connects to the database and reads other player locations and draws them. Problem is, if I'm drawing from that thread as well as the main game loop, they could disappear when the screen is redrawn in my main game loop.

The solution: Draw all the other players to another surface. Blit that to the screen from the main game loop, keeping it all drawing in the right order and not letting them disappear.

The problem with that is it might still be drawing to the surface when it blits it to the screen, so some other players might disappear.

The new solution: Blit them to a temporary surface, then copy that to the surface which is applied to the screen from the main loop at the very last minute.

The code is ugly since it's still in a debugging phase at the moment, but you should get the general gist of it.

This is the code for the thread: (See commented section at the end)
int do_mysql(void* foo) {
    ostringstream q;
    MYSQL_RES* res;
    MYSQL_ROW row;
    player* other_player;
    bool no_one_here = false;

    SDL_Surface* temp = NULL;
    while(true) {
        temp = SDL_CreateRGBSurface(SDL_SWSURFACE, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_DEPTH, RMASK, GMASK, BMASK, AMASK);
        //SDL_Delay(75);

        q.str("");
        q << "SELECT * FROM users WHERE status = 1 AND screen_id = " << the_game->get_player()->get_map()->get_id();
        q << " AND username != '" << the_game->get_player()->get_username() << "'";
        mysql_query(the_game->get_mysql(), q.str().c_str());
        res = mysql_use_result(the_game->get_mysql());

        no_one_here = true;

        while(row = mysql_fetch_row(res)) {
            no_one_here = false;
            other_player = new player(temp, NULL, ".\\img\\sprites.png", "", false);
            other_player->set_state(atoi(row[5]));
            other_player->set_coords(atoi(row[3]), atoi(row[4]));
            other_player->refresh(false);
            other_player->destroy();

            delete [] &other_player;
            other_player = NULL;
            delete &row;
        }

        mysql_free_result(res);
        SDL_BlitSurface(temp, NULL, players, &the_game->get_screen()->clip_rect);
        
        // i can see that its all on temp if i blit temp to the screen, like so:
        // SDL_BlitSurface(temp, NULL, the_game->get_screen(), &the_game->get_screen()->clip_rect);
        // but, if i blit players to the screen, even after i JUST blitted temp onto it, there's nothing
        // SDL_BlitSurface(temp, NULL, the_game->get_screen(), &the_game->get_screen()->clip_rect);
        // yeah, no blitting will actually happen here, this is just while i test different shit out
        SDL_FreeSurface(temp);

    }
}


The way I'm drawing that players surface in main is like so:
        this->p->refresh(true); // refresh the player and the map
        // blit all other players on the screen before refreshing
        SDL_BlitSurface(this->_players, NULL, this->_screen, &this->_screen->clip_rect);
        // REFRESH!!!
        SDL_Flip(this->_screen);
(It's passed and stored in the game class, hence the slightly different name.


The short bit, for those of you too lazy to read all that drivel:
Anyone got any suggestions as to how I can draw all the other players onto that surface from temp? It doesn't seem to copy?

Thanks in advance~! :^:

edit:
The players surface is initialised right at the beginning of main, like so:
players = SDL_CreateRGBSurface(SDL_SWSURFACE, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_DEPTH, RMASK, GMASK, BMASK, AMASK);
(a blank surface)

This post has been edited by gabehabe: 30 May 2009 - 08:30 AM


Is This A Good Question/Topic? 0
  • +

Replies To: SDL/C++ MORPG engine

#2 stayscrisp  Icon User is offline

  • フカユ
  • member icon

Reputation: 998
  • View blog
  • Posts: 4,173
  • Joined: 14-February 08

Re: SDL/C++ MORPG engine

Posted 30 May 2009 - 10:39 AM

Hey

I think this has something to do with the fact that the temporary surface does not match that of the screen, try converting it with
SDL_DisplayFormat(surface);



Although that might not be the problem, I don't know exactly what you want :s hehe.
Was This Post Helpful? 0
  • +
  • -

#3 saxasm  Icon User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 38
  • Joined: 30-May 08

Re: SDL/C++ MORPG engine

Posted 31 May 2009 - 05:54 AM

I'd say you are using a too complicated method.

The method i use is to have one glbal object, that is loaded from the sql database on startup, on the server. Then each client requests what is nearby and get it like "134","134","Player","1123". Then the client looks through it's local database for a player with the ID 1123. If it can't find him, he asks the server to send the character to him. If a character is gone from the area for more than 2 minutes, he is removed from the local database.

For rendering, the client reads from the database all of the players nearby and render them. I don't understand why you have multiple surfaces, you should draw them all at the same time from one database. That way, no players can dissapear during renderng. I maybe completely misunderstood what you are trying to achieve, but this is how i do it.
Was This Post Helpful? 0
  • +
  • -

#4 gabehabe  Icon User is offline

  • GabehabeSwamp
  • member icon




Reputation: 1382
  • View blog
  • Posts: 10,962
  • Joined: 06-February 08

Re: SDL/C++ MORPG engine

Posted 02 June 2009 - 04:28 AM

@saxasm I think you've gotten slightly confused from what I'm saying. I do use that single surface , which is global. But I need to draw to it from one thread and draw it to the screen in another - it could be drawn to the screen while it's incomplete since the threads are totally independent. Hence the new surface for them all to go on, then apply that to the players surface, meaning it's all done last-minute.

@stayscrisp thanks, but I've already tried that. :(

Basically, I want to draw all other players to that players surface. But, I can't draw directly to it incase it's being drawn to the screen in my main thread. Workaround: I use a temp surface, and put all that info onto the players surface right at the last minute, meaning it will always be complete when it gets drawn (it's never "in the process" of being drawn)

The format of the surface is definitely suited to the screen, I just don't understand why temp won't blit onto it. (Or perhaps it won't blit to the screen...?)

If we can't fix this, I think I've got a workaround figured out. Basically some sort of sync between the threads. More details this weekend, when I actually try it. :)

The basic problem:
I can blit temp to the screen, but I can't blit temp to players, and then blit players to the screen.

This post has been edited by gabehabe: 02 June 2009 - 04:32 AM

Was This Post Helpful? 0
  • +
  • -

#5 gabehabe  Icon User is offline

  • GabehabeSwamp
  • member icon




Reputation: 1382
  • View blog
  • Posts: 10,962
  • Joined: 06-February 08

Re: SDL/C++ MORPG engine

Posted 07 June 2009 - 03:40 AM

View Poststayscrisp, on 30 May, 2009 - 04:39 PM, said:

I think this has something to do with the fact that the temporary surface does not match that of the screen

Right, I've now come back to it with a fresh mind. Testing what you said, seems you were right. I did this:
if(players->format != temp->format) _Exit(200);
and it exits every time, meaning the temp surface's format doesn't match that of the players surface. Thing is, I can't do a straight
players = SDL_DisplayFormat(temp);
because (I think) it changes where the pointer points to (and it's passed to my game object)

Does this mean I need to alter the format of the players object somewhere? Any ideas how I could do that?

Cheers.

edit;
I also tried this:
memcpy(players, temp, sizeof(temp));
but that didn't seem to work either. (Though I would've thought that would bypass the pointer location issue)

This post has been edited by gabehabe: 07 June 2009 - 03:49 AM

Was This Post Helpful? 0
  • +
  • -

#6 gabehabe  Icon User is offline

  • GabehabeSwamp
  • member icon




Reputation: 1382
  • View blog
  • Posts: 10,962
  • Joined: 06-February 08

Re: SDL/C++ MORPG engine

Posted 07 June 2009 - 04:14 AM

BREAKTHROUGH!

I feel like I'm getting somewhere now, but it's a little off still.

SDL_BlitSurface(SDL_DisplayFormat(temp), NULL, players, &players->clip_rect);

The only problem is that it draws it with a black background. Display format is no longer an issue, I just need to figure that transparency. I can't really just remove the black, since there could be black on the sprites. Suggestions?
Was This Post Helpful? 0
  • +
  • -

#7 stayscrisp  Icon User is offline

  • フカユ
  • member icon

Reputation: 998
  • View blog
  • Posts: 4,173
  • Joined: 14-February 08

Re: SDL/C++ MORPG engine

Posted 07 June 2009 - 09:51 AM

Hmmm maybe you could try to use
SDL_DisplayFormatAlpha(temp)



If you use SDL image then you can use .PNG files which you can create with alpha channels instead of transparency, perhaps you were already doing this.
Was This Post Helpful? 1
  • +
  • -

#8 gabehabe  Icon User is offline

  • GabehabeSwamp
  • member icon




Reputation: 1382
  • View blog
  • Posts: 10,962
  • Joined: 06-February 08

Re: SDL/C++ MORPG engine

Posted 07 June 2009 - 11:09 AM

Yeah, that sounds right, cheers! :)

I broke it again though, it's not drawing anything now. :( Not sure what I did, but I'll have to fix it next weekend now. <_<

Thanks for your help though, if it weren't for your advice I don't think I'd even be at this point now! :)
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1