PS2 Linux Programming

 

Remote Camera Control Using UDP

 

Introduction

 

This tutorial extends the tutorial “3D Graphics API for PS2 Linux” to include an illustration of simple game style networking. In the original tutorial, a “first person” camera can be moved about the scene using a control pad. In this tutorial, the camera movement is extended so that the camera can be controlled remotely from a Windows PC in addition to the pad control. Berkeley Sockets are used on the PS2 and Windows Sockets are used on the Windows PC. The User Datagram Protocol (UDP) is used to perform the data transfer over the network.

 

 

Background

 

UDP in one of the commonly used protocols within the TCP/IP protocol suite (Internet Protocols) and is known as a connectionless and “unreliable” protocol. UDP is ideal for many types of gaming applications since it is fast and efficient and contains very little in the way of communication overheads. With UDP it is possible to send information from one computer to another over a network without requiring an explicit connection being made between the participating hosts.

 

 

UDP Socket Class

 

A UDP socket class with basic functionality has been created for the applications. The socket class is contained in the files hsfsocket.cpp and hsfsocket.h and operates on both Windows and Linux platforms. The class definition is shown below for clarity:

 

 

class CUDPSocket

{

public:

     CUDPSocket();

     ~CUDPSocket();

    

     int MakeNonBlocking(void);

     int Initialise(void);

     int Bind(const int Port);

     int Receive(char * Buffer);

     int Send(char * Buffer);

     void SetDestinationAddress(char * IP, const int Port);

     sockaddr_in GetDestinationAddress(void);

 

protected:

     SOCKET m_Socket;

     socklen_t m_SocketAddressSize;

     int m_Ret;

     struct sockaddr_in m_LocalAddress, m_RemoteAddress;

 

#ifdef USEWINSOCK

     WSADATA m_WSData;

#endif

};

 

 

Methods are available to Initialise() and Bind() a socket, to set a destination address and to Send() and Receive() data to and from a remote host. Within hsfsocket.h there are two defines, USEWINSOCK and USEUNIX and one of these should be commented out for the platform being used.

 

 

The Example Code

 

There are two applications associated with this tutorial. The windows application simply obtains key presses from the keyboard, packages up any information to be sent, and sends it over the network to the IP address of the PS2 on the network. The PS2 listens on UDP port 1500 for any incoming data. The Windows program in short and simple and is repeated here for clarity.

 

 

void main (void)

{

     CUDPSocket UDPSocket;

     char Buffer[PACKETSIZE], * pBuffer;

    

     UDPSocket.Initialise();

     UDPSocket.SetDestinationAddress("192.168.2.2", 1500);

 

     while(1)

     {

          pBuffer = Buffer;

          memset( Buffer, 0, PACKETSIZE );

 

          if (GetAsyncKeyState(VK_ESCAPE)) return;

 

          if (GetAsyncKeyState('A')) *pBuffer++ = 'A';

          else if (GetAsyncKeyState('D')) *pBuffer++ = 'D';        

         

          if (GetAsyncKeyState('S')) *pBuffer++ = 'S';

          else if (GetAsyncKeyState('W')) *pBuffer++ = 'W';

 

          if (GetAsyncKeyState(VK_UP)) *pBuffer++ = 'F';

          else if (GetAsyncKeyState(VK_DOWN)) *pBuffer++ = 'B';

 

          if (GetAsyncKeyState(VK_LEFT)) *pBuffer++ = 'L';

          else if (GetAsyncKeyState(VK_RIGHT))*pBuffer++ = 'R';

 

          *pBuffer = 0;

          if(*Buffer)

          {

              printf("%s\n", Buffer);

              UDPSocket.Send(Buffer);

          }

 

          Sleep(50);

     }

 

}

 

 

