💾 Archived View for mirrors.apple2.org.za › archive › ftp.gno.org › doc › genie › a2pro › genielamp … captured on 2024-12-18 at 06:45:14.

View Raw

More Information

-=-=-=-=-=-=-



     |||||| |||||| ||  || |||||| ||||||
     ||     ||     ||| ||   ||   ||
     || ||| ||||   ||||||   ||   ||||               Your
     ||  || ||     || |||   ||   ||
     |||||| |||||| ||  || |||||| ||||||             GEnieLamp Computing

     ||    |||||| ||    || ||||||                   RoundTable
     ||    ||  || |||  ||| ||  ||
     ||    |||||| |||||||| ||||||                   RESOURCE!
     ||    ||  || || || || ||
     ||||| ||  || ||    || ||


                     ~ WELCOME TO GENIELAMP A2Pro! ~
                       """""""""""""""""""""""""""
          ~ TIPS AND TECHNIQUES: Compressing Hi-Res Graphics ~
         ~ Scrolling Text ~ Linear Regression ~ Bezier Curves ~
     ~ 65C816 in an Atari? ~ Switching Processes in the GNO Shell ~
                  ~ HOT NEWS, HOT FILES, HOT MESSAGES ~

 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\////////////////////////////////////
  GEnieLamp A2Pro      ~ A T/TalkNET Publication ~       Vol.5, Issue 32
 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 Publisher.................................................John F. Peters
  Editor....................................................Tim Buchheim
 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\////////////////////////////////////
          ~ GEnieLamp IBM ~ GEnieLamp Atari ~ GEnieLamp PowerPC ~
         ~ GEnieLamp A2Pro ~ GEnieLamp Macintosh ~ GEnieLamp TX2 ~
          ~ GEnieLamp Windows ~ GEnieLamp A2 ~ LiveWire (ASCII) ~ 
             ~ Member Of The Digital Publishing Association ~
  GE Mail: GENIELAMP                       Internet: genielamp@genie.com
 ////////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

             >>> WHAT'S HAPPENING IN THE A2Pro ROUNDTABLE? <<<
             """""""""""""""""""""""""""""""""""""""""""""""""
                           ~ November 1, 1995 ~

 FROM MY DESKTOP ......... [FRM]        A2PRO ROUNDTABLE STAFF .. [DIR]
  Notes From The Editor.                 Directory of A2Pro Staff.              

 TIPS AND TECHNIQUES ..... [TIP]        HEY MISTER POSTMAN ...... [HEY]
  Compressing Hi-Res Graphics            Is That A Letter For Me?

 DEVELOPERS CORNER ....... [DEV]        LIBRARY BIT BONANZA ..... [LIB]
  News From Online Developers.           HOT Files You Can Download.
  
                     LOG OFF ................. [LOG]
                      GEnieLamp information.


[IDX]"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

READING GEnieLamp   GEnieLamp  has  incorporated  a  unique   indexing
"""""""""""""""""   system to help make  reading the  magazine easier.
To  utilize this system, load GEnieLamp into any ASCII  word processor
or text  editor.  In the index  you will find the  following  example:

                   A2PRO ROUNDTABLE STAFF .. [DIR]
                    Directory of A2Pro Staff.              

   To read this  article, set your  find or search command to [DIR].  If
you want to scan all of the articles, search for [EOA].  [EOF] will take
you to  the last page,  whereas [IDX]  will bring you back to the index.

MESSAGE INFO   To make it easy for you to respond to messages re-printed
""""""""""""   here in GEnieLamp, you will find all the information you
need immediately following the message.  For example:

                    (SMITH, CAT6, TOP1, MSG:58/M530)
        _____________|   _____|__  _|___    |____ |_____________
       |Name of sender   CATegory  TOPic    Msg.   Page number|

    In this  example, to  respond to  Smith's  message, log  on to  page
530 enter the bulletin board and set CAT 6. Enter your REPly in TOPic 1.

    A message number that is surrounded by brackets indicates  that this
message  is a "target" message and is  referring  to  a "chain"  of  two
or more  messages that are following the same topic.  For example: {58}.

ABOUT GEnie   GEnie's monthly fee is $8.95 which gives you up to four hours
"""""""""""   of non-prime time access to most GEnie services, such as
software downloads, bulletin boards, GE Mail, an Internet gateway, award-
winning multi-player games and friendly chat lines.  GEnie's non-prime time
connect rate is only $3.00 per hour.  Prime Time (8:00 am to 6:00 pm local
time on weekdays) is only $5.00 per hour.  To sign up for GEnie, just
follow these simple steps:

1.  Set your communications software to half duplex (local echo) 8 bits, no
 parity and 1 stop bit, at 300, 1200, 2400 or 9600 baud.

2.  Call (with modem) 1-800-638-8369 (US) or 1-800-387-8330 (Canada).

3.  Wait for the U#= prompt.  Type:  JOINGENIE and hit RETURN.  When you
 get the prompt asking for the signup/offer code, type: DSD524  and hit
 RETURN.

4.  Have a major credit card ready, as the system will prompt you for your
 information.  If you need more information, call GEnie's Customer Service
 department at 1-800-638-9636.
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""




[EOA]
[FRM]//////////////////////////////
                 FROM MY DESKTOP /
/////////////////////////////////
Notes From My Desktop
"""""""""""""""""""""
by Tim Buchheim
 [A2PRO.GELAMP]


    o TOP OF THE PAGE



                          >>>  TOP OF THE PAGE  <<<
                          """""""""""""""""""""""""
                        ~ A Letter From the Editor ~


GENIE OUTAGES   Last month I talked about GEnie's first ten years and how
"""""""""""""   much it has changed.  Well, it is still in the process of
change; GEnie is in the middle of both hardware and software upgrades.  In
the past few weeks, these upgrades have caused some problems with GEnie.
I've received a report on these problems and thought I should pass it on
so you know what's happening.

Here's the report I got:

"As many of you have no-doubt experienced, GEnie has recently had some
recent unplanned system outages.  These outages have been both hardware and
software related.  The hardware problems have been fixed, and a solution
for the software problem is undergoing rigorous testing and is slated to be
deployed around mid-November. We apologize for any inconvenience these
outages have caused."


Here's a chronology of what happened.  [GEIS is GEnie's parent company]

