______/\__________________________ __ ________________ ___ /\_______ \____ \ ________ _ _ ______ \ / \| \ ________ | \/ ______/ / | \ _) \ \_/ \ | \ / \ \ _) \ | \______ \ / | \ \ | \ | \/ \ \ / \ \ / \ \_____ /_______/___| /_______/\____\_____/_______/_________/________/ \_____/ |____/ Subscribers : 2547 DemoNews 141 - 02 February 1997 Archive Size : 3997M >------------------------------------------------------------------ Contents -- Introduction Calendar Week In Review Top Downloads New Uploads Articles Software Design for Demos - Volume 3 .......... Kiwidog Advertisement : X'97 Takeover ................. HarleQuiN General Information >-------------------------------------------------------------- Introduction -- Hello all, and welcome to DemoNews 141. _____Introduction So much to print, so little time. Even after releasing this 60k+ issue of DemoNews, I have another 110k worth of articles and reviews just waiting to be read. An article from Trixter, 2 from Shaithis, tons of /music reviews... For just a little while, I'm probably going to be releasing 2 issues of DemoNews a week; your standard-style DemoNews on Sunday night, and a "catchup" issue either Wednesday or Thursday. It's bad enough that files sit in /incoming as long as they do. It'd be a travesty to actually have them reviewed and not be able to print them in a timely fashion, agreed? Anyway, I'm sure things 'll calm down in a month or so. _____(knock knock) Anybody home? With 2600+ subscribers to DemoNews, I expect a few new issues to bounce. After all, people leave or get kicked out of school, change jobs or are fired; email address are a dime a dozen and sometimes go away unexpectedly. You'd be surprised how many issues of DemoNews bounce each week. Back in the good 'ole days, it'd be about 15 bounces per new issue. It's recently grown to about 70 or 80. 70 or 80 bounced issues x 60k per issue qualifies as mail bombing myself. Although the listserver is smart enough to unsubscribe non-functioning addresses, I still get that initial bounce. And even though they get saved to a separate mailbox (thank you procmail), I still gotta sift through them since the occasional DemoNews reply gets mixed in there. Be kind. If you know you're going to lose the address to which DemoNews is being sent, mail your friendly South African listserver@unseen.aztec.co.za with the words "unsubscribe demuan-list". _____%2B or +? I'd like to thank Knut Eldhuset who educated me on the finer points of encoded ascii in CGI search strings. This was the tip I needed to fix a bug in the HA search engine that caused secondary searches for "****+" to fail. This gets Slam! rating of 6. _____Email Gripes HTML is not yet an acceptable email format. Any mail sent to me in HTML only will be ignored and deleted. On a related note, please learn how to uuencode/uudecode if you don't know already. _____The Cleansing of /incoming Our /incoming directory is very busy. I want to take a minute to go over the basic rules for a happy uploading experience: 1. must be .zip format (multi-file uploads may use .arj, .a01, etc.) 2. file.txt description required with each file.zip please use /incoming/_forms/upload.frm (also see upload.exa) file.txt must be under 500 bytes! english only 3. lower case, not UPPER CASE 4. filenames must be 8 characters or less, not counting zip/arj extension 5. files uploaded to appropriate subdirectory 6. corrupted file.zip should be reuploaded as file.zip.good 7. check to see if there is already a file named the same as yours 8. only allowed to upload 1 production per day Any file breaking a rule is deleted automatically by script. Uploading means your file will stay on our site unless legitimate reasons are given for its removal. Please note that any files in /incoming that break rules #3 or #6 are deleted automatically at 4AM. For files breaking #2, a second-chance script is used to try and generate a .txt file based on a file_id.diz within the .zip. If that fails, the file is automatically deleted. Rule #8 might seem a bit odd. Rephrased, it might read: 8. if you upload 30 of your productions in one shot, one of our music reviewers gets stuck spending an unfair amount of time reviewing your music and ignoring everyone else's. I've deleted at least 200 unhappy files in the past 2 weeks. The official rules can be found in /incoming/.message _____South African Mirror Gone Please note that our mirror site at ftp.sun.ac.za has been discontinued. They simply don't have the resources anymore. _____Conclusion So what's with people sending html mail anyway? Maybe I should start replying in tar-gzipped uuencoded style. Snowman / Hornet - r3cgm@hornet.org >------------------------------------------------------------------ Calendar -- Date Event Location Contact Points ------------ ------------------- --------- ---------------------------------- 31 Jan 1997 PC96 Brazil x@wm.com.br wm.com.br/~x/pc96.html * <-- YOU ARE HERE 15 Feb 1997 General Probe 3 Poland s146630@ire.pw.edu.pl neutron.elka.pw.edu.pl/~mszklano 02 Mar 1997 Invasion Finland invasion@xuq.nullnet.fi www.koillismaa.fi/invasion 23 Mar 1997 Millennium Israel mlitvak@ort.org.il 26 Mar 1997 The Gathering Norway www.gathering.org 28 Mar 1997 Mekka & Symposium Germany amable@aol.com 28 Mar 1997 SiliConvention Germany www.siliconvention.com 04 Apr 1997 X Takeover Holland x97take@dds.nl 05 Apr 1997 Spring Break USA (CA) whutchin@sdcc13.ucsd.edu sdcc13.ucsd.edu/~whutchin 11 Apr 1997 The Trip Italy keyby@jnet.it www.logicom.it/trip 30 May 1997 Scream Canada scream97.educ.infinit.net furb@total.net 22 Aug 1997 AntIQ Hungary aboy@ttk.jpte.hu www.jpte.hu/~aboy 25 Aug 1997 The Place To Be 5 France www.mygale.org/05/dadu >------------------------------------------------------------- Week In Review -- -- /music ------------------------------------------------------------------> :: Snowman / Hornet - r3cgm@hornet.org _____Introduction No room. Must make short! _____The Good... Dee Musicdisk Two by Dee. Excellent. Download now! _____...The Bad, and The Ugly The "Kx Files" by Kxmode. Lame... ripped off Jester's song. Didn't even have the good sense to rip something obscure. "Hey Trixter, I'll change the songtext to The Crossing and say I wrote it... think anyone 'll notice?" Ripping is the cardinal sin of the scene, an action so reprehensible that we have a special marker for it. Slam! _____Conclusion I am making some people very angry with me by writing reviews like the one above. That's ok folks, I just call them as I see them. >------------------------------------------------------------- Top Downloads -- This represents combined ftp/http transfers for the last 7 days. Total files downloaded : 208,581 Size of files downloaded : 35,807,147k Times File Description ----- -------------------------------- -------------------------------------- -- /demos ------------------------------------------------------------------> 181 /1995/a/animate.zip Animate by Schwartz 144 /1993/s/symbolog.zip Symbology by Admire 143 /1993/u/unreal11.zip Unreal v1.1 by Future Crew 135 /1993/0-9/2ndreal1.lzh Second Reality by Future Crew [1/2] 128 /1993/0-9/2ndreal2.lzh Second Reality by Future Crew [2/2] 127 /1995/n/nooon_st.zip Stars (bugfixed) by Nooon 108 /1995/c/countdwn.zip Countdown by Realtech 106 /1993/c/cd2_trn.lzh Crystal Dreams 2 by Triton 102 /1996/a/ai_strok.zip Stroke by Ionic of Astroidea 88 /1992/c_dream.lzh Crystal Dreams by Triton -- /music ------------------------------------------------------------------> 96 /songs/1995/s3m/a/aryx.zip Aryx by K. Koch 95 /songs/1996/s3m/a/athought.zip Another Night of Thought by Zastar 76 /songs/1996/s3m/i/im_empir.zip The Hidden Empire by Karsten Koch 74 /songs/1996/s3m/i/im_chron.zip Chronologie Part 4 (remix) by Karsten 70 /songs/1997/xm/m/mcd-rain.zip Rain by MC Dreamer 56 /disks/1996/f/fm-plast.zip Blur Plastiq by Mellow-D of Five Music 55 /songs/1993/s3m/skyrider.zip Skyrider by Purple Motion of Future Cr 54 /songs/1996/s3m/f/fm-mech8.zip Mechanism Eight by Necros 54 /songs/1996/s3m/c/ccs-eps.zip Epsilon Eclipse by Mayhem 53 /songs/1995/s3m/c/ctgoblin.zip Catch That Goblin by Skaven -- /graphics ---------------------------------------------------------------> 26 /images/1994/i/incest5.zip Incest by Pentalysion 20 /programs/editors/fedit11.zip Font Editor v1.1 by PiCoder 20 /images/1996/a/airwar.zip Air War by Grape 18 /images/1996/a/aa_gargo.zip The Gargoyle by Coolhand 17 /images/1996/a/abc_pien.zip Pani Pienkowa by Grass 16 /programs/vector/veced300.zip 3D Vector Editor by Grey Cat 16 /programs/editors/char_122.zip Char Editor 1.22 by Escape 16 /programs/convert/bmp2avi.zip BMP to AVI by Paul Roberts 15 /programs/editors/gfx2b93.zip Grafx 2.00 Beta 93 by Sunset Design 15 /images/1996/h/hardcore.zip by Boss -- /code -------------------------------------------------------------------> 63 /tutorials/denthor/tut01new.zip Tutorial 1 in C by Snowman of Hornet 61 /3ds/3dsrdr12.zip 3D Studio .3DS File Reader v1.2 by Jar 60 /effects/water/water.zip Water by De-Phassed 57 /effects/scroll/motionrd.zip Motion Read Me by Patch of Avalanche 56 /tutorials/denthor/tut04new.zip Tutorial 4 in C by Snowman of Hornet 56 /effects/water/hq_water.zip Heart Quake's water source by ARM of I 53 /tutorials/denthor/tut09new.zip Tutorial 9 in C by Snowman of Hornet 53 /tutorials/denthor/tut02new.zip Tutorial 2 in C by Snowman of Hornet 52 /tutorials/denthor/tut06new.zip Tutorial 6 in C by Snowman of Hornet 52 /tutorials/denthor/tut05new.zip Tutorial 5 in C by Snowman of Hornet -- /incoming ---------------------------------------------------------------> 96 /demos/idx-magn.zip 77 /demos/ctswht95.zip 73 /TP96/demo/alto.zip 71 /TP96/demo/megademo.zip 65 /code/wavepic.zip 65 /code/midas060.zip 64 /code/gb_fmint.zip 61 /demos/fishlife.zip 58 /demos/balistic.zip 54 /code/rastrzep.zip >--------------------------------------------------------------- New Uploads -- All ratings are subjective. Filename Size Rated Description ------------------------------- ---- ----- ---------------------------------- -- /demos ------------------------------------------------------------------> /1996/0-9/1k_intro.zip 1 ***+ 1000 Byte Intro by Frenzy : 386DX /1996/b/burning1.zip 179 *** Burning Chrome by Hellcore : | 486,GUS/SB /1996/d/dufhk.zip 4 *+ BBS Harakiri by Darkness Unknown | Force : 486 /1996/e/e9-fett.zip 4 **** Fettina by Magic of Ethos 9 - | TP96:in4k:02: /1996/k/k_storm.zip 3 **+ BBS Dark Storm by Kloon /1996/k/kk-rvsf.zip 123 *** Reverse (final) by Ketchup Killers | - WIR96:in64:09: : 486,SVGA,GUS /1996/m/marsvoya.zip 3 **+ Mars Voyage by Daze of TMB - | TP96:in4k:08: /1996/r/riplview.zip 56 **+ Ripple Viewer by Hellcore /1996/s/shaolin_.zip 543 *** Shaolin by Live : GUS/SB /1996/s/spasmo.zip 632 **+ Spasmo Vidio by Hirn Tod /1996/s/stg_ntlf.zip 80 ** Not Too Late (final) by Skytech | Group - SAT96B:in64:06: /1996/t/timeout_.zip 3 ** Time Out by Zaifrun of Immaculate | - TP96:in4k:10: /1996/z/zrn-16.zip 148 **+ Zauron Is 16 by Index : 386,GUS/SB -- /music ------------------------------------------------------------------> /disks/1996/d/dna-unre.zip 1279 ***+ Unreleased - The Lost Collection | by DNA : The file DNA-UNRE.EXE | inside this .zip contained the | Alfons.1344 virus. The | executable was removed on 29 Jan | 1997 and repacked. /disks/1996/e/et9-emsn.zip 364 *** Emissions #1 by Ethos9 : | Collection of about 40 chip | songs... some good some bad. /disks/1996/g/g_bshift.zip 1309 ***+ Blueshift by Beek of Grey : Old | school style tracking dude. | Works well. No interface. /disks/1996/k/kx-files.zip 912 [rip] The Kx Files by Kxmode of Phluid : | The song kx-break.mod "Breaking | The Chains" is directly ripped | from Jester's "Elysium". Only | the sample text has been | changed. Ripping is | dishonorable and Kxmode has | proven himself an untrustworthy | tracker. /disks/1996/m/mfx_co6.zip 869 *** MFX - Compilation 6 by MFX : Wierd | slow trancy type tunes... long | samples... no interface. Very | odd. Very, very odd. /disks/1996/r/rr_cha-1.zip 903 ***+ Chapter X by Radical Rhythms [1/8] | : Includes 574k UNIVBE .zip | file, compressed and | uncompressed x-play/x-shell. | Most of the music is ok, but | they did a _really_ nice job | with the interface... give 'em a | star just for that. For a disk | this large, it's well put | together. /disks/1996/r/rr_cha-2.zip 1325 ***+ Chapter X by Radical Rhythms [2/8] /disks/1996/r/rr_cha-3.zip 1405 ***+ Chapter X by Radical Rhythms [3/8] /disks/1996/r/rr_cha-4.zip 1308 ***+ Chapter X by Radical Rhythms [4/8] /disks/1996/r/rr_cha-5.zip 1012 ***+ Chapter X by Radical Rhythms [5/8] /disks/1996/r/rr_cha-6.zip 1147 ***+ Chapter X by Radical Rhythms [6/8] /disks/1996/r/rr_cha-7.zip 1178 ***+ Chapter X by Radical Rhythms [7/8] /disks/1996/r/rr_cha-8.zip 1456 ***+ Chapter X by Radical Rhythms [8/8] /disks/1996/s/slkkro_1.zip 871 ***+ First Music Pack by Sunlikamelo-D | : Relaxed, professional, | inventive and creative music. | Almost a 4 star. /disks/1996/s/sr-nueva.zip 675 **+ Nueva Dimension by Sunrise : Not | bad techno, but tries to put too | many chords in (and | unfortunately has poorly tuned | samples). No interface. /disks/1996/s/stm121.zip 1203 *** Disk-Volume 12 by SDC, TOM [1/2] : | Each song in here is in an | embedded .zip or .arj file, | highly unwieldly as music disks | go. This is unfortunate because | the music is actually pretty | good and deserving of a higher | rating had the authors taken | time to package their tunes | professionally. No interface. /disks/1996/s/stm122.zip 1282 *** Disk-Volume 12 by SDC, TOM [2/2] /disks/1996/t/tm-skew1.zip 1405 *** Skew by T-Matic [1/3] : A very | wide range of quality levels for | the songs in this music disk. /disks/1996/t/tm-skew2.zip 1425 *** Skew by T-Matic [2/3] /disks/1996/t/tm-skew3.zip 1337 *** Skew by T-Matic [3/3] /disks/1996/t/tripto3a.zip 1212 **+ Tripout 3 by Trip Productionz | [1/2] : A few tiny chip .mdl's, | some that have a really groovy | beat, no interface. /disks/1996/t/tripto3b.zip 1253 **+ Tripout 3 by Trip Productionz | [2/2] /disks/1996/v/vr-pack1.zip 1023 *+ Music Pack by VampRabbit : A new | tracker with a little ways to | go. However, coming from Ohio | he is destined for success. /disks/1997/c/cchimera.zip 2947 *+ Contorted Chimera by Drop Zero, | Contrivance : Perhaps a bit | unpolished and heavy on the | high-hats. /disks/1997/d/dee213.zip 1400 ****+ Dee Musicdisk Two by Dee [1/3] : | Slam! This is how a music disk | should be done. Absolutely the | best interface I've seen for a | music disk since Epidemic. Not | only that, but the interface is | configurable... you can actually | use it for your own productions. | The music kicks ass. If you | only download a couple music | disks this year, be sure that | one of them is Dee Musicdisk | Two! /disks/1997/d/dee223.zip 1409 ****+ Dee Musicdisk Two by Dee [2/3] /disks/1997/d/dee233.zip 1285 ****+ Dee Musicdisk Two by Dee [3/3] /disks/1997/d/dzone.zip 777 *** Danger Zone by DZone : DZone took | time at least to do an interface | for this disk. Some songs | better than others. /disks/1997/n/ng-dura.zip 1850 ***+ Dura Master by Nearly Gods : Good | techno! 3 songs in AMF format, | with a nice player to go along. | Don't try to play these in Cubic | Player (out of memory) or under | Windows 95 (lose keyboard | handler). Would have given this | 4 stars if there had been more | songs. /disks/1997/p/ph-0197a.zip 1233 ***+ Phluid 01/97 by pHluid [1/2] : One | of pHluid's better music | disks... some really great | tunes. It's unfortunate that | Kxmode / pHluid was recently | caught ripping a song. /disks/1997/p/ph-0197b.zip 1295 ***+ Phluid 01/97 by pHluid [2/2] /disks/1997/r/rpinflrn.zip 1154 ** The Inflern by Mr. Mortal of Red | Power : This song could actually | get 4 stars if the samples were | updated and the pattern data | tweaked just a bit. | Structurally this disk is sound, | but the samples make it hard to | listen to. /disks/1997/s/s-new97.zip 1008 *+ New 97 by Space Invaders : Sounds | kind of like newbie music, but | with a lot of potential. /disks/1997/t/t_mellow.zip 952 *** Melodramatic Tendencies by Troll : | Decent music, just needs a | little polishing. Troll has | much potential. /disks/1997/t/triphop.zip 1266 *** Triphop by Riders of Skyjump Team | : Some pretty hip-hoppidy songs | in here. /disks/1997/v/v-debut1.zip 796 *** Debut by SML of VSL [1/3] : Songs | were a bit large (3 were 2 megs | each). However, they were | pretty good. /disks/1997/v/v-debut2.zip 719 *** Debut by SML of VSL [2/3] /disks/1997/v/v-debut3.zip 1017 *** Debut by SML of VSL [3/3] /disks/1997/v/visions.zip 1248 ** Visions by Bitstream of Tunnel | Vision : Music isn't too bad but | the samples sound muffled. | Author needs to be more | aggressive with his style. MDP | interface. -- /mags -------------------------------------------------------------------> /1996/pain0396.zip 271 **+ Pain March 1996 Issue by Pain /1996/pain0496.zip 335 **+ Pain April 1996 Issue by Pain /1996/pain0596.zip 197 **+ Pain May 1996 Issue by Pain /1996/pain0696.zip 157 **+ Pain June 1996 Issue by Pain /1996/pain0796.zip 144 **+ Pain July 1996 Issue by Pain /1996/pain0996.zip 151 **+ Pain September 1996 Issue by Pain /1996/pain1196.zip 260 **+ Pain November 1996 Issue by Pain /1997/pain0197.zip 410 *** Pain January 1997 Issue by Pain /1997/rc-vol01.zip 210 **+ Volvo Issue 1 by Rectum Cauda -- /party ------------------------------------------------------------------> /invites/1996/ascen96n.zip 79 ** Atlantic Scene '96 Convite & | Regras by Atlantic Dreams : SB /invites/1996/atl96tro.zip 66 *+ Atlantic Scene '96 Invitation | Intro by Atlantic Dremas : SB /invites/1996/bdn3invi.zip 319 *** BDN 3 Invitation Intro by Funk /invites/1996/jporno96.zip 608 **+ Jouluporno '96 Invitation Intro by | Complex, Orange >------------------------------------------------------------------ Articles -- ----------------------------------------------------------------------------> :: "Software Design for Demos - Volume 3" :: Kiwidog - chargrove@mail.ravensoft.com _____Introduction Many happy returns! After a couple articles of warm-up info to get everyone going, it's time to finally start writing some code ('bout time eh? :) This issue we'll be designing our screen class (actually classes, plural, as you'll soon see) that we started talking about at the end of the last article, as the beginning of a (probably pretty substantial) code base we'll be writing over the next several articles. It's highly unlikely I'll be able to cover the whole layout of the screen info this issue, due to the immense size of what needs to be covered, so we'll probably be doing this over the next several articles before moving on to the next big topic. I don't know how long this issue alone will end up being, but my gut tells me it's gonna be a doozy, so hold on. :) _____The Usual "But First..." But First... :) I got a couple mails this past week regarding the last article, and a few folks got a bit confused on the whole constructor/destructor thing. Don't worry, once you see 'em in action here with the screen classes it should all make perfect sense, so be patient. :) Also, I've gotten a good volume of mail about what to do with the 3D series, and an overwhelming majority of you said you just wanted me to release the articles alone in a .zip to get them out there, so that's what I'm going to do. It might be another week before I do so (I've been tied up in work related stuff for a little while), but the new zip will be called HRN_DN3D.ZIP, and will contain the articles for the first 5 of the series that went out here in DemoNews, along with five subsequent articles covering Gouraud Shading, Texture Mapping, Arbitrary Cameras, 3D Clipping, and Spline Paths, respectively. After some final touchups this week I'll release it; hopefully that'll be enough info to keep busy for a while. :) Also, during the naming conventions section of the last article I talked about prefixes and suffixes, and how for classes I use a prefix/suffixless system for my own code since all the classes were very intuitively named. Welp, I broke that "15 character" barrier I talked about during the week, so in order to not be a hypocrite, I switched to using a prefix. Since I've seen the "C_" prefix in a lot of places, I decided to give it a try and it seems to work well. Fortunately since I haven't written any major code with you guys yet, I can start out with this convention from the outset as far as the article series goes. So all the classes you'll see written in the series from this point on will start with capital C in the name. Just FYI. :) Ok, I guess that's all the initial junk, and since I doubt I've got a lot of free space to ramble this time, we better jump on in... :D _____Of Cabbages and Kings '"The time has come," the walrus said, "to talk of other things." And while the walrus probably wasn't coding, he does have a point. Sometimes you have to sit back for a little bit and think about what it really is you want to do before you end up doing something rash. The problem is, demo coding by nature tends to be very _very_ rash, so this can be a major task mentally. But it's a good habit to get into, because once you can get used to designing things even slightly in advance of actually coding them, it makes everything go that much smoother. The longer you think about your design beforehand, the more bugs, restrictions, and potential improvements you'll catch in your head before you even lay a finger on the keyboard. So before we start coding our screen class, let us ponder. :) One thing we know we want is non-mode-specific graphics. While doing multiple color bit-depths is certainly the most difficult part of this, since all the primitives change, we should at LEAST be able to do multiple resolutions at the same bit depth without any hassles, and have at least support somewhere for doing primitives for other bit depths. Also, we know we want it to be non-platform-specific enough to where it shouldn't be all too evil to port the video code between DOS and say, DirectX under Win95. If the design is good enough, very little code should change relatively in order for everything else to still work. Part of this non-specificness also brought up the idea of not having screens bound to any mode at all, so that we could use the same primitives for arbitrary buffers, bitmaps, dirty rectangles (for situations where they're needed), and so on. Sound like a lot to shoot for? It is, but it's feasible. :) _____Planes, Trains, and Devices This section will probably seem rather confusing at first. Don't worry about it, I'm just giving a rough overview of what we're about to do. :) Note that of course this is just one of an infinite number of design possibilities; if you like it that's wonderful, but basically I just want to stir up the gears... as long as this gets you thinking, I've accomplished my goal. :) Because we want three major things from this (arbitrary resolution, arbitrary bit depth, and arbitrary platform), we're gonna need a bit of indirection in our code to get everything done. We're gonna have some kind of "universal" CScreen that everything above the video layer uses, sure, but CScreen itself is gonna need to pass some of its responsibility to other classes... otherwise it would be too hardwired for the kinda design we want. Let's look at the "arbitrary platform" one first, since it seems like it would supersede the other two. If we think about it, DOS and Win95 only really differ in the end by how the video operations work. Instead of just setting modes and blitting in Win95, you go through DirectDraw (or some other abstraction mechanism). So the very first thing we'll want is to delegate the hardware specific stuff, like mode sets and blits, to another layer. Since most everyone uses offscreen buffers and blits them these days, doing an abstraction like this is painless... the linear offscreen buffers can be handled by CScreen while this "other layer" takes care of putting it onscreen. Now before we decide what that layer should do exactly, let's look at the other two requirements. The easiest of the two left is arbitrary resolution. As far as the CScreen-side buffering stuff goes, this just means a change in the buffer sizes and the resulting scanline lookup tables. But on the hardware side, if you decide to use a screen as a fullscreen mode, you're gonna need another layer below the initial hardware layer, one which is different for every fullscreen video mode you use. This means now we have CScreen at the highest level, a platform-specific level below that, and then another mode-specific level below the platform-specific level. Will that take care of all the hardware abstraction stuff we need? Hopefully, but let's check the last requirement, arbitrary bit depth, to make sure. Bit depth doesn't just affect the hardware mode sets and blits and stuff. It also affects your drawing primitives, because if you want any speed whatsoever you'll want primitives that are different for each color bit depth. Fortunately there are only a few depths to choose from, and even then you might not use all of them (8 bit palettized and 24 bit truecolor are the most likely grades), so this isn't a big deal. BUT it does add another layer of abstraction. Where's that layer go? Well, since the hardware aspect of bit depth variation (the mode sets and blits) is already taken care of by the fact that we have a layer to cover all of those modes _regardless_, the only thing left to deal with is the primitives problem. We could have put our primitives (drawing lines, cutting and pasting rectangles, etc) directly into our CScreen class if we were restricting ourselves to one depth like 256 colors. But by abstracting the primitives layer from CScreen as well, we cover that problem. That should take care of all our abstraction... finally, we might also want some kind of unified daemon-ish class that there's only one of, to control how the platforms and primitives are applied, as well as to control a couple other useful globalized things like automatically blitting the active "fullscreen" CScreen, etc. So that's five things total... the screen, the platform layer, the mode layer under the platforms, the primitives layer, and the unified hub. The names I gave the classes for these: - CScreen, for the screen class that interfaces with the outside world, - CVidControl, for the platform "control" mechanism dealing with the mode "devices" underneath, - CVidDevice, for each device itself, dealing with a particular mode - CVidPen, for the primitives, since the primitives act like a pen to draw on the screen, and - CVideoDaemon, a class acting as a hub, where only one of them exists which I named mVD (even though this isn't really a "daemon" in the true sense, I name my single-instance classes like this because it's easy to recognize their global purpose... all of my department daemon instances start with a lowercase m for main with an abbreviation, in this case mVD; I'm just clarifying incase it sounds odd). I know the classes may sound kinda wacky and huge, but each one's not really that big honestly. Hopefully the layout doesn't sound too confusing; if so, just keep reading and you'll probably pick up on it. Now, if you code DOS exclusively, you'll only need one CVidControl, maybe called vid_ControlDOS or whatever. In addition, if you only support a couple fullscreen modes like Mode 13h or certain VESA modes, you'll only need to code concrete devices for those modes in particular. Also, if you only support 256 color modes, you'll only need one concrete pen as well, for 8-bit color. The point of this architecture is simply EXTENSIBILITY, so that if you want to add extra support, it'll be easier to build more functionality in to the system later on. _____Slipping On Concrete If you've gotten confused by terms I've been using like layers being "under" one another, or coding "concrete" versions of a class, it means we'll be taking advantage of another big thing object-oriented programming allows... Inheritance. Inheritance is when you declare classes that "inherit" all the abilities of their ancestor classes... nearly all the data, the functions, etc. But inherited (descendent) classes can add extra stuff to the mix, as well as replace functions given in their ancestors. And when you have a function somewhere that takes a class parameter that's an ancestor of other classes, the descendents can _also_ be used as parameters to those functions. Don't worry about understanding it now, as I'll be going over it later in this article when we start writing our video code. Actually, why don't we start the code now... :) _____CVidDevice - No Guts, No Glory Since I doubt I have enough space to write all five classes in this issue, we'll start off taking care of the abstract CVidDevice class and showing a concrete class of it, to deal with video mode devices. The reason to start off with the devices before the others is simple; they don't need as much to exist beforehand... makes 'em easier to explain :) The abstract video device only has set the ground rules for doing a couple things: Setting a video mode, blitting a buffer to that video mode, and setting a palette entry (since palettized modes need this). There are a few other interfacing functions such as setting the device name and "registering" the device with the commanding CVidControl, but the core operational stuff is only a few functions. I should be using the term "methods", since class functions are called methods, but you get the idea. :) The first code I need to give is a header containing general definitions used by just about every other file you'll see from me. NOTE: Throughout the code you'll see references to "Colony" and the abbreviations "CL" and "COL". This is because my engine is called Colony (the group name is Terraformer so it fits), and the vast majority of the code I use will be directly from this code base. Hence, since this is not just example code but code that _is_ being used by its creator, should you use it in your own code base I'd appreciate some greets or other recognition in your production. I already go to great lengths to write these articles, let alone give out my code base, so the last thing I need is to get my hard work ripped. A greeting is all I ask. I say this because I had a rather INFURIATING experience earlier this month on EFNet #c where one guy came on and said "check 0ut my kewl 3d codeZ" and offered an xdcc. Since I was curious as to exactly how "kewl" his code was, I got the dcc offering and took a look. The guy had taken the supplement source from my 3D series article #2 and ripped it VERBATIM, except he took out all the comments and put his own nick at the top. Needless to say I got right back on IRC and looked for him to give him a piece of my mind, only to find that he had /quit while I was reading (hopefully after realizing who he dcc'ed to). I haven't seen him since, although I'd love the honor. >|0 So, once again, if you use my code at all, please give some recognition in the end result. And as a warning, if I find someone ripping my code again _and_ claiming it as their own like that guy did, I will cease writing any more articles without question and you'll have them to blame, by name. I tolerate a lot of things in life, but plagiarism is NOT one of them. Now that that's said, ----begin COLDEFS.H---- //************************************************************************ //** COLDEFS.H //** Colony Engine Version 0.3 //** Definitions Header //** Include for all .H files //************************************************************************ #ifndef _COLDEFS_H_ #define _COLDEFS_H_ #define _COLONY_VERSION_ 0.3 // typedefs typedef unsigned char byte; typedef unsigned short word; typedef unsigned long dword; typedef signed char sbyte; typedef signed short integer; typedef signed long longint; #endif ----end COLDEFS.H------ Here's the class header for CVidDevice, CVIDDEVI.H. I'll explain each piece of it next... ----begin CVIDDEVI.H---- #ifndef _C_CVIDDEVICE_H_ #define _C_CVIDDEVICE_H_ //************************************************************************** //** //** - CVIDDEVICE.H //** Colony Engine Version 0.3 //** Header - CVidDevice class module //** LM 1-4-97 Chris Hargrove //** //************************************************************************** //************************************************************************** //** HEADERS //************************************************************************** #include //************************************************************************** //** DEFINITIONS //************************************************************************** #define VID_256 8 #define VID_64k 16 #define VID_16M 24 //************************************************************************** //** EXTERNAL CLASS DECLARATION //************************************************************************** class CVidControl; //************************************************************************** //** //** CLASS CVidDevice //** //************************************************************************** class CVidDevice { private: dword xRes; dword yRes; dword bitDepth; char *sysmarker; dword type; char *devname; // mode title char *devinfo; // any other misc text void *devdata; // device information, optional protected: CVidControl *vidImp; // control interface void SetDevName(char *ndevname); void SetDevInfo(char *ndevinfo); void SetDevData(void *ndevdata); public: // Constructors CVidDevice(CVidControl *nVidImp, dword nxRes, dword nyRes, dword ntype); virtual ~CVidDevice(); // Operators // Functions - Implemented by concrete devices as much as possible // general mode operations virtual void Activate(); virtual void Blit(void *src); // fullscreen blit // color operations virtual void SetPalIndex(dword index, byte r, byte g, byte b); virtual void GetPalIndex(dword index, byte &rr, byte &rg, byte &rb); // info void GetModeInfo(dword &rxRes, dword &ryRes, dword &rbitDepth); char *GetDevName(); char *GetDevInfo(); void *GetDevData(); // Friends }; //************************************************************************** //** //** END CLASS //** //************************************************************************** #endif ----end CVIDDEVI.H------ Look menacing? Don't worry, it's simpler than you might think. :) The first thing is the standard #include , which was listed above. Notice the < > instead of " ".... for convenience I added my code's main directory as an include directory in my makefiles, so files like coldefs.h could be used universally without path information. You might find something like this very handy as well. :) The three defines given are just aliases to bit depths, and the external "class CVidControl;" is to let the rest of the header (and compiler) know that there exists a class data type called CVidControl, so don't be alarmed when it's used here in various parameters. The actual class definition for CVidControl will in another one of the .H files, so it'll be resolved when it comes time to compile CVIDDEVI.CPP. The rest of the file is the class definition itself, and as you can see there's a bit of meat in there. In order to explain it, we'll have to cover a few terms such as "public" "private" and "protected", as well as the term "virtual" you see a few times up there. :) _____The Untouchables One of the big things in object oriented programming is being able to hide information from other objects. While you can't completely "hide" the class structure itself in C++ due to the classes usually being in headers, you can still hide stuff as far as the compiler is concerned. Within a class, "public:" "private:" and "protected:" are used to accomplish this. "private:" means anything after it is private to that object alone. That means the members (variables) and/or methods listed can only be accessed or called from within the object's methods and nowhere else. For example, in this class, the "dword xRes" member is only accessible by this object's members. As far as every other object is concerned, that member doesn't exist; they can't see it. "public:" means the exact opposite... the members and methods listed are totally public, out in the open, and accessible by everyone and everything. Generally a lot of methods will be public, but you'll want to keep public members to a minimum. "protected:" is sort of a mixture of the two, and it deals with the inheritance thing I mentioned earlier in the article. Protected member variables and methods are private to just about everything, _except_ derived classes. Derived classes are the descendents I talked about, and we'll be making classes derived from CVidDevice to do "concrete" devices like I mentioned. Any derived classes automatically has access to protected stuff, while non-derived classes don't; to them, it's the same as private. You'll see up there that we have the device's mode resolution (xRes, yRes, and bitDepth), type (at present same as bitDepth but left for expansion) and some information extras private to the object. Any access to these members from the outside world has to go through this class's methods, so you control what can see or modify them. The controlling interface vidImp and functions for setting device info are protected, because while the rest of the world shouldn't be able to use them, derived (concrete) classes will want them to say what mode they're for, what controller they use, etc. Finally there are a whole bunch of public methods, which I separate into four groups, "constructors", "operators", "functions", and "friends". Operators and Friends I'll get to later on in the series; we don't need them for now. Functions are just general method functions like you're familiar with. But I think we should take another look at the first group... _____What Goes Up Must Come Down "Constructors" lists all of the constructors and destructors for the class. While these don't necessarily need to be public (there are a couple neat things you can do with protected constructors for example), most of them will be. I mentioned constructors and destructors briefly in the last article, but now we get to see them put to practical use. There's only one constructor listed: CVidDevice(CVidControl *nVidImp, dword nxRes, dword nyRes, dword ntype); Notice that it takes parameters, in this case four of them. This is a very powerful feature of C++ over C; the fact that you can declare an object of a class and have it take parameters in the declaration right from the start... this way you can initialize the object any way you see fit. Assuming we had a CVidControl called vid_ControlDOS, we could instantiate a CVidDevice called "exampleDev" like this: CVidDevice exampleDev(&vid_ControlDOS, 320, 200, VID_256); And it would instantly call the appropriate constructor matching those parameters when exampleDev is declared. This means that you can have functions get called _before_ main() is even called, if you happen to declare any objects globally. Very cool indeed. Plus, if you happen to have multiple constructors with the same number of parameters, then the compiler will choose the one that matches the parameters, within limits (you can sometimes get "ambiguous" errors where the compiler doesn't know which one to pick, so make sure if you do make constructors in this fashion that they're fairly explicit). Because of the whole construction-upon-declaration system, C++ also eliminates the need to declare all variables before any code in a function is started. You can declare a variable anywhere in a function now, and if there's a constructor involved, it'll be called then. Now one thing we _don't_ have in this class is a "default" constructor, CVidDevice(); The default constructor is the constructor called if you just declare a class instance without any variables. Normally a default constructor is just "assumed" to exist if no other constructors are given, and it'll just construct the object by filling all the members with zeros or whatever. But once you declare any explicit constructors like we did, that assumption disappears. As a result, if you tried this: CVidDevice exampleDev; you'd get a compiler error saying that there was no constructor for that form of declaration. This is good, because for CVidDevice, and hopefully all classes derived from it, we don't want a default. Now on to the other half of this process, the destructor. A destructor, listed just like a default constructor but with a ~ at the front, is automatically called when the object goes out of scope. For local instances, this means when the function ends. For globals, it's called after either main() ends or you call exit() to end the program prematurely. The "virtual" at the front of this destructor is something totally unrelated (and not used for all destructors by any means); I'll get to that in a moment. Destructors are incredibly handy to tearing down an object that was built up throughout the course of the program. For example, if you allocate memory for a member pointer, you can have the destructor automatically deallocate it. If you use a linked list inside, you can make it automatically walk the list and deallocate everything. It's the object's janitor, so to speak. :) Now, the only two things left up there that might be confusing for you C coders are the term "virtual", and that little referencing operator & used in the declarations of a few of those methods. We'll tackle the & operator first, since it's quick to explain. _____References Available Upon Request C++ is happy to present another wonderful way to pass by reference, thanks to the & operator. Where in C the only way to pass by reference was with a pointer using the * operator in the function declarations, C++ allows you to use & as well. & is the same as * except that inside the function, it looks like passing by value. It internally substitutes all the value references with pointer references. For example, look at the following two functions: void blah1(int *baygle) { *baygle = 3; } void blah2(int &baygle) { baygle = 3; } In C++ these two are functionally equivalent; the pointer reference has automatically been inserted for baygle in the second function because the & operator was used in the formal parameters. Because of this, calling blah2 doesn't require putting an address-of & at the front of an int passed in, either... int temp; blah1(&temp); blah2(temp); Basically this mechanism is very handy but can also be pretty dangerous; once you use the & operator in a declaration, it's up to YOU to remember that what you're passing in is by reference not value, and modifying the parameters WILL alter the actual parameter. So when debating whether to use * or &, choose, but choose wisely. :) Okay, now on to the last of the (possibly) unfamiliar stuff... _____Don't Look At Me, It Was Him! In order to explain virtual functions, we have to go back to the whole inheritance thing. As I said, inheritance allows classes to "descend" from other classes, and to take on their functionality automatically, subsequently being able to replace any inherited ancestor functions they desire, plus add any new ones. Declaring a derived class is a piece of cake... class v320x200 : public CVidDevice { public: // Constructors v320x200(CVidControl *nVidImp); // Operators // Functions void Activate(); void Blit(void *src); // Friends }; Just by adding that ": public CVidDevice" in the declaration, we've just inherited every public and protected member and method of CVidDevice as our own. If a function ever takes a CVidDevice as a parameter, we can throw in a v320x200 instead and the compiler will gladly accept. Derived classes are happily welcomed where their ancestors tread. :) A real life example would be animals... if we had an animal class, we could derive classes like mammal, amphibian, fish, etc. From there we derive even more classes from those derived classes, to describe different families and species. But while those classes may be derived, they're all still animals and should be accepted as such. So when we derive a class from an ancestor, all the public stuff from the ancestor is passed on to the derived class, and these derived classes can be accepted as parameters to functions using their ancestors. BUT this introduces a small problem. If we pass a class as a parameter into some function and inside the function we use one of that class's methods, how does the compiler know what method is being used? The only thing it can do at compile time is assume that we mean that class's method itself, and not a method from a derived class (which might also be passed in) which could have overwritten the method. But that might not be what we want. For example, say we have an ancestor class "Spider" with a method called "SearchForFood();" Now many spiders just eat other insects so the method for the generic spider class would involve the spider walking around the web and searching for anything that it trapped. But what about a derived class "BlackWidowSpider" ? A black widow might also eat its husband after mating, so that's another feeding option. Hence we'd replace the SearchForFood method with another method that's more specific to the black widow's feeding style. Now if we had a function called SpiderThink(Spider &activeSpider), where one of the options was to call activeSpider.SearchForFood(), how is the compiler gonna know if we're gonna called SpiderThink with a regular spider or a black widow? If it doesn't know what (if any) derived classes are gonna be used instead, it can't generate code, so by default it assumes you mean the generic spider's SearchForFood method. That would be bad for the black widow, since that would keep her from enjoying probably one of her favorite meals. Isn't there any way for the compiler to know that sometimes you might wanna use a derived class instead, so it'll wait until runtime to determine which method to use? There is. Welcome to virtual functions. By adding the word "virtual" to the beginning of a function's declaration inside a base class, the compiler is told "derived classes should have their functions called instead if they replace the base, so wait until runtime to resolve any calls for this method". You might think every method function should be virtual due to how natural it is, but honestly there's no reason for it a lot of the time... not all classes are intended to have descendents, and not all references to a class are intended to use derived ones, so you really only need to use it when you think it applies. There's also a small overhead issue... since the resolution of the method is done at runtime, the compiler will generate sets of function pointers in order to know what to choose. While this is a pretty trivial performance cost, it's something you wouldn't want to abuse in a putpixel for example. Fortunately you don't have to go much higher up than a putpixel before the cost of making a function virtual is effectively meaningless, so there's nothing to worry about (I find it funny how many people come telling me how horrible virtual functions are... well of course you don't use them inside a pixel-by-pixel loop, but you wouldn't use selective function pointers in a pixel-by-pixel loop either now would you? I thought virtual functions would be a horrible slowdown at first, but as long as you use them wisely they're nothing to be worried about). Now in our CVidDevice class, we have five virtual functions; the destructor, the Activate function (setting the video mode for fullscreen), the blit, and the two palette set/get methods. Note that you can't make a constructor virtual directly (how can you virtualize declaring a variable, when you have to know what you're declaring? :) but every other method, including the destructor, is game. We certainly want to virtualize the destructor because derived devices might add extra stuff to deallocate (dunno why they would want to, but it could happen) and since you never know what might be allocating or deallocating a device, it's a good idea. None of my code yet has done anything more than declare a prototype instance of each derived (concrete) device, so making the destructor non-virtual wouldn't make any difference so far, but I like to leave the option open. The other four are obviously intended to be virtual... that's the whole point of this abstraction layer, being able to call a mode set or blit without having to know which specific mode or which blitter to call at compile time. We wanna dynamically deal with modes, so we need to dynamically deal with what functions need calling. Simple as that. :) (BTW: You can do virtual constructors indirectly by making a virtual method designed to create a new instance of the current class and pass back the pointer to the caller; it's a design pattern often called a "factory method"... you'll probably see them along with many other design patterns later on in the series). _____Whoa Holy cow, I've broken 32k in this article... WAY more than I intended, and I still haven't scratched the surface. We still have yet to spell out CVIDDEVI.CPP, as well as the other four primary classes for this video system, so we've got another few articles left with this topic before moving on, that much is for sure. We'll finish up with the devices next time, then take a look at CVidControl, since the two go hand in hand. :) Until then, :) Chris Hargrove a.k.a. Kiwidog / Terraformer, Hornet alumni Technology Programmer, Raven Software email: Disclaimer: These articles are in no way affiliated with Raven Software, and represent the views and opinions of the author solely. ----------------------------------------------------------------------------> :: "Advertisement : X'97 Takeover" :: HarleQuiN / SuccesS - arjen@vin.nl Nostalgia and SuccesS invite you to X'97 Takeover! 04-06 April 1997, The Auditorium, Eindhoven. That's right, Holland's phattest, dopest, funkiest and fantasticest party returns once again! Come on down, and taste the atmosphere, the competitions, the live performances and some of the craziest, zaniest weirdos ever to sit behind a computer screen! For more information, please use the following media... x97take@dds.nl http://www.hacom.nl/~jal/X97-Takeover We really hope you're able to come! >------------------------------------------------------- General Information -- _____The Hornet Archive Master Site : USA (California) - (ftp|www).hornet.org/pub/demos Mirrors : Portugal - ftp.telepac.pt/pub/demos Sweden - ftp.luth.se/pub/msdos/demos USA (Wisconsin) - ftp.uwp.edu/pub/demos USA (Pennsylvania) - ftp.co.iup.edu/code (from /demos/code) _____DemoNews New issues - /incoming/info Old issues - /info/demonews Supplemental files - /info/dn_other How to subscribe: Mail - listserver@unseen.aztec.co.za Body - subscribe demuan-list FIRST_NAME LAST_NAME _or_ Body - subscribe demuan-list HANDLE DemoNews is sent to your e-mail's "Reply-To" field. How to unsubscribe: Mail - listserver@unseen.aztec.co.za Body - unsubscribe demuan-list _____Contact Address questions@hornet.org >------------------------------------------------------------------------------ EODN