home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / MAGAZINE / MISC / QBNWS203.ZIP / QBNWS203.NWS < prev    next >
Encoding:
Text File  |  1991-09-15  |  130.6 KB  |  2,971 lines

  1.      Volume  2, Number  3                                September 15, 1991
  2.  
  3.      
  4.      
  5.      
  6.      
  7.      
  8.      
  9.      
  10.      
  11.      
  12.      
  13.      
  14.      
  15.                    **************************************************
  16.                    *                                                *
  17.                    *                    QBNews                      *
  18.                    *                                                *
  19.                    *      International QuickBASIC Electronic       *
  20.                    *                  Newsleter                     *
  21.                    *                                                *
  22.                    *    Dedicated to promoting QuickBASIC around    *
  23.                    *                  the world                     *
  24.                    *                                                *
  25.                    **************************************************
  26.      
  27.      
  28.      
  29.      
  30.      
  31.      
  32.      
  33.      
  34.      
  35.      
  36.      
  37.      
  38.      
  39.      
  40.      
  41.      
  42.         The  QBNews  is  an electronic newsletter  published  by  Clearware
  43.      Computing. It can be freely distributed providing NO CHARGE is charged
  44.      for  distribution.  The  QBNews is copyrighted in  full  by  Clearware
  45.      Computing.  The  authors  hold  the  copyright  to  their   individual
  46.      articles.  All program code appearing in QBNews is released  into  the
  47.      public  domain.   You  may  do what you  wish  with  the  code  except
  48.      copyright  it.  QBNews  must  be  distributed  whole  and  unmodified.
  49.      
  50.      You can write The QBNews at:
  51.      
  52.           The QBNews
  53.           P.O. Box 507
  54.           Sandy Hook, CT 06482
  55.      
  56.      Copyright (c) 1991 by Clearware Computing.
  57.      
  58.      The QBNews                                                   Page    i
  59.      Volume  2, Number  3                                September 15, 1991
  60.  
  61.      
  62.  
  63.      ----------------------------------------------------------------------
  64.  
  65.                         T A B L E   O F   C O N T E N T S
  66.  
  67.      
  68.      1.  From the Editor's Desk
  69.           Greetings From The Microsoft Developers Conference ...........  1
  70.  
  71.      2.  Ask The Doctor
  72.           QB's Hidden Data Copying by Ethan Winer ......................  2
  73.  
  74.      3.  Advertisement
  75.           GFA-BASIC for MS-DOS and Windows 3.0 .........................  6
  76.  
  77.      4.  View Print
  78.           Spill the Wine By J.D. Hildebrand ............................  7
  79.  
  80.      5.  Graphically Speaking
  81.           Fonts in a Can by Larry Stone ................................ 12
  82.           Manipulating Sprites in Screen 13 by Fred Sexton Jr. ......... 17
  83.  
  84.      6.  Who ya gonna call? CALL INTERRUPT
  85.           A Bug Free CALL INTERRUPT by Cornel Huth ..................... 21
  86.  
  87.      7.  The QBNews Professional Library
  88.           An Event-driven Mouse Support Libary by Tony Elliot .......... 23
  89.  
  90.      8.  Advertisement
  91.           E-Tree Plus By EllTech Development, Inc. ..................... 37
  92.  
  93.      9.  Algorithms
  94.           Cardans's Method for Solving Cubes by Richard Jones .......... 39
  95.  
  96.      10.  Fun and Games
  97.           Lines With Style by Larry Stone and Charles Graham ........... 46
  98.  
  99.      11.  EOF
  100.           Receiving The QBNews ......................................... 48
  101.           Submitting Articles to The QBNews ............................ 49
  102.  
  103.  
  104.  
  105.  
  106.  
  107.  
  108.  
  109.  
  110.  
  111.  
  112.  
  113.  
  114.  
  115.  
  116.  
  117.      The QBNews                                                   Page   ii
  118.      Volume  2, Number  3                                September 15, 1991
  119.  
  120.  
  121.  
  122.      ----------------------------------------------------------------------
  123.                    F r o m   t h e   E d i t o r ' s   D e s k
  124.      ----------------------------------------------------------------------
  125.  
  126.      Greetings From The Microsoft Developers Conference
  127.      
  128.      I've just returned from the Microsoft Developers Conference held in
  129.      Seattle at the end of August. I'm sure it was a good time for all who
  130.      attended. It was nice to finally meet some of the people I've been
  131.      speaking to electronically over the years. For those who didn't or
  132.      couldn't attend, I recommend you try to make the next one when ever it
  133.      is held.
  134.      
  135.      The good news from Seattle came during Bill Gates keynote address.
  136.      When asked point blank if Microsoft has abandoned QuickBASIC for DOS
  137.      to concentrate on their Windows products, BG said no. In fact, he
  138.      stated that Microsoft was currently working on an upgrade to
  139.      QuickBASIC, and I believe him.
  140.      
  141.      So here is your chance. I want you to send in you suggestions on what
  142.      should be added to the next QuickBASIC. I'll compile the best
  143.      suggestions and see that Microsoft receives them. I'll also publish
  144.      the top 10 in the next QBNews. With a little luck, we may get some of
  145.      our suggestions incorporated into the next release.
  146.      
  147.      When making your suggestions, use all the new features included with
  148.      BASIC 7.1 PDS as the baseline as to what will be in the next
  149.      QuickBASIC. Also, keep in mind that QuickBASIC is a low end product.
  150.      Therefore, you aren't likely to see ISAM or OS/2 support ever. They
  151.      will always be contained in the PDS version of BASIC.
  152.      
  153.      Look forward to hearing your suggestions. Until next time, happy
  154.      reading.
  155.      
  156.      Dave Cleary - Editor of The QBNews
  157.      
  158.  
  159.  
  160.  
  161.  
  162.  
  163.  
  164.  
  165.  
  166.  
  167.  
  168.  
  169.  
  170.  
  171.  
  172.  
  173.  
  174.  
  175.  
  176.      The QBNews                                                     Page  1
  177.      Volume  2, Number  3                                September 15, 1991
  178.  
  179.  
  180.  
  181.      ----------------------------------------------------------------------
  182.                            A s k   T h e   D o c t o r
  183.      ----------------------------------------------------------------------
  184.  
  185.      Ask The Doctor
  186.      
  187.      Dear Dave,
  188.      
  189.      Enclosed are two sets of functions which are in effect identical, but
  190.      their differences cause a strange phenomenon.
  191.      
  192.      The code in Listing 1 appears to me to be much more involved and
  193.      confusing.  Constantly re assigning variable names from one to another
  194.      and GOSUB'ing to a called routine.
  195.      
  196.      The code in listing 2 directly calls the called routine without using
  197.      an intermediate variable.  This code is more readable, this code is
  198.      tighter, this code is smaller, this routine runs microscopically
  199.      faster.  When I slow my 386 to an effective 8mhz and I run the
  200.      routines in a FOR 1000 NEXT Loop, you will notice a time savings of a
  201.      wonderful 3 seconds.
  202.      
  203.      This code compiles 502 bytes LARGER !. . . .
  204.       
  205.                 Something is not right. . .
  206.       
  207.                          Obviously I am missing something. . .
  208.       
  209.      I am not one to quibble over milliseconds, I will sacrifice the 502
  210.      bytes for readability, but I would really like to understand why this
  211.      happens.
  212.      
  213.      Richard Gray
  214.      [See listings at end of the article]
  215.      
  216.      Ethan Winer responds,
  217.      
  218.      Richard,
  219.      
  220.      What you have discovered is BASIC's hidden copying of data, and in
  221.      your program this happens in two different but related ways.  In the
  222.      first program only variables are being passed to the ConcaveFrame and
  223.      QPrint routines.  The second program passes both numeric and text
  224.      constants (that is, literal numbers and quoted strings), and also
  225.      numeric and string expressions.  Regardless of whether you are passing
  226.      constant data or an expression, BASIC must make a copy of the data,
  227.      place it somewhere in memory, and then pass the address where the
  228.      result was stored.
  229.      
  230.      In contrast, when a variable is passed to a SUB or FUNCTION procedure,
  231.      BASIC can simply obtain the variable's address and place it on the CPU
  232.      stack.  The called routine may then read the data at that address, or
  233.      assign a new value based on the statements in your program.  But a
  234.      constant or expression must be protected from being changed.  Consider
  235.      
  236.      The QBNews                                                     Page  2
  237.      Volume  2, Number  3                                September 15, 1991
  238.  
  239.      the following CALL statement and SUB definition:
  240.      
  241.        CALL MySub("Test", 123)
  242.         ...
  243.         ...
  244.      
  245.        SUB MyProc(Work$, Value%)
  246.          Work$ = "Hi mom!"
  247.          IF Value% > 100 THEN Value% = 100
  248.        END SUB
  249.      
  250.      BASIC can't allow your program to alter either of the incoming
  251.      parameters, since that could affect other parts of the program that
  252.      use the same constants.  When the same quoted string is used more than
  253.      once in a program, BASIC stores a single copy of the data.  For
  254.      example, if you have the statement PRINT "Insert disk in drive A" four
  255.      times in your program, the quoted text is added only once.  If BASIC
  256.      allowed your program to assign new characters to this constant, the
  257.      other PRINT statements would display the wrong text!
  258.      
  259.      The same goes for numeric constants.  If BASIC stored the number 123
  260.      in memory and passed that address, a subprogram that changed its
  261.      incoming parameter would change the number when it is used in other
  262.      places in your program.  Therefore, BASIC always makes a copy of
  263.      constant data before sending it to a SUB or FUNCTION procedure.
  264.      
  265.      A similar situation occurs with data expressions.  When you pass the
  266.      expression LCol + 1 as an argument to a subprogram, BASIC must
  267.      calculate the result and store it somewhere.  And when passing the
  268.      expression STRING$(Length, "─") + "┘" to QPrint, BASIC again has to
  269.      save the result somewhere before passing it on.  To make matters worse
  270.      BASIC also adds code to delete the temporary strings it creates, to
  271.      release the memory they occupy when they are no longer needed.  In
  272.      your case you assigned Temp$ manually, and did not clear that string
  273.      each time after using it as BASIC would.
  274.      
  275.      When fixed-length strings are passed as parameters the situation is
  276.      even worse still.  In that case BASIC first copies the fixed-length
  277.      string to a regular string, passes the copy to the routine, makes the
  278.      call, copies the data back in case the routine changed it, and finally
  279.      erases the temporary string.
  280.      
  281.      I have a few suggestions that you may find useful.  First, if you have
  282.      a copy of Microsoft's CodeView debugger you will find it fascinating
  283.      to trace through the assembly language instructions that BASIC
  284.      creates.  Indeed, this is precisely how I learned about BASIC's hidden
  285.      data copying.  You should also consider buying my book "PC Magazine's
  286.      BASIC Techniques and Utilities" which is published by Ziff-Davis
  287.      Press.  This book is available at your local Waldenbooks and B. Dalton
  288.      book stores, and in it I go into great detail about BASIC's internal
  289.      workings.  There are also many performance and code size optimization
  290.      tips, as well as numerous other advanced BASIC topics.
  291.      
  292.      --Ethan Winer, Crescent Software
  293.      
  294.      The QBNews                                                     Page  3
  295.      Volume  2, Number  3                                September 15, 1991
  296.  
  297.      
  298.      
  299.      LISTING 1
  300.      ---------------------------------------------------------------------
  301.      DEFINT A-Z
  302.      
  303.      DECLARE SUB SetColor (Colur%)
  304.      DECLARE SUB ConcaveFrame (TRow%, LCol%, BRow%, RCol%)
  305.      DECLARE SUB QPrint (Text$, Row%, Col%, Colur%)
  306.      
  307.      TRow = 8
  308.      BRow = 22
  309.      LCol = 7
  310.      RCol = 73
  311.      CLS
  312.      
  313.      ConcaveFrame TRow, LCol, BRow, RCol
  314.      SUB ConcaveFrame (TRow, LCol, BRow, RCol) STATIC
  315.      
  316.         Length = RCol - LCol - 1
  317.      
  318.         R = TRow
  319.         C = LCol
  320.         Clr = 120
  321.      
  322.         Txt$ = "╔"
  323.         GOSUB ShowIt1
  324.      
  325.         C = LCol + 1
  326.         Txt$ = STRING$(Length, "═")
  327.         GOSUB ShowIt1
  328.      
  329.         C = RCol
  330.         Clr = 127
  331.         Txt$ = "╕"
  332.         GOSUB ShowIt1
  333.      
  334.         FOR N = TRow + 1 TO BRow - 1
  335.            R = N
  336.            C = LCol
  337.            Clr = 120
  338.            Txt$ = "║"
  339.            GOSUB ShowIt1
  340.      
  341.            C = RCol
  342.            Clr = 127
  343.            Txt$ = "│"
  344.            GOSUB ShowIt1
  345.         NEXT
  346.      
  347.         R = BRow
  348.         C = LCol
  349.         Clr = 120
  350.         Txt$ = "╙"
  351.      
  352.      The QBNews                                                     Page  4
  353.      Volume  2, Number  3                                September 15, 1991
  354.  
  355.         GOSUB ShowIt1
  356.      
  357.         C = LCol + 1
  358.         Clr = 127
  359.         Txt$ = STRING$(Length, "─")
  360.         GOSUB ShowIt1
  361.      
  362.         C = RCol
  363.         Txt$ = "┘"
  364.         GOSUB ShowIt1
  365.      
  366.         EXIT SUB
  367.      
  368.      ShowIt1:
  369.         QPrint Txt$, R, C, Clr
  370.      RETURN
  371.      
  372.      END SUB
  373.      
  374.      LISTING 2
  375.      ---------------------------------------------------------------------
  376.      DEFINT A-Z
  377.      
  378.      DECLARE SUB SetColor (Colur%)
  379.      DECLARE SUB ConcaveFrame (TRow%, LCol%, BRow%, RCol%)
  380.      DECLARE SUB QPrint (Text$, Row%, Col%, Colur%)
  381.      
  382.      CLS
  383.      ConcaveFrame 8, 7, 22, 73
  384.      
  385.      SUB ConcaveFrame (TRow, LCol, BRow, RCol) STATIC
  386.      
  387.         Length = RCol - LCol - 1
  388.      
  389.         QPrint "╔" + STRING$(Length, "═"), TRow, LCol, 120
  390.         QPrint "╕", TRow, RCol, 127
  391.      
  392.         FOR Row = TRow + 1 TO BRow - 1
  393.              QPrint "║", Row, LCol, 120
  394.              QPrint "│", Row, RCol, 127
  395.         NEXT
  396.      
  397.         QPrint "╙", BRow, LCol, 120
  398.      
  399.         QPrint STRING$(Length, "─") + "┘", BRow, LCol + 1, 127
  400.      
  401.      END SUB
  402.      
  403.      If you have a question for Ask The Doctor, please submit it to:
  404.         The QBNews
  405.         P.O. Box 507
  406.         Sandy Hook, CT 06482
  407.      
  408.  
  409.      The QBNews                                                     Page  5
  410.      Volume  2, Number  3                                September 15, 1991
  411.  
  412.  
  413.  
  414.      ----------------------------------------------------------------------
  415.                             A d v e r t i s e m e n t
  416.      ----------------------------------------------------------------------
  417.  
  418.                           ONLY ONE PROGRAMMING LANGUAGE 
  419.                      LETS YOU CROSS DEVELOP FOR WINDOWS 3.0 AND
  420.                           MS-DOS WITHOUT REWRITING CODE.
  421.      
  422.                               INTRODUCING GFA-BASIC
  423.      
  424.      GFA-BASIC gives you a simple, but powerful language for developing 
  425.      sophisticated, state-of-the-art Windows 3.0 and MS-DOS applications.  
  426.      Write a program with either the DOS or Windows version of GFA-BASIC and 
  427.      port it to the other platform-Doubling the fruits of your effort and
  428.      maintaining a common look and feel between both platforms.
  429.      
  430.      One Set of Source Code
  431.      ----------------------
  432.      Both versions of GFA-BASIC include 500 system and mathematical commands 
  433.      and functions to facilitate software development.  At the same time, 
  434.      common commands and functions enable you to develop and maintain a 
  435.      single set of source code for each program.
  436.      
  437.      Simplifies GUI Development
  438.      --------------------------
  439.      Another 400 commands and functions in the Windows version simplify the 
  440.      development of a complete GUI interface, including clipboard, DDE, 
  441.      DLL's and dialog boxes.  And, you don't need any additional libraries 
  442.      or the SDK
  443.           In the DOS version, a subset of the same commands and functions 
  444.      lets you bring Windows-like programs to AT and XT-class PC's without 
  445.      using any additional tools.
  446.      
  447.      
  448.                          HALF PRICE INTRODUCTORY OFFER
  449.                                                       list        intro
  450.                    GFA-BASIC for Windows 3.0         $ 495        $ 295
  451.                    GFA-BASIC for MS-DOS              $ 295        $ 195
  452.                    Both Windows & DOS versions       $ 790        $ 395
  453.      
  454.      Leverage your existing knowledge of BASIC and with GFA you can write
  455.      more powerful Windows and DOS programs easily right away.
  456.      
  457.      To see for yourself how powerful GFA-BASIC is, just ask for our free 
  458.      Demo Disk - or better yet, order either or both products including all
  459.      documentation on a trial basis with a full 100% money-back guarantee.
  460.      
  461.      Call 1-800-766-6GFA or write GFA Software Technologies, Inc.
  462.                                   27 Congress Street
  463.                                   Salem, MA 01970
  464.                             Fax:  1-508-744-8041
  465.                                   VISA/MasterCard accepted
  466.      
  467.  
  468.      The QBNews                                                     Page  6
  469.      Volume  2, Number  3                                September 15, 1991
  470.  
  471.  
  472.  
  473.      ----------------------------------------------------------------------
  474.                                V i e w   P r i n t
  475.      ----------------------------------------------------------------------
  476.  
  477.      Spill the Wine By J.D. Hildebrand
  478.      
  479.      The editors of this publication have asked me to share my observations
  480.      about language choices, and about where BASIC fits into the world.
  481.      It's my pleasure to toss a few thoughts into the ether. I hope you'll
  482.      respond with your own ideas.
  483.      
  484.      I've edited computer magazines for nearly a decade. It's a pretty good
  485.      job, but people do hit you up quite a bit for free advice.  "Should I
  486.      buy a Mac or a PC?" they ask. (Buy a PC.) "Should I upgrade to UNIX?"
  487.      (Sure, if you don't like software.) "How much memory and disk space do
  488.      I need?" (Fifty percent more than you can afford.)
  489.      
  490.      These questions come up at cocktail parties, usually at trade shows.
  491.      I'm attending in my official guise as Editor In Chief, which means
  492.      I've got a tie on and I've taken the trouble to shake hands with the
  493.      PR director for the sponsoring company, plus whoever he wants to
  494.      impress. (PR people accumulate brownie points--and earn commissions,
  495.      for all I know--by getting magazine editors to shake hands with
  496.      company executives. The theory is that the executives will think the
  497.      PR guy is so chummy with the editor that the company's products will
  498.      gain favorable attention within the editor's magazine. It's all very
  499.      cozy. Since neither the PR guy nor the executives ever bother to read
  500.      the magazine, it's quite harmless to let them go on believing what
  501.      they want to believe.)
  502.      
  503.      So I'm balancing a plate of fresh shrimp and oysters (they do feed
  504.      editors well at these shindigs) in one hand while holding a glass in
  505.      the other...and wondering how I'll manage to light a cigarette with
  506.      both hands full...when some door-crasher comes wandering over and
  507.      squints at my name badge. His eyes light up when he sees he's cornered
  508.      an editor.
  509.      
  510.      "So you work for a programming magazine," he says, "even though it's
  511.      one I've never heard of. So you must be some kind of expert, right?
  512.      What programming language should I use?"
  513.      
  514.      I sigh, resisting somehow the urge to make a too-frank comment about
  515.      the door-crasher's complexion. It's the notion that I have something
  516.      valid to say in response to this question that gets me invited to
  517.      these spill-wine-on-the-carpet bashes, after all, and ultimately make
  518.      it possible for me to pay the mortgage. So I look both ways to make
  519.      sure no one is listening, lean toward the door-crasher, and whisper
  520.      confidentially: "Use the language you know."
  521.      
  522.      "Huh?"
  523.      
  524.      "Look," I continue, "all programming languages do pretty much the same
  525.      things. It's amazing how alike they are. The main difference among
  526.      them, as far as you're concerned, is that you know one of them and
  527.      
  528.      The QBNews                                                     Page  7
  529.      Volume  2, Number  3                                September 15, 1991
  530.  
  531.      you're considering a jump to another. Don't do it. Your knowledge of
  532.      one language's idiosyncracies is at least as valuable as the flashy
  533.      features some other language might offer. Use the language you know
  534.      and don't apologize for it."
  535.      
  536.      The door-crasher sips his drink (his glass, I notice, is still nearly
  537.      full, while I'm stranded across the room from the bar with a tumbler
  538.      full of ice cubes) and shakes his head. "No," he says, "I really want
  539.      to learn a new language. Which should it be?"
  540.      
  541.      I know what he's doing...he's waiting for me to say he should learn C.
  542.      Years ago, I might have. C was, after all, the fastest-growing
  543.      language on the PC platform.
  544.      
  545.      But those days are gone. This year, for the first time since C
  546.      challenged Pascal in the middle of the last decade, the C market has
  547.      stopped growing--even, I'm sure, begun to shrink. So I couldn't just
  548.      tell d-c to learn C, nor C++ (while C was the clear successor to
  549.      Pascal, C so far has no clear successor).
  550.      
  551.      "Well," I say to him, "in the absence of original thought of your own,
  552.      you might do well to emulate your peers."
  553.      
  554.      "Huh?" He gawks at me.
  555.      
  556.      "Consider," I say, "that programmers in different kinds of
  557.      organizations choose different kinds of languages. Viz: Programmers
  558.      who work in shrinkwrap software companies--at Lotus and WordPerfect,
  559.      companies like that--use C and assembler. There are exceptions to the
  560.      rule, but the rule is that shrinkwrap software is written in C and
  561.      assembler."
  562.      
  563.      "Yes, but--"
  564.      
  565.      "Then there are in-house corporate developers, programmers who develop
  566.      software within companies whose main business is not software," I
  567.      continue. "These guys use conservative, stodgy, standardized languages
  568.      because the bottom line is riding on the programs they write and their
  569.      reliability. They use C, COBOL, and FORTRAN."
  570.      
  571.      "I don't think--"
  572.      
  573.      "Yes, there are isolated pockets of Pascal and Modula-2," I say, "and
  574.      of course there are the database systems, dBASE and Paradox and the
  575.      like--they're very strong in the in-house corporate developer
  576.      community."
  577.      
  578.      "But what about--"
  579.      
  580.      "Then there are the consultants," I continue. "This is the largest
  581.      group so far, and the most highly motivated. They have to finish their
  582.      software today so they can ship out the invoice first thing in the
  583.      morning. They can't afford to wrestle with bit-twiddling--they have to
  584.      install working apps. And they have to be able to correct or change
  585.      
  586.      The QBNews                                                     Page  8
  587.      Volume  2, Number  3                                September 15, 1991
  588.  
  589.      the apps months or years later. These guys use high-level languages to
  590.      write maintainable code--BASIC, Pascal, dBASE. The programs they write
  591.      often perform well, but performance isn't the primary concern for
  592.      these programmers. Staying in business is the important concern."
  593.      
  594.      "I still think--"
  595.      
  596.      "And hobbyists," I conclude, "use all kinds of languages, especially
  597.      BASIC, Pascal, and C. They don't have customers or deadlines,
  598.      generally, so they can afford to use any language they like."
  599.      
  600.      At this point the door-crasher is starting to look for an excuse to
  601.      sidle away. He holds up his now-empty glass and gestures toward the
  602.      bar, but I grab him by his tie.
  603.      
  604.      "Unless of course you're looking to become a Windows programmer," I
  605.      say, giving his tie a tug as his face turns red. "That's it, isn't it?"
  606.      
  607.      "Mrffle," he gasps.
  608.      
  609.      "Good thinking," I congratulate him. "These days there are three kinds
  610.      of PC programmers: the ones who already support Windows, the ones who
  611.      are developing a Windows strategy, and the ones who are out of
  612.      business but don't realize it yet."
  613.      
  614.      The door-crasher wheezes.
  615.      
  616.      "The way I see it," I say, "there are four routes to Windows
  617.      programming. Want to hear 'em?"
  618.      
  619.      The door-crasher shakes his head, signalling "no," but I'm on a roll.
  620.      
  621.      "First, there's C and the SDK. That's the Microsoft Software
  622.      Development Kit, got it? You've heard of it. For years, this was the
  623.      only way to write WinApps. But unless you've got the financial
  624.      resources of Lotus Development Corp. and the intellectual resources of
  625.      Charles Petzold to throw at the project, this just isn't a reasonable
  626.      way to write software. Life's too short."
  627.      
  628.      The door-crasher struggles as his face starts to flush.
  629.      
  630.      "Then there's C++ and class libraries. C++ is turning out to be a
  631.      pretty good language for writing Windows applications. I expect most
  632.      professional Windows programmers will use C++. Are you learning C++?"
  633.      
  634.      The door-crasher doesn't respond.
  635.      
  636.      "If you don't like C++, you could try one of the proprietary
  637.      object-oriented languages: Smalltalk, Actor, Turbo Pascal, TOOL, one
  638.      of those. The OOP languages promise to make it simple to write
  639.      WinApps, but so far most of them don't have very good libraries of
  640.      reusable classes. Without reusable class and object libraries, you
  641.      don't get many benefits from OOP."
  642.      
  643.      
  644.      The QBNews                                                     Page  9
  645.      Volume  2, Number  3                                September 15, 1991
  646.  
  647.      The door-crasher shakes his head vigorously. He seems to agree with me
  648.      quite fervently.
  649.      
  650.      "Or you could check out one of the drag-and-drop tools," I say, "like
  651.      Visual Basic. These tools let you design your application visually,
  652.      then integrate the graphical front-end with efficient processing
  653.      engines written with the same tool or in some other language.
  654.      Descendants of the screen-painter UI tools available under DOS, these
  655.      flashy new tools offer the best payoff in making Windows programming
  656.      accessible. If you're looking to get started as a Windows programmer,
  657.      I'd recommend these tools. Got it?"
  658.      
  659.      I release the door-crasher and he falls to his knees wheezing.
  660.      
  661.      "Look," I say, "I know you appreciate the advice, but this is
  662.      ridiculous. Get up, get up."
  663.      
  664.      The door-crasher wanders off and I make another quick cruise past the
  665.      food tables. Oddly enough, no one else comes over to talk with me.
  666.      
  667.      It's good being an editor.
  668.      
  669.      Now, this is a funny little story, and portions of it aren't true...
  670.      but there are some nuggets of truth in it too.
  671.      
  672.      We get caught up too often in defending our language choices. Bah.
  673.      They don't need defending. Use whatever works for you--that's the
  674.      strategy that's kept me writing 15,000 lines of BASIC code per year,
  675.      at a minimum, since 1978.
  676.      
  677.      When I joined the Programmer's Journal staff last month, I was
  678.      appalled to find a bunch of workers clustered around a table counting
  679.      names on a mailing list. Turns out they had to do a ZIP Code zone-
  680.      count for the Postal Service for third-class mailing. "I could write
  681.      a program to do this," I said.
  682.      
  683.      "Oh, we know," they said, "but it would take too long."
  684.      
  685.      Take too long? Well, maybe. They'd asked some of the other
  686.      programmers on the staff about the project, and they rightly
  687.      estimated that it would take a week or two of C coding. I wrote the
  688.      program for them in three hours using BC7.
  689.      
  690.      I'm pretty sure a C version of the program would work faster than my
  691.      BASIC version...but Programmer's Journal has been around for 10
  692.      years, and the zone counts have always been a manual process. Scary,
  693.      I think.
  694.      
  695.      BASIC is the language I choose whenever I have to finish a project
  696.      the same day I start it.
  697.      
  698.      Nine out of 10 BASIC programmers don't get paid for the programs they
  699.      write. That's one of the reasons BASIC has a reputation as a
  700.      hobbyists' language.
  701.      
  702.      The QBNews                                                     Page 10
  703.      Volume  2, Number  3                                September 15, 1991
  704.  
  705.      
  706.      What most folks don't know is that the 1 out of 10 professional BASIC
  707.      programmers outnumber the professional Pascal programmers and match
  708.      the number of professional C programmers. That's a lot of people.
  709.      
  710.      If I were to leave the editorial trades and return to programming,
  711.      and if I could choose just one language, it would surely be BASIC. I
  712.      can always earn a living with a good BASIC compiler. I may not get
  713.      much business from the Fortune 500, but the Unfortunate 5 Million
  714.      will know where to find me.
  715.      
  716.      Stay warm.
  717.      
  718.      JDH
  719.      
  720.      *********************************************************************
  721.      J.D. Hildebrand has edited computer magazines since joining Miller
  722.      Freeman Publications as technical editor of PORTABLE COMPUTER in 1983.
  723.      Along the way, he has worked on MICRO COMMUNICATIONS, PORTABLE 100,
  724.      EPSON WORLD, DATA GENERAL MICRO WORLD, PROFESSIONAL COMPUTING, VAR, PC
  725.      COMPANION, PORTABLE COMPUTER REVIEW, LAPTOP USER, CFO, AI EXPERT,
  726.      COMPUTER LANGUAGE, EMBEDDED SYSTEMS PROGRAMMING, SOFTWARE DEVELOPMENT
  727.      INTERNATIONAL, UNIX REVIEW, PROGRAMMER'S JOURNAL and the C GAZETTE. He
  728.      currently serves as editorial director at Springfield, Oregon-based
  729.      Oakley Publishing Co., and as editor of WINDOWS TECH JOURNAL, which
  730.      will commence monthly publication in January 1992.
  731.      *********************************************************************
  732.      
  733.  
  734.  
  735.  
  736.  
  737.  
  738.  
  739.  
  740.  
  741.  
  742.  
  743.  
  744.  
  745.  
  746.  
  747.  
  748.  
  749.  
  750.  
  751.  
  752.  
  753.  
  754.  
  755.  
  756.  
  757.  
  758.  
  759.      The QBNews                                                     Page 11
  760.      Volume  2, Number  3                                September 15, 1991
  761.  
  762.  
  763.  
  764.      ----------------------------------------------------------------------
  765.                      G r a p h i c a l l y   S p e a k i n g
  766.      ----------------------------------------------------------------------
  767.  
  768.      Fonts in a Can by Larry Stone
  769.      
  770.         You know how it goes - in the process of creating a nifty  program,
  771.      you get side tracked on an even more  nifty  subprogram.   Eventually,
  772.      this nifty subprogram turns into an extrodinary piece of  work.   Such
  773.      is the story behind PrintROMtable - a routine to produce a library  of
  774.      graphics fonts without a font library!
  775.      
  776.         The original PrintROMtable was developed for  FUSION  (published in
  777.      this issue).  Based upon code published by PC Magazine,
  778.      PrintROMtable was limited in it's scope.   Because my time,  like most
  779.      of us, is limited, I made an early release of the code on the Quik_BAS
  780.      internation echo, and asked others to join in it's  development.   The
  781.      responce was outstanding.  Rob Smetana immediately jumped into it with
  782.      code to create italics.  Francois Roy supplied code to elongate  char-
  783.      acters for a bold appearance.   Bill Beasley supplied code  to  create
  784.      tall characters, inspiring Mike Kelly to offer code that creates fonts
  785.      that are 8, 14, 16, 28, or 32 pixel points in height.   Both  Rob  and
  786.      Mike supplied code to allow CGA systems access to the  extended  ASCII
  787.      set (characters 128 through 255). Of course, my contribution continued
  788.      with left-handed italics,  underlined characters, inverse and backward
  789.      characters, strike through, stencil characters, double wide  and  even
  790.      condensed characters, and, not least of all, intergrating the  various
  791.      code supplied by the other, aforementioned contributors, into the  one
  792.      highly useful and variable module. You know how it goes - while in the
  793.      process of creating a nifty program, it goes on and on and on...
  794.      
  795.         Before we get much further,  you should know that PrintROM  is  run
  796.      from a test program called, ROMtest.bas,  and,  although ROMtest traps
  797.      and sets the screen to your highest resolution, the pixel  positioning
  798.      is coded for SCREEN 12. This means that if your computer monitor can't
  799.      handle this resolution then you will see only some of the nifty things
  800.      displayed or, in some cases, some of the diplay will be outside of the
  801.      monitor's graphic boundaries (you can always tweek the xAxis and yAxis
  802.      locations coded in the ROMtest program to place any string  into  your
  803.      system's view area).
  804.      
  805.         So, what's so special about PrintROMtable?   Plenty!   It is a huge
  806.      library of fonts without needing external libraries! The external libs
  807.      supplied provide extended ASCII set 128 through  255.   These are  not
  808.      necessary to the program unless your system is CGA and passes a string
  809.      containing a high ASCII character to PrintROMtable.  Even if your pro-
  810.      gram runs on EGA or VGA, you may wish to include one or more of  these
  811.      font files for the special characters they provide, such as the  copy-
  812.      right and registered trade mark symbols  (more on this subject later!)
  813.      PrintROMtable compiles to around a 13K object file - as small or smal-
  814.      ler than most "standard" font libraries!  As small as this is, you are
  815.      provided fonts ranging from 8 to 64 pixels tall in condensed,  normal,
  816.      bold, or double wide sizes; characters can  be  underlined,  shadowed,
  817.      italic (slanted left or right),  inverted,  backwards,  stenciled,  or
  818.      
  819.      The QBNews                                                     Page 12
  820.      Volume  2, Number  3                                September 15, 1991
  821.  
  822.      contain a strike through mark.   Furthermore, you can print from  left
  823.      to right, right to left, top-down, bottom-up, or even at an angle!
  824.      
  825.         PrintROMtable has limitations.  CGA systems can only use characters
  826.      8 pixels tall - this can be expanded to 16 by setting  PR.Tall = True.
  827.      EGA systems cannot access sizes 16, 32.   However, EGA can have size 8
  828.      expanded to 16 by setting PR.Tall = True.   If you try to have an  EGA
  829.      system use font size 16 or 32, PrintROMtable will reset the size to 14
  830.      or 28, respectively.  This means that using PR.Height = 32 and PR.Tall
  831.      equals True on EGA systems will produce a font 56 pixels high,  not 64
  832.      as intended.   Only VGA has the entire range of  8, 14, 16, 28, 32, 56
  833.      and 64 height characters.
  834.      
  835.         The heart of PrintROMtable is it's code to access the  where-abouts
  836.      of the ROM BIOS segment containing the character shape table.
  837.      
  838.         Once PrintROMtable has the pointer into the ROM segment  that  con-
  839.      taining the character shape tables,  it loops  through  the  passed-in
  840.      string, once for each character in the string.   If a background color
  841.      is called for, it uses LINE with a box and fill (BF) argument to paint
  842.      a background color.   If a background color is not requested then  the
  843.      background color is transparent.  The code then loops 4, 8, 14, 16, 28
  844.      32, 56, or 64 times for each scan line of the character  (depending on
  845.      such factors as PR.Height, PR.Condesned, and PR.Tall).
  846.      
  847.         The 1st item of business is to determine what value, based upon the
  848.      font size, need to be loaded into the BX register so that a subsequent
  849.      call to BIOS interrupt 10h, function 1130h can point us to the correct
  850.      memory address containing our scan lines:
  851.      
  852.              SELECT CASE PR.Height
  853.                  CASE 8               ' 8x8 font
  854.                      reg.bx = &H300
  855.                  CASE 14, 28          ' 8x14 font or 8x14 font double high
  856.                      reg.bx = &H200
  857.                  CASE 16, 32          ' 8x16 font or 8x16 font double high
  858.                      reg.bx = &H600
  859.                  CASE ELSE
  860.                      CLS : PRINT "Invalid Character Size": END
  861.              END SELECT
  862.      
  863.         Having determined the BX value, PrintROMtable then sets AX = &H1130
  864.      before it calls BIOS Video Service, &H10:
  865.      
  866.                 reg.ax = &H1130
  867.                 InterruptX &H10, reg, reg
  868.                 ofst& = reg.bp
  869.                 sgmt& = reg.es
  870.      
  871.      For those with inquiring minds, function AX = 1130h is called with  AX
  872.      and BX set as follows:
  873.      
  874.                 AX = 1130h
  875.                 BX = pointer specifier
  876.      
  877.      The QBNews                                                     Page 13
  878.      Volume  2, Number  3                                September 15, 1991
  879.  
  880.                     &H0   INT 1Fh pointer
  881.                     &H100 INT 44h pointer
  882.                     &H200 ROM 8 by 14 character font pointer
  883.                     &H300 ROM 8 by 8 double dot font pointer
  884.                     &H400 ROM 8 by 8 DD font (top half)
  885.                     &H500 ROM alpha alternate (9 by 14) pointer
  886.                     &H600 ROM alpha alternate (9 by 16) pointer
  887.      
  888.      On return, the ROM BIOS function supplies:
  889.      
  890.                 ES:BP = specified pointer
  891.                 CX    = bytes/character
  892.                 DL    = character rows on screen
  893.      
  894.         Even though PrintROMtable has the appropriate segment and offset to
  895.      the character shape table, they may not be correct!  The above call to
  896.      the BIOS is only good for EGA, MCGA, or VGA systems.  If PR.ScreenMode
  897.      is less than 7 or, if you tell PrintROMtable to force the CGA  address
  898.      then PrintROMtable sets the character shape table's segment to &HFFA6.
  899.      
  900.            IF PR.ForceAddress OR PR.ScreenMode < 7 THEN sgmt& = &HFFA6
  901.      
  902.      Segment &HFFA6 contains the character table but,  unlike  our  INT 10h
  903.      table pointer, this table only goes to the first 127 ASCII characters.
  904.      This means that if PR.ScreenMode is  1, 2, or 3  (same as SCREEN 1, 2,
  905.      or 3) or, if you instruct PrintROMtable to force the address then, you
  906.      cannot access the upper ASCII set without defining a disk font file.
  907.      
  908.         Since the objective of all of the contributors to this program  was
  909.      to create a self-contained, linkable module, we wanted to avoid asking
  910.      users to have to have, or load,  a 3rd-party file just to  access  the
  911.      upper ASCII character set. Several people answered our call for ideas.
  912.      
  913.         Mike Kelly was 1st to supply code to accomplish this aim.  Although
  914.      his code was self-contained, it required 4k of memory to use the data.
  915.      Cornel Huth described an approach similar to the one eventually  taken
  916.      with PrintROMtable: to use Int 1Fh to point to an array containing the
  917.      high characters. Similar approaches were suggested by Bill Beeler  and
  918.      Dave Cleary.  The final approach developed was by Rob Smetana  and  is
  919.      similar in operation to the  DOS program,  Graftabl.  Unlike Graftabl,
  920.      Rob's approach does not require a TSR and it uses a meager 1024  bytes
  921.      of memory.  It does, however, use small, 1024 byte external files.
  922.      
  923.         External fonts are loaded by the routine with one GET statement:
  924.      
  925.            j% = FREEFILE                         'Get a handle
  926.            OPEN FontFile$ FOR BINARY AS #j%      'Open with this handle
  927.            font$ = SPACE$(1024) 'Our fonts need just 1024 bytes (128 * 8).
  928.            GET #1, , font$: CLOSE #j%            'Close file with handle j%
  929.      
  930.         PrintROMtable is supplied with four disk font files that access the
  931.      characters used in international, U.S., Portuguese,  and French-Canada
  932.      ASCII sets.  There can be additional 1024 font files added to the list
  933.      by altering the appropriate area of the PrintROMtable routine.  To add
  934.      
  935.      The QBNews                                                     Page 14
  936.      Volume  2, Number  3                                September 15, 1991
  937.  
  938.      a new font file, search PrintROMtable for:
  939.      
  940.                 '**** You could create your own 1024 byte
  941.      
  942.      The code is self-expanatory and you should not have any trouble adding
  943.      to the list.
  944.      
  945.         If your program is to access one or more of these font  files,  you
  946.      might want to establish a default file to use  (if you don't designate
  947.      a default file then the routine sets the default to number 1 -- inter-
  948.      national).   To set a default font file, before you make any calls  to
  949.      PrintROMtable, LET PR.DefaultFile = ?    Where ? is the number of  the
  950.      file to use (presently, 1 through 4).
  951.      
  952.         Whether a default font file is established or not, you can,  at any
  953.      time, instruct the routine to load any of the font files.   First, you
  954.      should reset the current font file:
  955.      
  956.                             PR.ReadHiAscFile = -1
  957.                             CALL PrintROMtable(a$, PR)
  958.      
  959.      Then, to set the new file, simply:
  960.      
  961.                         PR.ReadHiAscFile = 2 (or 3, or 4, etc.)
  962.      
  963.      The next call to PrintROMtable will then read and use the new fonts.
  964.      
  965.         If your font files are not located in the default path,  before you
  966.      you make your first call to PRINTROMtable, you need to inform it where
  967.      to look.  This, too, is a simple instruction:
  968.      
  969.                         LSET PR.DiskFontLoc = "C:\OFF\IN\URANUS"
  970.      
  971.         Many QB programmers set their SCREEN mode by using  literals,  ie.,
  972.      they use code similar to, SCREEN 9.   PrintROMtable needs to know what
  973.      screen you are using.   To inform it which screen mode is in  use,  do
  974.      something like:
  975.      
  976.                         PR.ScreenMode = 12
  977.                         SCREEN PR.ScreenMode
  978.      
  979.         Putting it all together, your program should look something like:
  980.      
  981.             REM $INCLUDE: 'printrom.bi'
  982.      
  983.             LSET PR.DiskFontLoc = "D:\SNAZZY\FONT\AREA\"
  984.             PR.DefaultFile = 1
  985.      
  986.             PR.ScreenMode = 9
  987.             SCREEN PR.ScreenMode
  988.      
  989.             PR.Height = 8: PR.xAxis = 20: PR.yAxis = 30
  990.             PR.StepX = 9: PR.CharClr = 15: PR.Shadow = -1
  991.             PrintROMtable "Hello there, my name is", PR
  992.      
  993.      The QBNews                                                     Page 15
  994.      Volume  2, Number  3                                September 15, 1991
  995.  
  996.      
  997.             PR.Tall = -1: PR.xAxis = 20: PR.yAxis = 48
  998.             PrintROMtable "John Doe", PR
  999.      
  1000.         When working from within the QB environment,  you need to  load  QB
  1001.      by typing, "QB /Lqb".  The sample program that demonstrates how to use
  1002.      PrintROMtable is named, "ROMTEST.BAS". It is in the file, PRINTROM.ZIP
  1003.      along with PRINTROM.BI, and ROMTEST.MAK. Run QB with the "/Lqb" switch
  1004.      then open the file RomTest.Bas.  That's all you have to do.
  1005.      
  1006.         One final note.  PrintROMtable can do a great deal of fancy work to
  1007.      your strings.  The fancier your output, the more time required to per-
  1008.      form the work.  One saving grace is that all of the fancy manipulation
  1009.      performed by PrintROMtable is considerably faster once compiled as  an
  1010.      EXE file.  However, compiled or not, expect certain processes, such as
  1011.      PR.Elongate = 2 (double wide) to be slower than the simpler  processes
  1012.      like 8 pixel high, normal character writes.
  1013.      
  1014.      [EDITOR'S NOTE]
  1015.      All code for this article can be found in PRINTROM.ZIP
  1016.      
  1017.      **********************************************************************
  1018.           Larry  Stone is President of LSRGroup and is involved in  writing
  1019.      instructional and large data base application systems for business and
  1020.      institutional clients.  He is also the author of SERVICES, a shareware
  1021.      application program rated a trophy by "Public Brand Software". He  can
  1022.      be  reached  at LSRGroup, 2945 "A" Street, North Bend, OR 97459, or in
  1023.      care of this newsletter.
  1024.      **********************************************************************
  1025.      
  1026.  
  1027.  
  1028.  
  1029.  
  1030.  
  1031.  
  1032.  
  1033.  
  1034.  
  1035.  
  1036.  
  1037.  
  1038.  
  1039.  
  1040.  
  1041.  
  1042.  
  1043.  
  1044.  
  1045.  
  1046.  
  1047.  
  1048.  
  1049.  
  1050.      The QBNews                                                     Page 16
  1051.      Volume  2, Number  3                                September 15, 1991
  1052.  
  1053.      Manipulating Sprites in Screen 13 by Fred Sexton Jr.
  1054.      
  1055.      In January I bought my first real computer(386SX).I don't count the
  1056.      TI-99 that's still in the closet.After a month or so of GWBASIC I
  1057.      bought QuickBasic 4.5 .I was instantly hooked,and have spent alot of
  1058.      my spare time coding.
  1059.      
  1060.      I wanted to make a few animated educational games for my kids.I soon
  1061.      found that animation would require alot of "sprites".I needed an easy
  1062.      to use drawing program to create sprites in my favorite mode SCREEN 13
  1063.      (320x200x256).So I set out to create one.I ended up with "THE SPRITE
  1064.      MASTER" (so named because I finally had mastered them).  Along the way
  1065.      I learned alot about SCREEN 13.I decided to pass along some of it.
  1066.      NOTE:I always use DEFINT A-Z.So,all arrays discussed here are integer
  1067.      arrays.
  1068.      
  1069.      The easiest way to store an image is with Q.B.'s GET statement.  To
  1070.      find the minimum size to dimension an array,I set up a loop getting a
  1071.      10w X 10h image decreasing the number of elements each time until an
  1072.      error occurred.I don't care for the formula in the book.The result was
  1073.      that a 10w X 10h image required 52 elements or, DIM ary(51).The
  1074.      elements are numbered starting with zero by default. So,always
  1075.      remember to DIM an array with a value that is one less than you really
  1076.      want.Knowing that the colors are in the range of 0 - 255 we can
  1077.      determine that each pixel requires 8 bits (1byte) to store it's color
  1078.      value (255 = 11111111 B).So,in a 10w X 10h image there are 100 bytes
  1079.      or 50 words.We can conclude that GET needs the number of words in the
  1080.      image plus two additional words. 
  1081.      
  1082.          Therefore : elements = ((width * height) + 1) \ 2 + 2
  1083.                      (the "+ 1" takes care of odd values) 
  1084.      
  1085.      To find out what the two extra words are for,we'll GET a couple of
  1086.      different size images from a blank screen. Then we'll compare the
  1087.      values in the resulting arrays. 
  1088.      
  1089.      With image1 = 10w X 10h and image2 = 20w X 5h: 
  1090.      ary1(0) = 80        ary2(0) = 160 
  1091.      ary1(1) = 10        ary2(1) = 5 
  1092.      ary1(2-51) = 0      ary2(2-51) = 0 
  1093.      
  1094.      Now we know the first two elements are used by GET to store the image
  1095.      size information.The first element is the image width in bits.
  1096.      Remember we said 1 pixel = 8 bits.To find pixel width just divide by
  1097.      8.The second element is the height. To determine the rest of the
  1098.      pattern let's set a few points and get the image.
  1099.      
  1100.      FOR t = 0 TO 3
  1101.       PSET(t , 0), t + 1
  1102.       PSET(t , 1), t + 5 NEXT
  1103.      GET (0 , 0) - (3 , 1), ary
  1104.      
  1105.      We already know what's in the first two elements so let's look at the
  1106.      rest.
  1107.      
  1108.      The QBNews                                                     Page 17
  1109.      Volume  2, Number  3                                September 15, 1991
  1110.  
  1111.      
  1112.         ary(2) = 513
  1113.         on the byte level 
  1114.         low byte = 1    =>  value of the pixel (0,0)
  1115.         high byte = 2   =>  value of the pixel (1,0)
  1116.         
  1117.         ary(3) = 1027
  1118.         on the byte level 
  1119.         low byte = 3    =>  value of the pixel (2,0)
  1120.         high byte = 4   =>  value of the pixel (3,0)
  1121.         
  1122.         ary(4) = 1541
  1123.         on the byte level 
  1124.         low byte = 5    =>  value of the pixel (0,1)
  1125.         high byte = 6   =>  value of the pixel (1,1)
  1126.         
  1127.         ary(5) = 2055
  1128.         on the byte level 
  1129.         low byte = 7    =>  value of the pixel (2,1)
  1130.         high byte = 8   =>  value of the pixel (3,1)
  1131.      
  1132.      This was a 4w X 2h image.Starting at the low byte the third 
  1133.      element,the next four bytes correspond to the first row of four 
  1134.      pixels.The next four bytes correspond to the second row of four 
  1135.      pixels.Analysis of other images will show the same pattern.Thus we can
  1136.      conclude for an image with a width of W :
  1137.      
  1138.         Starting with the low byte of the third element,the first W # of 
  1139.         bytes will correspond to the pixels in the first row and the 
  1140.         second  W # of bytes will correspond to the pixels in the second 
  1141.         row and so on for each row.
  1142.      
  1143.      Once the pattern is known manipulating the arrays can accomplish many
  1144.      things.Here are a few examples.
  1145.      
  1146.      Change a color:
  1147.      
  1148.      To change a color in an image array we would search the array at the
  1149.      byte level for the source color.When it is found we will replace it
  1150.      with the new color.
  1151.      
  1152.      In pseudo code:
  1153.      
  1154.      FOR t = 0  TO  bytes - 1      (because we start with zero)
  1155.        IF PEEK (t + start offset) = oldcolor THEN
  1156.          POKE t + start offset, newcolor
  1157.        END IF
  1158.      NEXT
  1159.      
  1160.      Mirror an image:
  1161.          
  1162.      To create a mirror image we need to reverse the order of each row of
  1163.      pixels.We know the pixels are stored in groups corresponding to the
  1164.      width of the image.So,in a 10w X 10h image starting with the low byte
  1165.      
  1166.      The QBNews                                                     Page 18
  1167.      Volume  2, Number  3                                September 15, 1991
  1168.  
  1169.      of the third element the first byte would be the first pixel in the
  1170.      first row and the tenth byte would be the last pixel in the first
  1171.      row.To make it easier let's dimension a second array the same size as
  1172.      the first.Then after making the size information the same we can just
  1173.      copy the bytes from one to the other in the proper order (first to
  1174.      tenth,second to ninth,etc.).
  1175.      
  1176.      In pseudo code:
  1177.      
  1178.      aofs=offset of first pixel in first row of source
  1179.      bofs=offset of last pixel in first row of target
  1180.      
  1181.      FOR  first row  TO  last row
  1182.       FOR  first pixel  TO  last pixel
  1183.         PEEK at  aofs + increasing pixel number (0 to start)
  1184.         POKE to  bofs     
  1185.         decrease bofs to next lower pixel
  1186.       NEXT source pixel
  1187.      aofs=offset of first pixel in next row of source
  1188.      bofs=offset of last pixel in next row of target
  1189.      NEXT row
  1190.      
  1191.      Superimpose an image:
  1192.      
  1193.      To superimpose an image ie. put it front of or behind existing images
  1194.      without destroying them or messing the colors up.Again it is easiest
  1195.      to use a second array of the same size.First we get the area of the
  1196.      screen where we are planning to put the image.Then to put in front we
  1197.      take all non-zero (background) pixels from the first array and put
  1198.      them into the second array.To put behind we only poke pixels from the
  1199.      source array there are zeros in the second array.  The result can be
  1200.      PUT with PSET and we won't end up with the blacked out area we
  1201.      normally have.
  1202.      
  1203.      In pseudo code:
  1204.      
  1205.      IN FRONT:
  1206.      GET target area into work array
  1207.      
  1208.      FOR  first pixel in first row  TO  last pixel in last row
  1209.       PEEK at a source pixel
  1210.       IF pixel is not zero THEN POKE pixel into work array
  1211.      NEXT
  1212.      PUT work array PSET
  1213.      
  1214.      BEHIND:
  1215.      GET target area into work array
  1216.      
  1217.      FOR  first pixel in first row  TO  last pixel in last row
  1218.       PEEK at a work pixel
  1219.       IF pixel is zero THEN 
  1220.           PEEK at same pixel in source
  1221.           POKE pixel into work array
  1222.       END IF
  1223.      
  1224.      The QBNews                                                     Page 19
  1225.      Volume  2, Number  3                                September 15, 1991
  1226.  
  1227.      NEXT
  1228.      PUT work array
  1229.      PSET
  1230.      
  1231.      These are just a few of many possibilities.(The superimpose routine
  1232.      could be easily modified to allow partial PUTS.) The documented source
  1233.      for each routine discussed is in G13UTIL.BAS . 
  1234.      
  1235.      I recently started learning MASM and have converted these to faster
  1236.      versions.I plan to release a shareware library of fast routines for
  1237.      SCREEN 13,as well as a shareware version of "THE SPRITE MASTER". I
  1238.      plan to Upload them to COMPUSERVE and AMERICA ON LINE. Comments and/or
  1239.      suggestions would be appreciated. 
  1240.      
  1241.      [EDITOR'S NOTE]
  1242.      All code for this article can be found in SPRITE.ZIP
  1243.      
  1244.      *********************************************************************
  1245.      Fred Sexton Jr. is an electrician for Ford Motor Co. He works 
  1246.      extensively with Allen Bradley Programmable controllers and Kuka 
  1247.      robotics.He received electrical training in the NAVY as an electronics
  1248.      technician / reactor operator. He can be reached on Compuserve at
  1249.      70253,163 and on A.O.L. at 7408.
  1250.      *********************************************************************
  1251.      
  1252.  
  1253.  
  1254.  
  1255.  
  1256.  
  1257.  
  1258.  
  1259.  
  1260.  
  1261.  
  1262.  
  1263.  
  1264.  
  1265.  
  1266.  
  1267.  
  1268.  
  1269.  
  1270.  
  1271.  
  1272.  
  1273.  
  1274.  
  1275.  
  1276.  
  1277.  
  1278.  
  1279.  
  1280.  
  1281.      The QBNews                                                     Page 20
  1282.      Volume  2, Number  3                                September 15, 1991
  1283.  
  1284.  
  1285.  
  1286.      ----------------------------------------------------------------------
  1287.         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
  1288.      ----------------------------------------------------------------------
  1289.  
  1290.      A Bug Free CALL INTERRUPT by Cornel Huth
  1291.      
  1292.      There is a problem with the CALL INTERRUPT routine in QuickBASIC
  1293.      and BASIC PDS 7. This table highlights the problems.
  1294.      
  1295.        Problem                   4.0  4.0b  4.5  CH   6.0  7.0  7.1
  1296.      -----------------------------------------------+--------------
  1297.      1. DI parameter              X                 |  .    .
  1298.      2. INT25/26                  X    X    X       |  .    .    X
  1299.      3. INT24 environment         X    X    X    X  |  .    .
  1300.      4. INT24 EXE ON ERROR GOTO                     |  .    .    D
  1301.      5. INT24 EXE NO ERROR TRAP   X    X    X    X  |  .    .    D
  1302.                                                     |
  1303.         .   not tested
  1304.         X - error present
  1305.         D - DOS INT24 fatal error handler gains control
  1306.        CH - The CH version is the INTRPT.OBJ that's in QBNWS105.
  1307.      --------------------------------------------------------------
  1308.      1) typo causes the passed DI register parameter to NOT be used
  1309.      2) DOS INT25/26 will always report success even if it failed
  1310.      -- DOS fatal error (INT24) in:
  1311.      3) QB environment causes system crash
  1312.      4) EXE w/ ON ERROR GOTO handler causes system crash
  1313.      5) EXE with no ERROR handler causes system crash
  1314.      
  1315.      In the QuickBASIC 4.x environment any fatal DOS error during a CALL
  1316.      INTERRUPT crashes the system. In QB 4.x EXEs with ON ERROR GOTO
  1317.      handlers the error is trapped by the error handler. In QB 4.x EXEs
  1318.      without ON ERROR GOTO the runtime code starts to print the error text
  1319.      to the screen but only gets part of it printed before it locks up.
  1320.       
  1321.      In PDS 7, the evironment does not crash on a fatal DOS error because
  1322.      the BP register is saved (in b$SaveBP) before executing the interrupt.
  1323.      Apparently BASIC needs the original BP if a fatal DOS error occurs so
  1324.      that it can reference the return address of the caller.
  1325.      
  1326.      In PDS 7 EXEs, with or without ON ERROR GOTO handlers, fatal errors
  1327.      are simply passed through to the INT24 error handler. This brings up
  1328.      the Abort, Retry, Fail prompt. Pressing F returns to INTERRUPT.
  1329.      INTERRUPT then returns with the carry flag set and DOS error 83d in AX
  1330.      (83d=Fail on INT24). The ON ERROR GOTO handler is never invoked.
  1331.      Pressing A causes the entire program to immediately exit to DOS.
  1332.      
  1333.      Wouldn't it be great if CALL INTERRUPT worked predictably all the
  1334.      time?  Now it does. INTRPT2.OBJ is a direct replacement for either QB
  1335.      or PDS that traps fatal DOS errors and returns control, and decision
  1336.      making, to your program. When a fatal DOS error occurs, the carry flag
  1337.      is set and the DOS error code is returned in AX.
  1338.      
  1339.      For example, let's say you want to see if a file exists. What you
  1340.      
  1341.      The QBNews                                                     Page 21
  1342.      Volume  2, Number  3                                September 15, 1991
  1343.  
  1344.      could do is open the file and check for any errors. This works fine as
  1345.      long as the drive of the file is valid and ready. But if the drive is
  1346.      a floppy and the door is open, boom. In the QB4 environment the system
  1347.      would lockup, even if ON ERROR GOTO were set. In PDS EXE programs the
  1348.      default DOS INT24 handler pops up on a fatal error, even with ON ERROR
  1349.      GOTO. This messes up the screen with the infamous Abort, Retry, Fail
  1350.      prompt and lets the user abort with files possibly open.  My B-tree
  1351.      shareware libraries QBTree 5.5 and QBXDBF 1.0 (dBASE .DBF format) have
  1352.      support functions that make use of the INTERRUPT routines and I can't
  1353.      allow them to crash the system or present an Abort prompt.  No more
  1354.      surprises!
  1355.      
  1356.      To update your version of INTERRUPT(X) put INTRPT2.OBJ in your
  1357.      library directory and then do the following:
  1358.      
  1359.              C>lib QB.LIB -INTRPT +INTRPT2;
  1360.              C>link /qu QB.LIB,QB.QLB,nul,BQLB45.LIB;
  1361.      
  1362.      BQLB45.LIB pertains to QuickBASIC 4.5. Use BQLB40 for QB 4.00 and
  1363.      BQLB41 for QB 4.00b. For BASIC PDS 7.x replace references to QB with
  1364.      QBX.LIB and QBX.QLB, and use QBXQLB.LIB for the library prompt.
  1365.      
  1366.      The source to INTRPT2.ASM, a sample FileExists() function, a DOS
  1367.      error listing and INTRPT2.OBJ are in INTRPT2.ZIP file.
  1368.      
  1369.      *********************************************************************
  1370.      Cornel Huth is chief designer and programmer for ScanSoft. He can be
  1371.      reached at 6402 Ingram Road, San Antonio, Texas 78238. When he's not
  1372.      twiddling bits he's thinking of ways he could.
  1373.      *********************************************************************
  1374.      
  1375.  
  1376.  
  1377.  
  1378.  
  1379.  
  1380.  
  1381.  
  1382.  
  1383.  
  1384.  
  1385.  
  1386.  
  1387.  
  1388.  
  1389.  
  1390.  
  1391.  
  1392.  
  1393.  
  1394.  
  1395.  
  1396.  
  1397.  
  1398.      The QBNews                                                     Page 22
  1399.      Volume  2, Number  3                                September 15, 1991
  1400.  
  1401.  
  1402.  
  1403.      ----------------------------------------------------------------------
  1404.           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
  1405.      ----------------------------------------------------------------------
  1406.  
  1407.      An Event-driven Mouse Support Libary by Tony Elliot
  1408.      
  1409.      The mouse is one of the easiest-to-use interface devices available for
  1410.      PCs. Even though it has been extremely popular over the last several
  1411.      years, Microsoft didn't provide direct support for it in the BASIC
  1412.      programming language until the recent release of Visual BASIC for
  1413.      Windows (although the BASIC Professional Development System [PDS]
  1414.      includes indirect support of the mouse through routines in the "User
  1415.      Interface Toolbox" included with that product). This doesn't mean that
  1416.      the mouse has been unreachable from BASIC programs. Mouse services can
  1417.      be easily accessed through BASIC's "CALL Interrupt" routine (as
  1418.      illustrated in a previous issue of QBNews). Also, most BASIC add-on
  1419.      developers include mouse routines written in assembly language as part
  1420.      of their regular complement of functions. So why the need for
  1421.      *another* set of mouse routines? Well, there are several reasons:
  1422.      
  1423.      1. If you don't already own one, commercial add-on libraries can get
  1424.      rather expensive. If you are only interested in adding mouse support
  1425.      to your programs, you might have to shell out $100 to $200 (or more)
  1426.      for a product that consists of several hundred routines, only a few of
  1427.      which you'll use for this purpose. However, add-on libraries like
  1428.      MicroHelp's "Muscle" ($189) or Crescent's "QuickPak Professional"
  1429.      ($199) are definitely the way to go if you can afford it. Many of the
  1430.      other routines included in those products will no doubt be useful to
  1431.      you down the road.
  1432.      
  1433.      2. Many of the public domain or "shareware" mouse support alternatives
  1434.      are written in BASIC, usually invoking BASIC's "CALL Interrupt"
  1435.      service. Although this is a completely functional approach, there is a
  1436.      substantial amount of overhead required (in terms of speed and code
  1437.      generation). CALL Interrupt is a relatively slow service to begin
  1438.      with, and the results returned by it must then be translated into a
  1439.      usable form. Doing all of this from BASIC may not allow you to poll
  1440.      the mouse as frequently as required by some applications, therefore
  1441.      you may occasionally miss some real-time events such as button-clicks.
  1442.      
  1443.      3. Using routines written in assembly language for minor tasks such as
  1444.      mouse support is, in my humble opinion, the way to go. It adds a
  1445.      minimal amount of overhead to your BASIC programs and does the job as
  1446.      quickly as possible. This equates to smaller, faster, and from the
  1447.      users' point of view, more responsive programs.
  1448.      
  1449.      4. The set of mouse routines described in this article has one
  1450.      important feature that I haven't seen elsewhere in DOS-based BASIC.
  1451.      Utilizing the "ON UEVENT" service available since QB 4.00a, they allow
  1452.      you to create "mouse event-driven" programs. That is, instead of
  1453.      constantly polling the mouse for activity, you can go about your
  1454.      normal business and when a programmer-defined type of mouse activity
  1455.      occurs (a button press, release, or mouse movement), your program is
  1456.      interrupted and control is transferred to a subroutine that you
  1457.      
  1458.      The QBNews                                                     Page 23
  1459.      Volume  2, Number  3                                September 15, 1991
  1460.  
  1461.      specify. This allows you to logically group your mouse-specific code
  1462.      instead of having it sprinkled here and there throughout your program.
  1463.      
  1464.      The two mouse-programming paradigms, "polled" and "event-driven," each
  1465.      have advantages and disadvantages. We will discuss each in detail as
  1466.      the routines are being presented below. The file MOUSE.REF contains a
  1467.      reference listing each of the routines individually, along with the
  1468.      appropriate descriptions and parameter lists associated with them.
  1469.      
  1470.      The various code fragments used below each assume that the file
  1471.      MOUSE.BI is $Included at the top of your program. It contains the
  1472.      declarations and the TYPE..END TYPE structures required by these
  1473.      routines. Many of the code fragments also assume that you have already
  1474.      reset the mouse and the pointer is visible.
  1475.      
  1476.      Also keep in mind that we won't be talking too much about -how- the
  1477.      routines actually work. Fully commented assembly source code is
  1478.      provided for those enquiring minds that "what to know." An example
  1479.      program called MOUSE.BAS is also included. It demonstrates all of the
  1480.      mouse routines described in this article.
  1481.      
  1482.      ----------------------------------------------------------------------
  1483.                            Resetting the Mouse Driver
  1484.      ----------------------------------------------------------------------
  1485.      
  1486.      When writing programs that will recognize and accept input from a
  1487.      mouse, the first step is to determine if a software "driver" for the
  1488.      mouse is installed. If one is found, it must be "reset" before our
  1489.      program can actually communicate with the mouse. Calls to any of the
  1490.      other mouse routines described here (besides the three "reset"
  1491.      routines) will simply be ignored if the mouse has not been reset or is
  1492.      not present at all. As a convenience, three routines are provided to
  1493.      determine the presence of the mouse and to reset it, if desired:
  1494.      
  1495.      MouseReset% - An integer function that checks to see if a mouse driver
  1496.      is installed, and if so, resets it. The number of buttons the mouse
  1497.      has is returned as a result, or zero if a mouse driver is not
  1498.      installed.  When the mouse is reset, it is left in the following
  1499.      state:
  1500.      
  1501.           - Mouse pointer is at the center of the screen
  1502.      
  1503.           - Display page for mouse set to 0
  1504.      
  1505.           - Mouse pointer is hidden (off)
  1506.      
  1507.           - Mouse pointer shape is the default arrow shape in the
  1508.             graphics video modes or a reverse block in the text modes.
  1509.      
  1510.      MouseAlreadyReset% - An integer function that checks to see if the
  1511.      mouse has already been reset by this program. If so, it returns the
  1512.      number of buttons the mouse has, otherwise it returns zero and takes
  1513.      no further action. This is handy in situations where you don't want to
  1514.      reset the mouse if it has been reset previously (doing so
  1515.      
  1516.      The QBNews                                                     Page 24
  1517.      Volume  2, Number  3                                September 15, 1991
  1518.  
  1519.      unnecessarily takes a couple of seconds and has other, sometimes
  1520.      undesirable, effects such as those listed above).
  1521.      
  1522.      MouseInstalled% - An integer function that checks for the presence of
  1523.      a mouse without resetting it.
  1524.      
  1525.      Most of the time, MouseReset% will be all that you need. For example:
  1526.      
  1527.           NumberOfButtons% = MouseReset%
  1528.           IF NumberOfButtons% THEN
  1529.                PRINT NumberOfButtons%; " button mouse found and reset!"
  1530.           ELSE
  1531.                PRINT "Mouse not found."
  1532.           END IF
  1533.      
  1534.      Once the mouse has been successfully reset, you are then free to use
  1535.      any of the other functions.
  1536.      
  1537.      ----------------------------------------------------------------------
  1538.              Obtaining Information About Mouse Hardware and Software
  1539.      ----------------------------------------------------------------------
  1540.      
  1541.      If you wish to obtain specific information about the mouse hardware
  1542.      and software currently in use, the MouseGetInfo routine can be used to
  1543.      identify the version number of the mouse driver software, the type of
  1544.      mouse (bus, serial, InPort, PS/2, or HP), and the hardware interrupt
  1545.      line (IRQ) the mouse is sitting on. For example:
  1546.      
  1547.           CALL MouseGetInfo(MajorV%, MinorV%, MouseType%, Irq%)
  1548.           PRINT "Mouse software version:";MajorV% + MinorV% / 100
  1549.           PRINT "Mouse type: ";
  1550.           SELECT CASE MouseType%
  1551.                CASE 1
  1552.                     PRINT "Bus"
  1553.                CASE 2
  1554.                     PRINT "Serial"
  1555.                CASE 3
  1556.                     PRINT "InPort"
  1557.                CASE 4
  1558.                     PRINT "PS/2"
  1559.                CASE 5
  1560.                     PRINT "HP"
  1561.                CASE ELSE
  1562.                     PRINT "Beats the heck outta me! Type#";MouseType%
  1563.           END SELECT
  1564.           PRINT "Using IRQ";Irq%
  1565.      
  1566.      This information is useful in some cases, but generally there's no
  1567.      particular need for you to be aware of it.
  1568.      
  1569.      ----------------------------------------------------------------------
  1570.                                 The Mouse Pointer
  1571.      ----------------------------------------------------------------------
  1572.      
  1573.      
  1574.      The QBNews                                                     Page 25
  1575.      Volume  2, Number  3                                September 15, 1991
  1576.  
  1577.      After the mouse has been reset, you'll want to make the mouse
  1578.      "pointer" (or "cursor") visible. The visibility state of the mouse
  1579.      pointer is controlled by the MousePointerOn and MousePointerOff
  1580.      routines.  Remember, the MouseReset function initially turns the
  1581.      pointer OFF. For example:
  1582.      
  1583.           NumberOfButtons% = MouseReset%
  1584.           LINE INPUT "The mouse pointer is invisible. Press <Enter> .. ",A$
  1585.           CALL MousePointerOn
  1586.           LINE INPUT "The mouse pointer is visible. Press <Enter> .. ",A$
  1587.           CALL MousePointerOff
  1588.           PRINT "The mouse pointer is invisible again. Press <Enter> .. "
  1589.      
  1590.      By default, the mouse driver uses a "software pointer" while in the
  1591.      text video modes. This means that a mouse pointer is visible on the
  1592.      screen because the mouse driver is altering the screen's color
  1593.      attribute and/or the character at the location where the pointer is to
  1594.      be placed. This makes that location stand out from the rest of the
  1595.      data displayed on the screen. The default software pointer simply
  1596.      reverses the color attributes at the pointer position. When the
  1597.      pointer is moved, it restores the original attribute and character at
  1598.      the current position, stores the original attribute and character for
  1599.      the new position, and then applies the defined masks to the new
  1600.      position.
  1601.      
  1602.      Before updating the screen using PRINT, CLS, etc., it's necessary to
  1603.      turn the mouse pointer off. If you were to overwrite the screen at the
  1604.      mouse pointer position while the pointer is visible, the mouse driver
  1605.      would not be aware of this occurrence. The next time the pointer is
  1606.      moved, the original attribute and character stored by the mouse driver
  1607.      would be restored to that location. The result is what I like to refer
  1608.      to as "mouse droppings." For this reason, it's generally considered
  1609.      good practice to leave the mouse pointer off except when your program
  1610.      is waiting for input from the user.
  1611.      
  1612.      The mouse driver provides a service whereby you can customize the
  1613.      effects that the pointer has on the color attribute and character at
  1614.      the pointer position. This is accomplished by providing two
  1615.      "bit-masks" that define which bits comprising the attribute/character
  1616.      will be preserved (ANDed) and which will then be toggled (XORed).
  1617.      Since manipulation of the mouse pointer on this level is of little
  1618.      interest to most programmers and would require a crash course in video
  1619.      memory and bit manipulation, I'll skip the nitty-gritty and describe
  1620.      the supplied routine. If you would like more in-depth information
  1621.      about this function, refer to the Microsoft Mouse Programmers Guide,
  1622.      or leave a message for me on Compuserve. I'll be happy to help.
  1623.      
  1624.      The routine MouseSetSoftwarePointer is used to define the "AND" and
  1625.      "XOR" bit masks for the software cursor. For example:
  1626.      
  1627.           AndMask% = &H77FF
  1628.           XorMask% = &H7700
  1629.           CALL MouseSetSoftwarePointer(AndMask%, XorMask%)
  1630.      
  1631.      
  1632.      The QBNews                                                     Page 26
  1633.      Volume  2, Number  3                                September 15, 1991
  1634.  
  1635.      The first byte of each mask represents the changes made to the color
  1636.      attribute. The "77" part of the AND mask indicates that the foreground
  1637.      color (bits 0-2) and background color (bits 4-6) will be preserved and
  1638.      the high- intensity (bit 3) and blink (bit 7) bits will be turned-off.
  1639.      The "77" part of the XOR mask indicates that the bits comprising the
  1640.      foreground and background colors should then be toggled. The "FF" part
  1641.      of the AND mask indicates that all bits comprising the character
  1642.      should be preserved. The "00" part of the XOR mask indicates that none
  1643.      of the character's bits will be toggled. In other words, when the
  1644.      mouse pointer appears on the screen, the color of the cell will be
  1645.      modified but the character won't. To take another example, we'll leave
  1646.      the color attribute alone, but will change the mouse pointer to an
  1647.      asterisk:
  1648.      
  1649.        AndMask% = &HFF00  'Preserve all attribute bits and discard the char
  1650.        XorMask% = &H002A  'Don't mess with attribute, make char an "*"
  1651.        CALL MouseSetSoftwarePointer(AndMask%, XorMask%)
  1652.      
  1653.      Another type of pointer available in text video modes is the "hardware
  1654.      pointer." It is called that because it is similar to the normal scan
  1655.      line-oriented text cursor that we're all familiar with. It appears on
  1656.      the screen as a blinking block. You can define it size, and to a
  1657.      degree, it's shape. Like the text cursor, the mouse hardware pointer
  1658.      is comprised of from 0 to 7 scan lines. When defining a hardware
  1659.      pointer, you specify the starting and ending scan line number, with 0
  1660.      at the top of the character cell and 7 at the bottom, much like you
  1661.      would use BASIC's LOCATE statement to alter the shape of the text
  1662.      cursor. For example:
  1663.      
  1664.           'A full "block"
  1665.           StartScan% = 0
  1666.           EndScan% = 7
  1667.           CALL MouseSetHardwarePointer(StartScan%, EndScan%)
  1668.      
  1669.           'Or
  1670.      
  1671.           'A thin line in the middle of the character cell
  1672.           StartScan% = 3
  1673.           StartScan% = 4
  1674.           CALL MouseSetHardwarePointer(StartScan%, EndScan%)
  1675.      
  1676.      As some of you may be aware, the actual height of a character cell
  1677.      varies between 8 to 16 scan lines depending on the display adapter and
  1678.      the video mode used. This function automatically translates the
  1679.      requested 0-7 range into the scan line range appropriate for the
  1680.      display adapter and video mode in use.
  1681.      
  1682.      ----------------------------------------------------------------------
  1683.                              What's the Mouse Up To?
  1684.      ----------------------------------------------------------------------
  1685.      
  1686.      When working with the mouse, the big questions are "Where is the mouse
  1687.      pointer?" and "Is a button pressed or released?" This information is
  1688.      required to process the most rudimentary mouse action, the "click."
  1689.      
  1690.      The QBNews                                                     Page 27
  1691.      Volume  2, Number  3                                September 15, 1991
  1692.  
  1693.      The routine MouseGetStatus can used to answer these questions for you.
  1694.      For example:
  1695.      
  1696.           REM $INCLUDE: 'MOUSE.BI'
  1697.      
  1698.           DECLARE FUNCTION Pressed$(Button%) 'Used only by this example
  1699.      
  1700.           NumberOfButtons% = MouseReset%
  1701.           IF NumberOfButtons% = 0 THEN
  1702.                PRINT "No mouse detected."
  1703.                END
  1704.           END IF
  1705.           
  1706.           CALL MousePointerOn
  1707.      
  1708.           CLS
  1709.           PRINT "Press any key to end:"
  1710.           DO
  1711.                CALL MouseGetStatus(Lb%, Rb%, Cb%, Row%, Column%)
  1712.                LOCATE 3,1
  1713.                PRINT "  Left Button :"; Pressed$(Lb%)
  1714.                PRINT "  Right Button:"; Pressed$(Rb%)
  1715.                IF NumberOfButtons% > 2 THEN
  1716.                     PRINT " Center Button:"; Pressed$(Cb%)
  1717.                END IF
  1718.                PRINT "   Current Row:"; Row%
  1719.                PRINT "Current Column:"; Column%
  1720.           LOOP UNTIL LEN(INKEY$)
  1721.      
  1722.           CALL MousePointerOff
  1723.      
  1724.           END
  1725.      
  1726.           FUNCTION Pressed$(Button%)
  1727.                IF Button% THEN
  1728.                     Pressed$ = "Pressed"
  1729.                ELSE
  1730.                     Pressed$ = "Released"
  1731.                END IF
  1732.           END FUNCTION
  1733.      
  1734.      Again, the MouseGetStatus routine returns information about what is
  1735.      going on with the mouse -right now-. If your program was busy doing
  1736.      other things (e.g. "polling" the mouse infrequently) and the user
  1737.      clicked the left button quickly, you might not detect it. As you might
  1738.      have expected, there are contingencies for this situation as well.
  1739.      
  1740.      Let's take another situation. Say you are only interested in the mouse
  1741.      pointer position when a button is pressed or released, and you don't
  1742.      want to worry about polling the mouse frequently enough. The routines
  1743.      MousePressInfo and MouseReleaseInfo return the row and column position
  1744.      of the mouse pointer when the specified mouse button was *last*
  1745.      pressed or released, respectively. For example:
  1746.      
  1747.      
  1748.      The QBNews                                                     Page 28
  1749.      Volume  2, Number  3                                September 15, 1991
  1750.  
  1751.           Button% = 0              '0=left, 1=right and 2=center
  1752.           IF MousePressInfo%(Button%, Row%, Column%) THEN
  1753.                'Returns number of times the specified button was pressed
  1754.                ' since the last check
  1755.                PRINT "Left button last pressed at"; Row%; ","; Column%
  1756.           END IF
  1757.      
  1758.           Button% = 1                   'Right button
  1759.           IF MouseReleaseInfo%(Button%, Row%, Column%) THEN
  1760.                'Returns number of times the specified button was released
  1761.                ' since the last check
  1762.                PRINT "Right button last released at"; Row%; ","; Column%
  1763.           END IF
  1764.      
  1765.      Along the same lines, you can also determine the net physical distance
  1766.      that the mouse has moved. The routine MouseMovement returns the number
  1767.      of "Mickeys" (approximately 1/200th of an inch) the mouse has moved
  1768.      since the last time this routine was called. For example:
  1769.      
  1770.           CLS
  1771.           PRINT "Left button display distance and right button ends
  1772.      program"
  1773.           CALL MouseMovement(Rows%, Columns%)     'To zero the counter
  1774.           DO
  1775.                CALL MouseStatus(Lb%, Rb%, Cb%, Row%, Column%)
  1776.                IF Lb% THEN
  1777.                     CALL MouseMovement(Rows%, Columns%)
  1778.                     LOCATE 3,1
  1779.                     PRINT "  Mickeys moved (vertically):"; Rows%
  1780.                     PRINT "Mickeys moved (horizontally):"; Columns%
  1781.                     CALL MouseWaitForRelease
  1782.                END IF
  1783.           LOOP UNTIL Rb%
  1784.      
  1785.      If you were paying attention, then you noticed that I snuck a new
  1786.      routine into the above listing. MouseWaitForRelease suspends the
  1787.      program until all mouse buttons have been released. It's very handy
  1788.      for mouse-specific program "flow control."
  1789.      
  1790.      
  1791.      ----------------------------------------------------------------------
  1792.                        Writing Mouse Event-driven Programs
  1793.      ----------------------------------------------------------------------
  1794.      
  1795.      The various methods of gathering mouse-related information we've
  1796.      discussed so far require you to poll the mouse driver periodically to
  1797.      see if a specific event has occurred (mouse click, etc.). Wouldn't it
  1798.      be much easier if the mouse driver could simply interrupt your program
  1799.      anytime it needs attention and then transfer control to a specified
  1800.      subroutine? This way, you wouldn't have to be concerned about polling
  1801.      the mouse periodically.
  1802.      
  1803.      In QuickBASIC 4.00a (distributed with BASIC 6.x), 4.00b (bug fix
  1804.      update to 4.00 and 4.00a), 4.50, and QBX (distributed with PDS) there
  1805.      
  1806.      The QBNews                                                     Page 29
  1807.      Volume  2, Number  3                                September 15, 1991
  1808.  
  1809.      exists a little-known and seldom-used statement called "ON UEVENT
  1810.      GOSUB LineLabel." It's much like other BASIC event processing
  1811.      statements like "ON TIMER", "ON KEY", "ON COM", etc. in that it allows
  1812.      program control to be transferred to a subroutine when a special event
  1813.      occurs. A "UEVENT" or "User Event" is programmer-definable. In this
  1814.      case, we establish a "hook" into the mouse driver and when a specified
  1815.      type of mouse event occurs, the mouse driver notifies our assembly
  1816.      routine, which in turn notifies BASIC. The next time the BASIC runtime
  1817.      code processes events (at each line label or after each statement,
  1818.      depending on the use of the /V and /W compiler switches) control is
  1819.      transferred to the desired subroutine. Neat, huh?
  1820.      
  1821.      The routine MouseSetEvent is used to define the type of event(s) that
  1822.      you are interested in. These events can include any combination of a
  1823.      specific button being pressed or released, or any mouse movement at
  1824.      all. Once an event has occurred and program control has been
  1825.      transferred to your BASIC subroutine, the MouseGetEventInfo routine is
  1826.      used to determine exactly what type event occurred and where the mouse
  1827.      pointer was located at the time. When you wish to turn off the mouse
  1828.      event trap, call the MouseCancelEvent routine. Here's how it's done:
  1829.      
  1830.           REM $INCLUDE: 'MOUSE.BI'
  1831.      
  1832.           Buttons% = MouseReset%
  1833.      
  1834.           IF Buttons% = 0 THEN
  1835.                PRINT "Mouse not present."
  1836.                END
  1837.           END IF
  1838.      
  1839.           CALL MousePointerOn
  1840.      
  1841.           'First, define the types of event(s) you want to trap. This is
  1842.           ' done by passing value in EventMask%. Just pick the events you
  1843.           ' wish to trap, add up their values and pass it to the
  1844.           ' MouseSetEvent routine.
  1845.      
  1846.           '    1 = Any mouse movement
  1847.           '    2 = Left button pressed
  1848.           '    4 = Left button released
  1849.           '    8 = Right button pressed
  1850.           '    16 = Right button released
  1851.           '    32 = Center button pressed
  1852.           '    64 = Center button released
  1853.      
  1854.           'Let's trap a left or right button release. That's 4 + 16 = 20.
  1855.      
  1856.           EventMask% = 4 + 16
  1857.           CALL MouseSetEvent(EventMask%)
  1858.      
  1859.           'Next, tell BASIC to watch for the event and to transfer program
  1860.           ' control to the at the MouseEvent line label when an event
  1861.           ' occurs.
  1862.      
  1863.      
  1864.      The QBNews                                                     Page 30
  1865.      Volume  2, Number  3                                September 15, 1991
  1866.  
  1867.           ON UEVENT GOSUB MouseEvent    'Watch for the event
  1868.           UEVENT ON                     'Enable UEVENT checking
  1869.      
  1870.           'Let's set up an idle loop to demonstrate the event processing
  1871.      
  1872.           CLS
  1873.           PRINT "Each time you release the left or right mouse button, our"
  1874.           PRINT "event-handling code will be called. When you've seen"
  1875.           PRINT "enough, press any key to end this program."
  1876.           PRINT
  1877.      
  1878.           DO
  1879.           LOOP UNTIL LEN(INKEY$)   'Loop until a key press is detected
  1880.      
  1881.           'To turn off event checking
  1882.           UEVENT OFF
  1883.           CALL MouseCancelEvent
  1884.      
  1885.           CALL MousePointerOff
  1886.           END
  1887.           
  1888.      MouseEvent:                   'Transfer control here on a mouse event
  1889.           CALL MouseGetEventInfo(EventType%, Lb%, Rb%, Cb%, Row%, Column%)
  1890.           PRINT "Mouse event occurred: - ";
  1891.      
  1892.           '"AND" EventType% with the value of the event being checked
  1893.      
  1894.           IF EventType% AND 4 THEN
  1895.                PRINT "Left Button was released."
  1896.           END IF
  1897.           IF EventType% AND 16 THEN
  1898.                PRINT "Right Button was released."
  1899.           END IF
  1900.           PRINT "Mouse location:"; Row%; ","; Column% RETURN
  1901.      
  1902.      Using BASIC's event-trapping services generates larger executable
  1903.      programs because of the additional event-checking code required at
  1904.      runtime. However, there are ways to reduce this added overhead to a
  1905.      minimum.
  1906.      
  1907.      1. Use "UEVENT ON" and "UEVENT OFF" around code in which you wish to
  1908.      have event-trapping active. Putting a "UEVENT ON" at the top of your
  1909.      program without a following UEVENT OFF will cause BASIC to generate
  1910.      event-checking code for your entire program. If you selectively use
  1911.      UEVENT ON and UEVENT OFF (e.g. around your input or selection code), -
  1912.      you- can keep the overhead to a minimum.
  1913.      
  1914.      2. Programs that use BASIC event-traps must be compiled with the /V or
  1915.      /W switches. /V directs BASIC to check for an events after *every
  1916.      BASIC statement* (within the UEVENT ON and UEVENT OFF boundaries, that
  1917.      is).  /W directs BASIC to check for events only when crossing line
  1918.      labels.  The latter will obviously generate less overhead, but
  1919.      requires you to be more careful with your placement of line labels -
  1920.      no line labels, no event-checking.
  1921.      
  1922.      The QBNews                                                     Page 31
  1923.      Volume  2, Number  3                                September 15, 1991
  1924.  
  1925.      
  1926.      
  1927.      ----------------------------------------------------------------------
  1928.                            Fine-tuning the Mouse
  1929.      ----------------------------------------------------------------------
  1930.      
  1931.      In addition to controlling the mouse's visual characteristics, you can
  1932.      control its physical characteristics as well. This includes its
  1933.      sensitivity and double-speed threshold.
  1934.      
  1935.      "Sensitivity" is the ratio between the distance the mouse is
  1936.      physically moved (in Mickeys) and the distance the mouse pointer
  1937.      actually moves (in pixels) on the screen. The default ratios are one
  1938.      Mickey per pixel horizontally and two Mickeys per pixel vertically.
  1939.      The higher the ratio, the more physical mouse movement is required to
  1940.      move the mouse pointer. The routine MouseSetRatio is used to adjust
  1941.      the mouse sensitivity. For example:
  1942.      
  1943.           VertRatio% = 2
  1944.           HorizRatio% = 1
  1945.           CALL MouseSetRatio(VertRatio%, HorizRatio%)
  1946.      
  1947.      The "double-speed ratio" is the physical speed (in Mickeys per second)
  1948.      that the mouse must travel before the mouse pointer shifts into
  1949.      overdrive and moves across the screen twice as fast. The default is 64
  1950.      Mickeys per second (about 1/3 of an inch per second). The routine
  1951.      MouseSetDblSpd is used to adjust the double-speed ratio. For example:
  1952.      
  1953.           MickeysPerSecond% = 200            'Set to one inch per second
  1954.           CALL MouseSetDblSpd(MickeysPerSecond%)
  1955.      
  1956.      Using the MouseGetSensitivity routine, you can also retrieve the
  1957.      current sensitivity settings from the mouse driver. For example:
  1958.      
  1959.           CALL MouseGetSensitivity(VertRatio%, HorizRatio%, _
  1960.                                    MickeysPerSecond%)
  1961.      
  1962.      ----------------------------------------------------------------------
  1963.                           Miscellaneous Mouse Routines
  1964.      ----------------------------------------------------------------------
  1965.      
  1966.      The following list of "miscellaneous" mouse routines can be useful
  1967.      from time-to-time. They allow you to restrict the mouse movement,
  1968.      position the mouse pointer through software, save and restore the
  1969.      mouse "state," allow you to define the coordinate system the mouse
  1970.      pointer location is returned in (character-based row/column format or
  1971.      X/Y pixel-based format), and more.
  1972.      
  1973.      MouseSetWindow - Used to define a rectangular area on the screen in
  1974.      which the mouse pointer movement will be restricted. Once called, the
  1975.      user will not be able to move the mouse pointer out of the defined
  1976.      area. To disable a previously defined window, call this routine again
  1977.      with the dimensions of the entire screen. For example:
  1978.      
  1979.      
  1980.      The QBNews                                                     Page 32
  1981.      Volume  2, Number  3                                September 15, 1991
  1982.  
  1983.           TopRow% = 6
  1984.           LeftColumn% = 10
  1985.           BottomRow% = 20
  1986.           RightColumn% = 70
  1987.           CALL MouseSetWindow(TopRow%, LeftColumn%, BottomRow%,_
  1988.                               RightColumn%)
  1989.      
  1990.           'To turn the window off (assuming an 80 X 25 screen)
  1991.           TopRow% = 1
  1992.           LeftColumn% = 1
  1993.           BottomRow% = 25
  1994.           RightColumn% = 80
  1995.           CALL MouseSetWindow(TopRow%, LeftColumn%, BottomRow%,_
  1996.                               RightColumn%)
  1997.      
  1998.      MouseSetExclusionArea - When the mouse pointer is moved into the
  1999.      rectangular area of the screen defined by this routine, it is made
  2000.      invisible. Use the MousePointerOn routine to make the pointer visible
  2001.      again. For example:
  2002.      
  2003.           TopRow% = 6
  2004.           LeftColumn% = 10
  2005.           BottomRow% = 20
  2006.           RightColumn% = 70
  2007.           CALL MouseSetExclusionArea(TopRow%, LeftColumn%, BottomRow%,_
  2008.                                      RightColumn%)
  2009.           
  2010.           'To turn the mouse pointer back on:
  2011.           CALL MousePointerOn
  2012.      
  2013.      MouseSetPointer - Used to position the mouse pointer on the screen.
  2014.      For example:
  2015.      
  2016.           Row% = 5
  2017.           Column% = 20
  2018.           CALL MouseSetPointer(Row%, Column%)
  2019.      
  2020.      MousePixelsOn - Used to change the default coordinate system used by
  2021.      the mouse routines discussed in this article from character-based
  2022.      row/column coordinates (which is the default) to X/Y pixel-based
  2023.      coordinates. This routine defines the coordinate system used for both
  2024.      input -and- output. This routine is provided because row/column
  2025.      coordinates are generally preferred in text video modes and X/Y pixel-
  2026.      based coordinates are generally preferred in graphics video modes. Use
  2027.      the MousePixelsOff routine to switch back to row/column coordinates.
  2028.      For example:
  2029.      
  2030.           CALL MousePixelsOn       'Switch to X/Y pixel-based coordinates
  2031.           CALL MousePixelsOff      'Switch back to row/column format
  2032.      
  2033.      MouseSaveState - Saves the current mouse "state." This includes the
  2034.      current position, visibility, shape, and other mouse pointer
  2035.      characteristics. You could use this routine just prior to a SHELL so
  2036.      the original state could be easily restored on returning to your
  2037.      
  2038.      The QBNews                                                     Page 33
  2039.      Volume  2, Number  3                                September 15, 1991
  2040.  
  2041.      program. This routine automatically allocates the required amount of
  2042.      memory from DOS and releases it on the call the MouseRestoreState. The
  2043.      MouseSaveState routine can be declared as a SUB or an integer
  2044.      FUNCTION.  If declared as a FUNCTION, it returns -1 (TRUE) if the
  2045.      state was successfully saved and 0 (FALSE) if insufficient memory was
  2046.      available.  We have it DECLAREd as a FUNCTION in the MOUSE.BI file
  2047.      included with this article. For example:
  2048.           
  2049.           Success% = MouseSaveState%
  2050.           IF Success% THEN
  2051.                PRINT "Mouse state saved!"
  2052.                CALL MouseRestoreState
  2053.           ELSE
  2054.                PRINT "Insufficient memory to save mouse state!"
  2055.           END IF
  2056.      
  2057.      MouseSetPage - Sets the video display page on which the mouse pointer
  2058.      will be visible. Normally, the mouse driver is aware of changes in
  2059.      active video pages, so it is not usually necessary to call this
  2060.      routine. However, if you are using non-standard methods of switching
  2061.      video pages, this is how you can tell the mouse driver what you are up
  2062.      to. The function MouseGetPage% is used to return what the mouse driver
  2063.      believes to be the active video page number current in use. For
  2064.      example:
  2065.      
  2066.           SCREEN ,,1,1                  'Switch BASIC into page 1
  2067.           PageNum% = 1
  2068.           CALL MouseSetPage(PageNum%)   'Tell the mouse driver about it
  2069.           PRINT "Mouse pointer on page";
  2070.           PRINT MouseGetPage%
  2071.      
  2072.      MouseExit - Releases all memory allocated by these mouse routines and
  2073.      unhooks the "user mouse service" function required by MouseSetEvent.
  2074.      You need to call this routine ONLY if:
  2075.      
  2076.           You are about to CHAIN to another program and the MOUSE.OBJ is
  2077.           *not* in a BASIC 6.X or PDS extended runtime library, or
  2078.      
  2079.           You are about to SHELL and the MOUSE.OBJ file -is- in an extended
  2080.           runtime library.
  2081.      
  2082.      If your BASIC program terminates normally (with an "END" or "SYSTEM"
  2083.      statement), there is no need to call MouseExit at all.
  2084.      
  2085.      ----------------------------------------------------------------------
  2086.                              Special Considerations
  2087.      ----------------------------------------------------------------------
  2088.      
  2089.      If your BASIC program terminates via the "END" or "SYSTEM" statements,
  2090.      we automatically release memory that we've allocated and "unhook" the
  2091.      mouse driver. Using a service called "B_OnExit", the BASIC runtime
  2092.      code calls our internal clean-up code just prior to returning system
  2093.      control back to DOS.
  2094.      
  2095.      
  2096.      The QBNews                                                     Page 34
  2097.      Volume  2, Number  3                                September 15, 1991
  2098.  
  2099.      However, if you CHAIN to another program, the CHAINing program
  2100.      actually terminates but BASIC does not process the B_OnExit chain
  2101.      allowing us to clean up our mess. Essentially this means that your
  2102.      system can potentially lock up if you've used the MouseSetEvent or the
  2103.      MouseSaveState routines. See the entry for MouseExit above for more
  2104.      information.
  2105.      
  2106.      ----------------------------------------------------------------------
  2107.                                Using the Routines
  2108.      ----------------------------------------------------------------------
  2109.      
  2110.      Now since we've gotten all of that technical stuff out of the way,
  2111.      you're probably about ready to actually being using the routines.
  2112.      Included with this article, you find a file called MOUSE.OBJ. It is an
  2113.      object file which contains all of the mouse routines described here.
  2114.      You can put this .OBJ file in a QuickLibrary, a LINK library, or LINK
  2115.      it directly to your compiled programs. It's completely compatible with
  2116.      QuickBASIC versions 4.00a - 4.50, BASIC 6.X, and PDS 7.x.
  2117.      
  2118.      Distributed with this article is a batch program called BLDLIB.BAT.
  2119.      It will automatically build a QuickLibrary (.QLB) and LINK library
  2120.      (.LIB) for your compiler version. Type "BLDLIB" at the DOS prompt for
  2121.      instructions. However, if you prefer to know about the "hows" and
  2122.      "whys" and would like to build your libraries manually, read on.
  2123.      
  2124.      To build a QuickLibrary so you can call the mouse routines from with
  2125.      the QB(x) development environments, issue the following command at the
  2126.      DOS prompt:
  2127.      
  2128.           LINK /Q MOUSE, MOUSE.QLB, NUL, BQLB45;
  2129.      
  2130.      The above LINK command will generate a QuickLibrary for QuickBASIC
  2131.      version 4.50. Change the QuickLibrary support module name (listed
  2132.      above as BQLB45) to BQLB41 or QBXQLB to build a QuickLibrary for
  2133.      QuickBASIC 4.00x and QBX, respectively.
  2134.      
  2135.      To build a LINK library or to add the MOUSE.OBJ file to an existing
  2136.      LINK library, type the following at the DOS prompt:
  2137.      
  2138.           LIB MOUSE +MOUSE.OBJ ;
  2139.      
  2140.      The above LIB command will create a library called MOUSE.LIB. If you
  2141.      wish to add the mouse routines to an existing library, substitute that
  2142.      library name for the first occurrence of MOUSE above.
  2143.      
  2144.      To load the example program into the environment, type the following
  2145.      at the DOS prompt:
  2146.      
  2147.           QB MOUSETST /L MOUSE               For QB 4.X
  2148.           QBX MOUSETST /L MOUSE              For QBX
  2149.      
  2150.      The above commands load the example program MOUSETST.BAS into the
  2151.      environment along with the MOUSE.QLB QuickLibrary we created earlier.
  2152.      
  2153.      
  2154.      The QBNews                                                     Page 35
  2155.      Volume  2, Number  3                                September 15, 1991
  2156.  
  2157.      To compile and LINK your program, you can select "Make an EXE" from
  2158.      the QB(x) environments (assuming you have constructed matching .QLB
  2159.      and .LIB files per the above instructions), or you can manually
  2160.      compile and link from the DOS prompt. The latter is the preferred
  2161.      method because it gives you more control over compiler switches used.
  2162.      For example:
  2163.      
  2164.           BC MOUSETST /O/W ;
  2165.           LINK /EX MOUSETST + MOUSE ;
  2166.      
  2167.      Or, if you've placed MOUSE.OBJ in a link library, you can do this:
  2168.      
  2169.           LINK /EX MOUSETST,,NUL, LibraryName ;
  2170.      
  2171.      [EDITOR'S NOTE]
  2172.      All files for this article can be found in the file MOUSE.ZIP.
  2173.      
  2174.      *********************************************************************
  2175.      Tony Elliott has been programming in BASIC and assembly langauge for
  2176.      over ten years. He worked for MicroHelp, Inc. for almost four years as
  2177.      their Technical Support Manager and was directly involved in the
  2178.      development of many of their QuickBASIC/PDS products. He has spoken at
  2179.      a number of BASIC Symposiums conducted around the country between 1989
  2180.      - 1991, and was a speaker at the August, 1991 Microsoft Developers
  2181.      Tools Forum held in Seattle. He has written articles for BASICPro
  2182.      Magazine and MicroHelp's "BASIC Users Group" Newsletter. He is now
  2183.      Vice President of EllTech Development, Inc. which recently developed
  2184.      and is currently marketing a network-ready replacement for PDS
  2185.      ISAM called "E-Tree Plus" (see the ad included in this issue).
  2186.      **********************************************************************
  2187.      
  2188.  
  2189.  
  2190.  
  2191.  
  2192.  
  2193.  
  2194.  
  2195.  
  2196.  
  2197.  
  2198.  
  2199.  
  2200.  
  2201.  
  2202.  
  2203.  
  2204.  
  2205.  
  2206.  
  2207.  
  2208.  
  2209.  
  2210.  
  2211.      The QBNews                                                     Page 36
  2212.      Volume  2, Number  3                                September 15, 1991
  2213.  
  2214.  
  2215.  
  2216.      ----------------------------------------------------------------------
  2217.                             A d v e r t i s e m e n t
  2218.      ----------------------------------------------------------------------
  2219.  
  2220.      E-Tree Plus By EllTech Development, Inc.
  2221.      
  2222.         Finally, a network-ready B+Tree file indexing library designed
  2223.      specifically for BASIC programmers that's FAST and EASY TO USE!  If
  2224.      you are already familiar with Novell's Btrieve or Microsoft PDS ISAM,
  2225.      you can be up and running in 15 minutes ..  no kidding! For those of
  2226.      you new to network database programming, it may take a little longer.
  2227.         For those of you currently using PDS ISAM, this product is an ideal
  2228.      network solution for you. Our function syntax is very similar, we
  2229.      provide a conversion utility for your existing databases, and we even
  2230.      have a section in our manual that will take you step-by-step through
  2231.      converting your existing program source code.
  2232.      
  2233.                                      Easy to Use
  2234.         Automatically detects the presence of Novell or NETBIOS compatible
  2235.      networks and handles file and recording locking for you. However, you
  2236.      still have full control over how the locks are implemented, timeouts,
  2237.      etc., should you have a need to override our default actions.
  2238.         11 high-level functions allow you to: create E-Tree database files;
  2239.      add and delete indexes; change the active index; insert, update,
  2240.      retrieve and delete records; locate a specific record or groups of
  2241.      records quickly and easily. In addition, over 40 low-level functions
  2242.      are provided to give you complete control over almost every aspect of
  2243.      the database manipulation.
  2244.         Convert existing PDS ISAM applications to E-Tree Plus with minimal
  2245.      effort. E-Tree Plus's functions use syntax and naming conventions
  2246.      similar to PDS ISAM. In many cases, existing code can be used with
  2247.      only minor modifications.
  2248.         Simplified database maintenance. We include a utility ("EUTIL.EXE")
  2249.      you can use to create databases, modify an existing database's
  2250.      structure (add or delete a field), import and export ASCII data,
  2251.      convert Btrieve dBase compatible files, and PDS ISAM file to E-Tree,
  2252.      and more.
  2253.         We automatically determine the optimum file page size, record
  2254.      length, etc., for you. There are no complicated formulas and no
  2255.      cryptic function numbers to remember.
  2256.         Includes a fully indexed, reference oriented, 200+ page manual.  It
  2257.      includes example programs, a database/network tutorial, complete specs
  2258.      on the E-Tree Plus database format, and even a "Quick Start" section
  2259.      for the seasoned database programmer.
  2260.         The product is provided in LINKable libraries and .OBJect files.
  2261.      No TSR programs to load or to get in the way.
  2262.      
  2263.                                    Fast and Flexible
  2264.         Written using a combination of BASIC and assembly language for the
  2265.      perfect mixture of versatility and speed.
  2266.         All BASIC data types are supported, and then some.
  2267.         Flexible indexing. You can add or delete indexes at any time. Up to
  2268.      1023 indexes (more than you'll ever need) can be defined at one time.
  2269.      Indexed "keys" can be defined as unique, duplicates allowed,
  2270.      
  2271.      The QBNews                                                     Page 37
  2272.      Volume  2, Number  3                                September 15, 1991
  2273.  
  2274.      modifiable, non-modifiable, segmented (comprised of pieces of one or
  2275.      more fields), ascending, descending, and auto-incrementing (ideal for
  2276.      invoice or order numbers).
  2277.         File sizes up to 4 billion bytes. The maximum number of records per
  2278.      file is limited only by available disk space.
  2279.         Supports fixed-length records, variable-length records, and
  2280.      combinations of both.
  2281.         Efficiently uses system resources. Automatically detects and uses
  2282.      LIM Expanded Memory for file I/O buffers.
  2283.      
  2284.                                     Reliable
  2285.         Built-in data integrity checking. Using 32-bit CRC, the integrity
  2286.      of your data is checked with near 100% accuracy. If a problem should
  2287.      develop, the chances are very good that all of your data can be
  2288.      recovered or reconstructed.
  2289.         Stores data records, indexes, and its "data dictionary" in the same
  2290.      file. This means that there are no "index" files or "definition" files
  2291.      for your customers to lose track of, and only one DOS file handle is
  2292.      required per open database.
  2293.      
  2294.                                      Affordable
  2295.      Distribute E-Tree Plus applications and the EUTIL.EXE database
  2296.      maintenance utility royalty-free.
  2297.      
  2298.      One version supports QuickBASIC 4.x, BASCOM 6.x, Microsoft PDS 7.x,
  2299.      and PowerBASIC 2.x.
  2300.      
  2301.      Includes structured, fully commented BASIC and assembly language
  2302.      source code at no additional charge.
  2303.      
  2304.      Price includes free, full-time technical support. We even provide 24
  2305.      hour support through our BBS. Customers can download maintenance
  2306.      releases of E-Tree Plus free of charge! Just ask our competitors if
  2307.      they can offer the same!
  2308.      
  2309.         Introductory Offer: $199.00 until 11/30/91
  2310.      Shipping and handling: $  6.00 (U.S. addresses)
  2311.      
  2312.      Orders and Product Info:    (800) 553-1327 (U.S. and Canada)
  2313.            Technical Support:    (404) 928-8960
  2314.                          BBS:    (404) 928-7111 (HST)
  2315.      E-Tree Plus will be available for shipping on September 15, 1991.
  2316.      Prices are listed in US Dollars. All trademarks belong to their
  2317.      respective owners.
  2318.                               EllTech Development, Inc.
  2319.                         4374 Shallowford Industrial Parkway
  2320.                                 Marietta, GA 30066
  2321.      
  2322.  
  2323.  
  2324.  
  2325.  
  2326.  
  2327.  
  2328.      The QBNews                                                     Page 38
  2329.      Volume  2, Number  3                                September 15, 1991
  2330.  
  2331.  
  2332.  
  2333.      ----------------------------------------------------------------------
  2334.                                A l g o r i t h m s
  2335.      ----------------------------------------------------------------------
  2336.  
  2337.      Cardans's Method for Solving Cubes by Richard Jones
  2338.      
  2339.      One of the most common tasks in mathematics and its applications is
  2340.      that of root-finding. That is, we have some function, f(x), and we
  2341.      want to find the value(s) of x for which f(x) = 0. It is
  2342.      disillusioning to note that all centuries upon centuries of
  2343.      mathematics can say about the general case, including monsters like
  2344.      
  2345.           a * x^2 * exp(-b * x) - sin(c * x) = 0,
  2346.      
  2347.      is that there may be one, several, or an infinite number of roots, or
  2348.      maybe none at all, which really tells us a lot. Fortunately, a lot
  2349.      more is known about a smaller and more common category of functions,
  2350.      polynomials of degree n, of the form
  2351.      
  2352.          a(0) + a(1) * x + ... + a(n) * x ^ n = 0, n >= 0.
  2353.      
  2354.      Back in high school, we all learned about the n = 1, or linear, and
  2355.      the n = 2, or quadratic, cases of polynomials. We found that the
  2356.      linear equation a*x + b = 0 has exactly one root given by x = -b/a and
  2357.      that the two roots of a quadratic a*x^2 + b*x + c = 0 are given by the
  2358.      reknown quadratic formula:
  2359.      
  2360.                x = (-b +- (b^2 - 4*a*c)^(1/2)) / 2a.  (3)
  2361.      
  2362.      We then noticed what appeared to be a hint of a relation between the
  2363.      degree of a polynomial and the number of roots. After high school, we
  2364.      went off to college and, depending on what field of study we chose,
  2365.      began to go down the path of one of the various branches of higher
  2366.      mathematics and, along the way, perhaps learned some theorems about
  2367.      polynomial equations and the nature of the roots. It's interesting to
  2368.      note that while a lot may have been said about the nature of the
  2369.      roots, nothing was really said about how to find them for the case of
  2370.      n >= 3. It turns out that analytic solutions for polynomials up to the
  2371.      fourth degree are known (equations of higher degree cannot be solved
  2372.      exactly by any finite number of arithmetic operations - you have to
  2373.      resort to approximate numerical methods).  The solutions to cubic and
  2374.      quartic equations are quite involved, though, which is one of the
  2375.      reasons nobody bothers with them. This, at long last, brings us to the
  2376.      subject of this article: a QuickBASIC implementation of the solution
  2377.      to the cubic equation known as the Tartaglia-Cardan solution or simply
  2378.      Cardan's method.
  2379.      
  2380.      
  2381.      Roots of Polynomials
  2382.      
  2383.      A little background theory on polynomial roots will helpful in
  2384.      understanding how our method works. A polynomial of degree n, pn(x),
  2385.      will have exactly n roots provided we expand the range of an
  2386.      acceptable solution to include the set of complex numbers. While the
  2387.      
  2388.      The QBNews                                                     Page 39
  2389.      Volume  2, Number  3                                September 15, 1991
  2390.  
  2391.      linear equation's root, -b/a, is always real, what happens when the
  2392.      term under the square root in equation (3) is negative? The notion of
  2393.      a complex number was actually invented to handle this case. Notice how
  2394.      complex things become when we go from n = 1 to just n = 2; we have to
  2395.      "invent" a new class of number. You might think that more numbers
  2396.      would have to be invented to handle the n = 3 case, but it turns out
  2397.      that the set of complex numbers will suffice for any n. Unlike the set
  2398.      of reals, this set is closed, which means that any operation performed
  2399.      on any of the members will always produce another member of the set.
  2400.      
  2401.      Complex roots of polynomials with real coefficients (this doesn't
  2402.      apply if the coefficients themselves are complex) will occur in
  2403.      conjugate pairs which means that there will always be an even number
  2404.      of such roots. Therefore, an equation of odd degree must have at least
  2405.      one real root. This can be easily seen by considering the values of
  2406.      pn(x) and pn(-x) as x grows large and the high order term dominates.
  2407.      If n is odd, pn(x) and pn(-x) must be of opposite sign and, since
  2408.      polynomial functions are nice and continuous, the curve must then
  2409.      cross the x-axis at least once. Knowing this, we can say that a cubic
  2410.      equation must have either three real roots, or one real and a pair of
  2411.      complex conjugate roots.
  2412.      
  2413.      
  2414.      Cardan's Method.
  2415.      
  2416.      Unlike the quadratic, it's impractical to write the solution to the
  2417.      cubic as a single formula - it's far better presented as a series of
  2418.      steps which are somewhat involved, so hang on. The first step is to
  2419.      divide through by the coefficient of the cubic term and write the
  2420.      equation in the so-called standard form:
  2421.      
  2422.           x^3 + a*x^2 + b*x + c = 0.         4)
  2423.      
  2424.      There is no direct solution for the equation in this form, however,
  2425.      and so we must make a change of variable to eliminate the quadratic
  2426.      term. The substitution x = u - a/3 will accomplish this and we will
  2427.      have a "reduced" cubic of the following form:
  2428.      
  2429.           u^3 + p*u + q = 0,                 5)
  2430.      
  2431.      where the new coefficients, p and q are given in terms of those of 4)
  2432.      by
  2433.      
  2434.           p = (3b - a^2) / 3,
  2435.      
  2436.           q = (2a^2 - 9ab + 27c) / 27.
  2437.      
  2438.      Like a quadratic, a cubic equation has a discriminant, D, whose sign
  2439.      tells us some things about the nature of our roots. The discriminant
  2440.      of the cubic in the form of 5) is given by
  2441.      
  2442.           D = q^2 / 4 + p^3 / 27.
  2443.      
  2444.      There are three distinct cases depending on the sign of D:
  2445.      
  2446.      The QBNews                                                     Page 40
  2447.      Volume  2, Number  3                                September 15, 1991
  2448.  
  2449.      
  2450.           D > 0   -> one real root and a pair of complex conjugates.
  2451.           D = 0   -> degenerate case - 3 real roots of which at least 2 are
  2452.                      equal.
  2453.           D < 0   -> 3 real and distinct roots.
  2454.      
  2455.      Now calculate the two values A and B given by the following:
  2456.      
  2457.           A = (-q/2 + D^(1/2))^(1/3), and
  2458.      
  2459.           B = (-q/2 - D^(1/2))^(1/3).
  2460.      
  2461.      And, finally, the 3 roots of 5), u1, u2 and u3, are then given by
  2462.      
  2463.           u1 = A + B,                                  6)
  2464.      
  2465.           u2 = -u1 / 2 + i(A - B) * 3^(1/2) / 2, and   7)
  2466.      
  2467.           u3 = -u1 / 2 - i(A - B) * 3^(1/2) / 2,       8)
  2468.      
  2469.      where i represents the famous (or infamous) square root of -1.
  2470.      
  2471.      The three roots of the original equation, x1, x2 and x3, are given by
  2472.      the substitution relation above, x = u - a / 3.
  2473.      
  2474.      
  2475.      Note that if D > 0, x1 is real and x2 & x3 are complex conjugates.  If
  2476.      D = 0, then A = B and the imaginary terms in 7) and 8) are zero and u2
  2477.      = u3 and hence x2 = x3. Also, our substitution may produce p = q = 0,
  2478.      in which u1 = u2 = u3 = 0, and our 3 roots will all be equal and given
  2479.      by x1 = x2 = x3 = -a / 3. Such cases are known as multiple roots - we
  2480.      still say the equation has 3 roots but it just happens that two or
  2481.      more are equal to each other.
  2482.      
  2483.      Now for the hard part, the D < 0 case. Notice that if D < 0, the
  2484.      calculation of A and B requires us to extract the cube roots of two
  2485.      complex numbers. Twenty years ago, this would be a time for despair,
  2486.      but now that we all have enormous amounts of computing power sitting
  2487.      on our desks and handy-dandy high-level language compilers like MS
  2488.      QuickBASIC with a wealth of built-in math functions to utilize that
  2489.      power, it's a piece of cake. A complex number, z, which is usually
  2490.      written in rectangular form as some x + i*y, also has a so-called
  2491.      polar form, z = r * exp(i*R), where r, known as the magnitude or
  2492.      modulus, and R, known as the argument or simply the angle, are given
  2493.      by a simple pythagorean relation:
  2494.      
  2495.           r = (x^2 + y^2)^(1/2), and
  2496.           R = arctan(y / x).
  2497.      
  2498.      In polar form, exponentiation is simple. We raise the modulus (always
  2499.      a positive real) to the desired power and simply multiply the angle by
  2500.      this power. So, to take the cube root of a complex number, we put it
  2501.      in polar form, take the cube root of the modulus, and divide the angle
  2502.      by three. Trigonometric functions then get us back to rectangular
  2503.      
  2504.      The QBNews                                                     Page 41
  2505.      Volume  2, Number  3                                September 15, 1991
  2506.  
  2507.      form. Since in this case A and B are conjugates, things can be
  2508.      simplified somewhat and we can write our u's as follows:
  2509.      
  2510.           u1 = 2r * cos(R).                            9)
  2511.           u2 = r * (3^(1/2) * sin(R) - cos(R)), and    10)
  2512.           u3 = -r * (3^(1/2) * sin(R) + cos(R)),       11)
  2513.      
  2514.      where r is given by
  2515.      
  2516.           r = (q^2 / 4 - D)^(1/6),
  2517.      
  2518.      and the angle R is given by
  2519.      
  2520.           R = arctan( -2 * D^(1/2) / q ) / 3.
  2521.      
  2522.      It's rather interesting that, after all this complex arithmetic, the
  2523.      results are purely real, and that the D < 0 case requires
  2524.      transcendental operations, elementary trigonometric ones in our case.
  2525.      (Transcendentals are called such because they "transcend" the realm of
  2526.      ordinary arithmetic - the only kind we know how to do.  They cannot be
  2527.      calculated exactly by any finite number of additions, multiplications,
  2528.      or exponentiations.) It's actually cheating a bit to say that we have
  2529.      an analytic solution for the D < 0 case because of the
  2530.      transcendentals. We can write a formula down only because we've
  2531.      invented a special notation for the trig functions, namely "sin",
  2532.      "cos", and "arctan", which can only be approximated. (Think about it.
  2533.      Using only a pad and pencil, try to calculate the sine of a 37 degree
  2534.      angle. If you remember the power series and don't mind doing long
  2535.      division with 10 - 30 digit numbers, you might get it to 5 places in
  2536.      an hour or two. Personally, I'd get a protractor and a carpenter's
  2537.      square and "experimentally" measure it and might manage to get two or
  2538.      three places.)
  2539.      
  2540.      
  2541.      
  2542.      Cardan's Method in QuickBASIC
  2543.      
  2544.      Whew! Now that we've got Cardan's method down pat, it's easy to write
  2545.      a QB program to carry out the steps. The listing is of the program
  2546.      which I've written to implement Cardan's method. It consists of a
  2547.      subroutine, CUBERT, which does the work, and a simple driver which
  2548.      gets the coefficients of equation from the user, prints out the roots,
  2549.      and prints out the value of the function at one of the supposed roots
  2550.      that the subroutine returns as a check. I've also included a function,
  2551.      POLY, which evaluates polynomials the "right" way. I'll say more about
  2552.      this later. The driver is fairly simple and pretty much
  2553.      self-explanatory in function.
  2554.      
  2555.      CUBERT follows the procedure above fairly closely, and I've tried to
  2556.      use variable names that correspond to those in the equations above.
  2557.      The routine expects to be passed an array, A#(), containing the
  2558.      coefficients of the cubic, an array, X#(), in which to place the roots
  2559.      it calculates, and a flag, F%, to indicate the type of the roots
  2560.      returned. If F% = 1, all the roots are real and distinct and their
  2561.      
  2562.      The QBNews                                                     Page 42
  2563.      Volume  2, Number  3                                September 15, 1991
  2564.  
  2565.      values will be in elements 1 through 3 of X#(). F% = 2 corresponds to
  2566.      the D >= 0 cases and X#(1) will contain the one real root and the next
  2567.      two elements will contain the real and imaginary components of the
  2568.      conjugate pair of complex roots.  Notice the use of the STATIC keyword
  2569.      on the subroutines. This causes the compiler to allocate local
  2570.      variables statically in DGROUP rather the on the stack and can save
  2571.      time in routines with a lot of local variable accesses on older 8088
  2572.      machines. This is not compatible with recursion, though.
  2573.      
  2574.      The first thing CUBERT does is calculate the coefficients of the
  2575.      standard form and from this calculates the p and q coefficients and
  2576.      then finds the discriminant. And IF statement checks the sign of the
  2577.      discriminant. If D >= 0, the routine calculates the roots according to
  2578.      equations 6) - 8). The calculation of the numbers A and B requires the
  2579.      calculation of the cube roots of two values that can be negative. The
  2580.      QB library code can't raise negative numbers to non-integral powers
  2581.      (because the method used has to take the logarithm of the base) and
  2582.      this requires the code to check the signs. If one is negative it
  2583.      calculates its cube root as the negative of the cube root of the
  2584.      absolute value. (Related to the fact that a polynomial of degree n has
  2585.      n roots is the fact that any number has exactly n nth roots. While for
  2586.      odd n, the principle nth root of a negative number is always complex,
  2587.      one of these n roots will simply be the negative of the principle nth
  2588.      root of that number's absolute value. While we are biased toward
  2589.      principle roots, any of the n nth roots will usually work in most
  2590.      situations.) After taking these cube roots, the code returns the roots
  2591.      of the equation as outlined above.
  2592.      
  2593.      I didn't bother to include an ELSEIF clause to check for the case of D
  2594.      being exactly equal to zero for a number of reasons. Remember that
  2595.      computer floating point arithmetic is finite and approximate, not
  2596.      exact. It is very rare indeed when you'll find two things exactly
  2597.      equal because there is always a little (or a lot, with unstable
  2598.      algorithms) bit of "noise" involved in every calculation. Also, the D
  2599.      = 0 case corresponds to the case of multiple roots and numerical
  2600.      analysis tells us that in this case the roots are poorly conditioned
  2601.      with respect to the coefficients anyway. ("Conditioning" is a term
  2602.      from numerical analysis which can be thought of as a kind of signal-
  2603.      to-noise ratio. It is a measure of how sensitive a calculation is to
  2604.      this floating point noise.) So what you'll find in this case is that
  2605.      the imaginary components returned are very small relative to the real
  2606.      components, or that two or more of the real and "distinct" roots are
  2607.      very close if the "noise" makes D slightly negative.
  2608.      
  2609.      
  2610.      
  2611.      If the discriminant is negative, the code follows equations 9) - 11)
  2612.      above. The magnitude calculation is straightforward, but the angle
  2613.      calculation is a tricky affair. We have to calculate the angle as an
  2614.      arctangent of the ratio of the imaginary and real components. But what
  2615.      happens if the real part is zero? In this case the angle is 90
  2616.      degrees, but we'll overflow when we take the ratio if the real part is
  2617.      small enough. The way to avoid this is to check the denominator before
  2618.      taking the ratio. If it's > 1, we can go ahead, but if it's < 1 we
  2619.      
  2620.      The QBNews                                                     Page 43
  2621.      Volume  2, Number  3                                September 15, 1991
  2622.  
  2623.      have to make sure the division won't overflow. We want to make sure
  2624.      that, say, a / b <= c, but without doing the division. This will be
  2625.      true only if a <= c * b, and this what CUBERT does. If the ratio will
  2626.      be greater than a constant, which I called BIG# and set to 1E40, the
  2627.      code sets the angle to 90 degrees. (While the tangent of a right angle
  2628.      is infinite, 1E40 is about as close to infinity as we need in this
  2629.      case.) Finally, if the ratio is negative QB's ATN function will return
  2630.      an angle in the fourth quadrant, but the angle we want lies in the
  2631.      second, so the code has to adjust the angle if needed.
  2632.      
  2633.      That just about wraps up the operation of CUBERT. Once CUBERT returns
  2634.      the roots, the driver calls function POLY to evaluate the cubic at the
  2635.      first root. As I said before, POLY evaluates polynomials the right
  2636.      way. At first blush, we might try something like this to evaluate a
  2637.      polynomial of degree n at x whose coefficients are in an array:
  2638.      
  2639.                P# = A#(0)
  2640.                FOR I% = 1 TO N%
  2641.                    P# = P# + A#(I%) * X# ^ (N%)
  2642.                NEXT I%
  2643.      
  2644.      But this requires n additions, n multiplications, and n
  2645.      exponentiations. POLY# does the same thing using Horner's method with
  2646.      only n additions and multiplications and no exponentiations. The above
  2647.      method is also much more "noisy" than POLY#.
  2648.      
  2649.      Cardan's method certainly falls into the category of the obscure and
  2650.      as a result many people aren't aware of the way to solve cubic
  2651.      equations and resort to numerical root-finders when they need to solve
  2652.      them. CUBERT can be used in any program that needs to find the roots
  2653.      of cubic equations and, I think, will be a helpful addition to your
  2654.      library. I hope this program will make solving cubics as easy and as
  2655.      common as solving quadratics. If you have in questions, comments or
  2656.      witticisms about this article or the program, feel free to contact me
  2657.      anytime.
  2658.      
  2659.      For a bibliography and a "for further reading" section I would
  2660.      recommend the following texts:
  2661.      
  2662.            Thompson, J. E.: "Algebra for the Practical Worker," 4th ed.,
  2663.            Van Nostrand Reinhold Co., New York, NY, 1982.
  2664.      
  2665.      (While, as its title implies, the above is a lower-level text, it
  2666.      neverless contains an excellent discussion of Cardan's Method.)
  2667.      
  2668.            Churchill, R. V. & Brown, J. W.: "Complex Variables and
  2669.            Applications,"
  2670.            4th ed., McGraw-Hill, New York, NY, 1984.
  2671.      
  2672.            Beyer, W. H.: "CRC Standard Mathmatical Tables," 28th ed.,
  2673.            CRC Press, Boca Raton, FL, 1988.
  2674.      
  2675.            Mizrahi, A. & Sullivan, M.: "Calculus and Analytic Geometry,"
  2676.            Wadsworth Publishing Co, Belmont, CA, 1982.
  2677.      
  2678.      The QBNews                                                     Page 44
  2679.      Volume  2, Number  3                                September 15, 1991
  2680.  
  2681.      
  2682.            Stoer, J. & Bulirsch, R.: "Introduction to Numerical Analysis,"
  2683.            Springer-Verlag, New York, NY, 1980
  2684.      
  2685.      The above constitute my standard references on the math covered in the
  2686.      article, but please note this represents a personal preference and
  2687.      shouldn't be considered the best possible sources.
  2688.      
  2689.      **********************************************************************
  2690.      Richard Jones is an "almost" graduate of Clemson University in SC. He
  2691.      majored in Physics there, but lack 4 hrs. of a foreign language for
  2692.      his B.S. His main interests include math, physics, and programming,
  2693.      and is currently employed with P.C. Electric Co. in Greenville, SC. He
  2694.      can be reached on Compuserve at 76636,536.
  2695.      **********************************************************************
  2696.      
  2697.  
  2698.  
  2699.  
  2700.  
  2701.  
  2702.  
  2703.  
  2704.  
  2705.  
  2706.  
  2707.  
  2708.  
  2709.  
  2710.  
  2711.  
  2712.  
  2713.  
  2714.  
  2715.  
  2716.  
  2717.  
  2718.  
  2719.  
  2720.  
  2721.  
  2722.  
  2723.  
  2724.  
  2725.  
  2726.  
  2727.  
  2728.  
  2729.  
  2730.  
  2731.  
  2732.  
  2733.  
  2734.  
  2735.      The QBNews                                                     Page 45
  2736.      Volume  2, Number  3                                September 15, 1991
  2737.  
  2738.  
  2739.  
  2740.      ----------------------------------------------------------------------
  2741.                             F u n   a n d   G a m e s
  2742.      ----------------------------------------------------------------------
  2743.  
  2744.      Lines With Style by Larry Stone and Charles Graham
  2745.      
  2746.         During the Winter of the Big Freeze, with nothing to  do  and  much
  2747.      time on his hands, Charles Graham, during a state of extreme  boredom,
  2748.      found himself alone with a glass of wine in one hand and  his  fingers
  2749.      at the keyboard with his other hand.  Thus was born an algorithm later
  2750.      to be shared with us all as source code for his program, "ENERGY".
  2751.      
  2752.         Aside:  Charles' called to complain that the glass of  wine  wasn't
  2753.      in hand until AFTER he created his code <GRIN>.
  2754.      
  2755.         FUSION, based upon Charles' original algorithm, produces a kaleido-
  2756.      scope of colors, design, music and sounds that will provide  hours  of
  2757.      delightful fascination.
  2758.      
  2759.         Before we get much further, you should know that FUSION  only  runs
  2760.      in EGA screen 9 or VGA screen 12.   Even if your monitor cannot handle
  2761.      these modes you will still benefit from FUSION's  many  other,  useful
  2762.      routines.
  2763.      
  2764.         For example, the PrintROMtable subprogram gives you pixel by  pixel
  2765.      control for the ASCII characters 1 through 128. See the article Fonts
  2766.      in a Can earlier in this issue for more on this subroutine.
  2767.      
  2768.         If you study FUSION.BAS, you will notice that except for one  PAINT
  2769.      and a couple of PALETTE commands, all graphics are  produced  via  the
  2770.      BASIC LINE or CIRCLE statement.  Closer examination reveals the  heart
  2771.      of the program is the LINE statement.   QB's LINE statement is one  of
  2772.      the most powerful graphic commands available.   Conversely,  it is may
  2773.      be one of the least understood graphic command.  Although entire books
  2774.      could be written about the LINE statement, only  one  of its  optional
  2775.      variables will be examined here -- the "style%" argument.
  2776.      
  2777.         Simply put, the integer variable, style%, is a mask or stencil laid
  2778.      over the line.  When we "paint" the line, the paint falls through  the
  2779.      holes of the "stencil" and is held back by the "mask".   Probably  the
  2780.      easiest way to show this is by following the logic of  the  subprogram
  2781.      called, PrintROMtable.
  2782.      
  2783.         One final note to you Tech-Heads.  The algorithm that computes  and
  2784.      displays "energy" and "plasma" drawings is derived by calculating  the
  2785.      polar equations for  each  ellipse  generated  from  weighted,  random
  2786.      numbers.  Random numbers are weighted by expressions such as:
  2787.      
  2788.         g = INT(RND * 590) + 50   '50 - 640 possible points to each drawing
  2789.         w = INT(RND * 1.9) + .1   'weighted factor used for yavg, etc.
  2790.      
  2791.      Where g is a random number whose value is forced to lie between 50 and
  2792.      640 and, where w is a random number whose value  is  forced  to  range
  2793.      between 0.1 and 1.9, respectively.   Albert Einstein would have  loved
  2794.      
  2795.      The QBNews                                                     Page 46
  2796.      Volume  2, Number  3                                September 15, 1991
  2797.  
  2798.      this algorithm - the programmer's universe is totally random  but  the
  2799.      programmer is using "dice" that are loaded.  The effect is random, yet
  2800.      symmetrical designs.  My additions to Charles' algorithm continue this
  2801.      mix of order and chaos - "muon" and "quark" trails  are  produced  and
  2802.      displayed with weighted, random numbers.  The same mix of symmetry and
  2803.      randomness is employed with color and with the number of drawings that
  2804.      display at one time.   Thank you,  Charles Graham,  for the  wonderful
  2805.      algorithm.
  2806.      
  2807.      [EDITOR'S NOTE]
  2808.      All code for this article can be found in FUSION.ZIP
  2809.      
  2810.      **********************************************************************
  2811.           Larry  Stone is President of LSRGroup and is involved in  writing
  2812.      instructional and large data base application systems for business and
  2813.      institutional clients.  He is also the author of SERVICES, a shareware
  2814.      application program rated a trophy by "Public Brand Software". He  can
  2815.      be  reached  at LSRGroup,  P.O.  Box 5715, Charleston, OR 97420, or in
  2816.      care of this newsletter.
  2817.      **********************************************************************
  2818.      
  2819.      **********************************************************************
  2820.      Charles Graham is a division head for a local government agency in St.
  2821.      Louis County, Missouri.   He  also  teaches  QuickBASIC part time at a
  2822.      local community college.   He  is  the  author  of  several  shareware
  2823.      products including MOVIES . ON . LINE  and,  Quick Dial.   He  can  be
  2824.      contacted at Post Office  Box 58634, St.  Louis, MO 63158, and on  the
  2825.      National QuickBASIC Conference.
  2826.      **********************************************************************
  2827.      
  2828.  
  2829.  
  2830.  
  2831.  
  2832.  
  2833.  
  2834.  
  2835.  
  2836.  
  2837.  
  2838.  
  2839.  
  2840.  
  2841.  
  2842.  
  2843.  
  2844.  
  2845.  
  2846.  
  2847.  
  2848.  
  2849.  
  2850.  
  2851.  
  2852.      The QBNews                                                     Page 47
  2853.  
  2854.  
  2855.      ----------------------------------------------------------------------
  2856.                                       E O F
  2857.      ----------------------------------------------------------------------
  2858.  
  2859.      Receiving The QBNews
  2860.      
  2861.           The  QBNews is distributed mainly through BBS systems around  the
  2862.      world.  Some  of  the networks it gets  distributed  through  are  SDS
  2863.      (Software   Distribution   System) and  PDN  (Programmers Distribution
  2864.      Network). Ask the  sysop of your  local  board about these networks to
  2865.      see if there is a  node  in your area.
  2866.      
  2867.           The  QBNews  can  also  be found  on  CompuServe  in  the  MSLang
  2868.      (Microsoft  Language)  forum. It can be found in file area 1 or  2  of
  2869.      that  forum. Just search for the keyword QBNEWS. The QBNews will  also
  2870.      be available on PC-Link. I send them to Steve Craver, who is the BASIC
  2871.      Programming  Forum Host on PC-LINK and he will make them available.  I
  2872.      would appreciate anybody who could upload The QBNews to other services
  2873.      such as GENIE since I don't have access to these.
  2874.      
  2875.           I  have also set up a high speed distribution network for  people
  2876.      who  would  like to download The QBNews at 9600  baud.  The  following
  2877.      boards allow first time callers download privileges also. They are:
  2878.      
  2879.          Name           Sysop       Location       Number         Node #
  2880.      ---------------------------------------------------------------------
  2881.      
  2882.      Treasure Island  Don Dawson    Danbury, CT    203-791-8532   1:141/730
  2883.      
  2884.      Gulf Coast BBS   Jim Brewer New PortRichey,FL 813-856-7926   1:3619/20
  2885.      
  2886.      221B Baker St.   James Young   Panama City,FL 904-871-6536   1:3608/1
  2887.      
  2888.      EMC/80           Jim Harre     St. Louis, MO  314-843-0001   1:100/555
  2889.      
  2890.      Apple Capitol BBS Bob Finley   Wenatchee, WA  509-663-3618   1:344/61
  2891.      
  2892.      
  2893.           Finally, you can download The QBNews from these vendors BBS's:
  2894.      
  2895.      The Crescent Software Support BBS   203-426-5958
  2896.      
  2897.      The EllTech Support BBS             404-928-7111
  2898.      
  2899.      The Microhelp BUG BBS               404-552-0567
  2900.                                          404-594-9625
  2901.      
  2902.      
  2903.      You do not have to be a customer of these vendors in order to download
  2904.      The  QBNews, but the Microhelp BBS only allows non-members 15  minutes
  2905.      of time per call.
  2906.      
  2907.         If you would like to receive The QBNews on disk, I offer a yearly
  2908.      subscription for $15.00. This includes four disks containing each
  2909.      
  2910.      The QBNews                                                     Page 48
  2911.      Volume  2, Number  3                                September 15, 1991
  2912.  
  2913.      issue as it is published. If you would like a disk with all the back
  2914.      issues of The QBNews, please enclose an additional $5.00. The pricing
  2915.      structure is as follows:
  2916.      
  2917.      Base Price for 1 Year -       $15.00
  2918.      Disk with Back Issues -        $5.00
  2919.      3.5" disk surcharge -          $5.00
  2920.      Canada and Mexico surcharge -  $5.00
  2921.      All other foreign orders -    $10.00
  2922.      
  2923.           The  base price includes 5.25" 360k disks. Send a check or  money
  2924.      order in U.S. funds to:
  2925.      
  2926.           The QBNews
  2927.           P.O. Box 507
  2928.           Sandy Hook, CT 06482
  2929.      
  2930.           Please  be  sure  to specify what archive format  you  want.  The
  2931.      QBNews normally uses PKZip as it's archiver.
  2932.      ----------------------------------------------------------------------
  2933.  
  2934.      Submitting Articles to The QBNews
  2935.      
  2936.           The QBNews relies on it's readers to submit articles. If you  are
  2937.      interested in submitting an article, please send a disk of Ascii  text
  2938.      of no more than 70 characters per line to:
  2939.      
  2940.           The QBNews
  2941.           P.O. Box 507
  2942.           Sandy Hook, CT 06482
  2943.      
  2944.      Articles can also be submitted via E-Mail. Send them via Compuserve to
  2945.      76510,1725 or via FidoNet to 1:141/777. I can be reached at the  above
  2946.      addresses as well as on Prodigy as HSRW18A.
  2947.      
  2948.  
  2949.  
  2950.  
  2951.  
  2952.  
  2953.  
  2954.  
  2955.  
  2956.  
  2957.  
  2958.  
  2959.  
  2960.  
  2961.  
  2962.  
  2963.  
  2964.  
  2965.  
  2966.  
  2967.  
  2968.  
  2969.      The QBNews                                                     Page 49
  2970.  
  2971.