Re: [Alephmodular-devel] Platform-independence structure (was: Developer Rant #1 :) )
Status: Pre-Alpha
Brought to you by:
brefin
From: Woody Z. I. <woo...@sb...> - 2003-01-15 02:36:03
|
All right talked to death yes; my hope is that this message does a little forward-looking as well as back- (trying to swing the previous discussion around somewhat into more immediately helpful stuff). On Tuesday, January 14, 2003, at 06:10 PM, Mark Levin wrote: > There should be no "preferred" branch. There is high-level game code > which should be 100% platform agnostic and low-level platform code > which is necessarily restricted to 1 platform. I disagree about the lack of a "preferred" branch, but you know that. I also disagree on the latter part though - a good, practical decomposition would not have only two levels like this. Maybe I haven't been clear on this whole SDL thing. Yes, there would be high-level game code that is totally platform-independent. Yes, it would interact with lower-level code through some well-defined interface. But that lower-level code is *not* necessarily separate for every platform. Indeed, an SDL-based software renderer, or sound system, could serve many different specific platforms, just as stdio- or fstreams- or whatever-based file I/O could serve many different specific platforms. So maybe (almost) all platforms use stdio for saving/loading data from disk, but they have different locations to place and search for those files. And if some of them support mmap()-type functionality and some don't, then those that do are free to use it instead of stdio. But the baseline, the first effort at writing this lower-level code in the new modular format, should use methods that are as portable as possible, and should resort to platform-specificity only when there are significant gains to doing so. Well I say the first effort, but I guess I don't really mean that - the first effort _could_ be Mac OS only, as long as that code knows it's doomed, and is, in fact, replaced to the greatest degree possible with more portable code when the latter arrives (which I would hope would be very shortly thereafter). From my point of view one of the major problems with A1 currently is that there are often two versions of the same thing "in parallel", when the cross-platform case *could* completely replace the Mac OS-specific version. >> (Of course this is essentially the same argument as for using standard >> library calls and SDL instead of Mac OS calls whenever possible, >> though they are different issues. Shared code, not separate >> branches. Shared code, not separate branches!!) > > Of course, the flip side of that is, what if we *do* want to take > advantage of features only available on 1 platform? Clearly, when it's advantageous to use a more platform-specific interface for doing something, the platform-specific code simply overrides the generic implementation. > There was an enormous argument on the A1 list over whether plain XML or > Apple's property list format should be used for the preferences file, > the primary arguments being the former was cross-platform and the > latter was much easier on a Mac. If the preferences code was properly > modular, it would have been possible to write a MacOS-specific plist > loader and an XML loader for everything else. This would have been a Bad Thing (serves no function except to complicate the code and encourage platform differences), but I understand you're using it merely as an example. > And what if we want to use something like Quicktime, which is probably > far more powerful than SDL's media handlers? You might be surprised at how much SDL_image and SDL_mixer can do. But if platforms with QuickTime want to use QuickTime (e.g. for video content, if no suitable widely-available alternative can be found), there's no problem with that. But the initial, basic implementation should be one that is as widely-applicable as possible. The Windows and Mac OS versions can *then* choose to override the baseline with QuickTime-based routines if they see fit. If there's functionality that really isn't already available in a cross-platform package somewhere (like sound input, to my knowledge), then we have to go through the whole 9 yards of writing a different implementation for every platform. But that should be the exception, not the norm. (Especially when C/C++ standard library authors, SDL authors, etc. have *already* done all the work of writing a different implementation for every platform and giving them all the same interface!) > As for the specific example, I think the cut would be in the > implementation of *get*_control_value. I think we agree (though I'm not sure of the significance of the *'s around get). The high-level game code says "Ok, user clicked Gather Network Game, so let's handle that." Probably most platforms have the same routine for this, which says "Ok, first let's put up the Setup Network Game dialog". Probably most platforms have the same routine for _this_, which first consists of like "Ok, find and display the dialog box with this id:". Now here, the platforms start to diverge more widely. Maybe the baseline SDL code constructs the dialog programmatically. Maybe the Cocoa version asks the Mac OS to construct it from a resource or a nib or something instead, so it conforms to the Aqua UI. But then they return to that shared "Setup Network Game dialog" routine, which next says "Ok, let's fill in the values from the Preferences." And again, most platforms use the same routine for *that*, which consists of calling (alternately) accessors to get Preferences values and "set dialog item value to:" routines. This latter routine has perhaps the same implementation on all platforms that are using the baseline GUI stuff, but the Mac OS version has its own version that instead calls SetDialogItemText() or whatever the Mac-specific API is. If someone later wants the Windows version to have a Windows-like UI, they can override some of the baseline routines ("set dialog item value to:", "find and display dialog box with id:", etc.) with Win32-specific routines. If someone later wants to add new items to the Setup Network Game box, they can put the code to initialize the values, update control states (enabled, etc.) as appropriate when the new items are used, and read the values back into the game_info (or whatever the structure's called) when the user hits "OK". And then, the people who maintain (look, there *I* go now ;) ) the Mac OS UI and the Windows UI merely have to update the dialog-creation so that the new elements show up; there's no need to re-code the initialization, control-state logic, reading back, etc. for each different UI platform. One obvious way to do this is to have base classes for these things that use the least-common-denominator implementations, which platform-specific classes inherit by default but may override (or completely replace) if they wish. And there only need to be platform-specific classes if the platform indeed wishes to override some methods; else the generic (base class) version can be used directly. Some sort of centralized resource (some might call it a "Factory") would be responsible for dishing out a WindowsSetupNetworkGameDialog object or a WindowsDialogInterface (this latter being the part that maps set_control_value() to whatever the Win32 routine is) or just a plain SetupNetworkGameDialog object (or DialogInterface) based on some criteria or other when code says "Hey, give me the Setup Network Game Dialog object". It would not have to dish out only all Windows components or all generic components, of course, either; it could mix n match according to the builder's/user's/whatever's whim. Its ability to mix-n-match would naturally be greatly influenced by the object granularity - if there's only one big platform object that is responsible for all the details of drawing and sound playback and dialogs and files etc. then it can only be used or not. OTOH, having a little object for every minute aspect of dialog management would be not only cumbersome, but perhaps even error-prone as some versions of routines may be incompatible with other versions of other routines, and it'd be difficult for the "Factory" to get all the details right. (The inherit-the-class way is not the only way of course, but given that we're using C++ it seems the most obvious.) > In fact, there would be no get_control_value call at all; there would > be an (e.g.) get_screen_size call exposed from the preferences module > which corresponds to some other call inside the module that obtains the > value from the GUI or the preferences database. There wouldn't be a > set_control_value call either, there would be a set_screen_size called > by (e.g.) pressing F1 that would update the platform-specific elements. I think you're off-track here. Yes there should be a routine to ask the preferences for the user's preferred screen size. But that doesn't mean that that routine is used in the Preferences dialog. Likewise, there should be a routine that says "Make the screen size one notch bigger!" or "Set the screen size to NxM!" but again, these would not be used by the Preferences dialog. Well, not in my formulation anyway. > The problem is that A1 has pretty much painted itself into a corner and > the effort of adding all these nice features would be more than that > expended to bring AM up to A1's level and then adding the features :) I'm not convinced this is the case - or more accurately, I'm not convinced that modularizing A1, rather than M2, and then adding the new features would be more effort. But, as noted, it doesn't really matter at this point. Ok and as a final parting shot about the SDL stuff, it is completely possible and practical to use, say, SDL_Video to insulate you against the differences between DisplaySprocket and DirectDraw et al., or between wgl and agl et al. (for attaching OpenGL contexts to on-screen windows etc.), etc. without committing to using SDL_main to insulate you from differences in application initialization between platforms, and without committing to using SDL_event as the basis for your event loop. (Perhaps Br'fin's negative experiences have primarily been with these latter components.) So you can mix-n-match. :) Woody |