10/17 (Tuesday) around 21:10:   All members were knocked off line. By 21:45
'''''''''''''''''''''''''''''   GEnie was back on line. The problem was
diagnosed as a software problem for which GEIS had a formulated fix.  The
fix has been undergoing rigorous testing and is slated to be deployed
around mid to late November.


10/23 (Monday) and 11/24 (Tuesday) around ~21:00-22:00:   On both days,
'''''''''''''''''''''''''''''''''''''''''''''''''''''''   GEnie members
again were knocked off line. The problem was diagnosed as a hardware
problem on GEIS equipment that GEnie requires for operation. On Wednesday,
the hardware vendor addressed the incidents by replacing boards that were
identified as bad.


10/27 (Friday) around 19:00 - 23:00:   Initially, only some clients were
''''''''''''''''''''''''''''''''''''   knocked off line, but eventually,
all were knocked off. This incident was attributed to a hardware failure
on yet another piece of GEIS equipment. This time a power supply blew out.
The power supply was replaced that evening, and GEnie service was restored.

Each of the incidents displayed the same symptoms, but were caused by
different problems.



EMAIL WEIRDNESS  There have also been some strange things happening with
"""""""""""""""  Email the past few weeks.  GEIS upgraded the internet mail
gateway, fixing several bugs but causing a minor problem.  As most of you
know, you can receive email sent to "yourname@genie.com" as well as
"yourname@genie.geis.com" but all outgoing mail is sent with
"yourname@genie.geis.com".

Or at least it's supposed to be that way.  When the INET03# mail
connector was upgraded to the new software a few months ago, no one had any
problems because it was configured right.  The main connectors,
INTERNET#, INET#, INET00#, and INET01# were upgraded this week but
weren't configured properly, so they send mail as "genie.com" instead of
the correct "genie.geis.com".This has caused problems for people on mailing
lists, because the mailing lists don't recognize this other address.

A temporary solution is to send all mail through INET03# rather than the
other connectors, if you need to have it sent with the "genie.geis.com"
address.  The other connectors may be reconfigured, or they may leave
them as "genie.com" since they were scheduled to be set to "genie.com" in a
month or so anyway.

Once they officially announce that internet mail will be through
"genie.com", you should unsubscribe to mailing lists through INET03# and
resubscribe through one of the main connectors, so they recognize your
"genie.com" address instead of "genie.geis.com".




                                              -- Timothy Carl Buchheim
                                                 Editor, GEnieLamp A2Pro



P.S.    You might have noticed that this issue is much bigger than usual.
        Well, I tried to keep it reasonable by not having the "RTC Watch"
        and "Spotlight On:" columns this month.  Look for those next month,
        unless I decide to skip them again in the interest of keeping
        download time to a minimum :)


P.P.S.  Sorry this issue was a few days late, but I had no time to work on
        before the 1st. :/



                              [*][*][*]


    Do you have something  to say about  GEnieLamp A2Pro?  Please
    post  any questions or  comments you  may have in Category 1,
    Topic 15 in A2Pro's BB (m530;1).  Or, feel free to talk to me
    (A2PRO.GELAMP) anytime you see  me in a Real Time Conference.

    Readers out there on the Internet:   feel free to email me at
    a2pro.gelamp@genie.com     When writing, please tell me where
    you got your copy of  GEnieLamp,  if it wasn't on GEnie.  I'm
    always interested to see how many places GEnieLamp ends up :)

    By the way,  the  current  issue  and  most  back issues  are
    available online in  many  places.  GEnie users  should check
    Library #2  in the  DigiPub libraries  (DIGIPUB, page 1395;3)
    Those of  you not on  GEnie  should  use  gopher  software to
    connect to gopher.genie.com for issues; all recent issues and
    most older ones are there.


                              [*][*][*]



[EOA]
[DIR]//////////////////////////////
          A2PRO ROUNDTABLE STAFF /
/////////////////////////////////
By Tim Buchheim
 [A2PRO.GELAMP]


    o   A2Pro STAFF LIST



                        >>> A2Pro STAFF LIST <<<
                        """"""""""""""""""""""""

                          ______________________________________________

                           APPLE II PROGRAMMERS & DEVELOPERS ROUNDTABLE
       _____  ______      ______________________________________________
      /_____|/______\
     /__/|__|  ___|__|         Head Sysop: Hangtime         (HANGTIME)  
    /__/_|__| /_____/         Your Sysops: Greg Da Costa    (A2PRO.GREG)
   /________|/__/       __ __ __           Todd P. Whitesel (A2PRO.TODDPW)
  /__/   |__|__/______ /_//_// /           Nathaniel Sloan  (A2PRO.HELP)
 /__/    |__|________//  / \/_/            Tim Buchheim     (A2PRO.GELAMP)




[EOA]
[FEA]//////////////////////////
         TIPS AND TECHNIQUES /
/////////////////////////////
Compressing Hi-Res Graphics
"""""""""""""""""""""""""""
By Russell Nielson
      [R.NIELSON1]


    o   COMPRESSING GRAPHICS

         o   THE PROGRAMS IN THE PIC.COMP10.BXY ARCHIVE




    Editor's note:   This is the  first of what I  hope will be a
    """"""""""""""   series of articles  written by readers.  But
    it will only  work if you send  in articles!  If your article
    is published, then you will be paid with GEnie usage credits.
    Any article related to programming Apple II computers will be
    considered.   Those articles which include sample source code
    are especially good, because the whole point of the series is
    to provide  programmers with  ideas and samples,  in order to
    encourage them to write new software for the Apple II!

    This month's article is about compressing graphics files, and
    is based on a file in the A2Pro library called PIC.COMP10.BXY
    which was uploaded by the author of this article.




                   >>>  COMPRESSING GRAPHICS   <<<
                   """""""""""""""""""""""""""""""


INTRODUCTION   As we all know, any type of graphics take up a lot of disk
""""""""""""   space, and when you have a lot of graphics in one place,
disk space can be eaten up very quickly.  I'd like to discuss one form of
graphics on the Apple II called hi-res graphics, which stands for high
resolution graphics.  All programmers that have ever programmed on the
Apple II in hi-res know that a single picture takes up a whopping 8187
bytes of memory or 17 blocks on a ProDOS disk!  When you have many pictures
stored on disk they can take up a lot of space.  Please be aware that
"picture" and "screen" both refer to a single hi-res graphics screen.

When developing software that uses graphic screens and pictures, you need
to store these picture files on disk, load them into memory, and display
them on the hi-res screen.  This isn't a problem until you start having
multiple pictures, like a title screen, a menu screen, an options screen, a
high scores screen, etc.. you are talking a lot of graphic data here! The
main problem usually shows up when you only have a certain amount of disk
space available for your entire project.  For instance, if you are
writing a cool game and plan on distributing it on one side of a 5.25"
floppy disk, your entire game (were talking all your graphics, code,
data, etc) has to fit in 140k!  Not only that, but if you want your disk to
boot into the game automatically then you need to leave enough space for
ProDOS (and BASIC.SYSTEM if part of your program is in Applesoft) to be
copied there.  As you can see you will run out of disk space rather
quickly.

During the development of one of my arcade games I had so many graphic
screens saved to disk that it really got me sick to see all the disk
space going to waste!  Not only that but loading an entire 8187 bytes of
data just to display one screen takes some time, so I sat back and
thought for a moment.  I have this rather simple screen, which is
practically a black screen with a colored border and a small graphic at the
top, which is taking as much disk space as any other screen.  I
determined that regardless of how complex or how simple the picture may be,
it's always the same size.  If you cleared the hi-res screen to black (a
blank screen) and saved it, it would still be a whopping 17 blocks.  The
reason behind this is because the graphics screen on Apple computers is
simply a chunck of memory that reflects what is seen on the monitor.  If
you save hi-res screen 1 you would be writing the area of memory from $2000
to $3FFF.  This block of memory is always the same size and doesn't
change even if the graphic image is very simple.  I needed to come up
with something here to save space.

One solution to saving disk space is to somehow represent the picture on
the screen in a different manner that does not take up the full 8187 bytes.
 Welcome to the world of compression.  There are many compression methods
around and they are used all the time.  For instance, Shrink-It and GS
Shrink-It use compression methods when placing files into archives. 
These programs take each file and compress them down as small as the
compression algorithm allows and then stored them into the archive.  Take
GEnie's Software Libraries for example, most everything is stored in a
compressed format (.SHK) because compressed files take up less disk space
and cut down on file transfer times.

Although the Shrink-It compression routines are quite complex, this does
not mean that every compression method is complicated.  When writing my
routine for compressing the hi-res screen, it had to ensure that no
information was lost during the compression so that the original picture
would be recreated and displayed on the screen EXACTLY how is was before
being compressed.


MY COMPRESSION METHOD   After loading numerous pictures and examining the
"""""""""""""""""""""   hex dump of the screens, I began to see repetitious
bytes and repeating patterns.  I figured that if I could store these
repeating sequences of bytes as a single number, or two, then I would be
saving space.  I used a very simple algorithm that would allow me to
represent groups of bytes on the screen in just a couple bytes.

Here's what I came up with:

All black colors on the screen are either $00 or $80, depending on the
color bit.  $00 is black #1 and $80 is black #2.  Remember that there are
two black colors and two white colors available in hi-res.  In contrast,
all white colors on the screen are either $7F or $FF, again depending on
the high bit.

So a black line on the hi-res screen would look something like this:

     00 00 00 00 00 00 00 00 00 00

  Note: All numbers are represented in hexadecimal.
  """"

This segment would be a black line ten bytes wide on the hi-res screen. 
The same goes for black #2 ($80), white #1 ($7F) and white #2 ($FF).  I
looked at this and said to myself, "Hmmm.. there's gotta be a better way
than to just keep repeating zeroes over and over again wasting space." 
So I came up with a method.  For every $00, $80, $7F, or $FF I find, I will
count the number that are in a row, store the color, and then store the
number of times this color is repeated.  So in the example above, I'd store
all those zeroes like this:

     00 0A

Only two bytes are needed to represent that entire group of zeroes!  The
above "00 0A" means that color 00 is repeated 10 times!  ($0A = 10
decimal). When it comes time to decompress it again, I simply check for a
$00, $80, $7F, or $FF and then repeat that color the number of times the
repeating byte says!  The repeating byte always follows directly after
the color byte.

For another example, here's how the following segment would compress:

Raw:      00 00 00 00 00 FF FF FF FF 7F 7F 7F 7F 7F 7F 7F 80 80 80 80 00 00
Compress: 00 05 FF 04 7F 07 80 04 00 02

See how it works?  The more repeating bytes in a row, the more space will
be saved!  So if you have a picture with lots of black and white areas,
then the compression will be excellent.  In the above sample, that's over
50% compression!


WHAT ABOUT COLORS?   After I wrote this routine and tested the compression
""""""""""""""""""   on various pictures, I still was not satisfied with
the results.  Why?  Well, when I had a picture will lots of black and white
areas, this compression scheme worked great, but when I had a picture
with lots of colors and hardly any black and white areas, the compression
was horrible.  The reason was because if there were hardly any repeating
black and white bytes, then there was not a whole lot to compress.

I started thinking of a better way to compress the screens and for new
ideas for better compression. After looking at a few more screen dumps, I
noticed that Green, Purple, Red, and Blue colors followed a pattern.  Maybe
I could use a compression method to represent repeating color?  Sure I
could!  Here's what I came up with:

After the examination of the screen dumps, this fact surfaced:

   Green  lines are repeating patterns of $2A and $55
   Purple lines are repeating patterns of $55 and $2A
   Red    lines are repeating patterns of $D5 and $AA
   Blue   lines are repeating patterns of $AA and $D5

So a green line on the screen would look like this:

     2A 55 2A 55 2A 55 2A 55 2A 55 2A 55

Wow!  I see a pattern.  I used the same algorithm as the black and white
method, but had to add in a little twist for pattern repetition.  Since the
black and white colors were represented as one byte (00, 80, 7F, FF) they
were easy to compress, I just had to store count the number of bytes in a
row and store that count (or repeat number) after the color byte.  But
now things are a little different because two bytes represent a color
instead of just one.

To handle colors (now meaning that black and white aren't colors), I will
use a method for pattern recognition by issuing a comparision of two
bytes instead of just one.  For example, if I was compressing a screen
and I came across a $2A, I'd immediately check the byte following it and
see if it was a $55.  If it was, then I would have found a pattern!  I'd go
on an count how many of these patterns were in a row and store that
repeat value as the repeating byte.  So in the above example, that green
line would be stored like this:

     2A 55 06

In this case, the "2A 55" is the pattern for a green line and the "06"
means that there are six of these patterns in a row.  When I'm
decompressing this screen and I came across the $2A byte, and after I
made sure that the next one after it was $55, then I would go ahead an
repeat this pattern 6 times!

The same thing goes for Purple, Red and Blue.  Except that I would
compare different numbers because the patterns would be made up of
different byte combinations.

That is basically the extent of my compression algorithm.  There are only
two cases in my routine, checking for a non-color byte, and checking for
a color byte. In the case of checking for a non-color sequence, I'd act
on 00, 80, 7F, and FF.  In the case of checking for a color pattern, I'd
act on $2A/$55, $55/$2A, $D5/$AA, and $AA/$D5 which represent color
sequences.  Any other values would be stored as normal, non-compressed.


DECOMPRESSION   Once the screen has been compressed and is stored in this
"""""""""""""   new format, it needs to be decompressed and end up in its
original form.  This process works just like the compression method but
it is much easier.  I start scanning the compressed data and I look for the
key values which are 00, 80, 7F, and FF.  Whenever I encounter such a
value, I take the next byte, which is the repeating value, and store that
number of the color value in a row to the screen.  So if I came across
"00 1D" I'd store twenty-nine 00's in a row.  I'd also scan for key color
sequences which are $2A/$55, $55/$2A, $D5/$AA, and $AA/$D5.  Whenever I
find one of these sequences I'd take the next byte, which (again) is the
repeating value, and store this pattern that many times. So ifI came across
"AA D5 03" I'd store three "AA D5"'s in a row on the screen.


DISADVANTAGES   Aren't there any disadvantages?  Yes, unfortunately there
"""""""""""""   are a few.  The good thing is that all the advantages
always outweigh the disadvantages.  The only bad part about my
compression algorithm is when there is only one $00, $80, $7F, or $FF in
a row, it takes one extra byte to store it compressed than it would to
leave it decompressed.  For instance a single $00 would compress to look
like this: 00 01.  This is a disadvantage because we started with one
byte and ended up with two.  The other bad part is when you only have one
color pattern in a row like $D5 $AA, it would compress to D5 AA 01.  We
went from having only two bytes to needing three.  The overall advantage is
that the compression method always comes out ahead of the game because
there are usually lots more repeating bytes in a row than there are
single bytes laying around, and because of what I am going to describe
below.


THERE'S GOTTA BE SOMETHING ELSE   With that done I went ahead and did some
"""""""""""""""""""""""""""""""   more compressions and studied the
results. Everything was working great except for one instance.  If I had
a majorly complex screen (one with hardly any repeating bytes) then the
compression would result in hardly any savings, and sometimes would end
up just a little bigger than the original!  This was not good.  I broke
open a few of my Apple books in search of a secret or two about the
hi-res screen that I may have overlooked, or simply failed to think about. 
And soon enough, I found something.

I found out that the hi-res screen was full of "screen holes".  What I
mean when I say screen holes, is that the screen has many areas which are
not visible to the viewer.  These areas can be safely zeroed out, and these
zeroed out areas will compress.  So even if there is not one single
repeating byte on the entire screen, after the compression it will still be
smaller, not by a whole lot, but definetly smaller.  Sometimes even just
a few bytes help.


HOW IS IT ALL ACCOMPLISHED?   Let me first explain that I have uploaded the
"""""""""""""""""""""""""""   entire source code to the A2Pro Software
Libraries.  Along with this source is a complete set of utilities to
load, compress, save, and decompress screens.  Download file PIC.COMP10.BXY
(file number 3596) if you want to have the entire source and utilities. 
I'll explain some of the source code here:


There are two constants I use here.  SCREEN is hires screen one, and BUFFER
is hires screen two, which I am using to hold the compressed picture data.

SCREEN       equ     $2000                 ; screen address
BUFFER       equ     $4000                 ; crunch data buffer


Here are some zero page storage variables.  Picture and Data are pointers.

Picture      equ     0                     ; picture to pack
Data         equ     2                     ; crunch data

PtrnByte1    equ     $FE                   ; 1st pattern byte to store
PtrnByte2    equ     $FF                   ; 2nd pattern byte to store


Here are the non-color and color pattern constants.

Black1       =       $00                   ; recognition values
Black2       =       $80
White1       =       $7F
White2       =       $FF
Green        =       $2A                   ; color recognition values
Purple       =       $55
Red          =       $AA
Blue         =       $D5


Now here is the crunch (or compression) routine.

Crunch
             jsr     Filter                ; filter screen "holes"

             lda     #>SCREEN              ; point to hires screen 1
             ldx     #<SCREEN
             sta     Picture+1
             stx     Picture

             lda     #>BUFFER              ; point to data buffer
             ldx     #<BUFFER
             sta     Data+1
             stx     Data

             ldy     #0
:NewByte
             lda     (Picture),y           ; load the screen byte
             beq     :blkwht               ; $00, $80, $7F, $FF
             cmp     #Black2               ;  bytes will repeat
             beq     :blkwht
             cmp     #White1
             beq     :blkwht
             cmp     #White2
             beq     :blkwht
             cmp     #Green                ; possible Green pattern
             beq     :green
             cmp     #Purple               ; possible Purple pattern
             beq     :purple
             cmp     #Red                  ; possible Red pattern
             beq     :red
             cmp     #Blue                 ; possible Blue pattern
             beq     :blue
             bne     :store                ; always

:green       jmp     :Dgreen
:purple      jmp     :Dpurple
:red         jmp     :Dred
:blue        jmp     :Dblue

:store       sta     (Data),y              ; store screen byte
             jsr     NextData
             jsr     NextPic
             bcs     :finished             ; carry set = finished
             jmp     :NewByte
:blkwht      sta     (Data),y              ; store repeat byte
             sta     :compbyte
             jsr     NextData
             ldx     #0
:repeat
             inx
             jsr     NextPic               ; get next picture byte
             bcs    :storerep              ; end of screen, store rep
             lda    (Picture),y
             cmp    :compbyte              ; match?
             beq    :same
:limit
             txa
             sta    (Data),y               ; store repeat counter
             jsr    NextData
             jmp    :NewByte
:same
             cpx    #0                     ; up the repeat counter
             beq    :limit                 ; max of 255 repeat bytes
             jmp    :repeat

:storerep
             txa
             sta    (Data),y               ; store repeat counter
             jsr    NextData

:finished    rts

:Dgreen      tax
             iny                           ; is this a green pattern?
             sta    PtrnByte1
             lda    (Picture),y
             cmp    #Purple
             bne    :pstore
             sta    PtrnByte2
             jsr    StorePtrn              ; store green pattern
             bcs    :finished
             jmp    :NewByte

:Dpurple     tax
             iny                           ; is this a purple pattern?
             sta    PtrnByte1
             lda    (Picture),y
             cmp    #Green
             bne    :pstore
             sta    PtrnByte2
             jsr    StorePtrn             ; store purple pattern
             bcs    :finished
             jmp    :NewByte

:Dred        tax
             iny                          ; is this a red pattern?
             sta    PtrnByte1
             lda    (Picture),y
             cmp    #Blue
             bne    :pstore
             sta    PtrnByte2
             jsr    StorePtrn             ; store red pattern
             bcs    :finished
             jmp    :NewByte

:Dblue       tax
             iny                          ; is this a blue pattern?
             sta    PtrnByte1
             lda    (Picture),y
             cmp    #Red
             bne    :pstore
             sta    PtrnByte2
             jsr    StorePtrn             ; store blue pattern
             bcs    :finished
             jmp    :NewByte

:pstore      dey
             txa
             jmp    :store

:compbyte    ds     1                     ; stores comparison byte



StorePtrn
             ldx    #0
             ldy    #0
             lda    PtrnByte1            ; store pattern data
             sta    (Data),y
             iny
             lda    PtrnByte2
             sta    (Data),y
             dey
             jsr    NextData
             jsr    NextData
:Ptrnloop
             lda    (Picture),y
             cmp    PtrnByte1
             bne    :endptrn
             iny
             lda    (Picture),y
             cmp    PtrnByte2
             beq    :match
             dey
:endptrn
             txa
             sta    (Data),y             ; store pattern repeat count
             jsr    NextData
             clc
             rts
:match
             dey
             jsr    NextPic
             jsr    NextPic
             bcs    :done
             inx
             bne    :Ptrnloop

:done        dey
             txa
             sta     (Data),y            ; store pattern repeat count
             sec                         ; indicate finished
             rts



Filter       lda    #>SCREEN             ; zero out the screen holes
             sta    Picture+1
             lda    #<SCREEN
             clc
             adc    #$78                 ; start at 1st screen hole
             sta    Picture

:Hole        lda    #0
             ldy    #8                   ; store all zeroes there
:loop        dey
             sta    (Picture),y
             bne    :loop

             lda    Picture
             clc
             adc    #$80                 ; advance to next hole
             sta    Picture
             bcc    :ok
             inc    Picture+1
:ok
             lda    Picture+1            ; finished last hole?
             cmp    #>SCREEN+$2000
             bne    :Hole                ; nope, loop for more
             rts                         ; yep,  finshed



NextPic      pha
             inc    Picture              ; next picture address
             bne    :noinc
             inc    Picture+1            ; see if at bottom of screen
:noinc       lda    Picture
             bne    :nottop
             lda    Picture+1
             cmp    #>SCREEN+$2000
             bcc    :nottop
             pla
             sec                         ; carry set = done
             rts
:nottop      pla
             clc                         ; carry clear, more
             rts



NextData     inc    Data                 ; next data buffer address
             bne    :noinc
             inc    Data+1
:noinc       rts



You'll notice that the first thing I do it call the Filter routine which
simply fills all the screen holes with zeroes so the compression routine
works effectively in all cases, regardless of the complexity of the screen.

Next I set up the Picture pointer to point to hires screen one and set up
the buffer to store the compressed data to hires screen two.  I am only
using hires screen two because it is a convienent place in memory to
store the data.  It could be anywhere.

Then the compression loop begins at :NewByte.  The next byte is loaded from
the hires screen and it is checked to see if it is a $00, $80, $7F, or $FF.
If the screen byte is any of these values then the program goes to the
:blkwht routine which stores the color value, counts the number of color
values in a row, and then stores the value as the repeating byte; then
loops for more.

If the screen byte is a $2A, $55, $AA, or $D5 then there is a possible
pattern so the program branches to the appropriate color routine which
checks the next byte to try and match a color pattern, then if a color
pattern is found it counts the number of patterns in a row and stores the
value as the repeating byte; then loops for more.

That's it for the compression routine.  Now for the decompression routine.


Unpack
             lda    #>SCREEN             ; point to hires screen 1
             ldx    #<SCREEN
             sta    Picture+1
             stx    Picture

             lda    #>BUFFER             ; point to data buffer
             ldx    #<BUFFER
             sta    Data+1
             stx    Data

             ldy    #0
:NewByte

             lda    (Data),y             ; load the data byte
             bmi    :high
             beq    :blkwht              ; $00, $80, $7F, $FF repeat
             cmp    #Green               ; possible Green Pattern
             beq    :green
             cmp    #Purple              ; possible Purple Pattern
             beq    :purple
             cmp    #White1
             beq    :blkwht
             bpl    :store
:high
             cmp    #Black2
             beq    :blkwht
             cmp    #Blue                ; possible Blue pattern
             beq    :blue
             cmp    #Red                 ; possible Red pattern
             beq    :red
             cmp    #White2
             beq    :blkwht

:store       sta    (Picture),y          ; store screen byte
             jsr    NextData
             jsr    NextPic
             bcs    :finished            ; carry set = finished
             bcc    :NewByte             ; always

:green       tax
             iny                         ; is this a green pattern?
             sta    PtrnByte1
             lda    (Data),y
             cmp    #Purple
             bne    :pstore
             sta    PtrnByte2
             jsr    ScreenPtrn           ; store green pattern
             bcs    :finished
             bcc    :NewByte             ; always

:purple      tax
             iny                         ; is this a purple pattern?
             sta    PtrnByte1
             lda    (Data),y
             cmp    #Green
             bne    :pstore
             sta    PtrnByte2
             jsr    ScreenPtrn           ; store purple pattern
             bcs    :finished
             bcc    :NewByte             ; always

:red         tax
             iny                         ; is this a red pattern?
             sta    PtrnByte1
             lda    (Data),y
             cmp    #Blue
             bne    :pstore
             sta    PtrnByte2
             jsr    ScreenPtrn           ; store red pattern
             bcs    :finished
             bcc    :NewByte             ; always

:blue        tax
             iny                         ; is this a blue pattern?
             sta    PtrnByte1
             lda    (Data),y
             cmp    #Red
             bne    :pstore
             sta    PtrnByte2
             jsr    ScreenPtrn           ; store blue pattern
             bcs    :finished
             bcc    :NewByte             ; always

:finished    rts

:blkwht      pha
             jsr    NextData             ; get repeat byte
             lda    (Data),y
             jsr    NextData
             tax                         ; and use as counter
             pla

:repeat      sta    (Picture),y          ; store to screen
             jsr    NextPic
             bcs    :finished
             dex
             bne    :repeat              ; loop
             jmp    :NewByte

:pstore      dey
             txa
             jmp    :store



ScreenPtrn
             jsr    NextData             ; grap repeat counter
             jsr    NextData
             ldy    #0
             lda    (Data),y
             tax
             jsr    NextData
:Ptrnloop
             ldy    #0                   ; store pattern to screen
             lda    PtrnByte1
             sta    (Picture),y
             iny
             lda    PtrnByte2
             sta    (Picture),y
             dey
             jsr    NextPic
             jsr    NextPic
             bcs    :out
             dex                         ; pattern loop
             bne    :Ptrnloop
             clc
:out         rts


The unpack (or decompress) routine starts just as the compression
routines did.  It sets up the Picture and Data pointers.  This time it
reads the Data byte and compares it to see if it is a $00, $80, $7F, or
$FF.  If it is one of these bytes then it grabs the repeating byte and
stores that many of the color value to the screen (or unpack address, which
happens to be hires screen one).  Then loops for more.

Just like the compression routine, again, when a color pattern is found, it
is stored to the screen as many times as the repeat value.

That's it!  My compression routines are not very complex but they work very
fast and very well for hires graphics.




            >>>  THE PROGRAMS IN THE PIC.COMP10.BXY ARCHIVE  <<<
            """"""""""""""""""""""""""""""""""""""""""""""""""""

All the programs and utilities are freeware, including the "dirty" graphics
that I "quickly" drew to demonstrate my routines.


PIC.COMPRESSOR   - This is the main compression program.  It allows you to
''''''''''''''     choose and load a hi-res graphic, compress it, and then
                   give you the option to save it and watch it decompress.
                   Use this program to compress all your pictures.

UNPACK.TEST      - This program will search the CRUNCHED subdirectory and
'''''''''''        load and unpack all the compressed picture files to the
                   screen.  It works like a slide show.

