[…]

The Advent Programming Contest, being organized by the IEEE Student Branch Klagenfurt[,] will provide a new problem every day from December 1st to December 24th. You can submit solutions any day until the contest ends on December 26[th]. You can choose to use C, C++, C#, Java, Perl, Python 2.x or Python 3.x as programming language.

[…]

Until a solution is correct you can submit your program as often as you want (but please don’t spam our server).

[…]

The event is open to everyone.

[…]

If you want to participate, please register at http://mooshak.nes.aau.at/ (Registration is also possible after 1st December)[.]

– Wilfried Elmenreich

Source: Advent Programming Contest 2015 [Self-Organizing Networked Systems, 30th November 2015]


Interrogating a Sony PlayStation 2 DualShock 2 controller; I've yet to figure out why SDL2 reports that the DualShock 2 has five axes (although my PlayStation-to-USB adapter might be to blame), I've yet to figure out a solution – which doesn't involve a ⅓ axis dead zone – to the problem of the thumbsticks on the DualShock 2 not always returning all the way to the origin when they're released, and I last touched a DualShock 2 a long, long time ago so I'd forgotten that the D-pad is disabled in analogue mode :/

Interrogating a Sony PlayStation 2 DualShock 2 controller; I’ve yet to figure out why SDL2 reports that the DualShock 2 has five axes (although my PlayStation-to-USB adapter might be to blame), I’ve yet to figure out a solution – which doesn’t involve a ⅓ axis dead zone – to the problem of the thumbsticks on the DualShock 2 not always returning all the way to the origin when they’re released, and I last touched a DualShock 2 a long, long time ago so I’d forgotten that the D-pad is disabled in analogue mode :/

I recently rebooted development of a project I tried to develop for the Ludum Dare 20 contest held in April 2011, the theme of which was “It’s dangerous to go alone! Take this!”

As the project will require a controller with an analogue stick to play I’ve begun to develop a utility to interrogate the capabilities of various controllers – and as I feel that the SDL2 documentation is lacking with regards to the joystick support offered by that library I’m posting here the source code to the third version of that utility, for the benefit both of myself and of others.

SDL2 joystick interrogator.mm:

#include <SDL2/SDL.h>
#include "seal_intToString.h"
#include "seal_stringConcatenation.h"
#include "seal_stringQueue.h"
#include "seal_tree.h"
#include "seal_tileBackground.h"

void p_StringToTileBackground( const char * const p_string, seal_TileBackground *p_tileBackground )
{
  const size_t transparent_sub_texture = 10 /* '0'..'9' */ + 26 /* 'A'..'Z' */ + 5 /* '+', '-', '.', '(', ')' */;
  p_tileBackground->p_SetAllSubTextures( transparent_sub_texture );
  size_t i = 0;
  int x = 0, y = p_tileBackground->f_Height() - 1;
  for( ; i < strlen( p_string ); i ++, x ++ )
  {
    const char character = p_string[ i ];
    size_t sub_texture = transparent_sub_texture;
    if(( character >= '0' ) && ( character <= '9' ))
      sub_texture = character - '0';
    else
      if(( character >= 'a' ) && ( character <= 'z' ))
        sub_texture = character - 'a' + 10;
      else
        if(( character >= 'A' ) && ( character <= 'Z' ))
          sub_texture = character - 'A' + 10;
        else
          switch( character )
          {
            case '+': sub_texture = 36; break;
            case '-': sub_texture = 37; break;
            case '.': sub_texture = 38; break;
            case '(': sub_texture = 39; break;
            case ')': sub_texture = 40;
          }
    if( character == '\n' )
    {
      x = -1;
      y --;
    }
    else
      p_tileBackground->p_SetSubTexture( x, y, sub_texture );
  }
}

static seal_Texture *g_font;
static seal_TileBackground *g_number_of_joysticks_background;

