home *** CD-ROM | disk | FTP | other *** search
Text File | 1997-01-21 | 6.7 KB | 237 lines | [TEXT/PJMM] |
- {Event processing speed test}
- {By Ingemar Ragnemalm 1997}
-
- {Many game programmers claim that you should not process events at all, not even with GetOSEvent,}
- {because it is too slow. Others claim that you should always use WaitNextEvent no matter what.}
- {}
- {I say that both are wrong. GetOSEvent is very fast. WaitNextEvent is not, not even when quitting all}
- {other applications except Finder, and quitting the Finder is no good habit IMHO. Reading the keyboard}
- {with GetKeys is fast, but hopelessly incompatible with other keyboard layouts than your own. There}
- {is a workaround, but few use it.}
- {}
- {This application is an experiment, to find out the truth. You can select any of four methods,}
- {GetNextEvent, WaitNextEvent( with a sleep time of zero), GetOSEvent and None (which uses Button}
- {and GetKeys).}
- {}
- {In my experiments, GetOSEvent had no significant disadvantage to Button/GetKeys. It even was}
- {a fair bit faster in many tests! Feel free to draw conclusions, and to hunt down any mistakes I may}
- {have made. This was a quick hack, and sure I may have overlooked something – but I kind of doubt it.}
-
- program EventSpeed;
- uses
- {$ifc UNDEFINED THINK_PASCAL}
- Types, QuickDraw, Events, Windows, Dialogs, Fonts, DiskInit, TextEdit, Traps,{}
- Memory, SegLoad, Scrap, ToolUtils, OSUtils, Menus, Resources, StandardFile,{}
- GestaltEqu, Files, Errors, Devices, QuickDrawText,
- {$elsec}
- InterfacesUI,
- {$endc}
- MyFakeAlert;
-
- var
- myEvent: EventRecord;
- w, whichWindow: WindowPtr;
- appleMenu, fileMenu: MenuHandle;
- gDone: Boolean;
-
- eventMode: Integer;
-
- const
- useGNE = 1;
- useWNE = 2;
- useGOE = 3;
- useNone = 4;
-
- procedure SynchMenus;
- begin
- CheckItem(fileMenu, useGNE, eventMode = useGNE);
- CheckItem(fileMenu, useWNE, eventMode = useWNE);
- CheckItem(fileMenu, useGOE, eventMode = useGOE);
- CheckItem(fileMenu, useNone, eventMode = useNone);
- end; {SynchMenus}
-
- procedure SetupMenus;
- begin
- appleMenu := NewMenu(128, stringof(char($14)));
- AppendMenu(appleMenu, 'About Event processing speed test…;(-');
- AppendResMenu(appleMenu, 'DRVR');
- InsertMenu(appleMenu, 0); { put apple menu at end of menu bar }
-
- fileMenu := NewMenu(129, 'File');
- AppendMenu(fileMenu, 'GetNextEvent/G;WaitNextEvent/W;GetOSEvent/O;None/N;(-;Quit/Q');
- InsertMenu(fileMenu, 0); { put file menu at end of menu bar }
- DrawMenuBar;
- SynchMenus;
- end; {SetupMenus}
-
- procedure MenuSelection (theSelection: Longint);
- var
- name: Str255;
- saveport: GrafPtr;
- begin
- case HiWord(theSelection) of
- 128:
- begin
- if LoWord(theSelection) = 1 then
- ReportStr('Experimental program. Why are game programmers so scared of GetOSEvent?')
- else
- begin
- GetPort(saveport);
- GetMenuItemText(appleMenu, 1, name); (* get name *)
- if OpenDeskAcc(name) = 0 then (* run the desk accessory *)
- ;
- SetPort(saveport);
- end;
- end;
- 129:
- case LoWord(theSelection) of
- useGNE, useWNE, useGOE, useNone:
- eventMode := LoWord(theSelection);
- otherwise
- gDone := true;
- end; {case MenuSelect}
- otherwise
- end;
- SynchMenus;
- HiLiteMenu(0);
- end; {MenuSelection}
-
- procedure HandleEvents;
- var
- hasEvent: Boolean;
- theKey: Char;
- whichPart: Integer;
- theSelection: Longint;
- myKeyMap: KeyMap;
- begin
- case eventMode of
- useGNE:
- begin
- {GetNextEvent is the old event processing method.}
- SystemTask;
- hasEvent := GetNextEvent(everyEvent, myEvent);
- end;
- useWNE:
- {WaitNextEvent is the new event processing method, recommended by Apple.}
- {The wait time is set to zero to get maximum performance (which also means that it is very unfriendly to}
- {other processes). It should NOT use zero if switched to the background - if it processes background events}
- {at all!}
- hasEvent := WaitNextEvent(everyEvent, myEvent, 0, nil);
- useGOE:
- {GetOSEvent is an low-level event processing method that doesn't give time to other processes at all.}
- {It is therefore very fast, but many newbie game programmers don't dare using it anyway. I think they should.}
- hasEvent := GetOSEvent(everyEvent, myEvent); {or perhaps mDownMask + updateMask + keyDownMask}
- useNone:
- begin
- hasEvent := false;
- {When Button is down, get an event the usual way. This means that menus are suppirted, but command-key}
- {equivalents are not. Button and GetKeys is what many games use.}
- if Button then
- hasEvent := WaitNextEvent(everyEvent, myEvent, 0, nil)
- else
- begin
- GetKeys(myKeyMap);
- if myKeyMap[12] and myKeyMap[55] then
- gDone := true; {Command-Q?}
- {Here we could find if command-Q is pressed etc. Rather tedious compared to doing it with events, and}
- {you can't be sure that all keyboards follow your layout! (Most special keys don't, like "+" and "-".)}
- {If you must use GetKeys, you should use KeyTrans/KeyTranslate.}
- end;
- end;
- otherwise
- begin
- SysBeep(1);
- hasEvent := WaitNextEvent(everyEvent, myEvent, 0, nil);
- end;
- end; {case}
-
- if hasEvent then
- case myEvent.what of
- updateEvt:
- if WindowPtr(myEvent.message) = w then
- begin
- BeginUpdate(w);
- {Draw here!}
- PaintRect(w^.portRect);
- EndUpdate(w);
- end;
- keyDown:
- begin
- theKey := char(BitAnd(myEvent.message, charCodeMask));
- if (BitAnd(myEvent.modifiers, cmdKey) <> 0) then
- MenuSelection(MenuKey(theKey))
- else
- {DoKey(theKey, theEvent.modifiers)}
- ;
- end;
- mouseDown:
- begin
- whichPart := FindWindow(myEvent.where, whichWindow);
- case whichPart of
- inMenuBar:
- begin
- theSelection := MenuSelect(myEvent.where);
- MenuSelection(theSelection);
- end;
- inSysWindow:
- SystemClick(myEvent, whichWindow);
- inContent:
- begin
- end;
- otherwise
- end; {case whichPart}
- end;
-
- otherwise
- end;{case myEvent.what}
- end; {HandleEvents}
-
- var
- i, j: Integer;
- pat: PixPatHandle;
- numLoops: Longint;
- startTicks: Longint;
- drawRect: Rect;
-
- begin
- {CodeWarrior needs inits here}
- {$IFC UNDEFINED THINK_PASCAL}
- { Initialize all the needed managers. }
- InitGraf(@qd.thePort);
- InitFonts;
- InitWindows;
- InitMenus;
- TEInit;
- InitDialogs(nil);
- MaxApplZone;
- {$ENDC}
-
- w := GetNewCWindow(128, nil, WindowPtr(-1));
- pat := GetPixPat(128);
- SetPort(w);
- PenPixPat(pat);
-
- eventMode := useGNE;
- SetupMenus;
-
- InitCursor;
-
- numLoops := 0;
- SetRect(drawRect, 0, 0, 150, 30);
- startTicks := TickCount;
- repeat
- HandleEvents;
- numLoops := numLoops + 1;
-
- {After 60 ticks have passed, print out the number of loops!}
- if startTicks + 60 <= TickCount then
- begin
- EraseRect(drawRect);
- MoveTo(4, 20);
- DrawString(StringOf(numLoops : 1, ' loops/sec'));
- startTicks := TickCount;
- numLoops := 0;
- end;
-
- until gDone;
- end.