Linux game programmingOur prior animation demoDecoupling ‘move’ from ‘draw’Linux provides ‘interval timers’structs timeval and itimervalSIGALRMOur signal-handlerMain program-loop “revised”‘draw’ versus ‘move’Giving the user controlThe ‘tty’ interface‘tty’ customizationSlide 13The ‘c_lflag’ fieldICANON and ECHOThe ‘c_cc[ ]’ arrayHow to setup ‘raw’ terminal-mode‘raw’ mode needs four changesDemo program: ‘rawtty.cpp’‘Noncanonical’ terminal i/oHandling a key-pressEnabling ‘asynchronous’ I/O‘animate2.cpp’Program-loop revised againEnhancment: more user-controlIn-class exercise #1In-class exercise #2Linux game programmingAn introduction to the use of interval timers and asynchronous input notificationsOur prior animation demo•We achieved the illusion of “smooth” and “flicker-free” animation, by synchronizing drawing-operations with Vertical Retrace •But more is needed in a game that’s “fun” •Some deficiencies in our ‘animate1’ demo:–Ball movements tied to Vertical Retrace–The viewer lacked any real-time control•How can we overcome these limitations?Decoupling ‘move’ from ‘draw’•Our program-loop had used logic like this:do {vsync(); // delay until start of the next retracehide_ball(); // “erase” the ballmove_ball(); // adjust its locationshow_ball(); // “redraw” the ball--count; // decrement a counter}while ( count > 0 );•So ball movement is delayed by vertical retracesLinux provides ‘interval timers’•#include <sys/time.h>•struct itimerval itval, itold;•itval.it_value.tv_sec = 2; •itval.it_value.tv_usec = 0;•itval.it_interval.tv_sec = 0;•itval.it_interval.tv_usec = 10000;•setitimer( ITIMER_REAL, &itval, &itold );•(See the ‘man’ page for additional details)structs timeval and itimerval tv_sec tv_usec struct timeval tv_sec tv_usec tv_sec tv_usec it_interval it_value struct itimervalIt_itimerval = next delay value, it_timeval = current delay valueSIGALRM•When timer “expires” our application gets notified, by being sent a signal from Linux•Normally an application gets terminated if the SIGALRM signal is delivered to it•But we can alter that default behavior, by installing a ‘signal-handler’ that we design•We can ‘move-the-ball’ when SIGALRM is received, regardless of Vertical RetraceOur signal-handler void on_alarm( int signum ){// modify these global variablesball_xcoordinate += xincrement;ball_ycoordinate += yincrement;}// The ‘signal()’ function “installs” our handlersignal( SIGALRM, on_alarm);Main program-loop “revised”•We can now omit ball-movement in main loop:do {vsync(); // delay until start of the next retracehide_ball(); // “erase” the old ball oldx = newx; oldy = newy; // remember new positionshow_ball(); // “redraw” the new ball--count; // decrement a counter}while ( count > 0 );• Ball-movement is managed by ‘signal-handler’‘draw’ versus ‘move’The code in this signal-handler takes care of all movementswhenever it’s time for themto occurThe code in thisloop handlesall the actual re-drawing in sync with thevertical retraceSignal-handlerProgram-loopThe Operating System takes care of switching the CPU between these two separate threads-of-controlGiving the user control•Linux supports “asynchronous” terminal i/o•We can reprogram the terminal console so a SIGIO signal will be sent to our program whenever the user decides to press a key•And we can install a ‘signal-handler’ of our own design that executes if SIGIO arrives •This will allow a user to “control” our gameThe ‘tty’ interface•‘tty’ is an acronyn for ‘TeleTYpe’ terminal•Such devices have a keyboard and screen•Behavior emulates technology from 1950s•Usually a tty operates in ‘canonical’ mode:–Each user-keystroke is ‘echoed’ to screen–Some editing is allowed (e.g., backspace)–The keyboard-input is internally buffered–The <ENTER>-key signals an ‘end-of-line’ –Programs receive input one-line-at-a-time‘tty’ customization•Sometimes canonical mode isn’t suitable (an example: animated computer games)•The terminal’s behavior can be modified!•UNIX provides a convenient interface:–#include <termios.h>–struct termios tty;–int tcgetattr( int fd, struct termios *tty );–int tcsetattr( int fd, int flag, struct termios *tty );How does the ‘tty’ work?TeleTYpe display deviceHARDWARESOFTWAREapplicationtty_driverc_lflaginput handlingc_iflagc_ccoutput handlingc_oflagterminal_driverc_cflagUser spaceKernel spacestruct tty { c_iflag; c_oflag; c_cflag; c_lflag; c_line; c_cc[ ]; };The ‘c_lflag’ field•This field is just an array of flag bits•Individual bits have symbolic names•Names conform to a POSIX standard•Linux names match other UNIX’s names•Though actual symbol values may differ•Your C/C++ program should use:#include <termios.h>for portability to other UNIX environmentsICANON and ECHO•Normally the ‘c_lflag’ field has these set•They can be cleared using bitwise logic:tty.c_lflag &= ~ECHO; // inhibit echotty.c_lflag &= ~ICANON; // no bufferingThe ‘c_cc[ ]’ array•‘struct termios’ objects include an array•The array-indices have symbolic names•Symbol-names are standardized in UNIX•Array entries are ‘tty’ operating parameters•Two useful ones for our purposes are:tty.c_cc[ VMIN ] and tty.c_cc[ VTIME ]How to setup ‘raw’ terminal-mode•Step 1: Use ‘tcgetattr()’ to get a copy of the current tty’s ‘struct termios’ settings•Step 2: Make a working copy of that object•Step 3: Modify its flags and control-codes•Step 4: Use ‘tcsetattr()’ to install changes•Step 5: Perform desired ‘raw’ mode input•Step 6: Use ‘tcsetattr()’ to restore the terminal to its original default settings‘raw’ mode needs four changes•tty.c_cc[ VMIN ] = 1;–so the ‘read()’ function will return as soon as at least one new input-character is available•tty.c_cc[ VTIME ] = 0;–so there will be no time-delay after each new key pressed until the ‘read()’ function returns•tty.c_lflag &= ~ECHO; // no echoing•tty.c_lflag &= ~ICANON; // no bufferingDemo program: ‘rawtty.cpp’•This program may soon prove useful•It shows the keyboard scancode values•It demonstrates ‘noncanonical’ tty mode•It clears the ISIG bit (in ‘c_lflags’ field)•This prevents <CONTROL>-C from being used to
View Full Document