void p_UpdateNumberOfJoysticksBackground( void )
{
  const int number_of_joysticks = SDL_NumJoysticks();
  char *number_of_joysticks_string = f_seal_IntToString( number_of_joysticks, false );
  char *message = f_seal_ConcatenateStrings(( number_of_joysticks == 0 )?( char* )"No":number_of_joysticks_string, " joystick", ( number_of_joysticks == 1 )?"":"s", " detected.", NULL );
  free( number_of_joysticks_string );
  p_StringToTileBackground( message, g_number_of_joysticks_background );
  free( message );
}

typedef struct t_JoystickTreeNode_struct
{
  SDL_JoystickID m_instanceId;
  bool m_open;
  SDL_Joystick *m_joystick;

  seal_TileBackground *m_nameBackground;

  int m_numberOfButtons;
  bool *m_buttonPressed;
  seal_TileBackground *m_buttonsPressedBackground;

  int m_numberOfAxes;
  Sint16 *m_axis;
  seal_TileBackground *m_axesBackground;
}
t_JoystickTreeNode;

class JoystickTree : public seal_Tree<t_JoystickTreeNode*, SDL_JoystickID>
{
  private:
    t_JoystickTreeNode *m_mostRecentlyAdded;

  public:
    JoystickTree( void )
    {
      m_mostRecentlyAdded = NULL;
    }

    void p_Open( const Sint32 p )
    {
      SDL_Joystick *joystick = SDL_JoystickOpen( p );
      const SDL_JoystickID instanceId = SDL_JoystickInstanceID( joystick );
      t_JoystickTreeNode *n = f_Get( instanceId );
      if( n == NULL )
      {
        n = ( t_JoystickTreeNode* )malloc( sizeof( t_JoystickTreeNode ));
        p_Set( n );
      }
      n->m_instanceId = instanceId;
      n->m_open = true;
      n->m_joystick = joystick;

      const char * const name = ( SDL_JoystickName( joystick ) != NULL )?SDL_JoystickName( joystick ):"NULL";
      n->m_nameBackground = new seal_TileBackground( g_font, strlen( name ), 1 );
      p_StringToTileBackground( name, n->m_nameBackground );

      n->m_numberOfButtons = SDL_JoystickNumButtons( joystick );
      n->m_buttonPressed = ( bool* )malloc( sizeof( bool ) * n->m_numberOfButtons );
      int i = 0;
      for( ; i < n->m_numberOfButtons; i ++ )
        n->m_buttonPressed[ i ] = SDL_JoystickGetButton( joystick, i );
      n->m_buttonsPressedBackground = new seal_TileBackground( g_font, 13, n->m_numberOfButtons + 1 );
      p_UpdateButtonsPressedBackground( n );

      n->m_numberOfAxes = SDL_JoystickNumAxes( joystick );
      n->m_axis = ( Sint16* )malloc( sizeof( Sint16 ) * n->m_numberOfAxes );
      for( i = 0; i < n->m_numberOfAxes; i ++ )
        n->m_axis[ i ] = SDL_JoystickGetAxis( joystick, i );
      n->m_axesBackground = new seal_TileBackground( g_font, 13, n->m_numberOfAxes + 1 );
      n->m_axesBackground->p_SetBottomLeftX( n->m_buttonsPressedBackground->f_Right());
      p_UpdateAxesBackground( n );

      n->m_nameBackground->p_SetBottomLeftY( n->m_buttonsPressedBackground->f_Top());

      m_mostRecentlyAdded = n;
    }

    void p_Close( const Sint32 p )
    {
      t_JoystickTreeNode *n = f_Get( p );
      if(( n != NULL ) && ( n->m_open ))
        p_Delete( n );
    }

    void p_PressButton( const SDL_JoystickID p_instanceId, const Uint8 p_button )
    {
      t_JoystickTreeNode *n = f_Get( p_instanceId );
      if(( n != NULL ) && ( n->m_open ))
      {
        n->m_buttonPressed[ p_button ] = true;
        p_UpdateButtonsPressedBackground( n );
      }
    }

    void p_ReleaseButton( const SDL_JoystickID p_instanceId, const Uint8 p_button )
    {
      t_JoystickTreeNode *n = f_Get( p_instanceId );
      if(( n != NULL ) && ( n->m_open ))
      {
        n->m_buttonPressed[ p_button ] = false;
        p_UpdateButtonsPressedBackground( n );
      }
    }

