---
title: WWDC2001 Session 109
framework: wwdc
role: article
path: wwdc/wwdc2001-109
---

# WWDC2001 Session 109

## Transcript

Kind: captions Language: en welcome good crowd today so that's me I work in DTS and today we're going to be talking about a number of Mac OS 10 solutions for graphics for games rather than go through kind of a dry boring you know line-by-line overview the API we're going to cover some particular topics that are of interest to game developers both some traditional problems and some things you might want to think about as you're moving to Mac OS 10 we're gonna talk about display management that's always a big problem how to change the screen resolution how to change the bit-depth refresh rate those kinds of things we're going to talk about mixing core graphics with quick-draw some of you may be full screen apps maybe not but some apps may want to start using some of the core graphics api's perhaps to draw some eddie alias text or some other things like that some of the advanced path features we'll talk about how to mix that with some existing quick-draw code I'm gonna cover a few quick-draw tidbits some other things about differences with quick-draw on Mac OS 10 versus Mac OS 9 another topic tear-free bleeding we're going to talk about what you can and can't do on Mac OS 10 and how to improve that and some changes to OpenGL OpenGL is a little bit different mostly we've added a bunch of new features for 10 and then we're also going to cover probably in more detail in some of the other sessions because this is the first one we're going to cover the games roadmap for WWC this year with that in mind we're not gonna really be covering much about quick-draw I'm assuming you either know what you need to know or you can find it we're not going to cover QuickTime in detail there's some other sessions on that I'm also not going to go through a general introduction to core graphics there are a number of other sessions at this conference for that and there are four more opengl sessions so i'm not really going to cover much beyond some real basic Mac OS 10 stuff for that so let's get into the display management as many of you know Duras brockett's been around for a while it works great on Mac OS 9 we've included it in Mac OS 10 it's available for you to use we've primarily put it in there for easy pouring the number of you have existing apps existing games that already used the draw sprocket API and we've got it in Mac OS 10 so you can bring that code over almost directly it is callable from CFM and mock oh so you don't have to worry about going through CF bundle api's or anything like that to get to it from CFM one thing that is a bit different though for some of you that we're used to putting up a window on top of draw sprocket to just draw into that window to do your graphics on Mac OS 10 you can't bring the window up on top of draw sprocket anymore so if you had been bringing a window up now you just need to get the front buffer and draw straight into that it's a pretty standard see graph pointer not too hard to do another thing is we've removed some API is like the user select context which used to let the user select the display so all of the gooey stuff is pretty much gone out of drawer sprocket now the new API on Mac os10 for doing display management is called CG direct display and that's part of core graphics you'll find it in under the application services umbrella framework and it lets you do a number of different things that you would expect you can enumerate displays you can enumerate the available video modes for a given display you can capture displays so that you'd control them completely you can switch the video modes on those displays and you can also if you really need to get access to screen memory directly and I'll show you some code on how to do all of these things so first of all the numerating displays you have an array of dissed by DS of you know you say you want to cover at least say eight displays or so you get the active display list so it gives you a list of the display IDs for each display that's active on the system and it also returns you the actual number of displays you found if you didn't get an error you can then iterate through that array and look at each display in turn once you get a display ID what can you do with it well you can find out a few things about it as well you can find out pixels wide pixel high those kinds of things find out the number of bytes per row always very useful once you've captured a display you can also get the base address this is the direct access I was talking about before but it's important to note this is only valid for a captured this boy once you've captured it the window server pretty much gives you control over it until you release it once you release it you can't draw directly to its bits anymore so keep that in mind you can also once you get a given display ID you can ask it what the available modes are so when you get ready to switch you want to find out what modes does it support CG display available modes will return you a CF array ref and then provide that that's not null you can find out the number of modes that the display supports and then loop through each of those modes that array is actually an array of CF dictionaries and each Dictionary describes one of the available modes so what can we do with a mode dictionary glad you asked for each mode you can get a number of different values the CG director spoi header CD direct display H describes in fairer detail what you can get out of that dictionary some things you can find out whether that mode is actually usable for aqua as you know aqua doesn't like to run in 640x480 doesn't like to run an 8-bit this will tell you whether or not that display mode supports aqua and here we just set a string you can also get pretty much any particular key the keys are listed mat header and find out the numeric value so you can find out refresh rate you can find out bit depth with those kinds of things once you've gone through your modes that are available for a given display presumably you pick one say you need 1024 by 768 by 16 bit you found the mode that identifies the one you want now we need to switch to it well in order to be able to switch back easily you can get the current display mode see and that gives you a dictionary ref that you can use to restore the mode later then you capture the display and once you've captured it you've got control over it as I mentioned then you can switch to whatever best mode you've decided you want to use you can also hide the cursor now the ordering of these three captures switch and hide the cursor is somewhat important if you switch the mode before you capture then the other apps in the system get a chance to notice that you've changed the display and if you remember draw sprocket on nine and some of the other mode changing API is things like finder icons used to move around to those kinds of things if you capture the display first then nobody notices things should move around on you at all and hiding the cursor is just whether you want the curse was still visible during all this some people may want to hide it then capture them switch and once you've gotten all this done you've got the dist way to yourself and your game code here if you need to get a see graph pointer to do quick draw operations you want to copy bits to this display whatever you can use an API create a new port for cg display ID this api is actually in the quick-draw header so don't go looking for it in the core graphics editor you won't find it and if you do create a port this way don't forget to call dispose port when you're done because as create might employ it does create a new one and you're responsible for releasing it once you're done with your game you need to shut down and you pretty much reverse the order the operations that we did earlier you put the cursor back you switch back to the original mode on that display and then you release the display to give it back to the system pretty straightforward stuff so now I'd like to show you a quick demo these are actually some little demos written by one of our core graphics engineers but they illustrate the point pretty well the first one is mode this is already up on our sample code website and all it does is use some of the code we've described to go out and simply ask what display is available what modes does it support as you can see here currently we're running 1024 by 768 by 32 bits 30 Hertz and it supports a number of different things and this is also listing for you whether or not that particular mode supports aqua or not so this is a good piece of code to look at especially if you're not too familiar with arrey ref and see if dictionary ref and how to manipulate those this code has a very nice simple structure to go through those that's one nice for the one and then to give you a brief example of drawing directly to the screen this one called color bars it shows you how to just draw straight to that base address very simple little demo and here we're just capturing this display switching it into a mode drawing some and switching back nothing too complicated there so moving back to the slides and as I mentioned both of those demos are already up on the sample code side if you'd like to go take a look at them so along with this point management comes palette manipulation and gamma tables and for this you combine the cg direct palette AP on a CG direct display API if you want to be able to create palette to manipulate them switch palettes and also many Pro at the gamma tables I'll give a display so creating palettes has a number of different options you can create a default one you can create it for a given display with a given capacity with some samples you already provide and I believe those are float samples and there's also one for convenience function you can create it directly with bite samples and then of course you have to release those once you're done with them with CG palette release for manipulating them you can get a particular color you can get the index for a given color you can set the color to a particular index you can compare palettes directly you can also create a new palette from an old pallet blended with a color so some nice little facilities there to make pallet manipulation a little bit easier and then of course you can ask a display whether you can set the pallet for that display and then you can actually set it if it says you can some displays may not support palettes at all for Gama there's a few API is here for setting the transfer functions and there's two ways to do it in this API either by a formula which is how a few parameters or by a table the values so if you happen to have your whole gamma specified in a table you can very easily call set display transfer by table we also have a convenience function to do it with bytes so you can either use bytes or floats you can also get the transfer back and you can do it by formula as well with these safety eyes we've got a quick little demo here this one has not been posted yet but it should be soon after and this is actually a direct port of an old sample called Mac gamma some of you may have seen that demo before it just runs through and starts using those API is to mess with the gamma it's a good demo install it on your friends machine and then hide it and leave it running okay so more slides so that's a little bit about display management the basic capabilities are there you can get the different displays find out what modes they support switch to modes manipulate those many people like palettes and gammas all of that facility is there for you now if you already have some quick dart code you already do a lot of quick draw drawing in your game but you want to start adding a little bit of CD code to your game how do you go about doing that first of all we're going to talk about if you've already got a quick-draw report say you've used carbon create your window you've got a window you can get the window port now you want to draw CG into that window there's some pretty easy code to use to get the core graphics context and start drawing one thing you need to watch out for the coordinate systems are a little different I'll talk about the differences in the coordinate systems and what you need to watch out for talk about some things that are also a little different with pixel addressing and then we'll get into covering a little bit of clipping and how clipping in core graphics differs from quick-draw so to create a CG context for a given port very simple there's one call create CGG context report you pass as a port pointed to a context ref couldn't be simpler do your cg drawing don't forget to release the context that you created when you're done but once you've got that context how does a coordinate system differ in quick-draw as many of you probably where the coordinate system the origin is in the upper left hand corner positive X goes right positive Y goes down well for PostScript PDF and of course core graphics which is based on the PDF imaging model the origin is the bottom left the positive y-axis points up and unlike quick-draw where you're pretty much always working with a port you can always get the port wrecked find out what the bounds are width and Heights and everything core graphics doesn't really have a concept of a bounds of a context and that's partly because it's supposed to be very device independent but also because once you start applying transforms and bangs it gets a little weird how do you define a rectangular bounds so pretty in particularly when you're working with a window context or if you create an off-screen context which I'll talk about in a little bit you know what the bounds are already so you pretty much just have to remember those who can't get them directly from the context itself so if the coordinates are different what can you do about it well the easiest thing is with a few simple calls and core graphics you can actually change the core graphics context coordinate system to match that a quick draw and for people that are used to thinking in nice simple quick draw coordinates this is probably the easiest way to go and as I mentioned you need to remember the bounds from the port or the view that you got it from so the first call to gsync context with origin tgc context origin with port excuse me that simply makes sure that if you've called set origin in your port in your quick report to move the origin around this will sync up the cg context origin with that change then you call translate to move the origin from the bottom left to the upper left and then you call scale to flip the y-axis of the positive Y points down so we got a little bit of code to do just that in this first part we create our context again we call sink origin with port so we've got our port in a context ref then we translate by the port height and it's positive port height because you're positive in terms of core graphics coordinate system right now and then minus one on the y-axis for the scale we leave the x-axis alone so that moves the origin up and flips the y-axis down one thing to note here and you'll probably run into this the first time you go through this I certainly hit it this does make the coordinate systems match and so you can start thinking in terms of quick draw coordinates again but when you start using CG to draw text the text draws upside down because the text honor is that translation matrix that we've been manipulating there and as soon as we scale it by -1 on the Y quarks is okay I'll try to play down no problem which is something you never could really do in quick-draw it's one nice feature so and you can also rotate text too so that's also very nice I hope you managed to get to some of the core graphics sessions so the CTM thing I mentioned it on this previous slide you see translate CTM scale CTM what is that thing that's the current transform matrix and you can do a number of fun things with that you can do basic translations you can do scales as we've already seen you can also do rotations which is very nice and you can do SKUs which are pretty much just arbitrary affine transforms so what are those primitives look like when you actually use them again we get our context then scale is simply you take a scale on the X and a scale on the y axis and those are floating-point numbers so you can scale by fractional scales as you saw before one pretty much means don't change that axis minus 1 means flip it upside down or left/right translate much the same you take a translate on the X and a translate on the Y moves your origin around rotation again very simple very straight forward angle in radians that rotates the CG context around at the current origin and then if you define an affine transform you can just concatenate that with the current transform so this is where you start getting into SKUs and other things so what does that all look like wrote a simple little app here to show you what you can do with transforms oh yeah that's right have to tell it picture globe so here we have a little rocket ship courtesy of Jeff Stahl and as you can see down here this is just calling draw graphic I have a little routine that draws graphic at the origin doesn't do anything exciting but using scaling over here using translation oh and these are all rotated a little bit so it's a little more interesting you can do some basic scaling and translation and then this confined mostly rotation and translation good little rocket ship to fly around in a figure 8 and in each of these cases I'm simply manipulating the transform matrix tweaking it a little bit doing a translation doing a rotation and then calling that one function and that function never changes to draw the graphic so as far as its concerned it's always drawing the rocket at the origin and it's always drawing it on the straight up the y-axis it doesn't have to care the transform matrix and all the CG operations take care of manipulating the pixels make things a little more interesting and this sample code will be posting pretty soon after WWC as well alright so as I mentioned in the beginning pixel addressing is a little bit different because core graphic context who try to abstract out away from the device some context and don't have the concept of a pixel really if you're printing you can sometimes get to the pixel sometimes not depending on if you're going to a postscript or raster printer if you're actually going to a PDF file for example you know they make a big deal out of being able to write out PDF files from just about anything you can actually have a context that represents a PDF document and you can draw a seating and draw a CG context calls into that context and it goes out into the PDF file well there's no pixels that you can get to behind that context so if you want to be able to say do some CG drawing and then get at the bits after that what do you do well there's a thing called CG bitmap context create that as you might imagine creates a bitmap context and you get to specify all of the parameters for this bitmap you can say what the data pointer is to initialize it with some data or you can pass no and it'll allocate the data blank for you you pass it with and hide the bits per component the color space you define essentially how each pixel is represented and this gives you a bitmap that you can then use CG calls and draw into but you can also get to the bits directly so this is what it looks like did your bitmap context create instead of just doing the crate for the port we do a bitmap context pass it in your initialization data a width and height bits per component to Co space then alpha info tells it whether there's an alpha at the beginning and alpha at the end no alpha at all those kinds of things and at this point you can just proceed with your normal core graphics operations just like it's any other context or as I mentioned you can access the bits because you still know where the data pointer is you still know where the bits are so you can go both ways there now I mentioned that clipping was also different when you use that code that I've showed you before to go from a port to a CG context there are some things that the context doesn't inherit in fact it inherits a very little of the quick-draw State clipping is one of them if you're using clip regions in your quick-draw port and you create a CG context and you start drawing with CG drawing commands it's going to draw all over everything it's going to ignore the quick-draw clip region so what do we do about that well this straightforward way you grab the clip region from the sea graph port and then you call this new call clip CG context a region and that simply takes the region you give it from quick-draw and actually turns that into a CG clip path this was a little bit more complicated so again we create our port and now we want to make the clip match this is an important step that new region when I tried to do this demo the first time I forgot that and it didn't work very well let's just leave it at that so you create a new region an empty region you also need the bounds and then you get the port clip region and you clip the CG context to region so a couple of simple steps and then you're also you're done with the region so you can dispose up at that point and at this point your CG context clip path matches the region that you had and quick-draw so let's do a quick little demo of that one same little rocketship it's into the same demo except in this case before I started I set a clip or set the clip reagent and quick-draw to a couple of ovals kind of ex-ored together and of course quick-draw would honor that by default but once you create the context and start drawing these cg context images into that they're not going to honor it so you use this code that I've shown you pass in this clip region to CG and it turns it into a clip path and just does the right thing and incidentally it also Clips because I clip before the the erase of the back buffer to black so it Clips ID as well okay so there are a few things about quick-draw on 10 they're a little different than online one interesting thing you need to be a little bit of wary of this crate Newport which you use create a new graph board at the moment the pointer points to the screen and some people have already been using that to start drawing directly to the screen not a good plan it may or may not always point to the screen don't count on that that's kind of undocumented behavior and you shouldn't really rely on that another thing to note is that in the past especially for things where you were using copy mask or seed and fill and things like that you needed a graph port and you need essentially one bit buffer to hold the mask you used open port and create port or a new port excuse me well those have been replaced by create new port but create new port can't create black and white craft boards it only creates sea graph ports and so if you're going to actually be using those routines and you're porting your code to carbon you need to be aware of that and instead you can actually use yugi world and create a 1-bit deep g world all of the API is that were designed originally to use graph ports are now aware of this and they will actually take one bit deep G world another thing that's different about quick-draw is because of the double buffered Windows and Mac os10 you need this little thing called QD flush port buffer and for the most part you may or may not run into this depending on how you do your event loop but if you're used to not calling wit next event you know your game likes to take over the whole machine and you start doing quick draw drawing in a loop you may find that your animation never appears on the screen and you scratch your head for a while well it turns out if you're not calling wait next event which is when an implicit flush of the back buffer occurs you need to call QD flush port buffer and that will actually tell the window system to flush the back buffer to the screen and so if you're in a tight little loop doing some animation or whatever you need to call that another I guess bonus of QD flush port buffer is when it comes to VBL synching I'll talk about this in a little bit but QD flush port buffers also VBL synched where it's possible it's not possible so that leads us directly into tear-free bleeding a good goal and for most of you out there we've got you covered open geo itself can sink to the BBL and in fact that's one of the best ways to do it because it's the card itself doing the BBL sinking and there's one quick call AGL set integer on the context except the swap interval to one and that will take care of telling up a GL that you'd really like it - only swap one the vertical blank so for all of you fullscreen open GL apps out there there you go now for those of you that are doing windowed apps you can use the back buffer this is also an important point we already provide a back buffer so if you're doing your own double buffering system you're going to be triple buffering and that'll be a big performance hit on Mac OS 10 so you might want to take a look and use our back buffer instead of your own off screen so use our back buffer and also when you flush the back buffer for the window to the screen using QD flush port buffer or if you're using the cg context there's a cg context flush that's essentially the same thing we flush that sink to the BBL for you when it's actually supported by the hardware on the machine so you can use that to get good tear free bleeding so along the lines of tear free bleeding some other things to watch out for since Mac OS 10 is a fully pre-emptive OS you don't always have control of the whole machine you'd always have control of when you get swapped in and out so if you try to do direct screen access which you can do with the cg directors play API it's gonna be very hard to sync to the BBL because the scheduler is always trying to balance things and swap things in and out to make sure everybody has time you may be halfway through drawing to the screen and get swapped out so way things go so that makes it very difficult so if possible let let us do the video syncing for you we've got the best chance of making it happen on the given hardware and we can do it easily so use the a geo set integer or use the actual flushing of window buffers let us do the sinking for you it's got a couple of quick demos of this give you a peek at what no VBL sinking looks like it actually tears pretty bad on my machine here that tears every now and then let's see if it'll do it for us it's actually not bad Figgy so demo works better than its supposed to oh wait nice alright there it goes that's better no respect that's what tearing looks like for those of you that have never seen VBA tearing so now if we actually use the QD flush port buffer we can sing to the BBL right not exactly and that's one of the things I was initially very disappointed that this demo didn't work when I got here because I had this all planned gone to the work to make it sink very nicely made sure that we could get nice smooth animation no tearing good in the demo room it doesn't work great what am I gonna do well it turns out this brings up a very interesting point you can't always sink to the BBL no matter how much you want to some hardware it's just not possible in this case there's who knows what kind of video switching equipment and everything else between the computer and the display so you may not even be able to find out what the refresh rate is or anything so it's amazing it works as well as it does there's also in general hardware is moving in the direction of not having a concept of a vertical blank anyway on some high-speed display or digital displays there's no real concept of a beam position anyway it's there's nothing to sync to now some displays the vertical blank is essentially very very tiny or non-existent and be aware that no matter how much you want to sink to the VBL no matter how much you want the demo to work it may not ah so let's talk a little bit about a few OpenGL changes many of you are using OpenGL got some great games out there using OpenGL OpenGL and Mac OS 10 rocks good performance but there are a few differences and you need to be aware of and we'll also talk a little bit about how it's different with respect to using it with draw sprocket on Mac OS 9 there were some things you had to do when you wanted to use opengl fullscreen withdraw sprocket and that's a little bit different now so a few important differences Ajo fullscreen works that's a big one in the past on Mac OS 9 Ajo fullscreen wasn't there on Mac OS 10 you can call a GL fullscreen I believe you can pass it even the resolution you want the bit depth and it does all the work for you very good way to get into full screen mode and OpenGL a hurry OpenGL does all the heavy lifting for you we've also added a few new features we have support percent stencil buffers and aux buffers I'd like to point out stencil buffers in particular there's an OpenGL talk coming up Thursday morning I believe an advanced rendering techniques and in that one Troy Dawson will be talking about how to do dynamic shadows with stencil buffers so that's pretty cool he's also got a few other cool demos in there as well so that's a good talk to go to and I'll point you to that once we get to the end of the talk and then there's some new extensions we've support packed pixels now and a few other good things so for more information on those things go to the opengl sessions and they'll give you some more information another thing to note is OpenGL is fully supported you can call it from carbon and cocoa from carbon you can use all the AGL api's from cocoa there's actually some very good classes for NS OpenGL there's NS OpenGL View which makes it very easy to bring an open view into your window and get all the information set up for OpenGL and then start making OpenGL calls a few more differences Ajo update context is more critical you need to call it when you make changes to the contexts that OpenGL knows what's going on and I think in some cases you could get away with not calling it everywhere on Mac OS 9 but on 10 it's much more critical you need to call it and also HL set drawable a number of people could get away with calling a geo set drawable just passing in the window pointer because on Mac OS 9 window Porter was pretty much the same as I see grep pointer well Mac OS 10 they're not the same thing and if you've got a window ref on Mac OS 10 from a carbon window you need to make sure you call get window port and pass that port to set drawable otherwise it's not going to do what you expect so how do we make this play with draw sprocket well a mac os9 when you wanted to be able to get hardware acceleration multiple monitors to be able to support all those things typically what you would do is you would create a window on top of draw sprocket as I mentioned earlier just create a full screen window others black nobody would know the difference and you'd actually pass that off to set drawable and that would make sure took care of multiple monitors hardware acceleration all the good things on that goes 10 you don't need to do that anymore and in fact you can't because once you've taken over the screen with draw sprocket it's the topmost window so you can't put a window up on top of it so what you need to do now is call this DSP context to get front buffer and that will return you a see graph pointer and that's the graph pointer you can actually pass to a jail set drawable so that'll get you OpenGL draw sprocket everything now one thing to note since a Gio full screen works you may or may not have to do this anymore you should revisit your code and see if you really need to do use draw sprocket anymore so a quick summary before we get into more discussion of the road map use draw sprocket or CG direct display they're great the api's are there for you to manipulate the displays capture the displays as I mentioned CG direct display takes care of making sure that your finder icons don't move around on you when you change resolutions and those kinds of things also if you've gotten quick-draw drawing that you're already doing you can start mixing in some poor graphics so for some of the games that you know don't take over the screen just do OpenGL you can start mixing in some core graphics to do some nice arcs and antialiased drawing and antialiased text and the nice current transform matrix manipulations another important thing to take out of here is Mac os10 double buffer so you don't have to so if you're already doing a bunch of work to double buffer your drawing we've got that covered for you every Windows double buffered when you draw into the window port you're actually drawing into the back buffer which also means don't forget to call flush make sure you call CG flush port buffer or if your drawing and a quick draw make sure you call cutie flush port buffer also watch out for some of those minor quick draw changes did I mentioned before and OpenGL and Mac OS 10 it's there it works at rocks use it so let's take a look at all of the games related sessions that are coming up this week we're already into Tuesday afternoon but there's a few other sessions on that 17th session track that I'm not gonna call out I'm just gonna hit some of the highlights here OpenGL for very good OpenGL talks coming up tomorrow afternoon and Thursday morning you might want to look into those high performance 2d it's going to show you how to do some multi texturing of large images and scrolling of images and things for 2d with the techniques that Jeff's going to present you could put together a really cool side scroller actually scroll all over the place in both directions right after that in the same room we're gonna cover a geometry and modeling Todd is going to take you through how to go a little bit beyond that little spinning square demo that we have in a lot of our sample apps to some more advanced modeling and animation then Friday morning right now Thursday morning excuse me John Stauffer is going to cover some optimization techniques and how to get more performance out of your OpenGL code and how to speed things up and also talk about some other interesting aspects of OpenGL performance and then right after that Thursday morning we have advanced rendering as I mentioned we're going to cover some stencil buffer techniques also going to cover bump mapping and cubic environment mapping and I forget what the fourth one is but good stuff all four of those are good if you have some feedback for us as far as OpenGL goes and the work we're doing Thursday at 5:00 come to the feedback forum make sure you come and give us your feedback but wait there's more so input for games Friday at 10:30 the morning just going to be talking about input for games as many of you know input sprocket is not on Mac OS 10 but we're gonna be talking about hidden which is the input sprocket replacement and then following that afternoon we're gonna cover sound and networking so we'll be talking a little bit about the carbon sound manager about QuickTime also some about core audio and some things you can do with it and then get into some open transport open play things like that and another feedback forum Friday at 5:00 if you have some feedback for us as far as games related technologies and things like that please come to the feedback session Friday at 5:00 and so who to contact if you have contact information we will have questions send it to DTS at apple.com we'll be glad to help you out you