SCREEN.HOLES     - Little program I used while trying to find all those
''''''''''''       screen holes.

CRUNCH           - This is the machine language compression and unpack
''''''             routines.  It does all the compressing and decompressing
                   because of its speed.

UNPACK           - This is ONLY the unpack routine.  If you write a program
''''''             that needs to load and unpack compressed pictures, then
                   this is all you need.  You don't need the compressor
                   because you won't be compressing pictures, you'll just
                   unpack them.



DIRECTORY STRUCTURE   The way the programs are set up now, they will look
"""""""""""""""""""   for picture files in the subdirectory called PICS.
When the compression program saves the crunched picture it will save it
in the subdirectory called CRUNCHED with the extension .PCC.  So every
picture that you would like to crunch must be copied into the PICS
subdirectory.


TECHNICAL BABBLE   The way the routines are set up now, the compressed
""""""""""""""""   picture must be loaded onto hi-res screen 2 ($4000) and
it gets unpacked to hi-res screen 1 ($2000).  The compressing/unpacking
routines are at $7000 and $7003.  After loading CRUNCH, a CALL to 28672
will compress the picture on screen 1 to screen 2 and a CALL to 28675
will unpack the compressed picture on screen 2 to screen 1.

After loading UNPACK, it will reside at $7000 also, except that only one
CALL is used.  A CALL to 28672 will unpack the compressed picture
residing on screen 2 to screen 1.


SOURCE CODE   The source code to the routines was written with the MERLIN """""""""""   assembler.  The CRUNCH.S source and UNPACK.S source may be
modified to suit your needs.  You can change the compile address (ORG) to
something else if you'd like the (un)compression routines to reside
somewhere else in memory.  You can also change the values of "Picture"
and "Data" to tell the routines where to look for the compressed picture
and where to uncompress the picture to.  You may want to set up a "load"
buffer where the compressed picture will be loaded and then unpack it to
either of the hi-res screens.  It's up to you.

The source code is fully commented therefor I think that you will find it
very interesting to browse through and read all the other technical junk as
well.



                               [*][*][*]


    We want your  articles!  If you want  to write an article for
    GEnieLamp A2Pro, then  contact  the editor,  A2PRO.GELAMP for
    more information.  We pay for articles with usage credits.


                               [*][*][*]



[EOA]
[HEY]//////////////////////////////
              HEY MISTER POSTMAN /