    void p_MoveAxis( const SDL_JoystickID p_instanceID, const Uint8 p_axis, const Sint16 p_value )
    {
      t_JoystickTreeNode *n = f_Get( p_instanceID );
      if(( n != NULL ) && ( n->m_open ))
      {
        n->m_axis[ p_axis ] = p_value;
        p_UpdateAxesBackground( n );
      }
    }

    void p_Render( void )
    {
      if(( m_mostRecentlyAdded != NULL ) && ( m_mostRecentlyAdded->m_open ))
      {
        m_mostRecentlyAdded->m_nameBackground->p_Render();
        m_mostRecentlyAdded->m_buttonsPressedBackground->p_Render();
        m_mostRecentlyAdded->m_axesBackground->p_Render();
      }
    }

  private:
    t_seal_TREE_BRANCH_DIRECTION f_Compare_TT( t_JoystickTreeNode *p_old, t_JoystickTreeNode *p_new )
    {
      if( p_new->m_instanceId < p_old->m_instanceId )
        return k_seal_TREE_BRANCH_DIRECTION__LEFT;
      if( p_new->m_instanceId > p_old->m_instanceId )
        return k_seal_TREE_BRANCH_DIRECTION__RIGHT;
      return k_seal_TREE_BRANCH_DIRECTION__STRAIGHT;
    }

    t_seal_TREE_BRANCH_DIRECTION f_Compare_TU( t_JoystickTreeNode *p_content, SDL_JoystickID p_identifier )
    {
      if( p_identifier < p_content->m_instanceId )
        return k_seal_TREE_BRANCH_DIRECTION__LEFT;
      if( p_identifier > p_content->m_instanceId )
        return k_seal_TREE_BRANCH_DIRECTION__RIGHT;
      return k_seal_TREE_BRANCH_DIRECTION__STRAIGHT;
    }

    t_JoystickTreeNode *f_IsNotInTree( SDL_JoystickID p )
    {
      return NULL;
    }

    void p_Delete( t_JoystickTreeNode *p )
    {
      if( p->m_open )
      {
        p->m_open = false;
        SDL_JoystickClose( p->m_joystick );
        delete p->m_nameBackground;
        free( p->m_buttonPressed );
        delete p->m_buttonsPressedBackground;
        free( p->m_axis );
        delete p->m_axesBackground;
      }
    }

    void p_UpdateButtonsPressedBackground( t_JoystickTreeNode *p )
    {
      seal_StringQueue sQ;
      if( p->m_numberOfButtons == 0 )
        sQ.p_Push(( char* )"No buttons" );
      else
      {
        sQ.p_Push(( char* )"Buttons (" );
        char *number_of_buttons = f_seal_IntToString( p->m_numberOfButtons, false );
        sQ.p_Push( number_of_buttons );
        free( number_of_buttons );
        sQ.p_Push(( char* )")\n" );
      }
      int i = 0;
      for( ; i < p->m_numberOfButtons; i ++ )
      {
        if(( p->m_numberOfButtons >= 100 ) && ( i < 100 ))
          sQ.p_Push(( char* )" " );
        if(( p->m_numberOfButtons >= 10 ) && ( i < 10 ))
          sQ.p_Push(( char* )" " );
        char *i_string = f_seal_IntToString( i, false );
        sQ.p_Push( i_string );
        free( i_string );
        sQ.p_Push(( char* )" .. " );
        sQ.p_Push(( char* )(( !p->m_buttonPressed[ i ] )?"Up":"Down" ));
        if( i + 1 < p->m_numberOfButtons )
          sQ.p_Push(( char* )"\n" );
      }
      char *s = sQ.f_String();
      p_StringToTileBackground( s, p->m_buttonsPressedBackground );
      free( s );
    }

