2011-08-23 61 views
1

我重写了Lode's raycasting tutorial代码以使其在单独的线程中处理事件。我发现任何调用xlib函数的SDL调用都必须是主线程,因此在此代码中,所有依赖xlib的函数都位于主线程中。来自多线程SDL应用程序的InvalidCursor错误

这是错误我还是从应用程序中获得随机

X Error of failed request: BadCursor (invalid Cursor parameter) 
    Major opcode of failed request: 95 (X_FreeCursor) 
    Resource id in failed request: 0x4a0000b 
    Serial number of failed request: 108 
    Current serial number in output stream: 107 

有时,当我运行它,我会得到这个错误,但如果我再次运行它,它会奏效。

我不确定我需要更改代码,因为所有的图形处理都在主线程中,单独的线程只处理事件处理。有人知道我在做什么错吗?

raycaster.cpp

#include <iostream> 
#include <cmath> 

#include "SDL.h" 
#include "SDL/SDL_image.h" 
#include "SDL/SDL_ttf.h" 

#include "game.hpp" 

using std::cout; 

static int SCREENW = 500; 
static int SCREENH = 500; 
static int BPP = 32; 

int events_loop(void* data); 

int main(int argc, char** argv) { 
    SDL_Init(SDL_INIT_EVERYTHING | SDL_INIT_EVENTTHREAD); 
    TTF_Init(); 

    SDL_Thread* events; 
    Game_state* gs = new Game_state(); 
    events = SDL_CreateThread(events_loop, (void*)gs); 

    SDL_Surface* screen = SDL_SetVideoMode(SCREENW, SCREENH, BPP, SDL_SWSURFACE); 
    SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); 
    SDL_WM_SetCaption("Raycaster (non-textured)", NULL); 

    Game* game = new Game(screen, SCREENW, SCREENH, BPP); 

    //BEGIN GAME VARIABLES 
    //game map 
    int map[Game::MAP_WIDTH][Game::MAP_WIDTH] = { 
    { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, 
    { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, 
    { 1, 0, 0, 4, 0, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, 
    { 1, 0, 3, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, 
    { 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, 
    { 1, 0, 0, 0, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, 
    { 1, 0, 4, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, 
    { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, 
    { 1, 0, 2, 0, 0, 2, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 1 }, 
    { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 0, 0, 0, 0, 0, 0, 1 }, 
    { 1, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, 
    { 1, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, 
    { 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, 
    { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, 
    { 1, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, 
    { 1, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1 }, 
    { 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 1 }, 
    { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 1 }, 
    { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, 
    { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } 
    }; 

    //direction variables 
    double pos_x = Game::PLAYER_START_X; 
    double pos_y = Game::PLAYER_START_Y; 
    double dir_x = -1; double old_dir_x; 
    double dir_y = 0; 
    int map_x, map_y; 

    //timing variables 
    double start_ticks = 0; 
    double end_ticks = 0; 
    double frame_time = 0; 

    //camera varibales 
    double camera_x; 
    double ray_pos_x, ray_pos_y; 
    double ray_dir_x, ray_dir_y; 
    double plane_x = 0; double plane_y = Game::FOV; double old_plane_x; 
    int line_height; 

    //DDA variables 
    double side_dist_x, side_dist_y; 
    double delta_dist_x, delta_dist_y; 
    double perpen_wall_dist; 
    int step_x, step_y; 
    bool EW_side; //east west side hit, negative implies north south side 
    bool hit = false; 

    //drawing variables 
    int draw_low_y, draw_high_y; 
    int r, g, b; 

    //movement variables 
    double move_speed, rotation_speed; 

    //BEGIN RENDERING LOGIC 
    while(gs->over == false) { 
     start_ticks = SDL_GetTicks(); 

     //lock screen to modify its pixels 
     /*if(SDL_MUSTLOCK(screen)) { 
      SDL_LockSurface(screen); 
     }*/ 

     game->clear_screen(); 

     //BEGIN DRAWING PIXELS 
     for(int x = 0; x < SCREENW; x++) { 
      //set up camera 
      camera_x = 2 * x/(double(SCREENW) - 1); 
      ray_pos_x = pos_x; ray_pos_y = pos_y; 

      ray_dir_x = dir_x + plane_x * camera_x; 
      ray_dir_y = dir_y + plane_y * camera_x; 

      delta_dist_x = sqrt(1 + (ray_dir_y * ray_dir_y)/(ray_dir_x * ray_dir_x)); 
      delta_dist_y = sqrt(1 + (ray_dir_x * ray_dir_x)/(ray_dir_y * ray_dir_y)); 

      //what box are we in? 
      map_x = int(ray_pos_x); map_y = int(ray_pos_y); 

      //calculate step and side_dist 
      if(ray_dir_x < 0) { 
       step_x = -1; 
       side_dist_x = (ray_pos_x - map_x) * delta_dist_x; 
      } 
      else { 
       step_x = 1; 
       side_dist_x = (map_x + 1.0 - ray_pos_x) * delta_dist_x; 
      } 

      if(ray_dir_y < 0) { 
       step_y = -1; 
       side_dist_y = (ray_pos_y - map_y) * delta_dist_y; 
      } 
      else { 
       step_y = 1; 
       side_dist_y = (map_y + 1.0 - ray_pos_y) * delta_dist_y; 
      } 

      //step using DDA until a wall is hit 
      hit = false; 
      while(hit == false) { 
       if(side_dist_x < side_dist_y) { 
        side_dist_x += delta_dist_x; 
        map_x += step_x; 
        EW_side = false; 
       } 
       else { 
        side_dist_y += delta_dist_y; 
        map_y += step_y; 
        EW_side = true; 
       } 

       if(map[map_x][map_y] > 0) { hit = true; } 
      } 

      //calculate dist from camera to wall that was hit 
      if(EW_side == false) { 
       perpen_wall_dist = fabs((map_x - ray_pos_x + (1 - step_x)/2)/ray_dir_x); 
      } 
      else { 
       perpen_wall_dist = fabs((map_y - ray_pos_y + (1 - step_y)/2)/ray_dir_y); 
      } 

      //calculate line height from perpendicular wall distance 
      line_height = abs(int(SCREENH/perpen_wall_dist)); 

      //calculate how high to draw the line 
      draw_high_y = -line_height/2 + SCREENH/2; 
      if(draw_high_y < 0) { draw_high_y = 0; } 

      draw_low_y = line_height/2 + SCREENH/2; 
      if(draw_low_y >= SCREENH) { draw_low_y = SCREENH - 1; } 
      if(draw_low_y < 0) { draw_low_y = 0; } //added (shouldn't need to be here) 

      //finally draw the line 
      game->draw_line(x, draw_low_y, draw_high_y, map[map_x][map_y], EW_side); 
     } 

     //unlock screen for blitting 
     /*if(SDL_MUSTLOCK(screen)) { 
      SDL_UnlockSurface(screen); 
     }*/ 

     //calculate timing and print the FPS 
     end_ticks = SDL_GetTicks(); 
     frame_time = (end_ticks - start_ticks)/1000.0; 

     game->blit_fps(frame_time); 
     game->blit_location(map_x, map_y); 

     if(SDL_Flip(screen) != 0) { 
      cout << "ERROR: couldn't draw to the screen <" << SDL_GetError() << ">\n"; 
     } 

     //BEGIN CALCULATING NEXT STEP 
     //calculate new direction based on frames drawn 
     move_speed = frame_time * Game_state::MOVEMENT_MULTIPLIER; 
     rotation_speed = frame_time * Game_state::ROTATION_MULTIPLIER; 

     //process movement for next frame 
     if(gs->movement_forward == Game_state::MOVE_UP) { 
      if(map[int(pos_x + dir_x * move_speed)][int(pos_y)] == 0) { pos_x += dir_x * move_speed; } 
      if(map[int(pos_x)][int(pos_y + dir_y * move_speed)] == 0) { pos_y += dir_y * move_speed; } 
     } 
     else if(gs->movement_forward == Game_state::MOVE_DOWN) { 
      if(map[int(pos_x - dir_x * move_speed)][int(pos_y)] == 0) { pos_x -= dir_x * move_speed; } 
      if(map[int(pos_x)][int(pos_y - dir_y * move_speed)] == 0) { pos_y -= dir_y * move_speed; } 
     } 

     if(gs->movement_side == Game_state::MOVE_RIGHT) { 
      old_dir_x = dir_x; 
      dir_x = dir_x * cos(-rotation_speed) - dir_y * sin(-rotation_speed); 
      dir_y = old_dir_x * sin(-rotation_speed) + dir_y * cos(-rotation_speed); 

      old_plane_x = plane_x; 
      plane_x = plane_x * cos(-rotation_speed) - plane_y * sin(-rotation_speed); 
      plane_y = old_plane_x * sin(-rotation_speed) + plane_y * cos(-rotation_speed); 
     } 
     else if(gs->movement_side == Game_state::MOVE_LEFT) { 
      old_dir_x = dir_x; 
      dir_x = dir_x * cos(rotation_speed) - dir_y * sin(rotation_speed); 
      dir_y = old_dir_x * sin(rotation_speed) + dir_y * cos(rotation_speed); 

      old_plane_x = plane_x; 
      plane_x = plane_x * cos(rotation_speed) - plane_y * sin(rotation_speed); 
      plane_y = old_plane_x * sin(rotation_speed) + plane_y * cos(rotation_speed); 
     } 
    } 

    delete gs; 
    delete game; 

    return 0; 
} 

int events_loop(void* data) { 
    Game_state* gs = (Game_state*)data; 

    SDL_Event evt; 
    while(1) { 
     while(SDL_PollEvent(&evt)) { 
      if(evt.type == SDL_QUIT) { gs->over = true; cout << "quit\n"; return 0; } 
      else if(evt.type == SDL_KEYDOWN) { 
       if(evt.key.keysym.sym == SDLK_w) { 
        gs->move(Game_state::MOVE_UP); 
       } 
       else if(evt.key.keysym.sym == SDLK_s) { 
        gs->move(Game_state::MOVE_DOWN); 
       } 
       else if(evt.key.keysym.sym == SDLK_a) { 
        gs->move(Game_state::MOVE_LEFT); 
       } 
       else if(evt.key.keysym.sym == SDLK_d) { 
        gs->move(Game_state::MOVE_RIGHT); 
       } 
       else if(evt.key.keysym.sym == SDLK_ESCAPE) { gs->over = true; cout << "escape\n"; return 0; } 
      } 
      else if(evt.type == SDL_KEYUP) { 
       if(evt.key.keysym.sym == SDLK_w) { 
        gs->stop_move(Game_state::MOVE_UP); 
       } 
       else if(evt.key.keysym.sym == SDLK_s) { 
        gs->stop_move(Game_state::MOVE_DOWN); 
       } 
       else if(evt.key.keysym.sym == SDLK_a) { 
        gs->stop_move(Game_state::MOVE_LEFT); 
       } 
       else if(evt.key.keysym.sym == SDLK_d) { 
        gs->stop_move(Game_state::MOVE_LEFT); 
       } 
      } 
      else { /* ignore */ } 
     } 
    } 
} 

game.cpp

#include <iostream> 

#include "game.hpp" 

using std::cout; using std::endl; 

Game_state::Game_state() { 
    movement_forward = NO_MOVE; 
    movement_side = NO_MOVE; 
    over = false; 
} 

void Game_state::move(int direction) { 
    switch(direction) { 
     case NO_MOVE: 
     break; 

     case MOVE_UP: 
     if(movement_forward == MOVE_DOWN) { movement_forward = NO_MOVE; } 
     else { movement_forward = MOVE_UP; } 
     break; 

     case MOVE_DOWN: 
     if(movement_forward == MOVE_UP) { movement_forward = NO_MOVE; } 
     else { movement_forward = MOVE_DOWN; } 
     break; 

     case MOVE_LEFT: 
     if(movement_side == MOVE_RIGHT) { movement_side = NO_MOVE; } 
     else { movement_side = MOVE_LEFT; } 
     break; 

     case MOVE_RIGHT: 
     if(movement_side == MOVE_LEFT) { movement_side = NO_MOVE; } 
     else { movement_side = MOVE_RIGHT; } 
     break; 

     default: 
     cout << "ERROR: invalid movement in Game_state::move() at time " << SDL_GetTicks() << endl; 
     break; 
    } 
} 

void Game_state::stop_move(int direction) { 
    switch(direction) { 
     case NO_MOVE: 
     break; 

     case MOVE_UP: 
     case MOVE_DOWN: 
     movement_forward = NO_MOVE; 
     break; 

     case MOVE_RIGHT: 
     case MOVE_LEFT: 
     movement_side = NO_MOVE; 
     break; 

     default: 
     cout << "ERROR: invalid movement in Game_state::stop_move() at time " << SDL_GetTicks() << endl; 
     break; 
    } 
} 

Game::Game(SDL_Surface* scr, int w, int h, int b) { 
    screen = scr; 
    scr_w = w; scr_h = h; bpp = b; 

    //fps printing vars 
    fps_location.x = 0; fps_location.y = 0; 
    fps_font = TTF_OpenFont("/usr/share/fonts/truetype/ttf-liberation/LiberationMono-Regular.ttf", 24); 
    fps_color.r = 0; fps_color.g = 0; fps_color.b = 255; //blue 

    //location printing vars 
    location_font = TTF_OpenFont("/usr/share/fonts/truetype/ttf-liberation/LiberationMono-Regular.ttf", 18); 

    //determine how high the font surface should be from the bottom 
    location_color.r = 0; location_color.g = 90; location_color.b = 240; 
    location_surface = TTF_RenderText_Solid(location_font, location_buffer, location_color); 
    location_location.x = 0; location_location.y = scr_h - location_surface->clip_rect.h; 

    //set up the wall colors 
    wall_color[OUTSIDE_WALL].r = 255; wall_color[OUTSIDE_WALL].g = 255; wall_color[OUTSIDE_WALL].b = 255; 
    wall_color[RED_WALL].r = 255; wall_color[RED_WALL].g = 0; wall_color[RED_WALL].b = 0; 
    wall_color[GRAY_WALL].r = 160; wall_color[GRAY_WALL].g = 160; wall_color[GRAY_WALL].b = 160; 
    wall_color[GOLD_WALL].r = 232; wall_color[GOLD_WALL].g = 211; wall_color[GOLD_WALL].g = 34; 
} 

void Game::clear_screen() { 
    SDL_FillRect(screen, &screen->clip_rect, SDL_MapRGB(screen->format, 0, 0, 0)); 
} 

void Game::blit_fps(double frame_time) { 
    sprintf(fps_buffer, "FPS: %3.3f", 1.0/frame_time); 
    fps_surface = TTF_RenderText_Solid(fps_font, fps_buffer, fps_color); 
    if(SDL_BlitSurface(fps_surface, NULL, screen, &fps_location) != 0) { 
     cout << "ERROR: couldn't blit the FPS surface <" << SDL_GetError() << ">\n"; 
    } 
} 

void Game::blit_location(int x, int y) { 
    sprintf(location_buffer, "location: %d, %d", x, y); 
    location_surface = TTF_RenderText_Solid(location_font, location_buffer, location_color); 
    if(SDL_BlitSurface(location_surface, NULL, screen, &location_location) != 0) { 
     cout << "ERROR: couldn't blit the location surface <" << SDL_GetError() << ">\n"; 
    } 
} 

//high_y means the y coord closest to the top of the screen 
void Game::draw_line(int x, int low_y, int high_y, int wall_type, bool EW_side) { 
    //cout << "high_y = " << high_y << " low_y = " << low_y << endl; 
    int r = wall_color[wall_type].r; 
    int g = wall_color[wall_type].g; 
    int b = wall_color[wall_type].b; 
    if(EW_side == true) { r /= 2; g /= 2; b /= 2; } 
    //cout << "r = " << r << " g = " << g << " b = " << b << "\n"; 

    //draw ceiling 
    /*for(int y = 0; y < high_y - 1; y++) { 
     put_pixel(x, y, 0, 255, 90); 
    }*/ 

    for(int y = high_y; y <= low_y; y++) { 
     put_pixel(x, y, r, g, b); 
    } 

    //draw floor (checkered) 
    /*for(int y = low_y + 1; y <= scr_h; y++) { 
     if(x % 20 > 10 && y % 20 > 10) { 
      put_pixel(x, y, 255, 255, 255); 
     } 
    }*/ 
} 

void Game::put_pixel(int x, int y, int r, int g, int b) { 
    int bpp = screen->format->BytesPerPixel; 
    Uint8* p = (Uint8*)screen->pixels + y * screen->pitch + x * bpp; 
    Uint32 pixel = SDL_MapRGB(screen->format, r, g, b); 

    switch(bpp) { 
     case 1: 
     *p = pixel; 
     break; 

     case 2: 
     *(Uint16*)p = pixel; 
     break; 

     case 3: 
     if(SDL_BYTEORDER == SDL_BIG_ENDIAN) { 
      p[0] = (pixel >> 16) & 0xff; 
      p[1] = (pixel >> 8) & 0xff; 
      p[2] = pixel & 0xff; 
     } 
     else { 
      p[0] = pixel & 0xff; 
      p[1] = (pixel >> 8) & 0xff; 
      p[2] = (pixel >> 16) & 0xff; 
     } 
     break; 

     case 4: 
     *(Uint32*)p = pixel; 
     break; 
    } 
} 

game.hpp

#include "SDL.h" 
#include "SDL/SDL_image.h" 
#include "SDL/SDL_ttf.h" 

class Game_state { 
    public: 
    //movement statics 
    static const int NO_MOVE = 0; 
    static const int MOVE_UP = 1; 
    static const int MOVE_DOWN = 2; 
    static const int MOVE_LEFT = 3; 
    static const int MOVE_RIGHT = 4; 
    static const double MOVEMENT_MULTIPLIER = 5.0; 
    static const double ROTATION_MULTIPLIER = 3.0; 

    int movement_forward; 
    int movement_side; 
    bool over; 

    Game_state(); 
    void move(int direction); 
    void stop_move(int direction); 
}; 

class Game { 
    private: 
    //fps vars 
    char fps_buffer[50]; 
    TTF_Font* fps_font; 
    SDL_Surface* fps_surface; 
    SDL_Rect fps_location; 
    SDL_Color fps_color; 

    //location vars 
    char location_buffer[24]; 
    TTF_Font* location_font; 
    SDL_Surface* location_surface; 
    SDL_Rect location_location; 
    SDL_Color location_color; 

    void put_pixel(int x, int y, int r, int g, int b); 

    public: 
    //game statics 
    static const int MAP_WIDTH = 20; 
    static const int MAP_HEIGHT = 20; 
    static const double FOV = 0.66; 
    static const int PLAYER_START_X = 1; 
    static const int PLAYER_START_Y = 1; 

    //wall options 
    static const int FLOOR = 0; 
    static const int OUTSIDE_WALL = 1; 
    static const int RED_WALL = 2; 
    static const int GRAY_WALL = 3; 
    static const int GOLD_WALL = 4; 

    //game variables 
    SDL_Surface* screen; 
    int scr_w; 
    int scr_h; 
    int bpp; 

    SDL_Color wall_color[5]; 

    Game(SDL_Surface* scr, int w, int h, int b); 
    void clear_screen(); 
    void blit_fps(double frame_time); 
    void blit_location(int x, int y); 
    void draw_line(int x, int low_y, int high_y, int wall_type, bool EW_side); 
}; 

回答