First Winsock and the socket are initialised, then the destination IP address and port number for the PS2 are set. The reader will obviously need to set the IP address to that of the PS2 being used. The keys being used on the keyboard are the arrow keys to control the forward/backward and left/right movement of the camera and the “A S D W” keys to control the rotation of the camera round the Y and X axes. The key presses are coded using letters, packaged into a character array of 80 characters in size then sent to the PS2. Notice that the buffer is only sent if there is information to send and that due to the Sleep(50) line of code, the maximum transmission rate will be 20 packets per second.

 

In the PS2 application a UDP socket is set up to listen for data on port 1500. This is accomplished with the following lines of code, which are performed during the initialisation of the application:

 

 

CUDPSocket UDPSocket;

UDPSocket.Initialise();

UDPSocket.MakeNonBlocking();

UDPSocket.Bind(LOCALPORT);

 

char NetMsg[PACKETSIZE], * pNetMessage;

 

 

There are a few things to note about the above code: firstly, after the socket is initialised it is set into a non-blocking state so that the game loop does not stall on any calls to receive data. There are several ways to handle the requirement of maintaining the game loop running but this method is simple and effective. Secondly, the socket is bound to port 1500 (LOCALPORT) so that listening is undertaken on this port. Finally, a character array NetMsg[80] is defined to hold the received data.

 

During the game loop the any incoming network traffic is checked and processed using the following code:

 

 

// Get any camera movements from the network

// Clear buffer

memset(NetMsg, 0x0, PACKETSIZE);

 

// reset the pointer

pNetMessage = NetMsg;

 

// receive message

int BytesReceived = UDPSocket.Receive(NetMsg);

 

// do net processing only if there is a message

if(BytesReceived > 0)

{

     //printf("Got Something -> %s\n", NetMsg);

     do

     {

          if (*pNetMessage == 'A') XRot = 0.2f;

          else if (*pNetMessage == 'D') XRot = -0.2f;

         

          if (*pNetMessage == 'S') YRot = 0.2f;

          else if (*pNetMessage == 'W') YRot = -0.2f;

 

          if (*pNetMessage == 'F') Advance = -0.5f;

          else if (*pNetMessage == 'B') Advance = 0.5f;

 

          if (*pNetMessage == 'L') Strafe = -0.5f;

          else if (*pNetMessage == 'R') Strafe = 0.5f;

             

          pNetMessage++;

 

     }while(*pNetMessage != 0);  

}        

 

 

Firstly the incoming receive buffer is cleared to 0 and a pointer to the buffer is initialised to the start of the buffer. A non-blocking call to receive from the socket in made. UDPSocket::Receive() returns the number of bytes received or -1 if there is no data to read. If there is incoming data, the message array is scanned for appropriate key press data and the required changes to the camera position and orientation are made. No processing is undertaken if there is no incoming data, making this a fast and efficient method of dealing with the network connection.

 

 

Running The Applications

 

 

Compile and run the application on the PS2 and a scene is rendered on screen with a 3D model, terrain and some other artefacts as illustrated in the accompanying screen shot. The camera can be controlled in the normal manner using the analogue joy sticks on the control pad. This application is self contained and will run successfully without the requirement for the Windows application.

 

Running the Windows application provided the ability to remotely control the position and orientation of the camera using the arrow keys and “ASDW” keys as described above. Execute the application and control the camera position with the keys. It is possible to start and stop the windows application without any adverse affect on the PS2 application.

 

 

Conclusions

 

This tutorial illustrates a simple method of using the UDP protocol to control the movement of a first person camera over a network. There are many ways in which the application can be enhanced and extended. It may be noticed that due to the slow update rate of the network data, and due to the possible congestion of the network being used, the motion of the camera under remote control may be jerky and uneven. This is a situation where “dead-reckoning” can be employed to smooth out the camera movement and the reader is encouraged to investigate dead-reckoning algorithms and incorporate them into this application.

 

 

Dr Henry S Fortuna

University of Abertay Dundee

h.s.fortuna@abertay.ac.uk