    void p_UpdateAxesBackground( t_JoystickTreeNode *p )
    {
      seal_StringQueue sQ;
      if( p->m_numberOfAxes == 0 )
        sQ.p_Push(( char* )"No axes" );
      else
      {
        sQ.p_Push(( char* )"Axes (" );
        char *number_of_axes = f_seal_IntToString( p->m_numberOfAxes, false );
        sQ.p_Push( number_of_axes );
        free( number_of_axes );
        sQ.p_Push(( char* )")\n" );
      }
      int i = 0;
      for( ; i < p->m_numberOfAxes; i ++ )
      {
        char *i_string = f_seal_IntToString( i, false );
        sQ.p_Push( i_string );
        free( i_string );
        sQ.p_Push(( char* )" .. " );
        char *axis = f_seal_IntToString( p->m_axis[ i ], true );
        sQ.p_Push( axis );
        free( axis );
        if( i + 1 < p->m_numberOfAxes )
          sQ.p_Push(( char* )"\n" );
      }
      char *s = sQ.f_String();
      p_StringToTileBackground( s, p->m_axesBackground );
      free( s );
    }
};

int main( const int argc, const char * const argv[] )
{
  const int W = 494, H = 304;

  SDL_Init( SDL_INIT_VIDEO | SDL_INIT_JOYSTICK );
  SDL_Window *window = SDL_CreateWindow( "SDL2 joystick interrogator", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, W, H, SDL_WINDOW_OPENGL );
  SDL_GLContext context = SDL_GL_CreateContext( window );

  glMatrixMode( GL_PROJECTION );
  glLoadIdentity();
  glOrtho( 0, W, 0, H, -1, 1 );
  glMatrixMode( GL_MODELVIEW );
  glClearColor( 0.5, 0.5, 0.5, 1.0 );
  glEnable( GL_TEXTURE_2D );
  glEnableClientState( GL_VERTEX_ARRAY );
  glEnableClientState( GL_TEXTURE_COORD_ARRAY );

  g_font = new seal_Texture( "font.png", 19, 19 );
  g_number_of_joysticks_background = new seal_TileBackground( g_font, 23, 1 );
  g_number_of_joysticks_background->p_SetBottomLeftY( H - 19 );
  JoystickTree *joysticks = new JoystickTree();

  p_UpdateNumberOfJoysticksBackground();

  bool quit = false;
  do
  {
    SDL_Event event;
    while( SDL_PollEvent( &event ))
      switch( event.type )
      {
        case SDL_QUIT:
          quit = true;
          break;
        case SDL_JOYDEVICEADDED:
          p_UpdateNumberOfJoysticksBackground();
          joysticks->p_Open( event.jdevice.which );
          break;
        case SDL_JOYDEVICEREMOVED:
          p_UpdateNumberOfJoysticksBackground();
          joysticks->p_Close( event.jdevice.which );
          break;
        case SDL_JOYBUTTONDOWN:
          joysticks->p_PressButton( event.jbutton.which, event.jbutton.button );
          break;
        case SDL_JOYBUTTONUP:
          joysticks->p_ReleaseButton( event.jbutton.which, event.jbutton.button );
          break;
        case SDL_JOYAXISMOTION:
          joysticks->p_MoveAxis( event.jaxis.which, event.jaxis.axis, event.jaxis.value );
      }
    glClear( GL_COLOR_BUFFER_BIT );
    g_number_of_joysticks_background->p_Render();
    joysticks->p_Render();
    SDL_GL_SwapWindow( window );
  }
  while( !quit );

  delete joysticks;
  delete g_number_of_joysticks_background;
  delete g_font;

  SDL_GL_DeleteContext( context );
  SDL_DestroyWindow( window );
  SDL_Quit();
  return 0;
}

font.png:

font


Priest

11Sep15

I’ve just achieved the rank of “priest” at CodeAbbey for solving sixty-five problems.


Ludum Dare 33

22Aug15

Ludum Dare 33 has begun; the theme is “You are the Monster”.


Interrogating a Sony PlayStation 2 DualShock 2 controller.

Interrogating a Sony PlayStation 2 DualShock 2 controller.