/////////////////////////////////
Is That A Letter For Me?
""""""""""""""""""""""""
By Tim Buchheim
 [A2PRO.GELAMP]


    o   BULLETIN BOARD HOT SPOTS

         o   WHAT'S NEW

              o   PROGRAMMERS' TIPS

                   o   MESSAGE SPOTLIGHT                             




                     >>>  BULLETIN BOARD HOT SPOTS  <<<
                     """"""""""""""""""""""""""""""""""
                        ~ Where All the Action Is! ~


 [*]  CAT 2,  TOP 5,  MSG {59}.....Using the Merlin 8 assembler
 [*]  CAT 2,  TOP 8,  MSG {43}.....Assembly language and AppleSoft BASIC
 [*]  CAT 3,  TOP 4,  MSG {113}....The Merlin 16+ Assembler
 [*]  CAT 3,  TOP 19, MSG {138}....General Assembly Questions
 [*]  CAT 11, TOP 8,  MSG {111}....Programming Algorithms and Structures





                           >>>  WHAT'S NEW  <<<
                           """"""""""""""""""""
                            ~ Announcements ~


A HALLOWEEN VISITOR   BOO!  
"""""""""""""""""""
I am sure programmers just love computer goblins <g>

                    (SKELETON, CAT1, TOP2, MSG:211/M530)





                        >>>  PROGRAMMERS' TIPS  <<<
                        """""""""""""""""""""""""""
                    ~ Helpful Advice from the Experts ~



STARTING SOURCEROR   Help!  My Merlin-8 manual is packed away and I cannot
""""""""""""""""""   remember...

How do I start Sourceror?  I remember the BRUN SOURCER/OBJ, but then what?

                    (PAUL.RSM, CAT2, TOP5, MSG:59/M530)



>>>>>   Paul,
"""""
 1.  Load the program to be disassembled.
 2.  BRUN SOURCEROR
 3.  Accept the $2500 (default) address for the source file.
 4.  Hit <return> if the loaded program is at its "running location"

 Is that enough?

 ...John at Wood-n-Shavings
   _____
  /     \
  (=====)
  \___+_/
      !... Hans
                    (H.HAUMANN, CAT2, TOP5, MSG:61/M530)



<<<<<   I found a friend's Merlin manual.  After BRUN SOURCER/OBJ, enter
"""""   the editor.  Kill the 80 column screen with Esc Ctrl-Q. Type USER.

                    (PAUL.RSM, CAT2, TOP5, MSG:62/M530)





SCROLLING TEXT   I need to be able to scroll the IIe 40-column text screen
""""""""""""""   upwards.  Does anyone have or know of a routine that can
do that for me?

This looks comparatively trivial to do, and I sat down to write the code,
only to discover that I have nearly completely forgotten how to code 6502
assembly.  Use it or lose it. <sigh>

I can relearn assembly, but I would rather get this project on the road
=now=. <g>

TomZ
                     (A2.TOMZ, CAT2, TOP8, MSG:43/M530)



<<<<<   >I need to be able to scroll the IIe 40-column text screen upwards.
"""""
Oops.  I =meant= to say DOWNwards.  It's not hard to get it to scroll
upwards.  <g>

TomZ
                    (A2.TOMZ, CAT2, TOP8, MSG:44/M530)



>>>>>   First, I've never done this so I'm speculating, but...
"""""
If you want to scroll downward and back upward, as in a word processor
file, then maybe you need a buffer with the text properly broken into
line-length sections.  Then it's a small matter to re-draw the screen by
shifting pointers.  I'm sure that there is a better way to do this. ;)

Will you control the text content, or will it be input by the user?

Charlie
                    (A2.CHARLIE, CAT2, TOP8, MSG:45/M530)



<<<<<   The program would be doing all writing to the screen. This is
"""""   intended to be an arcade effect for an Eamon game in development.

All I need is a routine that will write each line to the line below it.
This was once =well= within my capabilities as an assembly user, but I
haven't written a line of assembly in several years and find that I have
totally lost everything I once knew on the subject. (I find this
discovery to be extremely depressing, BTW)

If nobody has such a routine handy, we can work around it OK. We're not
even sure we want to do it that way.

TomZ
                    (A2.TOMZ, CAT2, TOP8, MSG:46/M530)



>>>>>   Maybe this will help...
"""""
First push the registers to the stack to store them so that you can restore
them after you are finished.

PHA
TYA
PHA
TXA
PHA

You can also store any other flags, etc. that way.

Next, you'll need a routine for locating the cursor. Load the x register
with the horizontal cursor location, and the y register with the vertical
location. Then JSR GOTOXY

GOTOXY    DEX       ;go back one for range
          STX CH    ;store horiz. location  CH = $24
          DEY       ;go back one for range
          TYA
          PHA       ;calculate base address
          LSR       ; based on BASCALC ($FBC1)
          AND #3
          ORA #4
          STA BASH  ;BASH = $29
          PLA
          AND #$18
          BCC :1
          ADC #$7F
:1        STA BASL  ;BASL = $28
          ASL
          ASL
          ORA BASL
          STA BASL
          RTS

Next set up a counter to use to loop through the lines from 23 to 2.

BEGIN     LDX #1
          STX HOR   :HOR = $06
          LDX #23
          STX VER   ;VER = $07
:1        LDX HOR
          LDY VER
          JSR GOTOXY
          LDY CH    ;horiz. pos
:2        LDX HOR
          LDA (BASL),Y   ;get character on screen
          STA BUFFER,X   ;BUFFER = $200
          INC HOR
          INC CH
          LDY CH
          CPY #40   ;finished with line?
          BNE :2
          LDX #1
          STX HOR
          LDX VER
          INX
          STX VER
          JSR GOTOXY
          LDY CH
:3        LDX HOR
          LDA BUFFER,X
          STA (BASL),Y
          INC HOR
          INC CH
          LDY CH
          CPY #40
          BNE :3
          LDX #1
          STX HOR
          LDX VER
          DEX
          DEX
          STX VER
          CPX #1
          BEQ :4
          JMP :1
:4        RTS

After this you will have to place the new line 1 message on line 1. Be sure
to restore your registers when you are done.

Hope this helps.

Charlie
                     (A2.CHARLIE, CAT2, TOP8, MSG:47/M530)



>>>>>   That'll get you up and running, but if you decide to go with it
"""""   then you'll probably want to speed it up. BTW you didn't mention if
it should respect the text window or not; Charlie's routine uses the
numbers for the whole screen.

Todd Whitesel
                    (A2PRO.TODDPW, CAT2, TOP8, MSG:48/M530)



>>>>>   Hey Tom!!
"""""
I wrote a blazingly fast downscroll routine for use in a project for
Softdisk 8-bit, but they ceased publication and I haven't finished the
program yet.  The project was the ProDOS version of Electric Duet and it
uses the 40-column text mode exclusively, written in 6502 opcodes so it's
compatible on all Apple II's!!  This is so fast because I use text screen
row tables instead of computing the address.

All you need to do here is make sure Top, Bottom, Left, and Right are set
to the values to define the text window, normally they are setup for full
screen, but this routine allows you to scroll ANY portion of the text
screen!  The neat thing about this routine is that after the text window is
scrolled, the top line is filled with spaces.

Charlies' routine looks as if it will work, but if you want speed (usually
arcade style games need the fastest code possible) then try my routine! :)

Have fun!
- Russ

P.S.  If you'd rather not type this in, I'll be happy to shoot the source
code file to you via attached file in email.




ptr       equ  $06  ; general usage pointer (trashable)

Left      equ  $20  ; left margin of text window
Right     equ  $21  ; right margin of text window
Top       equ  $22  ; top of text window
Bottom    equ  $23  ; bottom of text window

zp        equ  $eb  ; general zero page (trashable)



Downscroll
          lda  Bottom    ; start at bottom of text window
          sta  zp
          dec  zp
:Next_Row
          ldy  zp        ; get current row
          lda  LOTAB,y   ; set up "from" copy address
          sta  :downmod+1
          lda  HITAB,y
          sta  :downmod+2
          dec  zp        ; get previous row address
          ldy  zp        ; set up "to" copy address
          lda  LOTAB,y
          sta  ptr
          lda  HITAB,y
          sta  ptr+1

          ldy  Left      ; start at left of text window
          dey
:Do_Row
          lda  (ptr),y   ; get screen byte
:downmod  sta  $FFFF,y   ; store one line down (self modified!)
          cpy  Right     ; finished row?
          bne  :Do_Row   ; nope, keep going

          lda  Top       ; at top of text window?
          cmp  zp
          bne  :Next_Row ; nope, do next screen row

Blankline
          lda  #" "      ; fill with spaces character
          ldy  Left      ; start at left of text window
:Blank
          sta  (ptr),y   ; put space there
          iny
          cpy  Right     ; finished row?
          bne  :Blank    ; nope, keep going

          rts            ; ok, finished



LOTAB     hex  0080008000800080
          hex  28a828a828a828a8
          hex  50d050d050d050d0
HITAB     hex  0404050506060707
          hex  0404050506060707
          hex  0404050506060707

                     (R.NIELSON1, CAT2, TOP8, MSG49/M530)



>>>>>   Use Russ' routine. :)  Mine was just a quick hack to get you
"""""   heading in the right direction; his is good. :)

Charlie
                    (A2.CHARLIE, CAT2, TOP8, MSG:51/M530)



>>>>>   Here's a slightly tweaked up version of Russell's screen downscroll
"""""   routine that's a tad smaller, a tad faster, and missing an infinite
loop bug :)

Note that this uses an additional pair of zero page locations ($FE,$FF)
which I've found are typically safe to grab... Also the Blankline routine
is no longer externally callable.


     case se   ;enable case sensitivity
     tr   on
     tr   adr
     xc   off  ;kill 65C02/802/816 ops
     org  $900 ;or wherever...

ptr  equ  $06  ;general usage pointer (trashable)
zp   equ  $EB  ;general zero page (trashable)
XtraZP    equ  $FE  ;Russ didn't use this originally.

Left equ  $20  ;left margin of text window
Right     equ  $21  ;right margin of text window
Top  equ  $22  ;top of text window
Bottom    equ  $23  ;bottom of text window

Downscroll
     ldx  Bottom    ;get bottom of current window
     dex       ;refer to prev line

 ]LnLp     lda  LOTAB,x   ;set up the "Get" pointer
     sta  ptr
     lda  HITAB,x
     sta  ptr+1

     dex  ;get previous line number
     stx  zp   ;prep for 'nother pass

     lda  LOTAB,x   ;and the "Put" ptr...
     sta  XtraZP
     lda  HITAB,x
     sta  XtraZP+1

     ldy  Left ;start at left of text window
]MvLp     dey
     lda  (ptr),y   ;get screen byte
     sta  (XtraZP),y     ;store one line down (self modified!)
     cpy  Right     ;finished line?
     bne  ]MvLp     ;nope, so loop

     ldx  zp   ;assume another loop needed...
     cpx  Top  ;at top of window yet?
     bne  ]LnLp     ;nope, do next screen row

     lda  #" " ;fill with spaces character
]Clr sta  (ptr),y   ;put space there
     dey
     cpy  Left ;finished row?
     bne  ]Clr ;nope, keep going
     rts  ;ok, finished

LOTAB     hex  0080008000800080
     hex  28A828A828A828A8
     hex  50D050D050D050D0

HITAB     hex  0404050506060707
     hex  0404050506060707
     hex  0404050506060707

 -Harold
(hope the formatting comes out Ok...)

                    (HAROLD.H, CAT2, TOP8, MSG:51/M530)



>>>>>   Charlie,  your quick hack was a good one!  The reason I've never
"""""   used the BASCalc monitor routines is because I have a habit of
doing everything on my own, and in my own way... just so I can customize
any routine I write to do EXACTLY what I need it to do. :)

                   (R.NIELSON1, CAT2, TOP8, MSG:53/M530)

>>>>>   > and missing an infinite loop bug :)
"""""
I KNEW IT!! Ratz!  I posted that routine directly from my project code
but there was a little editing that I had to do to the code here in the
post.  In my original downscroll routine I had certain columns of the
screen that didn't get scrolled (they were data dividers) so I had the
routine skip these specified columns.  I edited out the column checking
code from the routine and I must've done it hastily and left an infinite
loop in there... thanks for spotting it and reposted a better version
Harold.

The reason the Blankline routine was external was because it was used by
the Downscroll _and_ Upscroll routines, which saved valuable bytes in the
object code, because I was running low on space.

Anyway,
Cool!
                   (R.NIELSON1, CAT2, TOP8, MSG:54/M530)





