home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-09-15 | 130.6 KB | 2,971 lines |
- Volume 2, Number 3 September 15, 1991
-
-
-
-
-
-
-
-
-
-
-
-
-
- **************************************************
- * *
- * QBNews *
- * *
- * International QuickBASIC Electronic *
- * Newsleter *
- * *
- * Dedicated to promoting QuickBASIC around *
- * the world *
- * *
- **************************************************
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The QBNews is an electronic newsletter published by Clearware
- Computing. It can be freely distributed providing NO CHARGE is charged
- for distribution. The QBNews is copyrighted in full by Clearware
- Computing. The authors hold the copyright to their individual
- articles. All program code appearing in QBNews is released into the
- public domain. You may do what you wish with the code except
- copyright it. QBNews must be distributed whole and unmodified.
-
- You can write The QBNews at:
-
- The QBNews
- P.O. Box 507
- Sandy Hook, CT 06482
-
- Copyright (c) 1991 by Clearware Computing.
-
- The QBNews Page i
- Volume 2, Number 3 September 15, 1991
-
-
-
- ----------------------------------------------------------------------
-
- T A B L E O F C O N T E N T S
-
-
- 1. From the Editor's Desk
- Greetings From The Microsoft Developers Conference ........... 1
-
- 2. Ask The Doctor
- QB's Hidden Data Copying by Ethan Winer ...................... 2
-
- 3. Advertisement
- GFA-BASIC for MS-DOS and Windows 3.0 ......................... 6
-
- 4. View Print
- Spill the Wine By J.D. Hildebrand ............................ 7
-
- 5. Graphically Speaking
- Fonts in a Can by Larry Stone ................................ 12
- Manipulating Sprites in Screen 13 by Fred Sexton Jr. ......... 17
-
- 6. Who ya gonna call? CALL INTERRUPT
- A Bug Free CALL INTERRUPT by Cornel Huth ..................... 21
-
- 7. The QBNews Professional Library
- An Event-driven Mouse Support Libary by Tony Elliot .......... 23
-
- 8. Advertisement
- E-Tree Plus By EllTech Development, Inc. ..................... 37
-
- 9. Algorithms
- Cardans's Method for Solving Cubes by Richard Jones .......... 39
-
- 10. Fun and Games
- Lines With Style by Larry Stone and Charles Graham ........... 46
-
- 11. EOF
- Receiving The QBNews ......................................... 48
- Submitting Articles to The QBNews ............................ 49
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The QBNews Page ii
- Volume 2, Number 3 September 15, 1991
-
-
-
- ----------------------------------------------------------------------
- F r o m t h e E d i t o r ' s D e s k
- ----------------------------------------------------------------------
-
- Greetings From The Microsoft Developers Conference
-
- I've just returned from the Microsoft Developers Conference held in
- Seattle at the end of August. I'm sure it was a good time for all who
- attended. It was nice to finally meet some of the people I've been
- speaking to electronically over the years. For those who didn't or
- couldn't attend, I recommend you try to make the next one when ever it
- is held.
-
- The good news from Seattle came during Bill Gates keynote address.
- When asked point blank if Microsoft has abandoned QuickBASIC for DOS
- to concentrate on their Windows products, BG said no. In fact, he
- stated that Microsoft was currently working on an upgrade to
- QuickBASIC, and I believe him.
-
- So here is your chance. I want you to send in you suggestions on what
- should be added to the next QuickBASIC. I'll compile the best
- suggestions and see that Microsoft receives them. I'll also publish
- the top 10 in the next QBNews. With a little luck, we may get some of
- our suggestions incorporated into the next release.
-
- When making your suggestions, use all the new features included with
- BASIC 7.1 PDS as the baseline as to what will be in the next
- QuickBASIC. Also, keep in mind that QuickBASIC is a low end product.
- Therefore, you aren't likely to see ISAM or OS/2 support ever. They
- will always be contained in the PDS version of BASIC.
-
- Look forward to hearing your suggestions. Until next time, happy
- reading.
-
- Dave Cleary - Editor of The QBNews
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The QBNews Page 1
- Volume 2, Number 3 September 15, 1991
-
-
-
- ----------------------------------------------------------------------
- A s k T h e D o c t o r
- ----------------------------------------------------------------------
-
- Ask The Doctor
-
- Dear Dave,
-
- Enclosed are two sets of functions which are in effect identical, but
- their differences cause a strange phenomenon.
-
- The code in Listing 1 appears to me to be much more involved and
- confusing. Constantly re assigning variable names from one to another
- and GOSUB'ing to a called routine.
-
- The code in listing 2 directly calls the called routine without using
- an intermediate variable. This code is more readable, this code is
- tighter, this code is smaller, this routine runs microscopically
- faster. When I slow my 386 to an effective 8mhz and I run the
- routines in a FOR 1000 NEXT Loop, you will notice a time savings of a
- wonderful 3 seconds.
-
- This code compiles 502 bytes LARGER !. . . .
-
- Something is not right. . .
-
- Obviously I am missing something. . .
-
- I am not one to quibble over milliseconds, I will sacrifice the 502
- bytes for readability, but I would really like to understand why this
- happens.
-
- Richard Gray
- [See listings at end of the article]
-
- Ethan Winer responds,
-
- Richard,
-
- What you have discovered is BASIC's hidden copying of data, and in
- your program this happens in two different but related ways. In the
- first program only variables are being passed to the ConcaveFrame and
- QPrint routines. The second program passes both numeric and text
- constants (that is, literal numbers and quoted strings), and also
- numeric and string expressions. Regardless of whether you are passing
- constant data or an expression, BASIC must make a copy of the data,
- place it somewhere in memory, and then pass the address where the
- result was stored.
-
- In contrast, when a variable is passed to a SUB or FUNCTION procedure,
- BASIC can simply obtain the variable's address and place it on the CPU
- stack. The called routine may then read the data at that address, or
- assign a new value based on the statements in your program. But a
- constant or expression must be protected from being changed. Consider
-
- The QBNews Page 2
- Volume 2, Number 3 September 15, 1991
-
- the following CALL statement and SUB definition:
-
- CALL MySub("Test", 123)
- ...
- ...
-
- SUB MyProc(Work$, Value%)
- Work$ = "Hi mom!"
- IF Value% > 100 THEN Value% = 100
- END SUB
-
- BASIC can't allow your program to alter either of the incoming
- parameters, since that could affect other parts of the program that
- use the same constants. When the same quoted string is used more than
- once in a program, BASIC stores a single copy of the data. For
- example, if you have the statement PRINT "Insert disk in drive A" four
- times in your program, the quoted text is added only once. If BASIC
- allowed your program to assign new characters to this constant, the
- other PRINT statements would display the wrong text!
-
- The same goes for numeric constants. If BASIC stored the number 123
- in memory and passed that address, a subprogram that changed its
- incoming parameter would change the number when it is used in other
- places in your program. Therefore, BASIC always makes a copy of
- constant data before sending it to a SUB or FUNCTION procedure.
-
- A similar situation occurs with data expressions. When you pass the
- expression LCol + 1 as an argument to a subprogram, BASIC must
- calculate the result and store it somewhere. And when passing the
- expression STRING$(Length, "─") + "┘" to QPrint, BASIC again has to
- save the result somewhere before passing it on. To make matters worse
- BASIC also adds code to delete the temporary strings it creates, to
- release the memory they occupy when they are no longer needed. In
- your case you assigned Temp$ manually, and did not clear that string
- each time after using it as BASIC would.
-
- When fixed-length strings are passed as parameters the situation is
- even worse still. In that case BASIC first copies the fixed-length
- string to a regular string, passes the copy to the routine, makes the
- call, copies the data back in case the routine changed it, and finally
- erases the temporary string.
-
- I have a few suggestions that you may find useful. First, if you have
- a copy of Microsoft's CodeView debugger you will find it fascinating
- to trace through the assembly language instructions that BASIC
- creates. Indeed, this is precisely how I learned about BASIC's hidden
- data copying. You should also consider buying my book "PC Magazine's
- BASIC Techniques and Utilities" which is published by Ziff-Davis
- Press. This book is available at your local Waldenbooks and B. Dalton
- book stores, and in it I go into great detail about BASIC's internal
- workings. There are also many performance and code size optimization
- tips, as well as numerous other advanced BASIC topics.
-
- --Ethan Winer, Crescent Software
-
- The QBNews Page 3
- Volume 2, Number 3 September 15, 1991
-
-
-
- LISTING 1
- ---------------------------------------------------------------------
- DEFINT A-Z
-
- DECLARE SUB SetColor (Colur%)
- DECLARE SUB ConcaveFrame (TRow%, LCol%, BRow%, RCol%)
- DECLARE SUB QPrint (Text$, Row%, Col%, Colur%)
-
- TRow = 8
- BRow = 22
- LCol = 7
- RCol = 73
- CLS
-
- ConcaveFrame TRow, LCol, BRow, RCol
- SUB ConcaveFrame (TRow, LCol, BRow, RCol) STATIC
-
- Length = RCol - LCol - 1
-
- R = TRow
- C = LCol
- Clr = 120
-
- Txt$ = "╔"
- GOSUB ShowIt1
-
- C = LCol + 1
- Txt$ = STRING$(Length, "═")
- GOSUB ShowIt1
-
- C = RCol
- Clr = 127
- Txt$ = "╕"
- GOSUB ShowIt1
-
- FOR N = TRow + 1 TO BRow - 1
- R = N
- C = LCol
- Clr = 120
- Txt$ = "║"
- GOSUB ShowIt1
-
- C = RCol
- Clr = 127
- Txt$ = "│"
- GOSUB ShowIt1
- NEXT
-
- R = BRow
- C = LCol
- Clr = 120
- Txt$ = "╙"
-
- The QBNews Page 4
- Volume 2, Number 3 September 15, 1991
-
- GOSUB ShowIt1
-
- C = LCol + 1
- Clr = 127
- Txt$ = STRING$(Length, "─")
- GOSUB ShowIt1
-
- C = RCol
- Txt$ = "┘"
- GOSUB ShowIt1
-
- EXIT SUB
-
- ShowIt1:
- QPrint Txt$, R, C, Clr
- RETURN
-
- END SUB
-
- LISTING 2
- ---------------------------------------------------------------------
- DEFINT A-Z
-
- DECLARE SUB SetColor (Colur%)
- DECLARE SUB ConcaveFrame (TRow%, LCol%, BRow%, RCol%)
- DECLARE SUB QPrint (Text$, Row%, Col%, Colur%)
-
- CLS
- ConcaveFrame 8, 7, 22, 73
-
- SUB ConcaveFrame (TRow, LCol, BRow, RCol) STATIC
-
- Length = RCol - LCol - 1
-
- QPrint "╔" + STRING$(Length, "═"), TRow, LCol, 120
- QPrint "╕", TRow, RCol, 127
-
- FOR Row = TRow + 1 TO BRow - 1
- QPrint "║", Row, LCol, 120
- QPrint "│", Row, RCol, 127
- NEXT
-
- QPrint "╙", BRow, LCol, 120
-
- QPrint STRING$(Length, "─") + "┘", BRow, LCol + 1, 127
-
- END SUB
-
- If you have a question for Ask The Doctor, please submit it to:
- The QBNews
- P.O. Box 507
- Sandy Hook, CT 06482
-
-
- The QBNews Page 5
- Volume 2, Number 3 September 15, 1991
-
-
-
- ----------------------------------------------------------------------
- A d v e r t i s e m e n t
- ----------------------------------------------------------------------
-
- ONLY ONE PROGRAMMING LANGUAGE
- LETS YOU CROSS DEVELOP FOR WINDOWS 3.0 AND
- MS-DOS WITHOUT REWRITING CODE.
-
- INTRODUCING GFA-BASIC
-
- GFA-BASIC gives you a simple, but powerful language for developing
- sophisticated, state-of-the-art Windows 3.0 and MS-DOS applications.
- Write a program with either the DOS or Windows version of GFA-BASIC and
- port it to the other platform-Doubling the fruits of your effort and
- maintaining a common look and feel between both platforms.
-
- One Set of Source Code
- ----------------------
- Both versions of GFA-BASIC include 500 system and mathematical commands
- and functions to facilitate software development. At the same time,
- common commands and functions enable you to develop and maintain a
- single set of source code for each program.
-
- Simplifies GUI Development
- --------------------------
- Another 400 commands and functions in the Windows version simplify the
- development of a complete GUI interface, including clipboard, DDE,
- DLL's and dialog boxes. And, you don't need any additional libraries
- or the SDK
- In the DOS version, a subset of the same commands and functions
- lets you bring Windows-like programs to AT and XT-class PC's without
- using any additional tools.
-
-
- HALF PRICE INTRODUCTORY OFFER
- list intro
- GFA-BASIC for Windows 3.0 $ 495 $ 295
- GFA-BASIC for MS-DOS $ 295 $ 195
- Both Windows & DOS versions $ 790 $ 395
-
- Leverage your existing knowledge of BASIC and with GFA you can write
- more powerful Windows and DOS programs easily right away.
-
- To see for yourself how powerful GFA-BASIC is, just ask for our free
- Demo Disk - or better yet, order either or both products including all
- documentation on a trial basis with a full 100% money-back guarantee.
-
- Call 1-800-766-6GFA or write GFA Software Technologies, Inc.
- 27 Congress Street
- Salem, MA 01970
- Fax: 1-508-744-8041
- VISA/MasterCard accepted
-
-
- The QBNews Page 6
- Volume 2, Number 3 September 15, 1991
-
-
-
- ----------------------------------------------------------------------
- V i e w P r i n t
- ----------------------------------------------------------------------
-
- Spill the Wine By J.D. Hildebrand
-
- The editors of this publication have asked me to share my observations
- about language choices, and about where BASIC fits into the world.
- It's my pleasure to toss a few thoughts into the ether. I hope you'll
- respond with your own ideas.
-
- I've edited computer magazines for nearly a decade. It's a pretty good
- job, but people do hit you up quite a bit for free advice. "Should I
- buy a Mac or a PC?" they ask. (Buy a PC.) "Should I upgrade to UNIX?"
- (Sure, if you don't like software.) "How much memory and disk space do
- I need?" (Fifty percent more than you can afford.)
-
- These questions come up at cocktail parties, usually at trade shows.
- I'm attending in my official guise as Editor In Chief, which means
- I've got a tie on and I've taken the trouble to shake hands with the
- PR director for the sponsoring company, plus whoever he wants to
- impress. (PR people accumulate brownie points--and earn commissions,
- for all I know--by getting magazine editors to shake hands with
- company executives. The theory is that the executives will think the
- PR guy is so chummy with the editor that the company's products will
- gain favorable attention within the editor's magazine. It's all very
- cozy. Since neither the PR guy nor the executives ever bother to read
- the magazine, it's quite harmless to let them go on believing what
- they want to believe.)
-
- So I'm balancing a plate of fresh shrimp and oysters (they do feed
- editors well at these shindigs) in one hand while holding a glass in
- the other...and wondering how I'll manage to light a cigarette with
- both hands full...when some door-crasher comes wandering over and
- squints at my name badge. His eyes light up when he sees he's cornered
- an editor.
-
- "So you work for a programming magazine," he says, "even though it's
- one I've never heard of. So you must be some kind of expert, right?
- What programming language should I use?"
-
- I sigh, resisting somehow the urge to make a too-frank comment about
- the door-crasher's complexion. It's the notion that I have something
- valid to say in response to this question that gets me invited to
- these spill-wine-on-the-carpet bashes, after all, and ultimately make
- it possible for me to pay the mortgage. So I look both ways to make
- sure no one is listening, lean toward the door-crasher, and whisper
- confidentially: "Use the language you know."
-
- "Huh?"
-
- "Look," I continue, "all programming languages do pretty much the same
- things. It's amazing how alike they are. The main difference among
- them, as far as you're concerned, is that you know one of them and
-
- The QBNews Page 7
- Volume 2, Number 3 September 15, 1991
-
- you're considering a jump to another. Don't do it. Your knowledge of
- one language's idiosyncracies is at least as valuable as the flashy
- features some other language might offer. Use the language you know
- and don't apologize for it."
-
- The door-crasher sips his drink (his glass, I notice, is still nearly
- full, while I'm stranded across the room from the bar with a tumbler
- full of ice cubes) and shakes his head. "No," he says, "I really want
- to learn a new language. Which should it be?"
-
- I know what he's doing...he's waiting for me to say he should learn C.
- Years ago, I might have. C was, after all, the fastest-growing
- language on the PC platform.
-
- But those days are gone. This year, for the first time since C
- challenged Pascal in the middle of the last decade, the C market has
- stopped growing--even, I'm sure, begun to shrink. So I couldn't just
- tell d-c to learn C, nor C++ (while C was the clear successor to
- Pascal, C so far has no clear successor).
-
- "Well," I say to him, "in the absence of original thought of your own,
- you might do well to emulate your peers."
-
- "Huh?" He gawks at me.
-
- "Consider," I say, "that programmers in different kinds of
- organizations choose different kinds of languages. Viz: Programmers
- who work in shrinkwrap software companies--at Lotus and WordPerfect,
- companies like that--use C and assembler. There are exceptions to the
- rule, but the rule is that shrinkwrap software is written in C and
- assembler."
-
- "Yes, but--"
-
- "Then there are in-house corporate developers, programmers who develop
- software within companies whose main business is not software," I
- continue. "These guys use conservative, stodgy, standardized languages
- because the bottom line is riding on the programs they write and their
- reliability. They use C, COBOL, and FORTRAN."
-
- "I don't think--"
-
- "Yes, there are isolated pockets of Pascal and Modula-2," I say, "and
- of course there are the database systems, dBASE and Paradox and the
- like--they're very strong in the in-house corporate developer
- community."
-
- "But what about--"
-
- "Then there are the consultants," I continue. "This is the largest
- group so far, and the most highly motivated. They have to finish their
- software today so they can ship out the invoice first thing in the
- morning. They can't afford to wrestle with bit-twiddling--they have to
- install working apps. And they have to be able to correct or change
-
- The QBNews Page 8
- Volume 2, Number 3 September 15, 1991
-
- the apps months or years later. These guys use high-level languages to
- write maintainable code--BASIC, Pascal, dBASE. The programs they write
- often perform well, but performance isn't the primary concern for
- these programmers. Staying in business is the important concern."
-
- "I still think--"
-
- "And hobbyists," I conclude, "use all kinds of languages, especially
- BASIC, Pascal, and C. They don't have customers or deadlines,
- generally, so they can afford to use any language they like."
-
- At this point the door-crasher is starting to look for an excuse to
- sidle away. He holds up his now-empty glass and gestures toward the
- bar, but I grab him by his tie.
-
- "Unless of course you're looking to become a Windows programmer," I
- say, giving his tie a tug as his face turns red. "That's it, isn't it?"
-
- "Mrffle," he gasps.
-
- "Good thinking," I congratulate him. "These days there are three kinds
- of PC programmers: the ones who already support Windows, the ones who
- are developing a Windows strategy, and the ones who are out of
- business but don't realize it yet."
-
- The door-crasher wheezes.
-
- "The way I see it," I say, "there are four routes to Windows
- programming. Want to hear 'em?"
-
- The door-crasher shakes his head, signalling "no," but I'm on a roll.
-
- "First, there's C and the SDK. That's the Microsoft Software
- Development Kit, got it? You've heard of it. For years, this was the
- only way to write WinApps. But unless you've got the financial
- resources of Lotus Development Corp. and the intellectual resources of
- Charles Petzold to throw at the project, this just isn't a reasonable
- way to write software. Life's too short."
-
- The door-crasher struggles as his face starts to flush.
-
- "Then there's C++ and class libraries. C++ is turning out to be a
- pretty good language for writing Windows applications. I expect most
- professional Windows programmers will use C++. Are you learning C++?"
-
- The door-crasher doesn't respond.
-
- "If you don't like C++, you could try one of the proprietary
- object-oriented languages: Smalltalk, Actor, Turbo Pascal, TOOL, one
- of those. The OOP languages promise to make it simple to write
- WinApps, but so far most of them don't have very good libraries of
- reusable classes. Without reusable class and object libraries, you
- don't get many benefits from OOP."
-
-
- The QBNews Page 9
- Volume 2, Number 3 September 15, 1991
-
- The door-crasher shakes his head vigorously. He seems to agree with me
- quite fervently.
-
- "Or you could check out one of the drag-and-drop tools," I say, "like
- Visual Basic. These tools let you design your application visually,
- then integrate the graphical front-end with efficient processing
- engines written with the same tool or in some other language.
- Descendants of the screen-painter UI tools available under DOS, these
- flashy new tools offer the best payoff in making Windows programming
- accessible. If you're looking to get started as a Windows programmer,
- I'd recommend these tools. Got it?"
-
- I release the door-crasher and he falls to his knees wheezing.
-
- "Look," I say, "I know you appreciate the advice, but this is
- ridiculous. Get up, get up."
-
- The door-crasher wanders off and I make another quick cruise past the
- food tables. Oddly enough, no one else comes over to talk with me.
-
- It's good being an editor.
-
- Now, this is a funny little story, and portions of it aren't true...
- but there are some nuggets of truth in it too.
-
- We get caught up too often in defending our language choices. Bah.
- They don't need defending. Use whatever works for you--that's the
- strategy that's kept me writing 15,000 lines of BASIC code per year,
- at a minimum, since 1978.
-
- When I joined the Programmer's Journal staff last month, I was
- appalled to find a bunch of workers clustered around a table counting
- names on a mailing list. Turns out they had to do a ZIP Code zone-
- count for the Postal Service for third-class mailing. "I could write
- a program to do this," I said.
-
- "Oh, we know," they said, "but it would take too long."
-
- Take too long? Well, maybe. They'd asked some of the other
- programmers on the staff about the project, and they rightly
- estimated that it would take a week or two of C coding. I wrote the
- program for them in three hours using BC7.
-
- I'm pretty sure a C version of the program would work faster than my
- BASIC version...but Programmer's Journal has been around for 10
- years, and the zone counts have always been a manual process. Scary,
- I think.
-
- BASIC is the language I choose whenever I have to finish a project
- the same day I start it.
-
- Nine out of 10 BASIC programmers don't get paid for the programs they
- write. That's one of the reasons BASIC has a reputation as a
- hobbyists' language.
-
- The QBNews Page 10
- Volume 2, Number 3 September 15, 1991
-
-
- What most folks don't know is that the 1 out of 10 professional BASIC
- programmers outnumber the professional Pascal programmers and match
- the number of professional C programmers. That's a lot of people.
-
- If I were to leave the editorial trades and return to programming,
- and if I could choose just one language, it would surely be BASIC. I
- can always earn a living with a good BASIC compiler. I may not get
- much business from the Fortune 500, but the Unfortunate 5 Million
- will know where to find me.
-
- Stay warm.
-
- JDH
-
- *********************************************************************
- J.D. Hildebrand has edited computer magazines since joining Miller
- Freeman Publications as technical editor of PORTABLE COMPUTER in 1983.
- Along the way, he has worked on MICRO COMMUNICATIONS, PORTABLE 100,
- EPSON WORLD, DATA GENERAL MICRO WORLD, PROFESSIONAL COMPUTING, VAR, PC
- COMPANION, PORTABLE COMPUTER REVIEW, LAPTOP USER, CFO, AI EXPERT,
- COMPUTER LANGUAGE, EMBEDDED SYSTEMS PROGRAMMING, SOFTWARE DEVELOPMENT
- INTERNATIONAL, UNIX REVIEW, PROGRAMMER'S JOURNAL and the C GAZETTE. He
- currently serves as editorial director at Springfield, Oregon-based
- Oakley Publishing Co., and as editor of WINDOWS TECH JOURNAL, which
- will commence monthly publication in January 1992.
- *********************************************************************
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The QBNews Page 11
- Volume 2, Number 3 September 15, 1991
-
-
-
- ----------------------------------------------------------------------
- G r a p h i c a l l y S p e a k i n g
- ----------------------------------------------------------------------
-
- Fonts in a Can by Larry Stone
-
- You know how it goes - in the process of creating a nifty program,
- you get side tracked on an even more nifty subprogram. Eventually,
- this nifty subprogram turns into an extrodinary piece of work. Such
- is the story behind PrintROMtable - a routine to produce a library of
- graphics fonts without a font library!
-
- The original PrintROMtable was developed for FUSION (published in
- this issue). Based upon code published by PC Magazine,
- PrintROMtable was limited in it's scope. Because my time, like most
- of us, is limited, I made an early release of the code on the Quik_BAS
- internation echo, and asked others to join in it's development. The
- responce was outstanding. Rob Smetana immediately jumped into it with
- code to create italics. Francois Roy supplied code to elongate char-
- acters for a bold appearance. Bill Beasley supplied code to create
- tall characters, inspiring Mike Kelly to offer code that creates fonts
- that are 8, 14, 16, 28, or 32 pixel points in height. Both Rob and
- Mike supplied code to allow CGA systems access to the extended ASCII
- set (characters 128 through 255). Of course, my contribution continued
- with left-handed italics, underlined characters, inverse and backward
- characters, strike through, stencil characters, double wide and even
- condensed characters, and, not least of all, intergrating the various
- code supplied by the other, aforementioned contributors, into the one
- highly useful and variable module. You know how it goes - while in the
- process of creating a nifty program, it goes on and on and on...
-
- Before we get much further, you should know that PrintROM is run
- from a test program called, ROMtest.bas, and, although ROMtest traps
- and sets the screen to your highest resolution, the pixel positioning
- is coded for SCREEN 12. This means that if your computer monitor can't
- handle this resolution then you will see only some of the nifty things
- displayed or, in some cases, some of the diplay will be outside of the
- monitor's graphic boundaries (you can always tweek the xAxis and yAxis
- locations coded in the ROMtest program to place any string into your
- system's view area).
-
- So, what's so special about PrintROMtable? Plenty! It is a huge
- library of fonts without needing external libraries! The external libs
- supplied provide extended ASCII set 128 through 255. These are not
- necessary to the program unless your system is CGA and passes a string
- containing a high ASCII character to PrintROMtable. Even if your pro-
- gram runs on EGA or VGA, you may wish to include one or more of these
- font files for the special characters they provide, such as the copy-
- right and registered trade mark symbols (more on this subject later!)
- PrintROMtable compiles to around a 13K object file - as small or smal-
- ler than most "standard" font libraries! As small as this is, you are
- provided fonts ranging from 8 to 64 pixels tall in condensed, normal,
- bold, or double wide sizes; characters can be underlined, shadowed,
- italic (slanted left or right), inverted, backwards, stenciled, or
-
- The QBNews Page 12
- Volume 2, Number 3 September 15, 1991
-
- contain a strike through mark. Furthermore, you can print from left
- to right, right to left, top-down, bottom-up, or even at an angle!
-
- PrintROMtable has limitations. CGA systems can only use characters
- 8 pixels tall - this can be expanded to 16 by setting PR.Tall = True.
- EGA systems cannot access sizes 16, 32. However, EGA can have size 8
- expanded to 16 by setting PR.Tall = True. If you try to have an EGA
- system use font size 16 or 32, PrintROMtable will reset the size to 14
- or 28, respectively. This means that using PR.Height = 32 and PR.Tall
- equals True on EGA systems will produce a font 56 pixels high, not 64
- as intended. Only VGA has the entire range of 8, 14, 16, 28, 32, 56
- and 64 height characters.
-
- The heart of PrintROMtable is it's code to access the where-abouts
- of the ROM BIOS segment containing the character shape table.
-
- Once PrintROMtable has the pointer into the ROM segment that con-
- taining the character shape tables, it loops through the passed-in
- string, once for each character in the string. If a background color
- is called for, it uses LINE with a box and fill (BF) argument to paint
- a background color. If a background color is not requested then the
- background color is transparent. The code then loops 4, 8, 14, 16, 28
- 32, 56, or 64 times for each scan line of the character (depending on
- such factors as PR.Height, PR.Condesned, and PR.Tall).
-
- The 1st item of business is to determine what value, based upon the
- font size, need to be loaded into the BX register so that a subsequent
- call to BIOS interrupt 10h, function 1130h can point us to the correct
- memory address containing our scan lines:
-
- SELECT CASE PR.Height
- CASE 8 ' 8x8 font
- reg.bx = &H300
- CASE 14, 28 ' 8x14 font or 8x14 font double high
- reg.bx = &H200
- CASE 16, 32 ' 8x16 font or 8x16 font double high
- reg.bx = &H600
- CASE ELSE
- CLS : PRINT "Invalid Character Size": END
- END SELECT
-
- Having determined the BX value, PrintROMtable then sets AX = &H1130
- before it calls BIOS Video Service, &H10:
-
- reg.ax = &H1130
- InterruptX &H10, reg, reg
- ofst& = reg.bp
- sgmt& = reg.es
-
- For those with inquiring minds, function AX = 1130h is called with AX
- and BX set as follows:
-
- AX = 1130h
- BX = pointer specifier
-
- The QBNews Page 13
- Volume 2, Number 3 September 15, 1991
-
- &H0 INT 1Fh pointer
- &H100 INT 44h pointer
- &H200 ROM 8 by 14 character font pointer
- &H300 ROM 8 by 8 double dot font pointer
- &H400 ROM 8 by 8 DD font (top half)
- &H500 ROM alpha alternate (9 by 14) pointer
- &H600 ROM alpha alternate (9 by 16) pointer
-
- On return, the ROM BIOS function supplies:
-
- ES:BP = specified pointer
- CX = bytes/character
- DL = character rows on screen
-
- Even though PrintROMtable has the appropriate segment and offset to
- the character shape table, they may not be correct! The above call to
- the BIOS is only good for EGA, MCGA, or VGA systems. If PR.ScreenMode
- is less than 7 or, if you tell PrintROMtable to force the CGA address
- then PrintROMtable sets the character shape table's segment to &HFFA6.
-
- IF PR.ForceAddress OR PR.ScreenMode < 7 THEN sgmt& = &HFFA6
-
- Segment &HFFA6 contains the character table but, unlike our INT 10h
- table pointer, this table only goes to the first 127 ASCII characters.
- This means that if PR.ScreenMode is 1, 2, or 3 (same as SCREEN 1, 2,
- or 3) or, if you instruct PrintROMtable to force the address then, you
- cannot access the upper ASCII set without defining a disk font file.
-
- Since the objective of all of the contributors to this program was
- to create a self-contained, linkable module, we wanted to avoid asking
- users to have to have, or load, a 3rd-party file just to access the
- upper ASCII character set. Several people answered our call for ideas.
-
- Mike Kelly was 1st to supply code to accomplish this aim. Although
- his code was self-contained, it required 4k of memory to use the data.
- Cornel Huth described an approach similar to the one eventually taken
- with PrintROMtable: to use Int 1Fh to point to an array containing the
- high characters. Similar approaches were suggested by Bill Beeler and
- Dave Cleary. The final approach developed was by Rob Smetana and is
- similar in operation to the DOS program, Graftabl. Unlike Graftabl,
- Rob's approach does not require a TSR and it uses a meager 1024 bytes
- of memory. It does, however, use small, 1024 byte external files.
-
- External fonts are loaded by the routine with one GET statement:
-
- j% = FREEFILE 'Get a handle
- OPEN FontFile$ FOR BINARY AS #j% 'Open with this handle
- font$ = SPACE$(1024) 'Our fonts need just 1024 bytes (128 * 8).
- GET #1, , font$: CLOSE #j% 'Close file with handle j%
-
- PrintROMtable is supplied with four disk font files that access the
- characters used in international, U.S., Portuguese, and French-Canada
- ASCII sets. There can be additional 1024 font files added to the list
- by altering the appropriate area of the PrintROMtable routine. To add
-
- The QBNews Page 14
- Volume 2, Number 3 September 15, 1991
-
- a new font file, search PrintROMtable for:
-
- '**** You could create your own 1024 byte
-
- The code is self-expanatory and you should not have any trouble adding
- to the list.
-
- If your program is to access one or more of these font files, you
- might want to establish a default file to use (if you don't designate
- a default file then the routine sets the default to number 1 -- inter-
- national). To set a default font file, before you make any calls to
- PrintROMtable, LET PR.DefaultFile = ? Where ? is the number of the
- file to use (presently, 1 through 4).
-
- Whether a default font file is established or not, you can, at any
- time, instruct the routine to load any of the font files. First, you
- should reset the current font file:
-
- PR.ReadHiAscFile = -1
- CALL PrintROMtable(a$, PR)
-
- Then, to set the new file, simply:
-
- PR.ReadHiAscFile = 2 (or 3, or 4, etc.)
-
- The next call to PrintROMtable will then read and use the new fonts.
-
- If your font files are not located in the default path, before you
- you make your first call to PRINTROMtable, you need to inform it where
- to look. This, too, is a simple instruction:
-
- LSET PR.DiskFontLoc = "C:\OFF\IN\URANUS"
-
- Many QB programmers set their SCREEN mode by using literals, ie.,
- they use code similar to, SCREEN 9. PrintROMtable needs to know what
- screen you are using. To inform it which screen mode is in use, do
- something like:
-
- PR.ScreenMode = 12
- SCREEN PR.ScreenMode
-
- Putting it all together, your program should look something like:
-
- REM $INCLUDE: 'printrom.bi'
-
- LSET PR.DiskFontLoc = "D:\SNAZZY\FONT\AREA\"
- PR.DefaultFile = 1
-
- PR.ScreenMode = 9
- SCREEN PR.ScreenMode
-
- PR.Height = 8: PR.xAxis = 20: PR.yAxis = 30
- PR.StepX = 9: PR.CharClr = 15: PR.Shadow = -1
- PrintROMtable "Hello there, my name is", PR
-
- The QBNews Page 15
- Volume 2, Number 3 September 15, 1991
-
-
- PR.Tall = -1: PR.xAxis = 20: PR.yAxis = 48
- PrintROMtable "John Doe", PR
-
- When working from within the QB environment, you need to load QB
- by typing, "QB /Lqb". The sample program that demonstrates how to use
- PrintROMtable is named, "ROMTEST.BAS". It is in the file, PRINTROM.ZIP
- along with PRINTROM.BI, and ROMTEST.MAK. Run QB with the "/Lqb" switch
- then open the file RomTest.Bas. That's all you have to do.
-
- One final note. PrintROMtable can do a great deal of fancy work to
- your strings. The fancier your output, the more time required to per-
- form the work. One saving grace is that all of the fancy manipulation
- performed by PrintROMtable is considerably faster once compiled as an
- EXE file. However, compiled or not, expect certain processes, such as
- PR.Elongate = 2 (double wide) to be slower than the simpler processes
- like 8 pixel high, normal character writes.
-
- [EDITOR'S NOTE]
- All code for this article can be found in PRINTROM.ZIP
-
- **********************************************************************
- Larry Stone is President of LSRGroup and is involved in writing
- instructional and large data base application systems for business and
- institutional clients. He is also the author of SERVICES, a shareware
- application program rated a trophy by "Public Brand Software". He can
- be reached at LSRGroup, 2945 "A" Street, North Bend, OR 97459, or in
- care of this newsletter.
- **********************************************************************
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The QBNews Page 16
- Volume 2, Number 3 September 15, 1991
-
- Manipulating Sprites in Screen 13 by Fred Sexton Jr.
-
- In January I bought my first real computer(386SX).I don't count the
- TI-99 that's still in the closet.After a month or so of GWBASIC I
- bought QuickBasic 4.5 .I was instantly hooked,and have spent alot of
- my spare time coding.
-
- I wanted to make a few animated educational games for my kids.I soon
- found that animation would require alot of "sprites".I needed an easy
- to use drawing program to create sprites in my favorite mode SCREEN 13
- (320x200x256).So I set out to create one.I ended up with "THE SPRITE
- MASTER" (so named because I finally had mastered them). Along the way
- I learned alot about SCREEN 13.I decided to pass along some of it.
- NOTE:I always use DEFINT A-Z.So,all arrays discussed here are integer
- arrays.
-
- The easiest way to store an image is with Q.B.'s GET statement. To
- find the minimum size to dimension an array,I set up a loop getting a
- 10w X 10h image decreasing the number of elements each time until an
- error occurred.I don't care for the formula in the book.The result was
- that a 10w X 10h image required 52 elements or, DIM ary(51).The
- elements are numbered starting with zero by default. So,always
- remember to DIM an array with a value that is one less than you really
- want.Knowing that the colors are in the range of 0 - 255 we can
- determine that each pixel requires 8 bits (1byte) to store it's color
- value (255 = 11111111 B).So,in a 10w X 10h image there are 100 bytes
- or 50 words.We can conclude that GET needs the number of words in the
- image plus two additional words.
-
- Therefore : elements = ((width * height) + 1) \ 2 + 2
- (the "+ 1" takes care of odd values)
-
- To find out what the two extra words are for,we'll GET a couple of
- different size images from a blank screen. Then we'll compare the
- values in the resulting arrays.
-
- With image1 = 10w X 10h and image2 = 20w X 5h:
- ary1(0) = 80 ary2(0) = 160
- ary1(1) = 10 ary2(1) = 5
- ary1(2-51) = 0 ary2(2-51) = 0
-
- Now we know the first two elements are used by GET to store the image
- size information.The first element is the image width in bits.
- Remember we said 1 pixel = 8 bits.To find pixel width just divide by
- 8.The second element is the height. To determine the rest of the
- pattern let's set a few points and get the image.
-
- FOR t = 0 TO 3
- PSET(t , 0), t + 1
- PSET(t , 1), t + 5 NEXT
- GET (0 , 0) - (3 , 1), ary
-
- We already know what's in the first two elements so let's look at the
- rest.
-
- The QBNews Page 17
- Volume 2, Number 3 September 15, 1991
-
-
- ary(2) = 513
- on the byte level
- low byte = 1 => value of the pixel (0,0)
- high byte = 2 => value of the pixel (1,0)
-
- ary(3) = 1027
- on the byte level
- low byte = 3 => value of the pixel (2,0)
- high byte = 4 => value of the pixel (3,0)
-
- ary(4) = 1541
- on the byte level
- low byte = 5 => value of the pixel (0,1)
- high byte = 6 => value of the pixel (1,1)
-
- ary(5) = 2055
- on the byte level
- low byte = 7 => value of the pixel (2,1)
- high byte = 8 => value of the pixel (3,1)
-
- This was a 4w X 2h image.Starting at the low byte the third
- element,the next four bytes correspond to the first row of four
- pixels.The next four bytes correspond to the second row of four
- pixels.Analysis of other images will show the same pattern.Thus we can
- conclude for an image with a width of W :
-
- Starting with the low byte of the third element,the first W # of
- bytes will correspond to the pixels in the first row and the
- second W # of bytes will correspond to the pixels in the second
- row and so on for each row.
-
- Once the pattern is known manipulating the arrays can accomplish many
- things.Here are a few examples.
-
- Change a color:
-
- To change a color in an image array we would search the array at the
- byte level for the source color.When it is found we will replace it
- with the new color.
-
- In pseudo code:
-
- FOR t = 0 TO bytes - 1 (because we start with zero)
- IF PEEK (t + start offset) = oldcolor THEN
- POKE t + start offset, newcolor
- END IF
- NEXT
-
- Mirror an image:
-
- To create a mirror image we need to reverse the order of each row of
- pixels.We know the pixels are stored in groups corresponding to the
- width of the image.So,in a 10w X 10h image starting with the low byte
-
- The QBNews Page 18
- Volume 2, Number 3 September 15, 1991
-
- of the third element the first byte would be the first pixel in the
- first row and the tenth byte would be the last pixel in the first
- row.To make it easier let's dimension a second array the same size as
- the first.Then after making the size information the same we can just
- copy the bytes from one to the other in the proper order (first to
- tenth,second to ninth,etc.).
-
- In pseudo code:
-
- aofs=offset of first pixel in first row of source
- bofs=offset of last pixel in first row of target
-
- FOR first row TO last row
- FOR first pixel TO last pixel
- PEEK at aofs + increasing pixel number (0 to start)
- POKE to bofs
- decrease bofs to next lower pixel
- NEXT source pixel
- aofs=offset of first pixel in next row of source
- bofs=offset of last pixel in next row of target
- NEXT row
-
- Superimpose an image:
-
- To superimpose an image ie. put it front of or behind existing images
- without destroying them or messing the colors up.Again it is easiest
- to use a second array of the same size.First we get the area of the
- screen where we are planning to put the image.Then to put in front we
- take all non-zero (background) pixels from the first array and put
- them into the second array.To put behind we only poke pixels from the
- source array there are zeros in the second array. The result can be
- PUT with PSET and we won't end up with the blacked out area we
- normally have.
-
- In pseudo code:
-
- IN FRONT:
- GET target area into work array
-
- FOR first pixel in first row TO last pixel in last row
- PEEK at a source pixel
- IF pixel is not zero THEN POKE pixel into work array
- NEXT
- PUT work array PSET
-
- BEHIND:
- GET target area into work array
-
- FOR first pixel in first row TO last pixel in last row
- PEEK at a work pixel
- IF pixel is zero THEN
- PEEK at same pixel in source
- POKE pixel into work array
- END IF
-
- The QBNews Page 19
- Volume 2, Number 3 September 15, 1991
-
- NEXT
- PUT work array
- PSET
-
- These are just a few of many possibilities.(The superimpose routine
- could be easily modified to allow partial PUTS.) The documented source
- for each routine discussed is in G13UTIL.BAS .
-
- I recently started learning MASM and have converted these to faster
- versions.I plan to release a shareware library of fast routines for
- SCREEN 13,as well as a shareware version of "THE SPRITE MASTER". I
- plan to Upload them to COMPUSERVE and AMERICA ON LINE. Comments and/or
- suggestions would be appreciated.
-
- [EDITOR'S NOTE]
- All code for this article can be found in SPRITE.ZIP
-
- *********************************************************************
- Fred Sexton Jr. is an electrician for Ford Motor Co. He works
- extensively with Allen Bradley Programmable controllers and Kuka
- robotics.He received electrical training in the NAVY as an electronics
- technician / reactor operator. He can be reached on Compuserve at
- 70253,163 and on A.O.L. at 7408.
- *********************************************************************
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The QBNews Page 20
- Volume 2, Number 3 September 15, 1991
-
-
-
- ----------------------------------------------------------------------
- W h o y a g o n n a c a l l ? C A L L I N T E R R U P T
- ----------------------------------------------------------------------
-
- A Bug Free CALL INTERRUPT by Cornel Huth
-
- There is a problem with the CALL INTERRUPT routine in QuickBASIC
- and BASIC PDS 7. This table highlights the problems.
-
- Problem 4.0 4.0b 4.5 CH 6.0 7.0 7.1
- -----------------------------------------------+--------------
- 1. DI parameter X | . .
- 2. INT25/26 X X X | . . X
- 3. INT24 environment X X X X | . .
- 4. INT24 EXE ON ERROR GOTO | . . D
- 5. INT24 EXE NO ERROR TRAP X X X X | . . D
- |
- . not tested
- X - error present
- D - DOS INT24 fatal error handler gains control
- CH - The CH version is the INTRPT.OBJ that's in QBNWS105.
- --------------------------------------------------------------
- 1) typo causes the passed DI register parameter to NOT be used
- 2) DOS INT25/26 will always report success even if it failed
- -- DOS fatal error (INT24) in:
- 3) QB environment causes system crash
- 4) EXE w/ ON ERROR GOTO handler causes system crash
- 5) EXE with no ERROR handler causes system crash
-
- In the QuickBASIC 4.x environment any fatal DOS error during a CALL
- INTERRUPT crashes the system. In QB 4.x EXEs with ON ERROR GOTO
- handlers the error is trapped by the error handler. In QB 4.x EXEs
- without ON ERROR GOTO the runtime code starts to print the error text
- to the screen but only gets part of it printed before it locks up.
-
- In PDS 7, the evironment does not crash on a fatal DOS error because
- the BP register is saved (in b$SaveBP) before executing the interrupt.
- Apparently BASIC needs the original BP if a fatal DOS error occurs so
- that it can reference the return address of the caller.
-
- In PDS 7 EXEs, with or without ON ERROR GOTO handlers, fatal errors
- are simply passed through to the INT24 error handler. This brings up
- the Abort, Retry, Fail prompt. Pressing F returns to INTERRUPT.
- INTERRUPT then returns with the carry flag set and DOS error 83d in AX
- (83d=Fail on INT24). The ON ERROR GOTO handler is never invoked.
- Pressing A causes the entire program to immediately exit to DOS.
-
- Wouldn't it be great if CALL INTERRUPT worked predictably all the
- time? Now it does. INTRPT2.OBJ is a direct replacement for either QB
- or PDS that traps fatal DOS errors and returns control, and decision
- making, to your program. When a fatal DOS error occurs, the carry flag
- is set and the DOS error code is returned in AX.
-
- For example, let's say you want to see if a file exists. What you
-
- The QBNews Page 21
- Volume 2, Number 3 September 15, 1991
-
- could do is open the file and check for any errors. This works fine as
- long as the drive of the file is valid and ready. But if the drive is
- a floppy and the door is open, boom. In the QB4 environment the system
- would lockup, even if ON ERROR GOTO were set. In PDS EXE programs the
- default DOS INT24 handler pops up on a fatal error, even with ON ERROR
- GOTO. This messes up the screen with the infamous Abort, Retry, Fail
- prompt and lets the user abort with files possibly open. My B-tree
- shareware libraries QBTree 5.5 and QBXDBF 1.0 (dBASE .DBF format) have
- support functions that make use of the INTERRUPT routines and I can't
- allow them to crash the system or present an Abort prompt. No more
- surprises!
-
- To update your version of INTERRUPT(X) put INTRPT2.OBJ in your
- library directory and then do the following:
-
- C>lib QB.LIB -INTRPT +INTRPT2;
- C>link /qu QB.LIB,QB.QLB,nul,BQLB45.LIB;
-
- BQLB45.LIB pertains to QuickBASIC 4.5. Use BQLB40 for QB 4.00 and
- BQLB41 for QB 4.00b. For BASIC PDS 7.x replace references to QB with
- QBX.LIB and QBX.QLB, and use QBXQLB.LIB for the library prompt.
-
- The source to INTRPT2.ASM, a sample FileExists() function, a DOS
- error listing and INTRPT2.OBJ are in INTRPT2.ZIP file.
-
- *********************************************************************
- Cornel Huth is chief designer and programmer for ScanSoft. He can be
- reached at 6402 Ingram Road, San Antonio, Texas 78238. When he's not
- twiddling bits he's thinking of ways he could.
- *********************************************************************
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The QBNews Page 22
- Volume 2, Number 3 September 15, 1991
-
-
-
- ----------------------------------------------------------------------
- T h e Q B N e w s P r o f e s s i o n a l L i b r a r y
- ----------------------------------------------------------------------
-
- An Event-driven Mouse Support Libary by Tony Elliot
-
- The mouse is one of the easiest-to-use interface devices available for
- PCs. Even though it has been extremely popular over the last several
- years, Microsoft didn't provide direct support for it in the BASIC
- programming language until the recent release of Visual BASIC for
- Windows (although the BASIC Professional Development System [PDS]
- includes indirect support of the mouse through routines in the "User
- Interface Toolbox" included with that product). This doesn't mean that
- the mouse has been unreachable from BASIC programs. Mouse services can
- be easily accessed through BASIC's "CALL Interrupt" routine (as
- illustrated in a previous issue of QBNews). Also, most BASIC add-on
- developers include mouse routines written in assembly language as part
- of their regular complement of functions. So why the need for
- *another* set of mouse routines? Well, there are several reasons:
-
- 1. If you don't already own one, commercial add-on libraries can get
- rather expensive. If you are only interested in adding mouse support
- to your programs, you might have to shell out $100 to $200 (or more)
- for a product that consists of several hundred routines, only a few of
- which you'll use for this purpose. However, add-on libraries like
- MicroHelp's "Muscle" ($189) or Crescent's "QuickPak Professional"
- ($199) are definitely the way to go if you can afford it. Many of the
- other routines included in those products will no doubt be useful to
- you down the road.
-
- 2. Many of the public domain or "shareware" mouse support alternatives
- are written in BASIC, usually invoking BASIC's "CALL Interrupt"
- service. Although this is a completely functional approach, there is a
- substantial amount of overhead required (in terms of speed and code
- generation). CALL Interrupt is a relatively slow service to begin
- with, and the results returned by it must then be translated into a
- usable form. Doing all of this from BASIC may not allow you to poll
- the mouse as frequently as required by some applications, therefore
- you may occasionally miss some real-time events such as button-clicks.
-
- 3. Using routines written in assembly language for minor tasks such as
- mouse support is, in my humble opinion, the way to go. It adds a
- minimal amount of overhead to your BASIC programs and does the job as
- quickly as possible. This equates to smaller, faster, and from the
- users' point of view, more responsive programs.
-
- 4. The set of mouse routines described in this article has one
- important feature that I haven't seen elsewhere in DOS-based BASIC.
- Utilizing the "ON UEVENT" service available since QB 4.00a, they allow
- you to create "mouse event-driven" programs. That is, instead of
- constantly polling the mouse for activity, you can go about your
- normal business and when a programmer-defined type of mouse activity
- occurs (a button press, release, or mouse movement), your program is
- interrupted and control is transferred to a subroutine that you
-
- The QBNews Page 23
- Volume 2, Number 3 September 15, 1991
-
- specify. This allows you to logically group your mouse-specific code
- instead of having it sprinkled here and there throughout your program.
-
- The two mouse-programming paradigms, "polled" and "event-driven," each
- have advantages and disadvantages. We will discuss each in detail as
- the routines are being presented below. The file MOUSE.REF contains a
- reference listing each of the routines individually, along with the
- appropriate descriptions and parameter lists associated with them.
-
- The various code fragments used below each assume that the file
- MOUSE.BI is $Included at the top of your program. It contains the
- declarations and the TYPE..END TYPE structures required by these
- routines. Many of the code fragments also assume that you have already
- reset the mouse and the pointer is visible.
-
- Also keep in mind that we won't be talking too much about -how- the
- routines actually work. Fully commented assembly source code is
- provided for those enquiring minds that "what to know." An example
- program called MOUSE.BAS is also included. It demonstrates all of the
- mouse routines described in this article.
-
- ----------------------------------------------------------------------
- Resetting the Mouse Driver
- ----------------------------------------------------------------------
-
- When writing programs that will recognize and accept input from a
- mouse, the first step is to determine if a software "driver" for the
- mouse is installed. If one is found, it must be "reset" before our
- program can actually communicate with the mouse. Calls to any of the
- other mouse routines described here (besides the three "reset"
- routines) will simply be ignored if the mouse has not been reset or is
- not present at all. As a convenience, three routines are provided to
- determine the presence of the mouse and to reset it, if desired:
-
- MouseReset% - An integer function that checks to see if a mouse driver
- is installed, and if so, resets it. The number of buttons the mouse
- has is returned as a result, or zero if a mouse driver is not
- installed. When the mouse is reset, it is left in the following
- state:
-
- - Mouse pointer is at the center of the screen
-
- - Display page for mouse set to 0
-
- - Mouse pointer is hidden (off)
-
- - Mouse pointer shape is the default arrow shape in the
- graphics video modes or a reverse block in the text modes.
-
- MouseAlreadyReset% - An integer function that checks to see if the
- mouse has already been reset by this program. If so, it returns the
- number of buttons the mouse has, otherwise it returns zero and takes
- no further action. This is handy in situations where you don't want to
- reset the mouse if it has been reset previously (doing so
-
- The QBNews Page 24
- Volume 2, Number 3 September 15, 1991
-
- unnecessarily takes a couple of seconds and has other, sometimes
- undesirable, effects such as those listed above).
-
- MouseInstalled% - An integer function that checks for the presence of
- a mouse without resetting it.
-
- Most of the time, MouseReset% will be all that you need. For example:
-
- NumberOfButtons% = MouseReset%
- IF NumberOfButtons% THEN
- PRINT NumberOfButtons%; " button mouse found and reset!"
- ELSE
- PRINT "Mouse not found."
- END IF
-
- Once the mouse has been successfully reset, you are then free to use
- any of the other functions.
-
- ----------------------------------------------------------------------
- Obtaining Information About Mouse Hardware and Software
- ----------------------------------------------------------------------
-
- If you wish to obtain specific information about the mouse hardware
- and software currently in use, the MouseGetInfo routine can be used to
- identify the version number of the mouse driver software, the type of
- mouse (bus, serial, InPort, PS/2, or HP), and the hardware interrupt
- line (IRQ) the mouse is sitting on. For example:
-
- CALL MouseGetInfo(MajorV%, MinorV%, MouseType%, Irq%)
- PRINT "Mouse software version:";MajorV% + MinorV% / 100
- PRINT "Mouse type: ";
- SELECT CASE MouseType%
- CASE 1
- PRINT "Bus"
- CASE 2
- PRINT "Serial"
- CASE 3
- PRINT "InPort"
- CASE 4
- PRINT "PS/2"
- CASE 5
- PRINT "HP"
- CASE ELSE
- PRINT "Beats the heck outta me! Type#";MouseType%
- END SELECT
- PRINT "Using IRQ";Irq%
-
- This information is useful in some cases, but generally there's no
- particular need for you to be aware of it.
-
- ----------------------------------------------------------------------
- The Mouse Pointer
- ----------------------------------------------------------------------
-
-
- The QBNews Page 25
- Volume 2, Number 3 September 15, 1991
-
- After the mouse has been reset, you'll want to make the mouse
- "pointer" (or "cursor") visible. The visibility state of the mouse
- pointer is controlled by the MousePointerOn and MousePointerOff
- routines. Remember, the MouseReset function initially turns the
- pointer OFF. For example:
-
- NumberOfButtons% = MouseReset%
- LINE INPUT "The mouse pointer is invisible. Press <Enter> .. ",A$
- CALL MousePointerOn
- LINE INPUT "The mouse pointer is visible. Press <Enter> .. ",A$
- CALL MousePointerOff
- PRINT "The mouse pointer is invisible again. Press <Enter> .. "
-
- By default, the mouse driver uses a "software pointer" while in the
- text video modes. This means that a mouse pointer is visible on the
- screen because the mouse driver is altering the screen's color
- attribute and/or the character at the location where the pointer is to
- be placed. This makes that location stand out from the rest of the
- data displayed on the screen. The default software pointer simply
- reverses the color attributes at the pointer position. When the
- pointer is moved, it restores the original attribute and character at
- the current position, stores the original attribute and character for
- the new position, and then applies the defined masks to the new
- position.
-
- Before updating the screen using PRINT, CLS, etc., it's necessary to
- turn the mouse pointer off. If you were to overwrite the screen at the
- mouse pointer position while the pointer is visible, the mouse driver
- would not be aware of this occurrence. The next time the pointer is
- moved, the original attribute and character stored by the mouse driver
- would be restored to that location. The result is what I like to refer
- to as "mouse droppings." For this reason, it's generally considered
- good practice to leave the mouse pointer off except when your program
- is waiting for input from the user.
-
- The mouse driver provides a service whereby you can customize the
- effects that the pointer has on the color attribute and character at
- the pointer position. This is accomplished by providing two
- "bit-masks" that define which bits comprising the attribute/character
- will be preserved (ANDed) and which will then be toggled (XORed).
- Since manipulation of the mouse pointer on this level is of little
- interest to most programmers and would require a crash course in video
- memory and bit manipulation, I'll skip the nitty-gritty and describe
- the supplied routine. If you would like more in-depth information
- about this function, refer to the Microsoft Mouse Programmers Guide,
- or leave a message for me on Compuserve. I'll be happy to help.
-
- The routine MouseSetSoftwarePointer is used to define the "AND" and
- "XOR" bit masks for the software cursor. For example:
-
- AndMask% = &H77FF
- XorMask% = &H7700
- CALL MouseSetSoftwarePointer(AndMask%, XorMask%)
-
-
- The QBNews Page 26
- Volume 2, Number 3 September 15, 1991
-
- The first byte of each mask represents the changes made to the color
- attribute. The "77" part of the AND mask indicates that the foreground
- color (bits 0-2) and background color (bits 4-6) will be preserved and
- the high- intensity (bit 3) and blink (bit 7) bits will be turned-off.
- The "77" part of the XOR mask indicates that the bits comprising the
- foreground and background colors should then be toggled. The "FF" part
- of the AND mask indicates that all bits comprising the character
- should be preserved. The "00" part of the XOR mask indicates that none
- of the character's bits will be toggled. In other words, when the
- mouse pointer appears on the screen, the color of the cell will be
- modified but the character won't. To take another example, we'll leave
- the color attribute alone, but will change the mouse pointer to an
- asterisk:
-
- AndMask% = &HFF00 'Preserve all attribute bits and discard the char
- XorMask% = &H002A 'Don't mess with attribute, make char an "*"
- CALL MouseSetSoftwarePointer(AndMask%, XorMask%)
-
- Another type of pointer available in text video modes is the "hardware
- pointer." It is called that because it is similar to the normal scan
- line-oriented text cursor that we're all familiar with. It appears on
- the screen as a blinking block. You can define it size, and to a
- degree, it's shape. Like the text cursor, the mouse hardware pointer
- is comprised of from 0 to 7 scan lines. When defining a hardware
- pointer, you specify the starting and ending scan line number, with 0
- at the top of the character cell and 7 at the bottom, much like you
- would use BASIC's LOCATE statement to alter the shape of the text
- cursor. For example:
-
- 'A full "block"
- StartScan% = 0
- EndScan% = 7
- CALL MouseSetHardwarePointer(StartScan%, EndScan%)
-
- 'Or
-
- 'A thin line in the middle of the character cell
- StartScan% = 3
- StartScan% = 4
- CALL MouseSetHardwarePointer(StartScan%, EndScan%)
-
- As some of you may be aware, the actual height of a character cell
- varies between 8 to 16 scan lines depending on the display adapter and
- the video mode used. This function automatically translates the
- requested 0-7 range into the scan line range appropriate for the
- display adapter and video mode in use.
-
- ----------------------------------------------------------------------
- What's the Mouse Up To?
- ----------------------------------------------------------------------
-
- When working with the mouse, the big questions are "Where is the mouse
- pointer?" and "Is a button pressed or released?" This information is
- required to process the most rudimentary mouse action, the "click."
-
- The QBNews Page 27
- Volume 2, Number 3 September 15, 1991
-
- The routine MouseGetStatus can used to answer these questions for you.
- For example:
-
- REM $INCLUDE: 'MOUSE.BI'
-
- DECLARE FUNCTION Pressed$(Button%) 'Used only by this example
-
- NumberOfButtons% = MouseReset%
- IF NumberOfButtons% = 0 THEN
- PRINT "No mouse detected."
- END
- END IF
-
- CALL MousePointerOn
-
- CLS
- PRINT "Press any key to end:"
- DO
- CALL MouseGetStatus(Lb%, Rb%, Cb%, Row%, Column%)
- LOCATE 3,1
- PRINT " Left Button :"; Pressed$(Lb%)
- PRINT " Right Button:"; Pressed$(Rb%)
- IF NumberOfButtons% > 2 THEN
- PRINT " Center Button:"; Pressed$(Cb%)
- END IF
- PRINT " Current Row:"; Row%
- PRINT "Current Column:"; Column%
- LOOP UNTIL LEN(INKEY$)
-
- CALL MousePointerOff
-
- END
-
- FUNCTION Pressed$(Button%)
- IF Button% THEN
- Pressed$ = "Pressed"
- ELSE
- Pressed$ = "Released"
- END IF
- END FUNCTION
-
- Again, the MouseGetStatus routine returns information about what is
- going on with the mouse -right now-. If your program was busy doing
- other things (e.g. "polling" the mouse infrequently) and the user
- clicked the left button quickly, you might not detect it. As you might
- have expected, there are contingencies for this situation as well.
-
- Let's take another situation. Say you are only interested in the mouse
- pointer position when a button is pressed or released, and you don't
- want to worry about polling the mouse frequently enough. The routines
- MousePressInfo and MouseReleaseInfo return the row and column position
- of the mouse pointer when the specified mouse button was *last*
- pressed or released, respectively. For example:
-
-
- The QBNews Page 28
- Volume 2, Number 3 September 15, 1991
-
- Button% = 0 '0=left, 1=right and 2=center
- IF MousePressInfo%(Button%, Row%, Column%) THEN
- 'Returns number of times the specified button was pressed
- ' since the last check
- PRINT "Left button last pressed at"; Row%; ","; Column%
- END IF
-
- Button% = 1 'Right button
- IF MouseReleaseInfo%(Button%, Row%, Column%) THEN
- 'Returns number of times the specified button was released
- ' since the last check
- PRINT "Right button last released at"; Row%; ","; Column%
- END IF
-
- Along the same lines, you can also determine the net physical distance
- that the mouse has moved. The routine MouseMovement returns the number
- of "Mickeys" (approximately 1/200th of an inch) the mouse has moved
- since the last time this routine was called. For example:
-
- CLS
- PRINT "Left button display distance and right button ends
- program"
- CALL MouseMovement(Rows%, Columns%) 'To zero the counter
- DO
- CALL MouseStatus(Lb%, Rb%, Cb%, Row%, Column%)
- IF Lb% THEN
- CALL MouseMovement(Rows%, Columns%)
- LOCATE 3,1
- PRINT " Mickeys moved (vertically):"; Rows%
- PRINT "Mickeys moved (horizontally):"; Columns%
- CALL MouseWaitForRelease
- END IF
- LOOP UNTIL Rb%
-
- If you were paying attention, then you noticed that I snuck a new
- routine into the above listing. MouseWaitForRelease suspends the
- program until all mouse buttons have been released. It's very handy
- for mouse-specific program "flow control."
-
-
- ----------------------------------------------------------------------
- Writing Mouse Event-driven Programs
- ----------------------------------------------------------------------
-
- The various methods of gathering mouse-related information we've
- discussed so far require you to poll the mouse driver periodically to
- see if a specific event has occurred (mouse click, etc.). Wouldn't it
- be much easier if the mouse driver could simply interrupt your program
- anytime it needs attention and then transfer control to a specified
- subroutine? This way, you wouldn't have to be concerned about polling
- the mouse periodically.
-
- In QuickBASIC 4.00a (distributed with BASIC 6.x), 4.00b (bug fix
- update to 4.00 and 4.00a), 4.50, and QBX (distributed with PDS) there
-
- The QBNews Page 29
- Volume 2, Number 3 September 15, 1991
-
- exists a little-known and seldom-used statement called "ON UEVENT
- GOSUB LineLabel." It's much like other BASIC event processing
- statements like "ON TIMER", "ON KEY", "ON COM", etc. in that it allows
- program control to be transferred to a subroutine when a special event
- occurs. A "UEVENT" or "User Event" is programmer-definable. In this
- case, we establish a "hook" into the mouse driver and when a specified
- type of mouse event occurs, the mouse driver notifies our assembly
- routine, which in turn notifies BASIC. The next time the BASIC runtime
- code processes events (at each line label or after each statement,
- depending on the use of the /V and /W compiler switches) control is
- transferred to the desired subroutine. Neat, huh?
-
- The routine MouseSetEvent is used to define the type of event(s) that
- you are interested in. These events can include any combination of a
- specific button being pressed or released, or any mouse movement at
- all. Once an event has occurred and program control has been
- transferred to your BASIC subroutine, the MouseGetEventInfo routine is
- used to determine exactly what type event occurred and where the mouse
- pointer was located at the time. When you wish to turn off the mouse
- event trap, call the MouseCancelEvent routine. Here's how it's done:
-
- REM $INCLUDE: 'MOUSE.BI'
-
- Buttons% = MouseReset%
-
- IF Buttons% = 0 THEN
- PRINT "Mouse not present."
- END
- END IF
-
- CALL MousePointerOn
-
- 'First, define the types of event(s) you want to trap. This is
- ' done by passing value in EventMask%. Just pick the events you
- ' wish to trap, add up their values and pass it to the
- ' MouseSetEvent routine.
-
- ' 1 = Any mouse movement
- ' 2 = Left button pressed
- ' 4 = Left button released
- ' 8 = Right button pressed
- ' 16 = Right button released
- ' 32 = Center button pressed
- ' 64 = Center button released
-
- 'Let's trap a left or right button release. That's 4 + 16 = 20.
-
- EventMask% = 4 + 16
- CALL MouseSetEvent(EventMask%)
-
- 'Next, tell BASIC to watch for the event and to transfer program
- ' control to the at the MouseEvent line label when an event
- ' occurs.
-
-
- The QBNews Page 30
- Volume 2, Number 3 September 15, 1991
-
- ON UEVENT GOSUB MouseEvent 'Watch for the event
- UEVENT ON 'Enable UEVENT checking
-
- 'Let's set up an idle loop to demonstrate the event processing
-
- CLS
- PRINT "Each time you release the left or right mouse button, our"
- PRINT "event-handling code will be called. When you've seen"
- PRINT "enough, press any key to end this program."
- PRINT
-
- DO
- LOOP UNTIL LEN(INKEY$) 'Loop until a key press is detected
-
- 'To turn off event checking
- UEVENT OFF
- CALL MouseCancelEvent
-
- CALL MousePointerOff
- END
-
- MouseEvent: 'Transfer control here on a mouse event
- CALL MouseGetEventInfo(EventType%, Lb%, Rb%, Cb%, Row%, Column%)
- PRINT "Mouse event occurred: - ";
-
- '"AND" EventType% with the value of the event being checked
-
- IF EventType% AND 4 THEN
- PRINT "Left Button was released."
- END IF
- IF EventType% AND 16 THEN
- PRINT "Right Button was released."
- END IF
- PRINT "Mouse location:"; Row%; ","; Column% RETURN
-
- Using BASIC's event-trapping services generates larger executable
- programs because of the additional event-checking code required at
- runtime. However, there are ways to reduce this added overhead to a
- minimum.
-
- 1. Use "UEVENT ON" and "UEVENT OFF" around code in which you wish to
- have event-trapping active. Putting a "UEVENT ON" at the top of your
- program without a following UEVENT OFF will cause BASIC to generate
- event-checking code for your entire program. If you selectively use
- UEVENT ON and UEVENT OFF (e.g. around your input or selection code), -
- you- can keep the overhead to a minimum.
-
- 2. Programs that use BASIC event-traps must be compiled with the /V or
- /W switches. /V directs BASIC to check for an events after *every
- BASIC statement* (within the UEVENT ON and UEVENT OFF boundaries, that
- is). /W directs BASIC to check for events only when crossing line
- labels. The latter will obviously generate less overhead, but
- requires you to be more careful with your placement of line labels -
- no line labels, no event-checking.
-
- The QBNews Page 31
- Volume 2, Number 3 September 15, 1991
-
-
-
- ----------------------------------------------------------------------
- Fine-tuning the Mouse
- ----------------------------------------------------------------------
-
- In addition to controlling the mouse's visual characteristics, you can
- control its physical characteristics as well. This includes its
- sensitivity and double-speed threshold.
-
- "Sensitivity" is the ratio between the distance the mouse is
- physically moved (in Mickeys) and the distance the mouse pointer
- actually moves (in pixels) on the screen. The default ratios are one
- Mickey per pixel horizontally and two Mickeys per pixel vertically.
- The higher the ratio, the more physical mouse movement is required to
- move the mouse pointer. The routine MouseSetRatio is used to adjust
- the mouse sensitivity. For example:
-
- VertRatio% = 2
- HorizRatio% = 1
- CALL MouseSetRatio(VertRatio%, HorizRatio%)
-
- The "double-speed ratio" is the physical speed (in Mickeys per second)
- that the mouse must travel before the mouse pointer shifts into
- overdrive and moves across the screen twice as fast. The default is 64
- Mickeys per second (about 1/3 of an inch per second). The routine
- MouseSetDblSpd is used to adjust the double-speed ratio. For example:
-
- MickeysPerSecond% = 200 'Set to one inch per second
- CALL MouseSetDblSpd(MickeysPerSecond%)
-
- Using the MouseGetSensitivity routine, you can also retrieve the
- current sensitivity settings from the mouse driver. For example:
-
- CALL MouseGetSensitivity(VertRatio%, HorizRatio%, _
- MickeysPerSecond%)
-
- ----------------------------------------------------------------------
- Miscellaneous Mouse Routines
- ----------------------------------------------------------------------
-
- The following list of "miscellaneous" mouse routines can be useful
- from time-to-time. They allow you to restrict the mouse movement,
- position the mouse pointer through software, save and restore the
- mouse "state," allow you to define the coordinate system the mouse
- pointer location is returned in (character-based row/column format or
- X/Y pixel-based format), and more.
-
- MouseSetWindow - Used to define a rectangular area on the screen in
- which the mouse pointer movement will be restricted. Once called, the
- user will not be able to move the mouse pointer out of the defined
- area. To disable a previously defined window, call this routine again
- with the dimensions of the entire screen. For example:
-
-
- The QBNews Page 32
- Volume 2, Number 3 September 15, 1991
-
- TopRow% = 6
- LeftColumn% = 10
- BottomRow% = 20
- RightColumn% = 70
- CALL MouseSetWindow(TopRow%, LeftColumn%, BottomRow%,_
- RightColumn%)
-
- 'To turn the window off (assuming an 80 X 25 screen)
- TopRow% = 1
- LeftColumn% = 1
- BottomRow% = 25
- RightColumn% = 80
- CALL MouseSetWindow(TopRow%, LeftColumn%, BottomRow%,_
- RightColumn%)
-
- MouseSetExclusionArea - When the mouse pointer is moved into the
- rectangular area of the screen defined by this routine, it is made
- invisible. Use the MousePointerOn routine to make the pointer visible
- again. For example:
-
- TopRow% = 6
- LeftColumn% = 10
- BottomRow% = 20
- RightColumn% = 70
- CALL MouseSetExclusionArea(TopRow%, LeftColumn%, BottomRow%,_
- RightColumn%)
-
- 'To turn the mouse pointer back on:
- CALL MousePointerOn
-
- MouseSetPointer - Used to position the mouse pointer on the screen.
- For example:
-
- Row% = 5
- Column% = 20
- CALL MouseSetPointer(Row%, Column%)
-
- MousePixelsOn - Used to change the default coordinate system used by
- the mouse routines discussed in this article from character-based
- row/column coordinates (which is the default) to X/Y pixel-based
- coordinates. This routine defines the coordinate system used for both
- input -and- output. This routine is provided because row/column
- coordinates are generally preferred in text video modes and X/Y pixel-
- based coordinates are generally preferred in graphics video modes. Use
- the MousePixelsOff routine to switch back to row/column coordinates.
- For example:
-
- CALL MousePixelsOn 'Switch to X/Y pixel-based coordinates
- CALL MousePixelsOff 'Switch back to row/column format
-
- MouseSaveState - Saves the current mouse "state." This includes the
- current position, visibility, shape, and other mouse pointer
- characteristics. You could use this routine just prior to a SHELL so
- the original state could be easily restored on returning to your
-
- The QBNews Page 33
- Volume 2, Number 3 September 15, 1991
-
- program. This routine automatically allocates the required amount of
- memory from DOS and releases it on the call the MouseRestoreState. The
- MouseSaveState routine can be declared as a SUB or an integer
- FUNCTION. If declared as a FUNCTION, it returns -1 (TRUE) if the
- state was successfully saved and 0 (FALSE) if insufficient memory was
- available. We have it DECLAREd as a FUNCTION in the MOUSE.BI file
- included with this article. For example:
-
- Success% = MouseSaveState%
- IF Success% THEN
- PRINT "Mouse state saved!"
- CALL MouseRestoreState
- ELSE
- PRINT "Insufficient memory to save mouse state!"
- END IF
-
- MouseSetPage - Sets the video display page on which the mouse pointer
- will be visible. Normally, the mouse driver is aware of changes in
- active video pages, so it is not usually necessary to call this
- routine. However, if you are using non-standard methods of switching
- video pages, this is how you can tell the mouse driver what you are up
- to. The function MouseGetPage% is used to return what the mouse driver
- believes to be the active video page number current in use. For
- example:
-
- SCREEN ,,1,1 'Switch BASIC into page 1
- PageNum% = 1
- CALL MouseSetPage(PageNum%) 'Tell the mouse driver about it
- PRINT "Mouse pointer on page";
- PRINT MouseGetPage%
-
- MouseExit - Releases all memory allocated by these mouse routines and
- unhooks the "user mouse service" function required by MouseSetEvent.
- You need to call this routine ONLY if:
-
- You are about to CHAIN to another program and the MOUSE.OBJ is
- *not* in a BASIC 6.X or PDS extended runtime library, or
-
- You are about to SHELL and the MOUSE.OBJ file -is- in an extended
- runtime library.
-
- If your BASIC program terminates normally (with an "END" or "SYSTEM"
- statement), there is no need to call MouseExit at all.
-
- ----------------------------------------------------------------------
- Special Considerations
- ----------------------------------------------------------------------
-
- If your BASIC program terminates via the "END" or "SYSTEM" statements,
- we automatically release memory that we've allocated and "unhook" the
- mouse driver. Using a service called "B_OnExit", the BASIC runtime
- code calls our internal clean-up code just prior to returning system
- control back to DOS.
-
-
- The QBNews Page 34
- Volume 2, Number 3 September 15, 1991
-
- However, if you CHAIN to another program, the CHAINing program
- actually terminates but BASIC does not process the B_OnExit chain
- allowing us to clean up our mess. Essentially this means that your
- system can potentially lock up if you've used the MouseSetEvent or the
- MouseSaveState routines. See the entry for MouseExit above for more
- information.
-
- ----------------------------------------------------------------------
- Using the Routines
- ----------------------------------------------------------------------
-
- Now since we've gotten all of that technical stuff out of the way,
- you're probably about ready to actually being using the routines.
- Included with this article, you find a file called MOUSE.OBJ. It is an
- object file which contains all of the mouse routines described here.
- You can put this .OBJ file in a QuickLibrary, a LINK library, or LINK
- it directly to your compiled programs. It's completely compatible with
- QuickBASIC versions 4.00a - 4.50, BASIC 6.X, and PDS 7.x.
-
- Distributed with this article is a batch program called BLDLIB.BAT.
- It will automatically build a QuickLibrary (.QLB) and LINK library
- (.LIB) for your compiler version. Type "BLDLIB" at the DOS prompt for
- instructions. However, if you prefer to know about the "hows" and
- "whys" and would like to build your libraries manually, read on.
-
- To build a QuickLibrary so you can call the mouse routines from with
- the QB(x) development environments, issue the following command at the
- DOS prompt:
-
- LINK /Q MOUSE, MOUSE.QLB, NUL, BQLB45;
-
- The above LINK command will generate a QuickLibrary for QuickBASIC
- version 4.50. Change the QuickLibrary support module name (listed
- above as BQLB45) to BQLB41 or QBXQLB to build a QuickLibrary for
- QuickBASIC 4.00x and QBX, respectively.
-
- To build a LINK library or to add the MOUSE.OBJ file to an existing
- LINK library, type the following at the DOS prompt:
-
- LIB MOUSE +MOUSE.OBJ ;
-
- The above LIB command will create a library called MOUSE.LIB. If you
- wish to add the mouse routines to an existing library, substitute that
- library name for the first occurrence of MOUSE above.
-
- To load the example program into the environment, type the following
- at the DOS prompt:
-
- QB MOUSETST /L MOUSE For QB 4.X
- QBX MOUSETST /L MOUSE For QBX
-
- The above commands load the example program MOUSETST.BAS into the
- environment along with the MOUSE.QLB QuickLibrary we created earlier.
-
-
- The QBNews Page 35
- Volume 2, Number 3 September 15, 1991
-
- To compile and LINK your program, you can select "Make an EXE" from
- the QB(x) environments (assuming you have constructed matching .QLB
- and .LIB files per the above instructions), or you can manually
- compile and link from the DOS prompt. The latter is the preferred
- method because it gives you more control over compiler switches used.
- For example:
-
- BC MOUSETST /O/W ;
- LINK /EX MOUSETST + MOUSE ;
-
- Or, if you've placed MOUSE.OBJ in a link library, you can do this:
-
- LINK /EX MOUSETST,,NUL, LibraryName ;
-
- [EDITOR'S NOTE]
- All files for this article can be found in the file MOUSE.ZIP.
-
- *********************************************************************
- Tony Elliott has been programming in BASIC and assembly langauge for
- over ten years. He worked for MicroHelp, Inc. for almost four years as
- their Technical Support Manager and was directly involved in the
- development of many of their QuickBASIC/PDS products. He has spoken at
- a number of BASIC Symposiums conducted around the country between 1989
- - 1991, and was a speaker at the August, 1991 Microsoft Developers
- Tools Forum held in Seattle. He has written articles for BASICPro
- Magazine and MicroHelp's "BASIC Users Group" Newsletter. He is now
- Vice President of EllTech Development, Inc. which recently developed
- and is currently marketing a network-ready replacement for PDS
- ISAM called "E-Tree Plus" (see the ad included in this issue).
- **********************************************************************
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The QBNews Page 36
- Volume 2, Number 3 September 15, 1991
-
-
-
- ----------------------------------------------------------------------
- A d v e r t i s e m e n t
- ----------------------------------------------------------------------
-
- E-Tree Plus By EllTech Development, Inc.
-
- Finally, a network-ready B+Tree file indexing library designed
- specifically for BASIC programmers that's FAST and EASY TO USE! If
- you are already familiar with Novell's Btrieve or Microsoft PDS ISAM,
- you can be up and running in 15 minutes .. no kidding! For those of
- you new to network database programming, it may take a little longer.
- For those of you currently using PDS ISAM, this product is an ideal
- network solution for you. Our function syntax is very similar, we
- provide a conversion utility for your existing databases, and we even
- have a section in our manual that will take you step-by-step through
- converting your existing program source code.
-
- Easy to Use
- Automatically detects the presence of Novell or NETBIOS compatible
- networks and handles file and recording locking for you. However, you
- still have full control over how the locks are implemented, timeouts,
- etc., should you have a need to override our default actions.
- 11 high-level functions allow you to: create E-Tree database files;
- add and delete indexes; change the active index; insert, update,
- retrieve and delete records; locate a specific record or groups of
- records quickly and easily. In addition, over 40 low-level functions
- are provided to give you complete control over almost every aspect of
- the database manipulation.
- Convert existing PDS ISAM applications to E-Tree Plus with minimal
- effort. E-Tree Plus's functions use syntax and naming conventions
- similar to PDS ISAM. In many cases, existing code can be used with
- only minor modifications.
- Simplified database maintenance. We include a utility ("EUTIL.EXE")
- you can use to create databases, modify an existing database's
- structure (add or delete a field), import and export ASCII data,
- convert Btrieve dBase compatible files, and PDS ISAM file to E-Tree,
- and more.
- We automatically determine the optimum file page size, record
- length, etc., for you. There are no complicated formulas and no
- cryptic function numbers to remember.
- Includes a fully indexed, reference oriented, 200+ page manual. It
- includes example programs, a database/network tutorial, complete specs
- on the E-Tree Plus database format, and even a "Quick Start" section
- for the seasoned database programmer.
- The product is provided in LINKable libraries and .OBJect files.
- No TSR programs to load or to get in the way.
-
- Fast and Flexible
- Written using a combination of BASIC and assembly language for the
- perfect mixture of versatility and speed.
- All BASIC data types are supported, and then some.
- Flexible indexing. You can add or delete indexes at any time. Up to
- 1023 indexes (more than you'll ever need) can be defined at one time.
- Indexed "keys" can be defined as unique, duplicates allowed,
-
- The QBNews Page 37
- Volume 2, Number 3 September 15, 1991
-
- modifiable, non-modifiable, segmented (comprised of pieces of one or
- more fields), ascending, descending, and auto-incrementing (ideal for
- invoice or order numbers).
- File sizes up to 4 billion bytes. The maximum number of records per
- file is limited only by available disk space.
- Supports fixed-length records, variable-length records, and
- combinations of both.
- Efficiently uses system resources. Automatically detects and uses
- LIM Expanded Memory for file I/O buffers.
-
- Reliable
- Built-in data integrity checking. Using 32-bit CRC, the integrity
- of your data is checked with near 100% accuracy. If a problem should
- develop, the chances are very good that all of your data can be
- recovered or reconstructed.
- Stores data records, indexes, and its "data dictionary" in the same
- file. This means that there are no "index" files or "definition" files
- for your customers to lose track of, and only one DOS file handle is
- required per open database.
-
- Affordable
- Distribute E-Tree Plus applications and the EUTIL.EXE database
- maintenance utility royalty-free.
-
- One version supports QuickBASIC 4.x, BASCOM 6.x, Microsoft PDS 7.x,
- and PowerBASIC 2.x.
-
- Includes structured, fully commented BASIC and assembly language
- source code at no additional charge.
-
- Price includes free, full-time technical support. We even provide 24
- hour support through our BBS. Customers can download maintenance
- releases of E-Tree Plus free of charge! Just ask our competitors if
- they can offer the same!
-
- Introductory Offer: $199.00 until 11/30/91
- Shipping and handling: $ 6.00 (U.S. addresses)
-
- Orders and Product Info: (800) 553-1327 (U.S. and Canada)
- Technical Support: (404) 928-8960
- BBS: (404) 928-7111 (HST)
- E-Tree Plus will be available for shipping on September 15, 1991.
- Prices are listed in US Dollars. All trademarks belong to their
- respective owners.
- EllTech Development, Inc.
- 4374 Shallowford Industrial Parkway
- Marietta, GA 30066
-
-
-
-
-
-
-
- The QBNews Page 38
- Volume 2, Number 3 September 15, 1991
-
-
-
- ----------------------------------------------------------------------
- A l g o r i t h m s
- ----------------------------------------------------------------------
-
- Cardans's Method for Solving Cubes by Richard Jones
-
- One of the most common tasks in mathematics and its applications is
- that of root-finding. That is, we have some function, f(x), and we
- want to find the value(s) of x for which f(x) = 0. It is
- disillusioning to note that all centuries upon centuries of
- mathematics can say about the general case, including monsters like
-
- a * x^2 * exp(-b * x) - sin(c * x) = 0,
-
- is that there may be one, several, or an infinite number of roots, or
- maybe none at all, which really tells us a lot. Fortunately, a lot
- more is known about a smaller and more common category of functions,
- polynomials of degree n, of the form
-
- a(0) + a(1) * x + ... + a(n) * x ^ n = 0, n >= 0.
-
- Back in high school, we all learned about the n = 1, or linear, and
- the n = 2, or quadratic, cases of polynomials. We found that the
- linear equation a*x + b = 0 has exactly one root given by x = -b/a and
- that the two roots of a quadratic a*x^2 + b*x + c = 0 are given by the
- reknown quadratic formula:
-
- x = (-b +- (b^2 - 4*a*c)^(1/2)) / 2a. (3)
-
- We then noticed what appeared to be a hint of a relation between the
- degree of a polynomial and the number of roots. After high school, we
- went off to college and, depending on what field of study we chose,
- began to go down the path of one of the various branches of higher
- mathematics and, along the way, perhaps learned some theorems about
- polynomial equations and the nature of the roots. It's interesting to
- note that while a lot may have been said about the nature of the
- roots, nothing was really said about how to find them for the case of
- n >= 3. It turns out that analytic solutions for polynomials up to the
- fourth degree are known (equations of higher degree cannot be solved
- exactly by any finite number of arithmetic operations - you have to
- resort to approximate numerical methods). The solutions to cubic and
- quartic equations are quite involved, though, which is one of the
- reasons nobody bothers with them. This, at long last, brings us to the
- subject of this article: a QuickBASIC implementation of the solution
- to the cubic equation known as the Tartaglia-Cardan solution or simply
- Cardan's method.
-
-
- Roots of Polynomials
-
- A little background theory on polynomial roots will helpful in
- understanding how our method works. A polynomial of degree n, pn(x),
- will have exactly n roots provided we expand the range of an
- acceptable solution to include the set of complex numbers. While the
-
- The QBNews Page 39
- Volume 2, Number 3 September 15, 1991
-
- linear equation's root, -b/a, is always real, what happens when the
- term under the square root in equation (3) is negative? The notion of
- a complex number was actually invented to handle this case. Notice how
- complex things become when we go from n = 1 to just n = 2; we have to
- "invent" a new class of number. You might think that more numbers
- would have to be invented to handle the n = 3 case, but it turns out
- that the set of complex numbers will suffice for any n. Unlike the set
- of reals, this set is closed, which means that any operation performed
- on any of the members will always produce another member of the set.
-
- Complex roots of polynomials with real coefficients (this doesn't
- apply if the coefficients themselves are complex) will occur in
- conjugate pairs which means that there will always be an even number
- of such roots. Therefore, an equation of odd degree must have at least
- one real root. This can be easily seen by considering the values of
- pn(x) and pn(-x) as x grows large and the high order term dominates.
- If n is odd, pn(x) and pn(-x) must be of opposite sign and, since
- polynomial functions are nice and continuous, the curve must then
- cross the x-axis at least once. Knowing this, we can say that a cubic
- equation must have either three real roots, or one real and a pair of
- complex conjugate roots.
-
-
- Cardan's Method.
-
- Unlike the quadratic, it's impractical to write the solution to the
- cubic as a single formula - it's far better presented as a series of
- steps which are somewhat involved, so hang on. The first step is to
- divide through by the coefficient of the cubic term and write the
- equation in the so-called standard form:
-
- x^3 + a*x^2 + b*x + c = 0. 4)
-
- There is no direct solution for the equation in this form, however,
- and so we must make a change of variable to eliminate the quadratic
- term. The substitution x = u - a/3 will accomplish this and we will
- have a "reduced" cubic of the following form:
-
- u^3 + p*u + q = 0, 5)
-
- where the new coefficients, p and q are given in terms of those of 4)
- by
-
- p = (3b - a^2) / 3,
-
- q = (2a^2 - 9ab + 27c) / 27.
-
- Like a quadratic, a cubic equation has a discriminant, D, whose sign
- tells us some things about the nature of our roots. The discriminant
- of the cubic in the form of 5) is given by
-
- D = q^2 / 4 + p^3 / 27.
-
- There are three distinct cases depending on the sign of D:
-
- The QBNews Page 40
- Volume 2, Number 3 September 15, 1991
-
-
- D > 0 -> one real root and a pair of complex conjugates.
- D = 0 -> degenerate case - 3 real roots of which at least 2 are
- equal.
- D < 0 -> 3 real and distinct roots.
-
- Now calculate the two values A and B given by the following:
-
- A = (-q/2 + D^(1/2))^(1/3), and
-
- B = (-q/2 - D^(1/2))^(1/3).
-
- And, finally, the 3 roots of 5), u1, u2 and u3, are then given by
-
- u1 = A + B, 6)
-
- u2 = -u1 / 2 + i(A - B) * 3^(1/2) / 2, and 7)
-
- u3 = -u1 / 2 - i(A - B) * 3^(1/2) / 2, 8)
-
- where i represents the famous (or infamous) square root of -1.
-
- The three roots of the original equation, x1, x2 and x3, are given by
- the substitution relation above, x = u - a / 3.
-
-
- Note that if D > 0, x1 is real and x2 & x3 are complex conjugates. If
- D = 0, then A = B and the imaginary terms in 7) and 8) are zero and u2
- = u3 and hence x2 = x3. Also, our substitution may produce p = q = 0,
- in which u1 = u2 = u3 = 0, and our 3 roots will all be equal and given
- by x1 = x2 = x3 = -a / 3. Such cases are known as multiple roots - we
- still say the equation has 3 roots but it just happens that two or
- more are equal to each other.
-
- Now for the hard part, the D < 0 case. Notice that if D < 0, the
- calculation of A and B requires us to extract the cube roots of two
- complex numbers. Twenty years ago, this would be a time for despair,
- but now that we all have enormous amounts of computing power sitting
- on our desks and handy-dandy high-level language compilers like MS
- QuickBASIC with a wealth of built-in math functions to utilize that
- power, it's a piece of cake. A complex number, z, which is usually
- written in rectangular form as some x + i*y, also has a so-called
- polar form, z = r * exp(i*R), where r, known as the magnitude or
- modulus, and R, known as the argument or simply the angle, are given
- by a simple pythagorean relation:
-
- r = (x^2 + y^2)^(1/2), and
- R = arctan(y / x).
-
- In polar form, exponentiation is simple. We raise the modulus (always
- a positive real) to the desired power and simply multiply the angle by
- this power. So, to take the cube root of a complex number, we put it
- in polar form, take the cube root of the modulus, and divide the angle
- by three. Trigonometric functions then get us back to rectangular
-
- The QBNews Page 41
- Volume 2, Number 3 September 15, 1991
-
- form. Since in this case A and B are conjugates, things can be
- simplified somewhat and we can write our u's as follows:
-
- u1 = 2r * cos(R). 9)
- u2 = r * (3^(1/2) * sin(R) - cos(R)), and 10)
- u3 = -r * (3^(1/2) * sin(R) + cos(R)), 11)
-
- where r is given by
-
- r = (q^2 / 4 - D)^(1/6),
-
- and the angle R is given by
-
- R = arctan( -2 * D^(1/2) / q ) / 3.
-
- It's rather interesting that, after all this complex arithmetic, the
- results are purely real, and that the D < 0 case requires
- transcendental operations, elementary trigonometric ones in our case.
- (Transcendentals are called such because they "transcend" the realm of
- ordinary arithmetic - the only kind we know how to do. They cannot be
- calculated exactly by any finite number of additions, multiplications,
- or exponentiations.) It's actually cheating a bit to say that we have
- an analytic solution for the D < 0 case because of the
- transcendentals. We can write a formula down only because we've
- invented a special notation for the trig functions, namely "sin",
- "cos", and "arctan", which can only be approximated. (Think about it.
- Using only a pad and pencil, try to calculate the sine of a 37 degree
- angle. If you remember the power series and don't mind doing long
- division with 10 - 30 digit numbers, you might get it to 5 places in
- an hour or two. Personally, I'd get a protractor and a carpenter's
- square and "experimentally" measure it and might manage to get two or
- three places.)
-
-
-
- Cardan's Method in QuickBASIC
-
- Whew! Now that we've got Cardan's method down pat, it's easy to write
- a QB program to carry out the steps. The listing is of the program
- which I've written to implement Cardan's method. It consists of a
- subroutine, CUBERT, which does the work, and a simple driver which
- gets the coefficients of equation from the user, prints out the roots,
- and prints out the value of the function at one of the supposed roots
- that the subroutine returns as a check. I've also included a function,
- POLY, which evaluates polynomials the "right" way. I'll say more about
- this later. The driver is fairly simple and pretty much
- self-explanatory in function.
-
- CUBERT follows the procedure above fairly closely, and I've tried to
- use variable names that correspond to those in the equations above.
- The routine expects to be passed an array, A#(), containing the
- coefficients of the cubic, an array, X#(), in which to place the roots
- it calculates, and a flag, F%, to indicate the type of the roots
- returned. If F% = 1, all the roots are real and distinct and their
-
- The QBNews Page 42
- Volume 2, Number 3 September 15, 1991
-
- values will be in elements 1 through 3 of X#(). F% = 2 corresponds to
- the D >= 0 cases and X#(1) will contain the one real root and the next
- two elements will contain the real and imaginary components of the
- conjugate pair of complex roots. Notice the use of the STATIC keyword
- on the subroutines. This causes the compiler to allocate local
- variables statically in DGROUP rather the on the stack and can save
- time in routines with a lot of local variable accesses on older 8088
- machines. This is not compatible with recursion, though.
-
- The first thing CUBERT does is calculate the coefficients of the
- standard form and from this calculates the p and q coefficients and
- then finds the discriminant. And IF statement checks the sign of the
- discriminant. If D >= 0, the routine calculates the roots according to
- equations 6) - 8). The calculation of the numbers A and B requires the
- calculation of the cube roots of two values that can be negative. The
- QB library code can't raise negative numbers to non-integral powers
- (because the method used has to take the logarithm of the base) and
- this requires the code to check the signs. If one is negative it
- calculates its cube root as the negative of the cube root of the
- absolute value. (Related to the fact that a polynomial of degree n has
- n roots is the fact that any number has exactly n nth roots. While for
- odd n, the principle nth root of a negative number is always complex,
- one of these n roots will simply be the negative of the principle nth
- root of that number's absolute value. While we are biased toward
- principle roots, any of the n nth roots will usually work in most
- situations.) After taking these cube roots, the code returns the roots
- of the equation as outlined above.
-
- I didn't bother to include an ELSEIF clause to check for the case of D
- being exactly equal to zero for a number of reasons. Remember that
- computer floating point arithmetic is finite and approximate, not
- exact. It is very rare indeed when you'll find two things exactly
- equal because there is always a little (or a lot, with unstable
- algorithms) bit of "noise" involved in every calculation. Also, the D
- = 0 case corresponds to the case of multiple roots and numerical
- analysis tells us that in this case the roots are poorly conditioned
- with respect to the coefficients anyway. ("Conditioning" is a term
- from numerical analysis which can be thought of as a kind of signal-
- to-noise ratio. It is a measure of how sensitive a calculation is to
- this floating point noise.) So what you'll find in this case is that
- the imaginary components returned are very small relative to the real
- components, or that two or more of the real and "distinct" roots are
- very close if the "noise" makes D slightly negative.
-
-
-
- If the discriminant is negative, the code follows equations 9) - 11)
- above. The magnitude calculation is straightforward, but the angle
- calculation is a tricky affair. We have to calculate the angle as an
- arctangent of the ratio of the imaginary and real components. But what
- happens if the real part is zero? In this case the angle is 90
- degrees, but we'll overflow when we take the ratio if the real part is
- small enough. The way to avoid this is to check the denominator before
- taking the ratio. If it's > 1, we can go ahead, but if it's < 1 we
-
- The QBNews Page 43
- Volume 2, Number 3 September 15, 1991
-
- have to make sure the division won't overflow. We want to make sure
- that, say, a / b <= c, but without doing the division. This will be
- true only if a <= c * b, and this what CUBERT does. If the ratio will
- be greater than a constant, which I called BIG# and set to 1E40, the
- code sets the angle to 90 degrees. (While the tangent of a right angle
- is infinite, 1E40 is about as close to infinity as we need in this
- case.) Finally, if the ratio is negative QB's ATN function will return
- an angle in the fourth quadrant, but the angle we want lies in the
- second, so the code has to adjust the angle if needed.
-
- That just about wraps up the operation of CUBERT. Once CUBERT returns
- the roots, the driver calls function POLY to evaluate the cubic at the
- first root. As I said before, POLY evaluates polynomials the right
- way. At first blush, we might try something like this to evaluate a
- polynomial of degree n at x whose coefficients are in an array:
-
- P# = A#(0)
- FOR I% = 1 TO N%
- P# = P# + A#(I%) * X# ^ (N%)
- NEXT I%
-
- But this requires n additions, n multiplications, and n
- exponentiations. POLY# does the same thing using Horner's method with
- only n additions and multiplications and no exponentiations. The above
- method is also much more "noisy" than POLY#.
-
- Cardan's method certainly falls into the category of the obscure and
- as a result many people aren't aware of the way to solve cubic
- equations and resort to numerical root-finders when they need to solve
- them. CUBERT can be used in any program that needs to find the roots
- of cubic equations and, I think, will be a helpful addition to your
- library. I hope this program will make solving cubics as easy and as
- common as solving quadratics. If you have in questions, comments or
- witticisms about this article or the program, feel free to contact me
- anytime.
-
- For a bibliography and a "for further reading" section I would
- recommend the following texts:
-
- Thompson, J. E.: "Algebra for the Practical Worker," 4th ed.,
- Van Nostrand Reinhold Co., New York, NY, 1982.
-
- (While, as its title implies, the above is a lower-level text, it
- neverless contains an excellent discussion of Cardan's Method.)
-
- Churchill, R. V. & Brown, J. W.: "Complex Variables and
- Applications,"
- 4th ed., McGraw-Hill, New York, NY, 1984.
-
- Beyer, W. H.: "CRC Standard Mathmatical Tables," 28th ed.,
- CRC Press, Boca Raton, FL, 1988.
-
- Mizrahi, A. & Sullivan, M.: "Calculus and Analytic Geometry,"
- Wadsworth Publishing Co, Belmont, CA, 1982.
-
- The QBNews Page 44
- Volume 2, Number 3 September 15, 1991
-
-
- Stoer, J. & Bulirsch, R.: "Introduction to Numerical Analysis,"
- Springer-Verlag, New York, NY, 1980
-
- The above constitute my standard references on the math covered in the
- article, but please note this represents a personal preference and
- shouldn't be considered the best possible sources.
-
- **********************************************************************
- Richard Jones is an "almost" graduate of Clemson University in SC. He
- majored in Physics there, but lack 4 hrs. of a foreign language for
- his B.S. His main interests include math, physics, and programming,
- and is currently employed with P.C. Electric Co. in Greenville, SC. He
- can be reached on Compuserve at 76636,536.
- **********************************************************************
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The QBNews Page 45
- Volume 2, Number 3 September 15, 1991
-
-
-
- ----------------------------------------------------------------------
- F u n a n d G a m e s
- ----------------------------------------------------------------------
-
- Lines With Style by Larry Stone and Charles Graham
-
- During the Winter of the Big Freeze, with nothing to do and much
- time on his hands, Charles Graham, during a state of extreme boredom,
- found himself alone with a glass of wine in one hand and his fingers
- at the keyboard with his other hand. Thus was born an algorithm later
- to be shared with us all as source code for his program, "ENERGY".
-
- Aside: Charles' called to complain that the glass of wine wasn't
- in hand until AFTER he created his code <GRIN>.
-
- FUSION, based upon Charles' original algorithm, produces a kaleido-
- scope of colors, design, music and sounds that will provide hours of
- delightful fascination.
-
- Before we get much further, you should know that FUSION only runs
- in EGA screen 9 or VGA screen 12. Even if your monitor cannot handle
- these modes you will still benefit from FUSION's many other, useful
- routines.
-
- For example, the PrintROMtable subprogram gives you pixel by pixel
- control for the ASCII characters 1 through 128. See the article Fonts
- in a Can earlier in this issue for more on this subroutine.
-
- If you study FUSION.BAS, you will notice that except for one PAINT
- and a couple of PALETTE commands, all graphics are produced via the
- BASIC LINE or CIRCLE statement. Closer examination reveals the heart
- of the program is the LINE statement. QB's LINE statement is one of
- the most powerful graphic commands available. Conversely, it is may
- be one of the least understood graphic command. Although entire books
- could be written about the LINE statement, only one of its optional
- variables will be examined here -- the "style%" argument.
-
- Simply put, the integer variable, style%, is a mask or stencil laid
- over the line. When we "paint" the line, the paint falls through the
- holes of the "stencil" and is held back by the "mask". Probably the
- easiest way to show this is by following the logic of the subprogram
- called, PrintROMtable.
-
- One final note to you Tech-Heads. The algorithm that computes and
- displays "energy" and "plasma" drawings is derived by calculating the
- polar equations for each ellipse generated from weighted, random
- numbers. Random numbers are weighted by expressions such as:
-
- g = INT(RND * 590) + 50 '50 - 640 possible points to each drawing
- w = INT(RND * 1.9) + .1 'weighted factor used for yavg, etc.
-
- Where g is a random number whose value is forced to lie between 50 and
- 640 and, where w is a random number whose value is forced to range
- between 0.1 and 1.9, respectively. Albert Einstein would have loved
-
- The QBNews Page 46
- Volume 2, Number 3 September 15, 1991
-
- this algorithm - the programmer's universe is totally random but the
- programmer is using "dice" that are loaded. The effect is random, yet
- symmetrical designs. My additions to Charles' algorithm continue this
- mix of order and chaos - "muon" and "quark" trails are produced and
- displayed with weighted, random numbers. The same mix of symmetry and
- randomness is employed with color and with the number of drawings that
- display at one time. Thank you, Charles Graham, for the wonderful
- algorithm.
-
- [EDITOR'S NOTE]
- All code for this article can be found in FUSION.ZIP
-
- **********************************************************************
- Larry Stone is President of LSRGroup and is involved in writing
- instructional and large data base application systems for business and
- institutional clients. He is also the author of SERVICES, a shareware
- application program rated a trophy by "Public Brand Software". He can
- be reached at LSRGroup, P.O. Box 5715, Charleston, OR 97420, or in
- care of this newsletter.
- **********************************************************************
-
- **********************************************************************
- Charles Graham is a division head for a local government agency in St.
- Louis County, Missouri. He also teaches QuickBASIC part time at a
- local community college. He is the author of several shareware
- products including MOVIES . ON . LINE and, Quick Dial. He can be
- contacted at Post Office Box 58634, St. Louis, MO 63158, and on the
- National QuickBASIC Conference.
- **********************************************************************
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The QBNews Page 47
-
-
- ----------------------------------------------------------------------
- E O F
- ----------------------------------------------------------------------
-
- Receiving The QBNews
-
- The QBNews is distributed mainly through BBS systems around the
- world. Some of the networks it gets distributed through are SDS
- (Software Distribution System) and PDN (Programmers Distribution
- Network). Ask the sysop of your local board about these networks to
- see if there is a node in your area.
-
- The QBNews can also be found on CompuServe in the MSLang
- (Microsoft Language) forum. It can be found in file area 1 or 2 of
- that forum. Just search for the keyword QBNEWS. The QBNews will also
- be available on PC-Link. I send them to Steve Craver, who is the BASIC
- Programming Forum Host on PC-LINK and he will make them available. I
- would appreciate anybody who could upload The QBNews to other services
- such as GENIE since I don't have access to these.
-
- I have also set up a high speed distribution network for people
- who would like to download The QBNews at 9600 baud. The following
- boards allow first time callers download privileges also. They are:
-
- Name Sysop Location Number Node #
- ---------------------------------------------------------------------
-
- Treasure Island Don Dawson Danbury, CT 203-791-8532 1:141/730
-
- Gulf Coast BBS Jim Brewer New PortRichey,FL 813-856-7926 1:3619/20
-
- 221B Baker St. James Young Panama City,FL 904-871-6536 1:3608/1
-
- EMC/80 Jim Harre St. Louis, MO 314-843-0001 1:100/555
-
- Apple Capitol BBS Bob Finley Wenatchee, WA 509-663-3618 1:344/61
-
-
- Finally, you can download The QBNews from these vendors BBS's:
-
- The Crescent Software Support BBS 203-426-5958
-
- The EllTech Support BBS 404-928-7111
-
- The Microhelp BUG BBS 404-552-0567
- 404-594-9625
-
-
- You do not have to be a customer of these vendors in order to download
- The QBNews, but the Microhelp BBS only allows non-members 15 minutes
- of time per call.
-
- If you would like to receive The QBNews on disk, I offer a yearly
- subscription for $15.00. This includes four disks containing each
-
- The QBNews Page 48
- Volume 2, Number 3 September 15, 1991
-
- issue as it is published. If you would like a disk with all the back
- issues of The QBNews, please enclose an additional $5.00. The pricing
- structure is as follows:
-
- Base Price for 1 Year - $15.00
- Disk with Back Issues - $5.00
- 3.5" disk surcharge - $5.00
- Canada and Mexico surcharge - $5.00
- All other foreign orders - $10.00
-
- The base price includes 5.25" 360k disks. Send a check or money
- order in U.S. funds to:
-
- The QBNews
- P.O. Box 507
- Sandy Hook, CT 06482
-
- Please be sure to specify what archive format you want. The
- QBNews normally uses PKZip as it's archiver.
- ----------------------------------------------------------------------
-
- Submitting Articles to The QBNews
-
- The QBNews relies on it's readers to submit articles. If you are
- interested in submitting an article, please send a disk of Ascii text
- of no more than 70 characters per line to:
-
- The QBNews
- P.O. Box 507
- Sandy Hook, CT 06482
-
- Articles can also be submitted via E-Mail. Send them via Compuserve to
- 76510,1725 or via FidoNet to 1:141/777. I can be reached at the above
- addresses as well as on Prodigy as HSRW18A.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The QBNews Page 49
-
-