I recently rebooted development of a project I tried to develop for the Ludum Dare 20 contest held in April 2011, the theme of which was “It’s dangerous to go alone! Take this!”

As the project will require a controller with an analogue stick to play I’ve begun to develop a utility to interrogate the capabilities of various controllers – and as I feel that the SDL2 documentation is lacking with regards to the joystick support offered by that library I’m posting here the source code to the second version of that utility, for the benefit both of myself and of others.

SDL2 joystick interrogator.mm:

#include <SDL2/SDL.h>
#include "seal_intToString.h"
#include "seal_stringConcatenation.h"
#include "seal_stringQueue.h"
#include "seal_tree.h"
#include "seal_tileBackground.h"

void p_StringToTileBackground( const char * const p_string, seal_TileBackground *p_tileBackground )
{
  const size_t transparent_sub_texture = 10 /* '0'..'9' */ + 26 /* 'A'..'Z' */ + 3 /* '.', '(', ')' */;
  p_tileBackground->p_SetAllSubTextures( transparent_sub_texture );
  size_t i = 0;
  int x = 0, y = p_tileBackground->f_Height() - 1;
  for( ; i < strlen( p_string ); i ++, x ++ )
  {
    const char character = p_string[ i ];
    size_t sub_texture = transparent_sub_texture;
    if(( character >= '0' ) && ( character <= '9' ))
      sub_texture = character - '0';
    else
      if(( character >= 'a' ) && ( character <= 'z' ))
        sub_texture = character - 'a' + 10;
      else
        if(( character >= 'A' ) && ( character <= 'Z' ))
          sub_texture = character - 'A' + 10;
        else
          if( character == '.' )
            sub_texture = 36;
          else
            if( character == '(' )
              sub_texture = 37;
            else
              if( character == ')' )
                sub_texture = 38;
    if( character == '\n' )
    {
      x = -1;
      y --;
    }
    else
      p_tileBackground->p_SetSubTexture( x, y, sub_texture );
  }
}

static seal_Texture *g_font;
static seal_TileBackground *g_number_of_joysticks_background;

void p_UpdateNumberOfJoysticksBackground( void )
{
  const int number_of_joysticks = SDL_NumJoysticks();
  char *number_of_joysticks_string = f_seal_IntToString( number_of_joysticks, false );
  char *message = f_seal_ConcatenateStrings(( number_of_joysticks == 0 )?( char* )"No":number_of_joysticks_string, " joystick", ( number_of_joysticks == 1 )?"":"s", " detected.", NULL );
  free( number_of_joysticks_string );
  p_StringToTileBackground( message, g_number_of_joysticks_background );
  free( message );
}

typedef struct t_JoystickTreeNode_struct
{
  SDL_JoystickID m_instanceId;
  bool m_open;
  SDL_Joystick *m_joystick;
  int m_numberOfButtons;
  bool *m_buttonPressed;
  seal_TileBackground *m_buttonsPressedBackground;
}
t_JoystickTreeNode;

class JoystickTree : public seal_Tree<t_JoystickTreeNode*, SDL_JoystickID>
{
  private:
    t_JoystickTreeNode *m_mostRecentlyAdded;

  public:
    JoystickTree( void )
    {
      m_mostRecentlyAdded = NULL;
    }

    void p_Open( const Sint32 p )
    {
      SDL_Joystick *joystick = SDL_JoystickOpen( p );
      const SDL_JoystickID instanceId = SDL_JoystickInstanceID( joystick );
      t_JoystickTreeNode *n = f_Get( instanceId );
      if( n == NULL )
      {
        n = ( t_JoystickTreeNode* )malloc( sizeof( t_JoystickTreeNode ));
        p_Set( n );
      }
      n->m_instanceId = instanceId;
      n->m_open = true;
      n->m_joystick = joystick;
      n->m_numberOfButtons = SDL_JoystickNumButtons( joystick );
      n->m_buttonPressed = ( bool* )malloc( sizeof( bool ) * n->m_numberOfButtons );
      int i = 0;
      for( ; i < n->m_numberOfButtons; i ++ )
        n->m_buttonPressed[ i ] = SDL_JoystickGetButton( joystick, i );
      n->m_buttonsPressedBackground = new seal_TileBackground( g_font, 13, n->m_numberOfButtons + 1 );
      p_UpdateButtonsPressedBackground( n );
      m_mostRecentlyAdded = n;
    }