>>>>>   Harold,
"""""
Sorry, but your version doesn't work.  I loaded it into Merlin, assembled
it, tested it, and it just fills the screen with random characters, and I
can see why.   :)

I can see a couple of problems right away:

      ldy  Left     ;start at left of text window
 ]MvLp
      dey            <====== DEY???
      lda  (ptr),y   ;get screen byte   <===== from ptr???
      sta  (XtraZP),y     ;store one line down (self modified!)
      cpy  Right     ;finished line?
      bne  ]MvLp     ;nope, so loop

You are starting at the Left margin, why would you DEY?  And, you have the
to pointers switched, you want to grab data from XtraZP and place at ptr. 
This should be:

      ldy  Left     ;start at left of text window
      dey
 ]MvLp
      iny
      lda  (XtraZP),y   ;get screen byte
      sta  (ptr),y     ;store one line down (self modified!)
      cpy  Right     ;finished line?
      bne  ]MvLp     ;nope, so loop

Tony,  here's my routine again without the infinite loop.



Downscroll
          lda  Bottom    ; start at bottom of text window
          sta  zp
:Next_Row
          dec  zp
          ldy  zp        ; get current row
          lda  LOTAB,y   ; set up "from" copy address
          sta  :downmod+1
          lda  HITAB,y
          sta  :downmod+2
          dec  zp        ; get previous row address
          ldy  zp        ; set up "to" copy address
          lda  LOTAB,y
          sta  ptr
          lda  HITAB,y
          sta  ptr+1

          ldy  Left      ; start at left of text window
          dey
:Do_Row
          iny            ; <==== this was the missing INY  :)
          lda  (ptr),y   ; get screen byte
:downmod  sta  $FFFF,y   ; store one line down (self modified!)
          cpy  Right     ; finished row?
          bne  :Do_Row   ; nope, keep going

          lda  Top       ; at top of text window?
          cmp  zp
          bne  :Next_Row ; nope, do next screen row

Blankline
          lda  #" "      ; fill with spaces character
          ldy  Left      ; start at left of text window
:Blank
          sta  (ptr),y   ; put space there
          iny
          cpy  Right     ; finished row?
          bne  :Blank    ; nope, keep going

          rts            ; ok, finished

                    (R.NIELSON1, CAT2, TOP8, MSG:56/M530)



>>>>>   Russell,
"""""
>> and missing an infinite loop bug :)

<< I KNEW IT!! Ratz! 

Hehehe, I've been there too (as you proceed to point out :)

Infact it seems that I'm there again... sigh.

>> The reason the Blankline routine was external was because it was used
>> by the Downscroll _and_ Upscroll routines, which saved valuable bytes in
>> the object code, because I was running low on space.

I suspected that might have been the case originally.

>> You are starting at the Left margin, why would you DEY?

uhm... Dyslexic Register Command Syndrome? ;-)

>> And, you have the to pointers switched, you want to grab data from
>> XtraZP and place at ptr.

Drat! I hate making stupid errors like that... (came about when I changed
your code from self modifying to zpage ptr)

Speaking of "saving valuable bytes"... Using a pair of Zpage locs that are
known to be expendable (instead of self modifying object) comes out several
bytes smaller (and faster by a few cycles too :) The locs that are used by
the monitor's RdKey routine (for the pseudo random number generator) are
free for the taking if you're not making use of them anyway. [a point I
often forget about, so I figure others might miss this too]

Take another look at my entry code... at least I got that part right, it's
tight enough to make a duck float ;-) {s quack}

-Harold
                    (HAROLD.H, CAT2, TOP8, MSG:57/M530)



>>>>>   Harold, using Zpage instead of self-modifying absolute only makes
"""""   the code faster if the loop executes just once. On most text
windows, you're executing the loop upwards of 10 times, so saving cycles
in the loop at the expense of the setup code is good from a speed standpoint.

If you really want to crank for speed, I'd recommend two things:

    1. use self-modifying absolute for both pointers

This saves you 2 cycles per loop over using Zpage for both, but costs 4 in
setup (1 from each ZP store changed to an absolute store). It breaks even
when the window is 2 wide and wins for anything wider.

    2. add "Left" to the pointers and loop from "Right-Left" down to 0

This eliminates a CPY from the loop, saving you 3 cycles times the width of
the window, but costs 15 cycles in setup. It breaks even when the window is 5
wide and wins for anything wider.

These changes would give you a core section that looked something like:

       ldx line
       clc
       lda lotab,x
       adc Left
       sta labld+1
       lda hitab,x
       sta labld+2
       lda lotab+1,x
       adc Left          ;carry already clear, from previous ADC
       sta labst+1
       lda hitab+1,x
       sta labst+2
       sec
       lda Right
       sbc Left
       tay
lp:
labld: lda $FFFF,y
labst: sta $FFFF,y
       dey
       bpl lp

Todd Whitesel
                  (A2PRO.TODDPW, CAT2, TOP8, MSG:58/M530)



>>>>>   Todd,
"""""
Nice explanation of execution cycle time and setup/overhead time.  Cool
example too.  :)

                    (R.NIELSON1, CAT2, TOP8, MSG:59/M530)



>>>>>   I may be off base here, but assuming you have an enhanced //e can't
"""""   you turn on the enhanced video firmware (PR#3), issue a CNTL-Q for
40 column screen and use the CNTL-V to scroll down and CNTL-W to scroll
up??

It's been a long time since I played with this but the information is in
the looseleaf "About Your Enhanced Apple IIe: Programmer's Guide" manual
that came with the //e Enhancement kit.

Bob, AF6C
                    (R.ECKWEILER, CAT2, TOP8, MSG:61/M530)





RESIZING YOUR STACK   Hi Assembly Gurus:
"""""""""""""""""""
I have written a couple of CDAs (in Merlin 16+); then I wrote a memory
query utility for GNO/ME THEN I obtained a pre-written GNO/ME mem util
(written in C).

Using these I found that I am using 65%+ of stack under GNO/ME and my
CDAs are using 4K each.

Now the question ... under assembly programs like Merlin 16+, how do I
control the allocated stack size.  Ok, how do I do it under ORCA/M as
well!!!

The pragma stacksize give me control under ORCA/C.

The Assembly manuals (Merlin and ORCA/M) mention the defaults BUT not how
to change them.

Thanks in advance!

                                        Doug M.

                    (D.MITTON, CAT3, TOP4, MSG:113/M530)



>>>>>   You override the GS/OS default stack size of 4k by linking a stack
"""""   segment into your program.  I don't know how to create a stack
segment, though.

for more information about stack/direct-page segments, see pages 38-39 and
476-477 in the _GS/OS Reference_.

                 (A2PRO.GELAMP, CAT3, TOP4, MSG:114/M530)


 
>>>>>   Doug,
"""""
Here is a piece of code that explains what I've been able to do.



    typ  TOL
    lkv  2

    asm  stuff.s
    asm  dp.s

    lnk  stuff.l

    sav  stuff

    knd  $12       ;"direct-page/stack" object segment  as mentioned
                   ;in Apple IIGS GS/OS Reference manual.  Page 37.
    lnk  dp.l
    sav dp



Next file



    typ  TOL

    rel

    ds   $200                ;Makes 2 pages of direct page space

    sav  dp.L




Next file



    type TOL

    rel

                             ;stuff's stuff

    sav  stuff.L




Clay

Warning!  Opinions will change due to new facts.
Clayburn W. Juniel, III - Effective Software Solutions
clay1@primenet.com

                (C.JUNIEL, CAT3, TOP4, MSG:115/M530)



>>>>>   And, since you asked, it's pretty much the same under ORCA/M.  The
"""""   details are in the manual; see the KIND directive on page 328 and
the various kind fields on page 490.  You can also do a lot more than just
create a stack segment, and I suspect Merlin can, too.

And now, back to our regularly featured assembler...

Mike Westerfield
                     (BYTEWORKS, CAT3, TOP4, MSG:116/M530)



>>>>>   Thanks for the information on creating a DP segment in Merlin 16+
"""""   (and ORCA/M), it was exactly what I was looking for.

One additional point to any other interested parties, make sure you are using
Linker.XL (lkv 2) for the previous examples to work.  My installation
defaulted to Linker.GS which was perfect for my CDAs and ProDOS8 stuff but
not for this.

ORCA/M was a little more straight forward to implement once I figured out
what was going on BUT I still don't think I would have gotten either out of
the manual(s).  (I know, they are for reference, not tutorial!!!! :-))

Thanks Again!!!

                                               Doug M.

                     (D.MITTON, CAT3, TOP4, MSG:117/M530)





LINEAR REGRESSION   Mike W,
"""""""""""""""""
I'd like to duplicate the curve fit function used by Quick Click Calc in a
small project. On p. 51 of the QCC manual, you give the equation for the
first, second, and third order fits. The third order fit is given as:

               2     3
y = A + Bx + Cx  + Dx

This looks a lot like a cubic polynomial expression for a spline function
(although the examples I've seen reverse the order of the terms). If this
is a spline function, then what basis matrix are you using? If not, what
are the A B C and D coefficients?

But the manual mentions that this is a "linear regression"--a term I
haven't heard of before. Worse, I can't find it in any of my books,
including a fairly recent college Algebra & Trig textbook. Is it safe to
assume that the coefficients are the dataset's y-values i, i+1, i+2, and
i+3?

Can you help me out?

Michael
                    (ANIMASIA, CAT11, TOP8, MSG:111/M530)



>>>>>   Hi Michael,
"""""
Linear regression is a pretty standard method for finding coefficients
yielding the smallest error between a curve fit and a set of data points. I
could cite a gob of sources, but most of the books I learned from (and
still use) are 20 years old, so you might have trouble finding them.  Try
looking through any halfway decent college probability & statistics text,
vurtually any data analysis book for the physical sciences, or a linear
algebra text that is engineering oriented, rather than oriented towards
theoretical mathematics.

I'll try to give you a quick version here, but do try to find the books--
among other things, they will tell you how to figure the error in the fit!

You basically create two matrices.  One is a cube; it has the sum of the
independent variable (x in most notations) raised to various powers. The
power starts at 0 in the top left position, and you add one across the
top row and left column.  The power for the interior values is the sum of
the power to the top and left.  So, showing only the powers in the
correct spot, the cubic array looks like this (ASCII is a pain for matrices
with powers; write it on a sheet of paper :)

  0  1  2  3  4  ...
  1  2  3  4  5
  2  3  4  5  6
  3  4  5  6  7
  4  5  6  7  8

You can keep going as long as you like.  The matrix I've shown is for a 4th
order polynomial fit.  To actually calculate the terms, you sum the
values raised to the power I've shown.  Since I can't use mathematical
notation, I'll use Pascal.  :)  In this case, all of the values are
stored in two arrays, x[size] and y[size].  So to compute the value for 4
in the array, you would sum all of the x values raised to the 4th power,
like this:

   s4 := 0.0;
   for i := 1 to size do
      s4 := s4 + sqr(sqr(x[i]));

The second array is a column (or a vector).  It's the sum of the
dependent variable times a power of the independent variable.  The powers
for the independent variable are the same as for the left column of the
square matrix.  Calculating the third term down would go something  like
this:

   sy2 := 0.0;
   for i := 1 to size do
      sy2 := sy2 + y[i]*sqr(x[i]);

There is a third matrix; it contains the coefficients for the polinomial.
From the manual, that's A, B, C, etc.  It's a column, too, just like the
second one.  The last step is to combine these equations into a matrix
equality.  Calling the square one S, the coefficients c, and the second
matrix with the x and y powers n, the equation is

   Sc = n

You solve this set of simultaneous equations for the coefficients.  For
higher or lower order polinomials, simply adjust the size of the matrices.

CAUTION:  The equations are not well behaved.  You can get numerical
''''''''  errors, like divide by zero, with many off the shelf equation
solvers.  Guard for that!

Finally, if this didn't make much sense, rest assured that it's a lot
easier with a blackboard or book, where you can use matrix notation,
powers, and summation signs.  :)  If this confused you, find a discussion
in a book.

Mike Westerfield
                    (BYTEWORKS, CAT11, TOP8, MSG:112/M530)



<<<<<   Mike--
"""""
Excellent overview! I actually understood your ASCII power notation matrice
and your Pascal sources, which is not surprising because I remember your
Call -APPLE articles being so well written. I feel I have a much better
idea of what I have to work towards than before. However, I still don't see
how the three matrices relate to eachother to produce the results that they
do. So it looks like I'm going to stop at the university library tomorrow
to investiage your sources; "data analysis for physcial sciences" sounds
like a good bet. I'll let you know how it works out. Thank you!

Michael
                    (ANIMASIA, CAT11, TOP8, MSG:113/M530)



>>>>>   Hi Michael,
"""""
If you got everything but how to solve the matrix equation, concentrate
on linear algebra books.  In fact, you might even want to find one of those
encyclopedia sized books on engineering mathematics that I assume are still
used to cover 4-6 math courses in an engineering curriculum.  Concetrate on
simultaneous solutions to multiple equations, which is what you are
actually doing.

Once you get to the point where you're actually doing it, switch to a
good introductory text on numerical analysis, or check out something like
Sedgewick's Algorithms book.  All will have better methods for actually
solving the matrix equations than the math books are likely to show,
since the methods that work well on a computer are a little different
from the ones that work well by hand.

Mike Westerfield
                    (BYTEWORKS, CAT11, TOP8, MSG:114/M530)



<<<<<   Mike,
"""""
I spent the better part of the day at the library looking through the types
of books you suggested. You were right; there are tons of books which cover
linear regression in many different fields. Some good. Some bad. I
backtracked and began investigating how to find the closest fit to a first
order function and even that slowed me down. Not surprisingly, I found
myself having to relearn much of the matrix operations for solving
simultaneous solutions. So it looks like I'll have to go back and start
from the beginning. I'll check into "Sedgewick's Algorithms" too. Still,
I'm enjoying this because it's no longer abstract theory.

Michael
                    (ANIMASIA, CAT11, TOP8, MSG:115/M530)



>>>>>   Cool.  FWIW, linear regression was the first thing I ever did with
"""""   a matrix (back in high school) and it remains one of the most-used,
and IMHO, most usefull things I've ever done with a matrix.  :)  And in
physics and math, I've seen quite a few matricies.

Mike Westerfield
                    (BYTEWORKS, CAT11, TOP8, MSG:116/M530)



>>>>>   One book that covers this subject fairly well is _Advanced
"""""   Engineering Mathematics_ by Erwin Kreyszig. It's an older college
text book (1964 - fourth edition) but should be able to be found in used
book stores. What I like about this book is that it contains a lot of
practical examples instead of just dry theory.

Another book that may be of interest is "BASIC Computer Programs in Science
and Engineering" by Jules Gilder 1980 (A Hayden PaperBack). It is full of
BASIC programs.  Chapter 4 is "Matrix Mathematics" and Chapter 5 is "Data
Analysis" including linear a least-squares fit and various logarithmic
least-squares fit programs

In the seventies and early eighties I wrote many programs on a Tektronix
4054 desktop computer.  It had built-in matrix functions and you could
solve multiple equations with multiple unknowns with one BASIC call.

Bob, AF6C
                    (R.ECKWEILER, CAT11, TOP8, MSG:117/M530)





BEZIER CURVES   Speaking of least-squares fit algorithms, I once had an
"""""""""""""   interest in how Bezier curves were drawn.  You know, a
spline curve where the points can be unordered in both the X and Y axes.
I wanted to, given a completely random set of points, draw a smooth curve
through the points.

Best I ever came up with was limited.  The method would only work if the X
(or Y) coordinates were listed in order (increasing or decreasing).

Does anyone know how these are computed?  I know it can be done, because I've
seen it in some paint/draw programs.

 ...Chris
                    (K.FLYNN, CAT11, TOP8, MSG:120/M530)



>>>>>   Chris,
"""""
Bezier curves are pretty easy to draw once you know how it's done. The
simplest Bezier curve has four points: two endpoints and two handle points
which define the shape of the curve. Image that the following four points
will create a smooth Bezier curve. ep is endpoint and hp is handle point.


                     hp1


        ep1


                                                          ep2




                                hp2

When a Bezier curve is drawn, the drawing algorithm starts drawing from the
first endpoint, ep1, toward the first handle point, hp1, but never actually
touches hp1 because as it goes along, it begins to head toward the next
handle point, hp2. Again, the curve doesn't touch hp2 because it heads
toward the last endpoint, ep2. The curve therefore touches the endpoints
but only heads toward the handle points. The handle points are called
handles because if you drag these handles around, you'll change the shape
of the curve. These are the curves that Postscript uses for its foundation;
same for most any illustration program.

There are two ways you can draw a Bezier curve. The first is to say that a
variable t will be increased from 0 to 1 over series of steps and a basis
matrice function will be solved for x and y with t. You simply connect the
x and y's as you increment t. This is slow and entirely too precise for
drawing on the screen.

The second way is much faster because it recursively splits the Bezier
curve into two smaller Bezier curves until the curves become straight
enough to be approximated by lines. This only uses shifts and adds and
you'll find the source code to this below.

Still, you wanted to know how to connect a whole series of points. That's
easy too. To lengthen a Bezier curve, add three more points: two handles
and an endpoint. Because the last endpoint of the first Bezier is the first
endpoint of the second Bezier, that endpoint is reused. So you need to have
"(curves * 3) + 1" points. Another thing to keep in mind is that to have
the overall Bezier curve look smooth between adjacent sub-curves requires
you to position the two handles on either side of an endpoint to line up in
a straight line across the endpoint. Otherwise, you'll have a sharp bend in
your curve, (which may be what you want too).

However, this won't _completely_ solve your problem because you
specificially wanted to have this curve pass through _all_ of your points.
Well, a Bezier curve, like I mentioned, only passes through the endpoints
but not the handles. There are different types of curves, and the one you
would want to use to pass through all points is a Catmull-Rom curve, which
are harder to draw than Bezier curves because you can't as easily subdivide
them.

But don't let that discourage you because Bezier curves are great and if
you can get them to work (no problem) you're on your way to creating an
illustration program for the GS :)

Michael

(This C source code is old and doesn't use the bit shift operator to divide
by two. This is because I assumed there was a problem with the way Orca/C
generated code if it tried to bit shift a negative number. I wanted to use
negatives because I wanted to have a Cartesian coordinate plane, but this
could easily be solved if you use only the positve quadrant of the plane,
such as screen coordinates. Also, it refers to endpoints as control
points.)

#include <types.h>
#include <quickdraw.h>

#define BezDepth  4    /* greater the depth, the smoother the curve */
#define NumBezPts 17   /* must be >= 2^BezDepth + 1 */
                       /* It's important to note that increasing BezDepth
                          makes smoother curves--up to a point. We reach
                          diminishing returns in increasing BezDepth too
                          much, since the accumulated error of repeated
                          averaging eventually throws the calculations off
                          by one or more pixels. This could be soved by
                          using fixed point math. */

typedef struct {int top, left, bottom, right;} rect2, *rect2ptr;

typedef struct
  {int x, y;} intVector2, intPoint2, *intVector2ptr, *intPoint2ptr;

intPoint2    bezPts [NumBezPts];
intPoint2ptr bezPtsPtr;
int          xCenter, yCenter;

void SubdivideBezier (intPoint2 p0, intPoint2 p1, intPoint2 p2, intPoint2
p3, int depth);
void DrawBezier (intPoint2 ctrl1, intPoint2 hand1, intPoint2 hand2,
intPoint2 ctrl2);


void main (void)
{
rect2     viewPort;
intPoint2 ctrl1, hand1, hand2, ctrl2;

/* Define Bezier curve's points: */
ctrl1.x = -100;  ctrl1.y =  0;     /* Cartesian coordinates */
hand1.x = -30;   hand1.y =  60;
hand2.x =  10;   hand2.y = -80;
ctrl2.x =  100;  ctrl2.y =  0;

GetPortRect ((RectPtr) &viewPort);
xCenter = (viewPort.left + viewPort.right)  / 2;
yCenter = (viewPort.top  + viewPort.bottom) / 2;

SetPenSize (2, 1);
SetPenMode (modeCopy);
SetSolidPenPat (0);

DrawBezier (ctrl1, hand1, hand2, ctrl2);

/* Draw handles as dots: */
MoveTo (hand1.x + xCenter, yCenter - hand1.y);
LineTo (hand1.x + xCenter, yCenter - hand1.y);

MoveTo (hand2.x + xCenter, yCenter - hand2.y);
LineTo (hand2.x + xCenter, yCenter - hand2.y);
}


void DrawBezier (intPoint2 ctrl1, intPoint2 hand1, intPoint2 hand2,
intPoint2 ctrl2)
{
int i;

 bezPtsPtr   = bezPts;
 *bezPtsPtr++ = ctrl1;

SubdivideBezier (ctrl1, hand1, hand2, ctrl2, BezDepth);

MoveTo (bezPts [0].x + xCenter, yCenter - bezPts [0].y);
for (i = 1; i < NumBezPts; i++)
  LineTo (bezPts [i].x + xCenter, yCenter - bezPts [i].y);
}


void SubdivideBezier (intPoint2 p0, intPoint2 p1, intPoint2 p2, intPoint2
p3, int depth)
{
intPoint2 q0, q1, q2, r0, r1, s0;
int       x, y;

if (!depth)
  {
  *bezPtsPtr++ = p3;
  return;
  }

q0.x = (p0.x + p1.x) / 2;  q0.y = (p0.y + p1.y) / 2;
x = q0.x;  y = q0.y;
q1.x = (p1.x + p2.x) / 2;  q1.y = (p1.y + p2.y) / 2;
x = q1.x;  y = q1.y;
q2.x = (p2.x + p3.x) / 2;  q2.y = (p2.y + p3.y) / 2;
x = q2.x;  y = q2.y;

r0.x = (q0.x + q1.x) / 2;  r0.y = (q0.y + q1.y) / 2;
x = r0.x;  y = r0.y;
r1.x = (q1.x + q2.x) / 2;  r1.y = (q1.y + q2.y) / 2;
x = r1.x;  y = r1.y;

s0.x = (r0.x + r1.x) / 2;  s0.y = (r0.y + r1.y) / 2;
x = s0.x;  y = s0.y;

SubdivideBezier (p0, q0, r0, s0, --depth);  /* subdivide into left half */
SubdivideBezier (s0, r1, q2, p3,   depth);  /* subdivide into right half */
}

                    (ANIMASIA, CAT11, TOP8, MSG:121/M530)


>>>>>   Oh yeah. I forgot to mention that to compile and use the code you
"""""   can use Prizm's Graphics Output window. Just open that window and 
choose Compile to Memory. It's best to make the Graphics Output window as
big as it can be (Mike- the zoom box on that window doesn't do anything.)
Also, the curve won't look stunningly smooth because of the accumulated
division error inherent in integer math. You'll need to use fixed-point
math to get perfectly smooth curves.

Michael
                    (ANIMASIA, CAT11, TOP8, MSG:122/M530)



                        >>>  MESSAGE SPOTLIGHT  <<<
                        """""""""""""""""""""""""""
                   ~ Important or Interesting Messages ~



65816 IN AN ATARI?   Greetings!  I've got a 65816 transplanted into my
""""""""""""""""""   8-bit Atari (please no flames) and was searching here
for some 65816 assembler examples. This seems to be the biggest collection
of '816 programmers on GEnie; what can you point to?  I've programmed for
over 10 years on the 6502, and was looking for fast signed multiply
routines, etc. Also, since everything here is ".BXY", can anyone suggest a
path to some other archive format like ARC or LZH? Thanks in advance...

                    (JDPOTTER, CAT3, TOP19, MSG:138/M530)



>>>>>   JDPOTTER,
"""""
>> I've got a 65816 transplanted into my 8-bit Atari (please no flames) and
>> was searching here for some 65816 assembler examples.

Hey, no flames from me! How did you get the 816 in the Atari anyway? (by
leaving pin 1 out of the socket?? That's what I did on my IIc, works great!
:))

Most likely most of the source you'll find here for 816's will be for the
Apple IIgs, which won't do you tooo much good... (the IIgs has a "toolbox"
(part rom, part in the OS) that covers a =lot= of ground... math routines
included.)