    void p_Close( const Sint32 p )
    {
      t_JoystickTreeNode *n = f_Get( p );
      if(( n != NULL ) && ( n->m_open ))
        p_Delete( n );
    }

    void p_PressButton( const SDL_JoystickID p_instanceId, const Uint8 p_button )
    {
      t_JoystickTreeNode *n = f_Get( p_instanceId );
      if(( n != NULL ) && ( n->m_open ))
      {
        n->m_buttonPressed[ p_button ] = true;
        p_UpdateButtonsPressedBackground( n );
      }
    }

    void p_ReleaseButton( const SDL_JoystickID p_instanceId, const Uint8 p_button )
    {
      t_JoystickTreeNode *n = f_Get( p_instanceId );
      if(( n != NULL ) && ( n->m_open ))
      {
        n->m_buttonPressed[ p_button ] = false;
        p_UpdateButtonsPressedBackground( n );
      }
    }

    void p_Render( void )
    {
      if(( m_mostRecentlyAdded != NULL ) && ( m_mostRecentlyAdded->m_open ))
        m_mostRecentlyAdded->m_buttonsPressedBackground->p_Render();
    }

  private:
    t_seal_TREE_BRANCH_DIRECTION f_Compare_TT( t_JoystickTreeNode *p_old, t_JoystickTreeNode *p_new )
    {
      if( p_new->m_instanceId < p_old->m_instanceId )
        return k_seal_TREE_BRANCH_DIRECTION__LEFT;
      if( p_new->m_instanceId > p_old->m_instanceId )
        return k_seal_TREE_BRANCH_DIRECTION__RIGHT;
      return k_seal_TREE_BRANCH_DIRECTION__STRAIGHT;
    }

    t_seal_TREE_BRANCH_DIRECTION f_Compare_TU( t_JoystickTreeNode *p_content, SDL_JoystickID p_identifier )
    {
      if( p_identifier < p_content->m_instanceId )
        return k_seal_TREE_BRANCH_DIRECTION__LEFT;
      if( p_identifier > p_content->m_instanceId )
        return k_seal_TREE_BRANCH_DIRECTION__RIGHT;
      return k_seal_TREE_BRANCH_DIRECTION__STRAIGHT;
    }

    t_JoystickTreeNode *f_IsNotInTree( SDL_JoystickID p )
    {
      return NULL;
    }

    void p_Delete( t_JoystickTreeNode *p )
    {
      if( p->m_open )
      {
        p->m_open = false;
        SDL_JoystickClose( p->m_joystick );
        free( p->m_buttonPressed );
        delete p->m_buttonsPressedBackground;
      }
    }

    void p_UpdateButtonsPressedBackground( t_JoystickTreeNode *p )
    {
      seal_StringQueue sQ;
      if( p->m_numberOfButtons == 0 )
        sQ.p_Push(( char* )"No buttons" );
      else
      {
        sQ.p_Push(( char* )"Buttons (" );
        char *number_of_buttons = f_seal_IntToString( p->m_numberOfButtons, false );
        sQ.p_Push( number_of_buttons );
        free( number_of_buttons );
        sQ.p_Push(( char* )")\n" );
      }
      int i = 0;
      for( ; i < p->m_numberOfButtons; i ++ )
      {
        if(( p->m_numberOfButtons >= 100 ) && ( i < 100 ))
          sQ.p_Push(( char* )" " );
        if(( p->m_numberOfButtons >= 10 ) && ( i < 10 ))
          sQ.p_Push(( char* )" " );
        char *i_string = f_seal_IntToString( i, false );
        sQ.p_Push( i_string );
        free( i_string );
        sQ.p_Push(( char* )" .. " );
        sQ.p_Push(( char* )(( !p->m_buttonPressed[ i ] )?"Up":"Down" ));
        if( i + 1 < p->m_numberOfButtons )
          sQ.p_Push(( char* )"\n" );
      }
      char *s = sQ.f_String();
      p_StringToTileBackground( s, p->m_buttonsPressedBackground );
      free( s );
    }
};