>> Also, since everything here is ".BXY", can anyone suggest a path to some
>> other archive format like ARC or LZH? Thanks in advance... 

Chances are if some file or other (or more than one :) sounds like a likely
candidate for what you're looking for it could be unpacked by one of the
folks around here and either emailed to you that way, or maybe packed up
using another method... (I think there's a utility around somewheres for
producing ARC files on an Apple II)

-Harold
                    (HAROLD.H, CAT3, TOP19, MSG:139/M530)



>>>>>   There's also a MS-DOS utility to unpack .BXY and .SHK archives
"""""   (both ShrinkIt archives), if that's of any help to you.

Doug
     "As Canadian as possible under the circumstances."--Heather Scott

                    (EDITOR.A2, CAT3, TOP19, MSG:140/M530)



>>>>>   There are some fast math routines for signed and insigned 2, 4 and
"""""   8 byte integer math in the ORCA/M package.  The source code is
available separately as GS-13 ORCA/Sublib Source $25, available from Byte
Works. The files are ASCII files with the SRC file type stamp.  The biggest
problem you would face is getting the files from the Apple IIGS 3.5" disk
they ship on to your computer.  A friend with an Apple ][ or Mac can help.

If you're interested, let me know.  I can send you a catalog; you can at
least get an idea what we have.  I'll need your mailing address if you want
the catalog.

Mike Westerfield
                    (BYTEWORKS, CAT3, TOP19, MSG:141/M530)



<<<<<   Harold.H, I got the 65816 from the guy who bought the rights to all
"""""   ICD Atari 8-bit products.  It's the 65C816 and a PAL mounted in a
socket, plugs directly into my 6502 socket.  I saw some interesting code
tips in the "Optomeisters" topic.  I'm really looking for a 16 x 16 -> 32
bit signed multiply; I was able to adapt some of their fast routines, but
would like to see more.  Thanks.

Jeff
                    (JDPOTTER, CAT3, TOP19, MSG:142/M530)



>>>>>   Jeff,
"""""
> I'm really looking for a 16 x 16 -> 32 bit signed multiply

You might want to check out the "Apple Assembly Lines" archives in the
libraries. They have some _excellent_ articles w/source on all sorts of
algorithms such as various sized multiples. (They even have a 8 x 8 -> 16
bit multiply that executes in 65 cycles!) Search on "AAL" for all the
issues, or "multiply" or "multiplication" for the ones you need.

Michael
                    (ANIMASIA, CAT3, TOP19, MSG:143/M530)






                               [*][*][*]


    While on GEnie,  do you spend  most of  your time downloading
    files?   If  so,  you  may  be  missing  out  some  excellent
    information in the Bulletin Board area.   The messages listed
    above  only  scratch  the  surface of  what's  available  and
    waiting for you in the bulletin board area.

    If you  are serious about your Apple II, the  GEnieLamp staff
    strongly urges  you to give  the bulletin board  area a  try.
    There are literally thousands  of messages posted from people
    like you from around the world.


                               [*][*][*]



[EOA]
[DEV]//////////////////////////////
              DEVELOPER'S CORNER /
/////////////////////////////////
News From The A2Pro Online Developers
"""""""""""""""""""""""""""""""""""""
By Tim Buchheim
 [A2PRO.GELAMP]


    o   ONLINE SUPPORT IN A2Pro

         o   EDIT-16 SUPPORT

              o   USING THE GNO SHELL

                   o   THE SPLAT! SOURCE LEVEL DEBUGGER




                      >>> ONLINE SUPPORT IN A2Pro <<<
                      """""""""""""""""""""""""""""""

     CAT  TOP  COMPANY
     ===  ===  =======
     29   INDEPENDENT DEVELOPERS ONLINE
           2   DYA/DigiSoft Innovations Online
           8   Simplexity Software Online
          14   Quality Computers Q-LABS Online
          20   DreamWorld Software Online
          26   METAL/FV Software Online
          32   Kitchen Sink Software Online
          38   EdIt-16 (Bill Tudor)

     30        PROCYON, INC.
     31        SOFTDISK PUBLISHING
     33        GS+ MAGAZINE
     34        JEM SOFTWARE
     35        PRODEV, INC.
     36        THE BYTE WORKS

     Each month this column feature highlights and news from various
developers who provide support via A2Pro.


                       >>>  EDIT-16 SUPPORT  <<<
                       """""""""""""""""""""""""


EDIT-16 REQUEST   Bill,
"""""""""""""""
Is there anything new to report about Edit-16 or are no more updates planned?

My only real desire is to have it handle files larger than 64k. Other than
that, I can't think of a thing. And if no further improvements are planned, I
can understand that.

Bob
                  (R.FISCHER7, CAT29, TOP38, MSG:108/M530)




                     >>>  USING THE GNO SHELL  <<<
                     """""""""""""""""""""""""""""


SWITCHING PROCESSES   How do you switch processes in GNO? I've found the
"""""""""""""""""""   GNO shell to be very confusing.  Is Edit-16
compatible? I haven't been able to get it to work with the shell yet.  Any
help would be appreciated!

Brian Gillespie, Jaunt! Software

                  (B.GILLESPIE3, CAT30, TOP2, MSG:193/M530)



<<<<<   I've learned some more about switching processes, but how do you
"""""   switch out of the ORCA editor? It eats the Control-Z keypress.
Thanks!

Brian Gillespie, Jaunt! Software

                  (B.GILLESPIE3, CAT30, TOP2, MSG:194/M530)



>>>>>   You need to set the auxtype of the ORCA editor to something (I
"""""   think $DC00 but it should be in the GNO docs somewhere, so don't
trust me, trust them) to tell GNO it needs to handle the input stuff
differently. Maybe someone else here can tell us just what it does
differently?

Todd Whitesel
                  (A2PRO.TODDPW, CAT30, TOP2, MSG:196/M530)



>>>>>   From the GNO Shell User's Manual (Appendix E, Non-Compliant
"""""   applications, page 50): "Setting the auxtype of an application to
$DC00 disables the interrupt driven keyboard buffering and turns off the
GNO/ME cursor.  Desktop programs use the GNO/ME keyboard I/O via the Event
Manager, and thus should NOT have their auxtype changed."

However, I always thought EXE (and S16) files were supposed to follow the
FTN that details the $DBxx auxtype. The ORCA editor has an auxtype of $DB01
(at least mine does.)

 - Tony
                    (A2.TONY, CAT30, TOP2, MSG:197/M530)



>>>>>   >However, I always thought that EXE (and S16) files were supposed
"""""   >to follow the FTN that details the $DBxx auxtype.

They are. :)  But when you use a S16 or EXE program in GNO, it is being
loaded and executed by GNO itself with direct calls to the System Loader
toolset..

Only _QuitGS looks for that $DBxx in the auxtype..  since GNO isn't loading
the program through _QuitGS, it can require the auxtype to be whatever it
needs. (I assume that it properly handles the defined bits in a $DBxx
auxtype, though.)

Note that GNO doesn't require any weird auxtypes for desktop programs..  so
leave them set to whatever is appropriate for the specific app.

                    (A2PRO.GELAMP, CAT30, TOP2, MSG:198/M530)



>>>>>   > Only _QuitGS looks for that $DBxx in the auxtype..
"""""
Okay, so there's no harm in changing EXE auxtypes for files that run on a
shell from $DB01 to $DC00 (ie. the ORCA editor.) However, I wouldn't want
to change a S16 auxtype like that unless I only plan on running the program
from the shell, right?

 - Tony
                    (A2.TONY, CAT30, TOP2, MSG:199/M530)



>>>>>   right, although I would assume that most S16 programs you use
"""""   aren't text programs, and therefore wouldn't need any auxtype
changes. (Programs that use the Event Manager, such as desktop programs,
work fine in GNO, from what I understand.. but I don't have GNO, so I can't
be sure. :)

                  (A2PRO.GELAMP, CAT30, TOP2, MSG:200/M530)



>>>>>   You can't change the auxtype of a S16 file to $DC00 if the file is
"""""   on an HFS volume, due to the way the HFS FST maps between ProDOS
and HFS types.   (At least, not the standard GS/OS way.  Don't know if you
can get around it by mucking with the optionList.)

                   (S.REEVES2, CAT30, TOP2, MSG:202/M530)



>>>>>   huh?  why can't you change the auxtype of a S16 file on an HFS
"""""   volume?  A S16 file with an auxtype of $DC00 would have a creator
type of "pdos" and a file type of "p" $B3 $DC $00

                    (A2PRO.GELAMP, CAT30, TOP2, MSG:203/M530)



>>>>>   The HFS FST won't preserve a non-zero auxtype of a S16 file unless
"""""   it starts with $DB (this is described on page 334 of the
Programmer's Reference for System 6.0).  It seems you can set it to $DC00
by directly changing the Mac filetype to "p" $B3 $DC $00 (via the
optionList), but you must do this manually.  GNO's standard chtyp command
won't do it for you.

                    (S.REEVES2, CA30, TOP2, MSG:204/M530)




>>>>>   yuck.  that's stupid. :(
"""""
                    (A2PRO.GELAMP, CAT30, TOP2, MSG:205/M530)




                   >>>  THE SPLAT! SOURCE LEVEL DEBUGGER  <<<
                   """"""""""""""""""""""""""""""""""""""""""


USING SPLAT!   Hi, I have two questions related to Splat!
""""""""""""

1.) I have searched the manual cover to cover trying to figure out how to
    display strings in hex in the variables window/dialog  a la the 'mem'
    command does in the ORCA debugger.  I am manipulating text, control
    characters and NULL's in char arrays and would like to see the changes
    in hex while stepping through the program. Can I do this with Splat!?  
    Currently I am using Splat! for debugging program control but switch
    over to ORCA debugger to watch the changes in the arrays because I can
    only get the ascii text in double quotes using Splat!.

Which brings me to question 2.

2.) Are there any known problems having Splat! and ORCA debugger in the
    ORCA shell at the same time.  So far I haven't noticed any problems but
    I would like to know ahead of time what to watch out for. 

My setup has the 'shell' version of Splat! installed in ORCA/shell 2.x, and
the ORCA/Debugger init and debugger utilities installed.  I use a script to
run ORCA/D. I 'cmpl +d {program}.cc keep={program}' once, and type 'splat
{program}' to use Splat! or 'debug {program}' to use the ORCA/D.

This, so far, works ok (my programs are ANSI C, text display only, no
toolbox) but I prefer Splat!'s interface to ORCA/D's and want to save the
hassle of jumping from one to the other.

Thanx.

Eric Heim
(of course, by using both there is no spent money wasted :) 

                     (E.HEIM3, CAT30, TOP9, MSG:31/M530)



>>>>>   Eric,
"""""
I'm not familiar with Orca/Debugger's mem command, but I'm afraid you can't
do what you're asking for (showing characters as hex) in Splat! at this
time.  I believe unprintable characters show up either as octal or hex
(it's been a while since I've used it much) but I know that's not what
you're after.

I don't know imagine there would be any problems with the setup you are
running (Orca INIT and Splat! shell version), but it's not something that
I've ever tested and certainly don't guarantee.  If it works, then it
works.  And until there's a major upgrade to Splat! (don't ask), I guess
you'll have to continue to use both to get what you want.  Sorry.

Mike Hackett
                    (M.HACKETT, CAT30, TOP9, MSG:32/M530)



<<<<<   Hi Mike H.,
"""""
Don't be sorry, Splat! is great.  ORCA/Debugger is great.  I'm glad I
have both.  I was just hoping that Splat! had EVERYTHING to save a little
time while trying to fix my latest 'index past the end of array' ;-)

Eric Heim
                    (E.HEIM3, CAT30, TOP9, MSG:33/M530)