int main( const int argc, const char * const argv[] )
{
  const int W = 437, H = 285;

  SDL_Init( SDL_INIT_VIDEO | SDL_INIT_JOYSTICK );
  SDL_Window *window = SDL_CreateWindow( "SDL2 joystick interrogator", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, W, H, SDL_WINDOW_OPENGL );
  SDL_GLContext context = SDL_GL_CreateContext( window );

  glMatrixMode( GL_PROJECTION );
  glLoadIdentity();
  glOrtho( 0, W, 0, H, -1, 1 );
  glMatrixMode( GL_MODELVIEW );
  glClearColor( 0.5, 0.5, 0.5, 1.0 );
  glEnable( GL_TEXTURE_2D );
  glEnableClientState( GL_VERTEX_ARRAY );
  glEnableClientState( GL_TEXTURE_COORD_ARRAY );

  g_font = new seal_Texture( "font.png", 19, 19 );
  g_number_of_joysticks_background = new seal_TileBackground( g_font, 23, 1 );
  g_number_of_joysticks_background->p_SetBottomLeftY( H - 19 );
  JoystickTree *joysticks = new JoystickTree();

  p_UpdateNumberOfJoysticksBackground();

  bool quit = false;
  do
  {
    SDL_Event event;
    while( SDL_PollEvent( &event ))
      switch( event.type )
      {
        case SDL_QUIT:
          quit = true;
          break;
        case SDL_JOYDEVICEADDED:
          p_UpdateNumberOfJoysticksBackground();
          joysticks->p_Open( event.jdevice.which );
          break;
        case SDL_JOYDEVICEREMOVED:
          p_UpdateNumberOfJoysticksBackground();
          joysticks->p_Close( event.jdevice.which );
          break;
        case SDL_JOYBUTTONDOWN:
          joysticks->p_PressButton( event.jbutton.which, event.jbutton.button );
          break;
        case SDL_JOYBUTTONUP:
          joysticks->p_ReleaseButton( event.jbutton.which, event.jbutton.button );
      }
    glClear( GL_COLOR_BUFFER_BIT );
    g_number_of_joysticks_background->p_Render();
    joysticks->p_Render();
    SDL_GL_SwapWindow( window );
  }
  while( !quit );

  delete joysticks;
  delete g_number_of_joysticks_background;
  delete g_font;

  SDL_GL_DeleteContext( context );
  SDL_DestroyWindow( window );
  SDL_Quit();
  return 0;
}

font.png:

font.png


SDL2 joystick interrogator animation

I recently rebooted development of a project I tried to develop for the Ludum Dare 20 contest held in April 2011, the theme of which was “It’s dangerous to go alone! Take this!”

As the project will require a controller with an analogue stick to play I’ve begun to develop a utility to interrogate the capabilities of various controllers – and as I feel that the SDL2 documentation is lacking with regards to the joystick support offered by that library I’m posting here the source code to the first version of that utility, for the benefit both of myself and of others.

SDL2 joystick interrogator.mm:

#include <SDL2/SDL.h>
#include "seal_intToString.h"
#include "seal_stringConcatenation.h"
#include "seal_tileBackground.h"

void p_StringToTileBackground( const char * const p_string, seal_TileBackground *p_tileBackground )
{
  const size_t transparent_sub_texture = 10 /* '0'..'9' */ + 26 /* 'A'..'Z' */ + 1 /* '.' */;
  p_tileBackground->p_SetAllSubTextures( transparent_sub_texture );
  size_t i = 0;
  for( ; i < strlen( p_string ); i ++ )
  {
    const char character = p_string[ i ];
    size_t sub_texture = transparent_sub_texture;
    if(( character >= '0' ) && ( character <= '9' ))
      sub_texture = character - '0';
    else
      if(( character >= 'a' ) && ( character <= 'z' ))
        sub_texture = character - 'a' + 10;
      else
        if(( character >= 'A' ) && ( character <= 'Z' ))
          sub_texture = character - 'A' + 10;
        else
          if( character == '.' )
            sub_texture = 36;
    p_tileBackground->p_SetSubTexture( i, 0, sub_texture );
  }
}