>>>>>   Eric,
"""""
> display strings in hex in the variables

Well it *is* possible, but it doesn't look pretty...

Here is a way to see 4 characters in hex from a string. The text characters
are stored in a pointer that doesn't really point to anything. Pointers are
displayed in their hex values. The hex values can also be displayed in
the output window.

Look at BadAddress to see the 4 chars displayed in hex, not what it
points to. It doesn't really point anywhere.:)


#pragma keep "Program"
#pragma debug -1

#include <stdio.h>
#include <string.h>
struct StringPlus
  {
   char SPlus[10];
  };
void main (void)
{
struct StringPlus ASP;
unsigned int x;
/*  Declare address and set to unique numbers  */
unsigned char *BadAddress;
    asm {
         lda #0xFFFF
         sta BadAddress+2
         lda #0xFFFF
         sta BadAddress
        }
strcpy(ASP.SPlus, "5678\n");
ASP.SPlus[6] = 0;
for(x=0;x<10;x++) {
/*  Notice ordering to keep string characters lined up  */
/*  Copy string characters to the hex address for hex display  */
    asm {      
         lda ASP
         sep #0x20
         sta BadAddress+3
         rep #0x20
        }         
    asm {      
         ldx #1
         lda ASP,x
         sep #0x20
         sta BadAddress+2
         rep #0x20
        }         
    asm {      
         ldx #2
         lda ASP,x       
         sep #0x20
         sta BadAddress+1
         rep #0x20
        }         
    asm {      
         ldx #3
         lda ASP,x
         sep #0x20
         sta BadAddress
         rep #0x20
        }         
/*  Increment string chars for viewing change  */
ASP.SPlus[0]++;
ASP.SPlus[1]++;
ASP.SPlus[2]++;
ASP.SPlus[3]++;
/*  Display some of string in hex in output window  */
printf(" Hex=%X, %X\n", ASP.SPlus[0], ASP.SPlus[2]);
                  }
exit(0);
}

More chars can be copied into more hex addresses for display,
but this can be used to view some important ones.

- James - [IMAGE]
                    (J.GRAY38, CAT30, TOP9, MSG:34/M530)



<<<<<   James,
"""""
Thanx for your reply.  

Actually, my interest in looking at the hex in the string was purely for
debugging purposes.  This particular function is a filter for raw data
and somehow (thanks to Splat! and ORCA/Debugger I found the problem) it
was indexing past the end of an array under certain conditions.  The array
is part of a structure and the next element was a pointer that would get
blasted when the indexing went too far.  Easy to fix once I saw what was 
happening :)

Eric Heim
                    (E.HEIM3, CAT30, TOP9, MSG:35/M530)





[EOA]
[LIB]//////////////////////////////
             LIBRARY BIT BONANZA /
/////////////////////////////////
HOT Files You Can Download
""""""""""""""""""""""""""
By Tim Buchheim
 [A2PRO.GELAMP]


    o   GREAT NEW FILES!




                      >>>  GREAT NEW FILES!  <<<
                      """"""""""""""""""""""""""


File #4871  MTL.PUB.SRC.BXY  (ALL)
Uploaded on 10/28/95 by JUST.DAVE
About 124K (d/l time approx. 9 minutes @ 2400 baud)

This file is part of the release of METAL v1.09.07.
It contains the source code that was released with METAL v1.09.07.
Read MTL7.README.TXT (file #25957) in the A2 library for details.



File #4870  FOREACH.BXY  (GS)
Uploaded on 10/19/95 by S.REEVES2
About 13K (d/l time approx. 1 minute @ 2400 baud)

This is a version of the UNIX shells' built-in "foreach" construction, for 
iterating a series of commands over different values of a variable.  It was
written by Sean McAfee (mcafee@umich.edu).  Requires an Apple IIgs and 
GNO 2.0 or higher (works with ORCA/Shell 2.0 too, but ORCA already has an
equivalent command).



File #4868  REZTHINGY.BXY    V1.0B2  (GS)
Uploaded on 10/15/95 by B.WELLS5
About 5K (d/l time under 1 minute @ 2400 baud)

This Spectrum script will allow you to name resources in your REZ source
code and then run the script to generate all the rName resources for each
'named' resource. Cool, eh? :) This is just a very quick hack, so the
only documentation is what appears when you run the script. An example
REZ file is also included.



File #4867  HTMLEDIT.BXY  (GS)
Uploaded on 10/14/95 by C.STILES3
About 81K (d/l time approx. 5 minutes @ 2400 baud)

Obtained from the Internet - source is Nova Scotia user group.  See the
description on A2 for more info, or just donload it and extract the info.
Promotes the use of HTML.  No doc file, but help button is available.



File #4864  PRSET1.0B1.BXY  (GS)
Uploaded on 10/1/95 by R.ECKWEILER
About 19K (d/l time approx. 1 minute @ 2400 baud)

PRSet is an ORCA utility that allows configuring the .PRINTER driver
directly from the ORCA command line or from an exec file.  By putting a
PRSET command in the LOGIN file for ORCA the printer may be configured
automatically each time ORCA is run.  The program allows you to set all the
parameters normally set by the CDA or CDEV programs and has extensive
printer initialization string inputting capabilities.




[EOA]
[LOG]///////////////////////////////
                         LOG OFF //
//////////////////////////////////
GEnieLamp Information
"""""""""""""""""""""

   o   COMMENTS: Contacting GEnieLamp

        o   GEnieLamp STAFF: Who Are We?



GEnieLamp Information   GEnieLamp is published on the 1st of every month
"""""""""""""""""""""   on GEnie page 515.  You can also find GEnieLamp on
the main menus in the following computing RoundTables.


RoundTable      Keyword  GEnie Page     RoundTable      Keyword  GEnie Page
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
DigiPub         DIGIPUB      1395        Atari ST        ST          475
Macintosh       MAC          605         IBM PC          IBMPC       615
Apple II        A2           645         Apple II Dev.   A2PRO       530
Macintosh Dev.  MACPRO       480         Geoworks        GEOWORKS    1050
BBS             BBS          610         CE Software     CESOFTWARE  1005
Mini/Mainframe  MAINFRAME    1145        Programming     PROGRAMMING 1445
Data Comm.      DATACOMM     1450        IBM PC Prog     IBMPCPRO     617
PowerPC         PPC          1435        PowerPCProg     PPCPRO      1440



    GEnieLamp is also distributed on CrossNet and many public and
commercial BBS systems worldwide.

    o To reach GEnieLamp on Internet send mail to genielamp@genie.com

    o Back issues of GEnieLamp are available in the DigiPub RoundTable
      Library #2 on page 1395 (M1395;3).  Internet users should use
      the GEnie gopher (gopher.genie.com) which has most back issues
      (but might be missing a few of them).  After you connect to
      gopher.genie.com, choose the "Magazines and newsletters" item
      and then choose the menu item for the Apple II.

    o GEnieLamp pays for articles submitted and published with online
      GEnie credit time.  Upload submissions in ASCII format to library
      #31 in the DigiPub RoundTable on page 1395 (M1395;3) or Email it to
      GENIELAMP.  On Internet send it to: genielamp@genie.com

    o We welcome and respond to all E-Mail.  To leave comments,
      suggestions or just to say hi, you can contact us in the DigiPub
      RoundTable (M1395) or send GE Mail to John Peters at [GENIELAMP] on
      page 200.

    o If you would like to meet the GEnieLamp staff "live" we meet every
      Wednesday night in the Digi*Pub Real-Time Conference at 9:00 EDT
      (M1395;2).

    o The Digital Publishing RoundTable is for people who are interested
      in pursuing publication of their work electronically on GEnie or via
      disk-based media.  For those looking for online publications, the
      DigiPub Software Libraries offer online magazines, newsletters,
      short-stories, poetry and other various text oriented articles for
      downloading to your computer.  Also available are writers' tools and
      'Hyper-utilties' for text presentation on most computer systems.  In
      the DigiPub Bulletin Board you can converse with people in the
      digital publishing industry, meet editors from some of the top
      electronic publications and get hints and tips on how to go about
      publishing your own digital book.  The DigiPub RoundTable is the
      official online service for the Digital Publishing Association.  To
      get there type DIGIPUB or M1395 at any GEnie prompt.


                         >>> GEnieLamp STAFF <<<
                         """""""""""""""""""""""

 GEnieLamp  o John Peters         [GENIELAMP]    Publisher
 """""""""  o Mike White          [MWHITE]       Managing Editor

  APPLE II  o Doug Cuff           [EDITOR.A2]    EDITOR
  """"""""  o Ray Pasold          [R.PASOLD]     A2 Staff Writer
            o Charlie Hartley     [A2.CHARLIE]   A2 Staff Writer

     A2Pro  o Tim Buchheim        [A2PRO.GELAMP] EDITOR
     """""

     ATARI  o Sheldon H. Winick   [GELAMP.ST]    ATARI EDITOR
     """""  o Bruce Smith         [B.SMITH123]   EDITOR/TX2
            o Mel Motogawa        [M.MOTOGAWA]   Atari Staff Writer
            o Richard Brown       [R.BROWN30]    Atari Staff Writer
            o Al Fasoldt          [A.FASOLDT]    Atari Staff Writer
            o Timothy V. Steed    [T.STEED1]     Atari Staff Writer
            o Lloyd E. Pulley     [LEPULLEY]     Atari Staff Writer

       IBM  o Sharon La Gue       [SHARON.LAMP]  IBM EDITOR
       """  o Tika Carr           [LAMP.MM]      MULTIMEDIA EDITOR
            o Susan M. English    [S.ENGLISH1]   Multimedia Graphics Artist
            o Wayne & Chris Ketner[C.KETNER]     IBM Staff Writers

 MACINTOSH  o Richard Vega        [GELAMP.MAC]   MACINTOSH EDITOR
 """""""""  o Tom Trinko          [T.TRINKO]     Mac Staff Writer
            o Bret Fledderjohn    [FLEDDERJOHN]  Mac Staff Writer
            o Ricky J. Vega       [GELAMP.MAC]   Mac Staff Writer

  POWER PC  o Ben Soulon          [BEN.GELAMP]   POWER PC EDITOR
  """"""""  o Eric Shepherd       [SHEPPY]       Power PC Staff Writer

   WINDOWS  o Bruce Maples        [GELAMP.WIN]   EDITOR
   """""""  o Tika Carr           [LAMP.MM]      Windows Staff Writer

      ETC.  o Jim Lubin           [J.LUBIN]      Add Aladdin Scripts
      """"  o Scott Garrigus      [S.GARRIGUS]   Search-ME!
            o Mike White          [MWHITE]       (oo) / DigiPub SysOp
            o John Peters         [GENIELAMP]    DigiPub SysOp
            o Phil Shapiro        [P.SHAPIRO1]   Contributing Columnist
            o Sanford E. Wolf     [S.WOLF4]      Contributing Columnist
            o Douglas Parks       [DELUXE]       Contributing Columnist


\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\////////////////////////////////////
 Opinions expressed herein are those  of the individual authors, and do
 not  necessarily  represent  opinions of  GEnie Information  Services,
 GEnieLamp Online Magazines, or T/TalkNet  Online Publishing.  Bulletin
 board messages are reprinted verbatim, and are included in this publi-
 cation with permission  from GEnie Information Services and the source
 RoundTable.   GEnie Information Services,  GEnieLamp Online Magazines,
 and T/TalkNet Publishing  do not guarantee the accuracy or suitability
 of any information included herein.   We reserve the right to edit all
 letters and copy.

 Material  published in  this edition may be  reprinted under the  fol-
 lowing terms only. Reprint permission granted, unless otherwise noted,
 to  registered computer  user groups and  not for profit publications.
 All articles  must remain unedited  and include  the issue  number and
 author  at the top of each article reprinted.  Please include the fol-
 lowing at the end of all reprints:

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\///////////////////////////////////
 The  preceeding article  is reprinted  courtesy of  GEnieLamp  Online
 Magazine.  (c) Copyright 1995 T/TalkNET  Publishing and  GEnie Infor-
 mation Services.  Join GEnie  now and receive $50.00 worth  of online
 credit. To join GEnie, set your modem to 9600 baud (or less) and half
 duplex (local echo). Have the modem dial 1-800-638-8369 in the United
 States or  1-800-387-8330  in Canada.  When you see the  U#=  prompt,
 type:  JOINGENIE  and hit the  RETURN  key.   When you get the prompt
 asking for the signup code, type  DSD524  and hit RETURN.  GEnie will
 then ask you for your signup information.   For more information call
 (voice) 1-800-638-9636.
////////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
[EOF]