static seal_TileBackground *g_number_of_joysticks_background;

void p_UpdateNumberOfJoysticksBackground( void )
{
  const int number_of_joysticks = SDL_NumJoysticks();
  char *number_of_joysticks_string = f_seal_IntToString( number_of_joysticks, false );
  char *message = f_seal_ConcatenateStrings(( number_of_joysticks == 0 )?( char* )"No":number_of_joysticks_string, " joystick", ( number_of_joysticks == 1 )?"":"s", " detected.", NULL );
  free( number_of_joysticks_string );
  p_StringToTileBackground( message, g_number_of_joysticks_background );
  free( message );
}

int main( const int argc, const char * const argv[] )
{
  const int W = 437, H = 19;

  SDL_Init( SDL_INIT_VIDEO | SDL_INIT_JOYSTICK );
  SDL_Window *window = SDL_CreateWindow( "SDL2 joystick interrogator", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, W, H, SDL_WINDOW_OPENGL );
  SDL_GLContext context = SDL_GL_CreateContext( window );

  glMatrixMode( GL_PROJECTION );
  glLoadIdentity();
  glOrtho( 0, W, 0, H, -1, 1 );
  glMatrixMode( GL_MODELVIEW );
  glEnable( GL_TEXTURE_2D );
  glEnableClientState( GL_VERTEX_ARRAY );
  glEnableClientState( GL_TEXTURE_COORD_ARRAY );

  seal_Texture *font = new seal_Texture( "font.png", 19, 19 );
  g_number_of_joysticks_background = new seal_TileBackground( font, 23, 1 );

  p_UpdateNumberOfJoysticksBackground();

  bool quit = false;
  do
  {
    SDL_Event event;
    while( SDL_PollEvent( &event ))
      switch( event.type )
      {
        case SDL_QUIT:
          quit = true;
          break;
        case SDL_JOYDEVICEADDED:
        case SDL_JOYDEVICEREMOVED:
          p_UpdateNumberOfJoysticksBackground();
      }
    glClear( GL_COLOR_BUFFER_BIT );
    g_number_of_joysticks_background->p_Render();
    SDL_GL_SwapWindow( window );
  }
  while( !quit );

  delete g_number_of_joysticks_background;
  delete font;

  SDL_GL_DeleteContext( context );
  SDL_DestroyWindow( window );
  SDL_Quit();
  return 0;
}

font.png:

font.png


Easy Prey

10Apr15
Easy Prey: Solve twenty-five of the fifty easiest problems

Easy Prey: Solve twenty-five of the fifty easiest problems


[…]

The Advent Programming Contest 2014, organized by the IEEE Student Branch Klagenfurt will provide a new problem every day from December 1st to December 24th. On Saturdays and Sundays, new problems will appear at 12:00 Central European Time, on workdays at 18:00 CET. You can submit solutions any day until the contest ends on December 26[th]. You can choose to use C, C++, Java, Python or Perl as programming language.

[…]

Until a solution is correct you can submit your program as often as you want (but please don’t spam our server).

[…]

The event is open to everyone. If you want to participate, please register at http://mooshak.nes.aau.at/

[…]

This is an individuals competition, not a team contest – be fair!
You can also join the contest after 1st December, registration is possible until December 24[th].

– Wilfried Elmenreich

Source: Advent Programming Contest 2014 [Self-Organizing Networked Systems, 1st December 2014]


Mini Ludum Dare 54, organised by Arthur Ward Jr., has begun; the theme is “it’s a race!”


Ludum Dare 30

23Aug14

Ludum Dare 30 has begun; the theme is “Connected Worlds”.




Follow

Get every new post delivered to your Inbox.