Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Messages - BillBuckels

#1
CP/M / Re: Is there any reason to use CP/M ?
March 02, 2010, 07:42 AM
Quote from: Hydrophilic on January 17, 2010, 02:21 PM
Thanks Bill, for your comments.  I agree that CP/M on the C128 was severly crippled.



Even CP/M by itself was severely crippled  ;D
#2
CP/M / Re: Faster CP/M - What's the Problem?
December 10, 2008, 09:27 PM
Quote from: airship on October 14, 2008, 03:51 AM
So.. what's the problem? Why didn't it work?

This sounds like an article worthy of being written.

Nigel Parker nigelp2k@yahoo.co.uk the publisher of Commodore Free Magazine http://www.commodorefree.com
wrote me this AM asking for contributions for an up-n-coming issue of C= Free with a CP/M theme due in two months.

Mr. Parker would likely be thrilled if some of us geniuses contributed a page or 10.

Mark, you seem to have lots of ink left in that pen of yours. I realize that you hide in an area of Norway somewhere in the US now but I know that you occasionally get in that Airship of yours and take a ride over to other parts of the world because I saw you in usenet just the other week.

I pointed Nigel over here. I'd prefer if some of the Real C-128 People told the CP/M tale. I don't know where Von Ertwine is these days but I know you and Lance and the rest of the folks here could probably carry-this-off with a little (WAY) more content than I am capable as a newbie.

Unless you have writer's cramp or writer's block in which case y'all are going-to be reading more self-agrandizing spam all about how Bill Buckels tamed CP/M for the masses in some emulator in Windows XP with Aztec-C again:)

Kindest Regards from the Land-Up_over,

Bill bbuckels@mts.net


#3
I am interested in this sort of thing.

My problem is that I have too many vintage interests and hardware projects on the go right now to restore a Commodore 128. It's on my list. The only Z80 machine that I have in working condition will be my Apple //e until then.

Even my C64 is down at the moment but a 1541 arrived today to replace the dead one.

My Aztec C compilers for the Z80 have manuals available now, but not the cross-compilers.

In the meanwhile thanks for the disk image.

Bill   
#4
Aztec C / Commodore Free Magazine and Aztec-C
May 05, 2008, 10:46 PM
Free Issues downloads:

Issue number 18 April 2008
#5
General chat / Re: What's up with Canada post?
April 15, 2008, 11:24 AM
Quote from: airship on April 15, 2008, 01:39 AM
I confess to being a die-hard Coke addict. I can leave Pepsi alone, but Coke is the nectar of the gods. I have to watch it, though, because I'm a diabetic. Once a day only. It's a good thing, or I'd be swigging the stuff 24/7. Because I wouldn't be able to sleep from all the caffeine.

I on the other hand am in de Nile about being a diabetic and have decided to pretend I am not by drastically losing weight and removing carbs from my diet wherever possible. But some days I would throw it all away for a coke... to wash down the cigarette that I don't have and cut the tar from the throat... but since I don't smoke anymore having quit for probably the 20th time in 40 years I don't miss it.
#6
Finally - Some Words about The Architecture

We have been reviewing some of the ways a programmer can use bit-mapped graphics on the C64 and C128. I used one of my products as an example for this discussion, and to bring all this to some kind of closure, I'll do a little post-mortem on the "What Time Is It?" product itself.

The TIME program for the Commodore 64 contains a completely rewritten English Language version of an application that I originally developed and published for the Apple IIe in 1991. The formal title of this program is "What Time Is It?".

The goal of the application is to teach Elementary School Children how to tell time. Regardless, my own goal in producing this program was to provide a full-blown application that demonstrates what a seasoned expert programmer can do in the Aztec C Environment for the Commodore 64

Now if all you are in this for is run programs and not to make them the TIME directory like all my other program directories contains the finished programs including a diskimage called time.d64. These programs are preloaded on the diskimage and run nicely in the vice emulator. If you are using these in WinVICE remember that while graphics load quickly in Warp Mode, the sound routines are time-based and you should take your emulator out-of Warp Mode for proper sound playback and time-based events.

Introduction

If you are reading this but have not reviewed all of the samples and all the projects in this programming environment please do not be offended if most of this goes completely over your head, or worse yet sounds like a nattering old man (which it should if it's flying high enough, since that was my intent).

Take comfort in the fact that I am giving you all the source code and graphics images that I used to produce the TIME application. All this is completely transparent. There are no trade secrets here and no TIME deadlines so take your TIME and enjoy the confusion because it's part of the game. It feels so good when you finally understand, for a moment... 'nuff said.

So let's get started and talk about the architecture and I am assuming that you have read the other make files and gained an understanding that memory management and mapping is "Job One".


Since this is quite a large overlay program, the MAKEFILE should prove quite interesting.

Balancing the TIME Overlays

I really enjoyed this part. Some of you can imagine how I hurried through getting all my samples and library routines written and tested so I could actually do something more-or-less meaningful.

I wondered myself at times whether I would be able to fit all the stuff I needed to into memory. My work on this particular application on the Apple IIe using Aztec C was in the PRODOS 128K environment which allowed me to store data in auxilliary memory. Even in that environment which is about the same size in conventional memory as this one, I needed to break down the Apple IIe version of TIME into more overlays than I did here and to keep the graphics data in upper memory... an option I don't have here.

So when I did all this and it just barely fit I knew I could show the rest of you how far this can go without breaking, Like I said above; memory management and mapping is "Job One" and showing someone what can be done makes the job fun.

You should have already figured-out from my other programs that I have beenplaying around with program memory holes, and sticking data into bits of memory that I couldn't run my programs in.

This is the way we do it. You should also have figured-out by now that the linker outputs the code and data sizes, and that my make files can be redirected to disk file so you can review errors and do something about them, or to examine actual data and code size and adjust the memory usage until there is barely any wasted space.

When I do overlays I am always trading-off what to put into the main (root) module and what to link into the overlays. If the main module gets too bloated and the overlay wipes-out the upper ram the program will finish but never get back to the BASIC prompt. My goal is always to get the user back to the OS whether I program for Windows, Linux, MS-DOS, Apple IIe ProDOS, or the C64. One must therefore consider all the overlays at once and realize where one must put what and when to discard and when not to.

In making TIME fit into SPACE I created some pretty neat tools to help save memory, and kept the code that I could in the main module, and the code that I couldn't in the overlays.

I run-length encoded my graphics and re-used buffers as well. The C64 disk drive is notoriously slow, so it is bad enough that I needed to read these overlays from disk but it would have been much worse if I needed to read additional graphics from disk, or worse yet, to read more overlays (like I needed to on the Apple IIe).

My comments are pretty good in the TIME modules, but sorry kids, they are intended for experts. So become one yourself if you aren't already and read the code and the MAKEFILE and run the thing and have some fun with it.

'Nuff Said on the balancing of overlays... some additional eulogies on the topic are in the TIME source code.



# ---------------------------------------------------------------------
# Aztec C64 makefile by bill buckels 2008
# Use this as the basis for your own C64 overlay programs
# ---------------------------------------------------------------------

PRG=time
OV1=cinit
OV2=mainmenu
OV3=t640
OV4=t641
OV5=t642

# I am using my usual nonsense goal of a B64 whatever that is.
# The real goal is of course a native mode C64 PRG
# That will run when loaded in BASIC 2 and return to the
# interpreter when done with the minor caveat that you
# will need to load it from disk each time you run it.
# As I remember, that was pretty well-behaved for a machine
# language program on the C64 back in those days.

# allowing 1.5K (1536 bytes) for data, hopefully enough
# 1.5K following default screen area for data
# in addition each overlay has its own data area
# which is swapped in and out when the overlay is loaded and discarded


$(PRG).B64: $(PRG).asm $(OV1).asm $(OV2).asm $(OV3).asm $(OV4).asm $(OV5).asm MAKEFILE
   as65 $(PRG).asm
   del $(PRG).asm
   as65 $(OV1).asm
   del $(OV1).asm
   as65 $(OV2).asm
   del $(OV2).asm
   as65 $(OV3).asm
   del $(OV3).asm   
   as65 $(OV4).asm
   del $(OV4).asm   
   as65 $(OV5).asm
   del $(OV5).asm   
   copy $(CLIB65)B64NAT.LIB .
   copy $(CLIB65)C64NAT.LIB .
   copy $(CLIB65)FLTNAT.LIB .
   copy $(CR65)ovloader.rel .
   copy $(CR65)ovbgn.rel .
   ln65 -b 810 -d 4000 -c 4480 -r $(PRG).rel ovloader.rel B64NAT.LIB FLTNAT.LIB C64NAT.LIB
   del $(PRG).rel
   del ovloader.rel
   ln65 $(OV1).rel $(PRG).rsm ovbgn.rel B64NAT.LIB FLTNAT.LIB C64NAT.LIB 
   ln65 $(OV2).rel $(PRG).rsm ovbgn.rel B64NAT.LIB FLTNAT.LIB C64NAT.LIB 
   ln65 $(OV3).rel $(PRG).rsm ovbgn.rel B64NAT.LIB FLTNAT.LIB C64NAT.LIB
   ln65 $(OV4).rel $(PRG).rsm ovbgn.rel B64NAT.LIB FLTNAT.LIB C64NAT.LIB   
   ln65 $(OV5).rel $(PRG).rsm ovbgn.rel B64NAT.LIB FLTNAT.LIB C64NAT.LIB 
   del $(PRG).rsm
   del $(OV1).rel
   del $(OV2).rel
   del $(OV3).rel 
   del $(OV4).rel
   del $(OV5).rel 
   del ovbgn.rel
   del C64NAT.LIB
   del B64NAT.LIB
   del FLTNAT.LIB
   ADDLOGO $(PRG)
   MKBASIC $(PRG).sys $(PRG).prg
   del $(PRG)
   del $(PRG).sys
     
# this pass converts the C programs to assembly language     
$(PRG).asm: $(PRG).c $(OV1).c $(OV2).c $(OV3).c $(OV4).c $(OV5).c MAKEFILE
    copy $(INCL65)stdio.h .
    copy $(INCL65)poke.h .
    copy $(INCL65)colors.h .
    copy $(INCL65)math.h .
    copy $(INCL65)sid.h .
    c65 $(PRG).c
    c65 $(OV1).c
    c65 $(OV2).c
    c65 $(OV3).c
    c65 $(OV4).c
    c65 $(OV5).c
    del stdio.h
    del poke.h
    del colors.h 
    del math.h
    del sid.h



Using The Graphics and Sound Routines

If you have looked at my graphics routines you know by now that I could have gone much further, but that was never my goal. I just wanted to have a little fun with this old compiler and show-off a little bit and leave the field wide-open for competition.

I also could have optimized a little further, or a lot further. But I already know where all this breaks and by now I think I got some of my money's worth back on my original purchase price in enjoyment.

Part of my goal was to showcase the B64NAT.LIB in all of this. I think that the C64 routines that I am leaving you with are better than what I did on the Apple. The sound is better of course and the gameplay is without doubt the same since the processor is the same. The memory saving technique of run length encoding can be taken further, but I kept it simple. Still, by comparison the C64 stuff is easily as robust as the Apple IIe equivalent ofusing bitmap graphics from upper memory. I am satisfied and can now leave this alone.

So by all means change the code, and have some fun yourself.

My selection of multicolour mode was deliberate. The graphics are simple since I originally drew then for the Apple II to avoid aliasing which effectively puts them somewhere close the same coarse resolution as on the C64. There are strange considerations when comparing low resolution graphics on the IBM-PC and Apple IIe and C64 which I have discussed in length in my Wikipedia articles etc. But the common denominator that I mostly went with was 4 Colors, and 2 of them being Black and White, with the other two mainly Red and Blue, and I will leave the rest for you to figure-out on your own.

Read the code, run the program and have fun!

Over and Out.


Quote from: A Seasoned and Expert Programmer
Note: Some reference above was made to imply that I might be a seasoned and expert programmer. Seasoning, like the type used on Turkey and other types of fowl is usually used in the preparation and cooking of said fowl. While it might be a quaint notion that the 4 seasons and the passing of TIME would somehow have a magical effect and would imbibe wisdom or a heightened ability and so forth more probably like the seasoned Turkey in the hot oven, the seasoning would just make one smell a little better, and if one remained in the oven a little too long, ones crispiness would apparently be quite enhanced to the point where like a turkey it would be quite unpalatable and a little too crusty. As far as experts who know more and more about less and less go... the only thing better than an outside expert is an out of town expert. We need to leave it there. 
#7
Code for Previous Module

There is probably little point in posting all 3 gameplay modules in this lot because they are all pretty similar. Now there is lots of other relative information that is not included in this online summary that I have done. You really need to download this whole affair and look at it in the detail that it deserves.

This is intended only as an overview of how we handle bitmapped graphics in an Aztec C program.


/* t640.c (C) Copyright Bill Buckels 2008 */
/* gameplay module 0 */

ovmain(name, answers)
int answers;
{

int c, crow, ccol, pos = 5, oldpos = 5, choice;
char *ptr;
int lastbox, x1, y1, x2, y2;

    gclr(0,-1,-1); /* clear screen */

    dowave(0); /* turn the blue off in the wave area */
    /* remove the blue in the pipe */
    for (c=1; c < 10; c++)dospout(c,0);

    /* unpack the screen onto the display */
decode_scr(&t640x[0],bmp,8000);
decode_scr(&t640x[2092],&t640x[0],clksize); /* unpack the clock from the end of
                                  the main screen to the beginning */

    putimage(snback,3,2,22,38,GET); /* save note area */
    /* display note if sound is on */
    if (sndflag == 1)putimage(snote,3,2,22,38,P_AND);

    while (kbhit()); /* wait for key release */
    kbflush();


  hrslimit=12; /* this module uses a 12 hour digital clock */
  lastbox = 0; /* draw each box only once */

  for (;;) {


    if (lastbox!=5) {
for (c = lastbox; c < multi; c++) {
   x1 = boxcords[c][0] * 4;
   y1 = boxcords[c][1];
   x2 = boxcords[c][2] * 4;
   y2 = boxcords[c][3];
   box(x1, y1, x2, y2, 3, 2);
   lastbox = multi;
}
    }

/* save background over font on last box position */
/* this prevents the colors in the wave from being
   wiped-out by the text in the font area on-screen. */
if (multi == 5) {
x1 = boxcords[4][4];
y1 = boxcords[4][5];
if (sndflag ==  1)putimage(snback,3,2,22,38,PUT);
putimage(timebak,bkrows,bkcols,y1,x1,GET);
if (sndflag ==  1)putimage(snote,3,2,22,38,P_AND);

}

/* do the first clock in the series */
choice=randval();
/* this module uses hours only so set minutes to 0 */
for(c=0;c<multi;c++)randmins[c]=0;
dohands(randhrs[choice],randmins[choice]);
    c = 0;
happy();

for (;;) {


if (pos == 5)ptr=sright;
else ptr = sleft;

ccol = boxcords[pos][0]-10;
crow = boxcords[pos][1];
crow = crow/8;

putimage(sback,srows,scols,crow,ccol,GET); /* save the screen */
putimage(ptr,srows,scols,crow,ccol,P_AND); /* put the cursor into position */

BEGIN:;

    c = toupper(getch());


        /* answer selection - spacebar or enter */
    if (c == 13 || c==32)  {

if (choice == pos) {

/* erase the wrong times */
for(c=0;c<multi;c++)
{
x1 = boxcords[c][4];
y1 = boxcords[c][5];
if(c!=choice) pfont(clrbuf,y1,x1,tc2,tc1,tc3);

}

putimage(sback,srows,scols,crow,ccol,PUT); /* put the screen back */

/* move the snail down */
pos = 5;
ptr=sright;
ccol = boxcords[pos][0]-10;
crow = boxcords[pos][1];
crow = crow/8;

putimage(sback,srows,scols,crow,ccol,GET); /* save the screen */
putimage(ptr,srows,scols,crow,ccol,P_AND); /* put the cursor into position */

answers++;

/* get a reward every 10 times */
if(answers==10||answers==20) {
  /* erase the correct time */
  x1 = boxcords[choice][4];
  y1 = boxcords[choice][5];
  pfont(clrbuf,y1,x1,tc2,tc1,tc3);
  if (multi == 5) {
  x1 = boxcords[4][4];
  y1 = boxcords[4][5];
  putimage(timebak,bkrows,bkcols,y1,x1,PUT);
  if (sndflag == 1)putimage(snote,3,2,22,38,P_AND);
  }
  break;
}

/* count off the answers */
/* fill the pipe */
dospout(answers,1);
if (sndflag == 1) {
/* play up to 9 notes starting at c-5 */
/* play each note for 200 milliseconds */
x1 = answers;
if (answers > 10)x1 = (x1-10);
/* go up the scale with a xylophone */
for(c=0;c<x1;c++) playnote(c+72,200,V_XYL,V_XYL,V_XYL);
}
/* erase the correct time */
x1 = boxcords[choice][4];
y1 = boxcords[choice][5];
pfont(clrbuf,y1,x1,tc2,tc1,tc3);

/* do the next clock in the series */
choice=randval();
/* this module uses hours only so set minutes to 0 */
for(c=0;c<multi;c++)randmins[c]=0;
dohands(randhrs[choice],randmins[choice]);
c = 0;
    }
    else {
   sappy();
}


}
    if (c == 'X') {
   sappy();
   for(c=0;c<multi;c++)
{
x1 = boxcords[c][4];
y1 = boxcords[c][5];
    pfont(clrbuf,y1,x1,tc2,tc1,tc3);

}
   if (multi == 5) {
    x1 = boxcords[4][4];
    y1 = boxcords[4][5];
    putimage(timebak,bkrows,bkcols,y1,x1,PUT);
    if (sndflag ==  1)putimage(snote,3,2,22,38,P_AND);
   }
   answers = 0;
   break;
}
if (c == 'S') {
if (sndflag == 0) {
               putimage(snote,3,2,22,38,P_AND);
   sndflag = 1;
}
else {
sndflag = 0;
putimage(snback,3,2,22,38,PUT);
}
happy();
}

/*

#define UP_ARROW      145
#define DOWN_ARROW   17
#define LEFT_ARROW   157
#define RIGHT_ARROW   29

*/
        if (c != 145 && c != 17) goto BEGIN;
        oldpos = pos;

    switch(c) {
           case 145:  /* uparrow */
                      if (pos == 0) break;
                      if (pos == 5) {
     pos = (multi-1); break;
  }
                      pos--;
                      break;


   case 17:  /* down arrow */
             if (pos == 5) break;
             if (pos == (multi - 1))break;
             pos++;
             break;


}
/* if no change in position cycle */
if (pos == oldpos) {
sappy();
goto BEGIN;
}

putimage(sback,srows,scols,crow,ccol,PUT); /* put the screen back */

}
if (answers != 0)reward();
/* either exiting or reward */
putimage(sback,srows,scols,crow,ccol,PUT); /* put the screen back */
if (answers == 20 || answers == 0)break;
    multi = 5;
   }
   /* don't waste any code cleaning-up */
   return(answers);
}

dohands(hour,minute)
int hour, minute;
{
   /* centre of the circle */
   int x1=116, y1=84, x2,y2;
   /* length of the hands */
   int hrbase=20, minbase=26;

   /* variables for time update */
   int temp;
   int part1;
   int part2;
   int x;

   double hrdegs;
   double mindegs;

   /* erase the old hands */
    putimage(clk,clkrows,clkcols,clkrow,clkcol,PUT);

   /* update the time */

   /* convert hours to ascii and plot in the appropriate box */
   temp=0;
   while(temp<multi)
   {
    part1=randhrs[temp]/10;
    part2=randhrs[temp]%10;

    if(part1==0)part1=32;
    else part1+=48;
    if(part2==0 && part1==32)part2=32;
    else part2+=48;

    timebuf[0]=(char)part1;
    timebuf[1]=(char)part2;

    part1=(randmins[temp]/10)+48;
    part2=(randmins[temp]%10)+48;
    timebuf[3]=(char)part1;
    timebuf[4]=(char)part2;

    /* zeros are hard to see in multicolor mode
       so use uppercase 'O' */
    for (x = 0; timebuf[x] != 0;x++)
        if (timebuf[x] == 48) timebuf[x] = 'O';

    pfont(timebuf,boxcords[temp][5],boxcords[temp][4],tbk,tc3,tc3);
    temp++;
    }

   mindegs=(double)6*minute;

   while(hour>11)hour-=12;
   hrdegs= (double)30*hour;
   /* adjust for between hours */
   hrdegs+= (double).5*minute;


   /* draw the new hands */
   x2=x1;
   y2=y1;
   circlepoints(&x2,&y2,minbase,mindegs);
   /* draw the minute hand */
   drawline(x1/2,y1,x2/2,y2,1,2);

   x2=x1;
   y2=y1;
   circlepoints(&x2,&y2,hrbase,hrdegs);
   /* draw the hour hand */
   drawline(x1/2,y1,x2/2,y2,3,2);

}


/* fill the spout with water from the top down during the game */
/* empty the spout during the reward */
/* valid values are 1-9 */
dospout(idx, onoff)
int idx, onoff;
{
int row, rows, cols, color;

if (idx > 10) idx = (idx - 10);
if (idx < 1 || idx > 9)return 0;
idx = (idx -1); /*adjust for base 0 */

row = sprow[idx];

/* set defaults */
rows = 2;
cols = sp1cols;

    switch(idx) {
/* the first section of pipe is 3 rows high */
/* the next 7 are 2 rows high */
case 0: rows = 3;
        break;
/* the bottom of the spout is a special case */
case 8:
        rows = sp2rows;
        cols = sp2cols;
        break;
}

    if (onoff == 0) color = tc2;
else color = tvram;

palset(vram,row,0,rows,cols,color,0);

}


/* special purpose function for the blue wave */
/* do on from the bottom */
/* do off from the top */
/* this is almost imperceptible due to the speed of the palette set */
/* but this is the way it would really work with real water */
dowave(onoff)
int onoff;
{

int color, rows, cols;

/* blue is color 1 */
/* black is color 0 */
/* set blue off by registering black as color1 in the wave area */
/* this will not affect the other colors */
    /* the blue wave is positioned at 14, 14 */


if (onoff == 0) {
color = tc2;
    cols = splcols - 10; /* blue must be on in the clockface area */
rows = 1;
        palset(vram,14,24,rows,cols,color,onoff);
}
else {
color = tvram;
onoff = 1;
}

cols = splcols;
rows = splrows;

palset(vram,15,14,rows,cols,color,onoff);

if (onoff != 0) {
    cols = splcols - 10; /* blue must be on in the clockface area */
rows = 1;
        palset(vram,14,24,rows,cols,color,onoff);
}

}


/* the reward function for this module */
reward()
{
int idx, vc = V_COL; /* colliape */
char *ptr;

/* time to drain the pipe */
    if (sndflag != 0)harmony();
for (idx = 0; idx < 6; idx ++) {
switch(idx) {
    case 0: /* here we go lubey-loo */
            dospout(1,0);
            ptr = (char *)&lub0[0];
            break;

    case 1: /* here we go lubey-lie */
            dospout(2,0);
            dospout(3,0);
            ptr = (char *)&lub1[0];
            break;

    case 2: /* here we go lubey-loo */
            dospout(4,0);
            dospout(5,0);
            ptr = (char *)&lub0[0];
            break;

    case 3: /* all on a saturday */
            dospout(6,0);
            dospout(7,0);
            ptr = (char *)&lub3[0];
            break;

    case 4: /* all on a saturday */
            dospout(8,0);
            ptr = (char *)&lub3[0];
            break;

    case 5: /* all on a saturday night */
            dospout(9,0);
            ptr = (char *)&lub4[0];
            break;
}

dowave(1);
if (sndflag != 0)play(ptr,vc,vc,vc);
    else playnote(255,2000,0,0,0);
dowave(0);

}
if (sndflag != 0)unison();
}


While this does not exhaust the topic by any means this overview is quite large enough, thank you very much. There is info here that should probably help you in some way or another unless you know what I know and in that case there is, unfortunately, no help for you.

Continued Next Message...
#8

Activity 1: 12 Hour Analog Clock - Hours Only

The 12-hour clock is a convention of time keeping in which the day runs from midnight to noon, then from noon to midnight, and is divided into 2 periods of 12 hours, numbered from 0 to 12. The 12-hour clock is only dominant in a handful of countries, particularly the United States and Canada (except Quebec). The 24-hour clock is the most commonly used time notation in the world today.

This activity teaches hours in the 12-hour clock time format. For each screen, a random time is displayed on the 12-hour analog clock. To the right of the analog clock is a multiple choice menu of different times in digital clock format, with only one that matches the time that is displayed on the analog clock.

For each screen, when the Snail Cursor is to moved to the digital clock that matches the analog clock, and the [RETURN] Key is pressed, a section of the Drain Pipe on the left of the screen will fill with water. For every 10 screens the water will empty from the drain pipe, and give the Snail a "bath".


Data for this module is below.


/* t640.c (C) Copyright Bill Buckels 2008 */
/* gameplay module 0 */

#include <poke.h>
#include <time.h>
#include <sid.h>

char *timebuf="  :00"; /* digital clock text */
char *clrbuf ="     ";
int bkrows = 8;
int bkcols = 6;

/* locations for the digital clock on the right */
/* box cords are given in byte, raster */
/* box is offset 4 rasters from top and bottom of 8 raster font */
/* boxes are 16 rasters high and spaced 16 rasters apart vertically */
/* text cords are given in col, row */
/* multiply col x 4 to use pixel plotting functions for multicolor mode */
/* multiply col x 8 to use pixel plotting functions for hires mode */
/* multiply row x 8 for pixel plotting in both modes */
int boxcords[6][6]={
                      /* box cords */        /* textcords */
                      32,4,     39, 19,     33, 1,
                      32,36,    39, 51,     33, 5,
                      32,68,    39, 83,     33, 9,
                      32,100,   39, 115,    33, 13,
                      32,132,   39, 147,    33, 17,
                      32,164,   0,  0,      0,  0};


/* screen image for this module */
/* followed by the clock at 2092 */
/* 2 pcx encoded arrays of C64 images */

/* the reason I combined these was to provide
   a contiguous buffer area to unpack
   the clock and to save the screen behind the
   snail cursor...

   in a low memory environment sometimes
   a little knitting is required

   This program's memory is pushed right
   to the top of what is available on the C64.

*/
char t640x[] = {
193,255,199,192,193,255,199,  0,193,255,199,
  0,193,255,199,  0,193,255,199,  0,193,255,
199,  0,193,255,199,  0,193,255,199,  0,193,
255,199,  0,193,255,199,  0,193,255,199,  0,
193,255,199,  0,193,255,199,  0,193,255,199,
  0,193,255,199,  0,193,255,199,  0,193,255,
199,  0,193,255,199,  0,193,255,199,  0,193,
255,199,  0,193,255,199,  0,193,255,199,  0,
193,255,199,  0,193,255,199,  0,193,255,199,
  0,193,255,199,  0,193,255,199,  0,193,255,
199,  0,193,255,199,  0,193,255,199,  0,193,
255,199,  0,193,255,199,  0,193,255,199,  0,
193,255,199,  0,193,255,199,  0,193,255,199,
  0,193,255,199,  0,193,255,199,  0,193,255,
199,  0,193,255,199,  3,200,192,255,  0,255,
  0,255,  0,255,  0,244,  0,200,  3,200,192,
255,  0,255,  0,255,  0,255,  0,244,  0,200,
  3,193,240,193,252,193,215,197,213,195,  0,
194,192,195,112,255,  0,255,  0,255,  0,255,
  0,236,  0,200,  3,193,213,193,245,193,253,
197,205,196, 92,196, 87,255,  0,255,  0,255,
  0,255,  0,236,  0,200,  3,195,195,193,253,
195,245,193,253,196, 87,195, 85, 87,195,  0,
193,192,195,112,193,192,255,  0,216,  0,  1,
199,  0, 85,199,  0, 84,255,  0,255,  0,250,
  0,200,  3,200,195,200, 87,255,  0,205,  0,
  1,  4, 16, 64,  0,  5, 20, 64,  0,194, 64,
76, 84, 64,197,  0,193,192,195,  4,  0, 51,
193,252, 48, 51,  5,196,  0,194,192,  0, 64,
20,  1,196,  0, 12,194,  0, 64, 80, 20, 21,
17, 64,198,  0, 64, 80,255,  0,255,  0,226,
  0,200,  3,195,195,193,253,195,245,193,253,
196, 87,195, 85, 87,195,  0,193,192,195,112,
193,192,248,  0,194,  1,  4, 20, 16,195, 64,
200,  0, 63,197, 12,194,  0,198,192,194,  0,
51, 60, 63,199,  0,193,192,197,  0, 60,197,
12,202,  0, 16,194,  4,  1,200,  0,194, 64,
194, 16,255,  0,255,  0,218,  0,200,  3,200,
195,200, 87,248,  0,194,  1,195,  4,195, 16,
194,  0, 79, 15,196,  3,194,  0,193,240,197,
204,242,  0, 48,193,204, 12,194, 48,193,192,
16, 20, 84,  4,195,  1,200,  0, 64,255,  0,
255,  0,210,  0,200,  3,195,195,193,253,195,
245,193,253,196, 87,195, 85, 87,195,  0,193,
192,195,112,193,192,240,  0,194, 16,198, 64,
  3,199,  0,193,240,247,  0,193,252,207,  0,
199, 64, 16,255,  0,255,  0,210,  0,200,  3,
200,195,200, 87,248,  0, 64,194, 67, 80,196,
64,193,240,194, 48,193,240,194, 48,193,192,
218,  0,  4,195, 21,  4,226,  0,193,240,194,
48,193,241,194, 48,193,240,  0,195, 16, 80,
196, 16,255,  0,255,  0,210,  0,200,  3,195,
195,193,253,195,245,193,253,196, 87,195, 85,
87,195,  0,193,192,195,112,193,192,240,  0,
197, 64,195, 16,199,  0,  3,199,  0,193,192,
255,  0,  0,200, 64,255,  0,255,  0,210,  0,
200,  3,200,195,200, 87,248,  0,194, 16,195,
  4,194,  1,  0,196,  3, 67,  3,  0, 64,194,
48,193,192,194, 48,193,192,242,  0, 48,193,
192,194,204,193,252,194, 12,  0,195,  1,  4,
84, 20,194, 16,255,  0,255,  0,218,  0,200,
  3,195,195,193,253,195,245,193,253,196, 87,
195, 85, 87,195,  0,193,192,195,112,193,192,
248,  0,194, 64, 16, 20,  4,194,  1,200,  0,
64, 63, 51,195,  3,194, 12, 64,204,  0,194,
12, 48, 63,201,  0, 60, 48, 60,195, 12, 60,
199,  0, 64,195,  0,  1,194,  4, 16, 80, 16,
194, 64,255,  0,255,  0,223,  0,200,  3,200,
195,200, 87,255,  0,201,  0, 16,  4,  1,197,
  0,194, 64,  0, 64, 20,  5,199,  0, 64, 84,
  1,194, 51, 15,  0,195,  4, 85,198,  0,  5,
84,196,  0,  1, 20, 64,  0, 17, 21, 20, 80,
64,195,  0, 64,255,  0,255,  0,233,  0,198,
  3, 23, 87,195,195,193,253,195,245,193,253,
196, 87,195, 85, 87,195,  0,193,192,195,112,
193,192,255,  0,255,  0,255,  0,255,  0,203,
  0,  1,197,  0,  5, 21, 85,194,  0,  1, 21,
194, 85, 80, 64,  5, 21, 85, 84, 80,195,  0,
87, 83, 67,196,  3, 23,200,195,200, 87,255,
  0,255,  0,255,  0,250,  0,  1,196,  0,  1,
  5,194, 85,194,  0,  5, 21, 85, 84, 80,  0,
  5,194, 85, 84, 64,195,  0, 84, 80,196,  0,
  5, 21,195,  0,  1, 21,194, 85, 80,  0,  5,
21, 85, 84, 80,194,  0,194, 87, 83, 67,196,
  3,195,195,193,253,195,245,193,253,196, 87,
195, 85, 87,195,  0,193,192,195,112,193,192,
255,  0,255,  0,255,  0,218,  0,  5,196,  0,
  1, 21,194, 85,  0,  1,  5,194, 85, 84, 64,
  0, 21,194, 85, 80,196,  0, 84, 64,195,  0,
  1,  5, 85,195,  0,  5, 21,194, 85, 84,  1,
  5,195, 85, 80,194,  0,194, 85, 80, 64,196,
  0, 64,207,  0,198,  3, 23, 87,200,195,200,
87,255,  0,255,  0,255,  0,201,  0,  1, 21,
196,  0,  5, 21, 85, 84,  0,  1, 21,194, 85,
80, 64,  0,194, 85, 84, 64,196,  0, 80, 64,
195,  0,  1, 21, 85,194,  0,  1,  5,195, 85,
80,  1, 21,194, 85, 84, 80,194,  0,194, 85,
80, 64,196,  0, 64,206,  0,  5,196,  0,  1,
21,194, 85,194,  0,  5, 21,196, 85,  5,198,
85, 84,198, 87, 67,  3,195,195,193,253,195,
245,193,253,196, 87,195, 85, 87,195,  0,193,
192,195,112,193,192,255,  0,255,  0,232,  0,
  5, 21,195,  0,  1,  5,194, 85, 84,  0,  5,
21, 85, 84, 80,194,  0,194, 85, 80, 64,195,
  0,  1, 80,196,  0,  5, 21, 85,194,  0,  1,
21,194, 85, 84, 80,  5,195, 85, 84, 64,194,
  0, 85, 84, 80,197,  0, 64,204,  0,  1,  5,
85,195,  0,  1, 21,195, 85,  0,  1, 21,196,
85, 84,197, 85, 84, 64,  0,195, 85, 84, 64,
195,  0, 85, 80, 64,197,  0, 64,199,  0,198,
  3,  7, 87,200,195,199, 87, 85,198,  0,194,
192,255,  0,255,  0,207,  0,  1,  5, 85,195,
  0,  1, 21,194, 85, 80,  1,  5,194, 85, 84,
64,194,  0, 85, 84, 80,196,  0,  5, 64,195,
  0,  1,  5,194, 85,194,  0,  5, 21,194, 85,
84, 64, 21,195, 85, 80,195,  0, 85, 84, 64,
203,  0,  1,  5,196,  0,  1, 21,194, 85,194,
  0,  1, 21,196, 85,  5,196, 85, 84, 64,  0,
195, 85, 84, 64,195,  0, 85, 84, 64,197,  0,
64,197,  0,  5, 85,196,  0,  1, 21,194, 85,
195,  0,  5,196, 85,  0,  1,198, 85, 21,199,
85,200, 87,195,195,197,192,194, 85,194,213,
193,245, 53, 61, 13,193,240,112,124, 92, 95,
194, 87, 85,198,  0,194,192,255,  0,238,  0,
  1, 21, 85,195,  0,  5,194, 85, 84, 64,  1,
21,194, 85, 80, 64,194,  0, 85, 84, 64,195,
  0,  1,  5,196,  0,  1, 21,194, 85,  0,  1,
  5,195, 85, 80, 64, 21,194, 85, 84, 64,195,
  0, 85, 80, 64,203,  0,  5, 85,195,  0,  1,
  5,195, 85,  0,  5, 21,195, 85, 80,  0,195,
85, 84, 80,195,  0, 85, 84, 64,196,  0,  1,
80,196,  0,  1, 21, 85,196,  0, 21,195, 85,
194,  0,  5,197, 85,  5,214, 85, 84,198, 85,
84,  0,197, 85, 84,194,  0,196, 85, 84,195,
  0,195, 87, 83,196,  3,200,192, 15,194,  3,
197,  0,194, 85,194,213,193,245, 53, 61, 13,
193,240,127,198, 85,194,  0,193,255,197, 85,
194,  0,193,192,127,196, 85,195,  0,193,255,
196, 85,195,  0,193,255,196, 85,195,  0,193,
255,196, 85,195,  0,193,255,196, 85,195,  0,
193,255,196, 85,195,  0,193,255,196, 85,195,
  0,193,255,196, 85, 63,194, 51,193,255,196,
115,196,  0,194, 85,196,  0,  5, 21, 85, 84,
194,  0,  5, 21, 85, 84, 80,195,  0, 85, 80,
64,195,  0,  1, 21,196,  0,  1,  5,194, 85,
  0,  1, 21,194, 85, 84, 80,  0,195, 85, 80,
64,195,  0, 84, 80,197,  0,  1,197,  0,  5,
85, 80,194,  0,  1, 21, 85, 80, 64,  0,  5,
21, 85, 84, 64,195,  0,194, 85, 64,196,  0,
  5, 80,196,  0,  5,194, 85,195,  0,  5,195,
85, 80,  0,  1, 21,195, 85, 84,  0, 21,196,
85, 84,194,  0,196, 85, 84,195,  0,195, 85,
84,196,  0,194, 85, 84,196,  0,  1, 85, 84,
197,  0, 85, 84,197,  0,  5, 85,198,  0,194,
85,197,  0,  1,194, 85,197,  0,195, 85,196,
  0,  1,195, 85,196,  3,196, 87,200,192,200,
  0, 15,  3,198,  0, 85,193,213, 63,197,  0,
195, 85,193,255,196,  0,196, 85,193,255,195,
  0,196, 85,193,255,195,  0,196, 85,193,255,
195,  0,196, 85,193,255,195,  0,196, 85,193,
255,195,  0,196, 85,193,255,195,  0,196, 85,
193,255,195,  0,196, 85,193,255,195,  0,127,
115,127,115,193,243,194, 51, 63,195,  0,196,
85,196,  0,196, 85,194,  0,  5,197, 85,  0,
199, 85,  0, 80,195, 64, 80,194, 85,197,  0,
21,194, 85,194,  0,  1,  5,196, 85,  0, 21,
198, 85,  0,195, 64, 80,195, 85,195,  0,  1,
21,195, 85,194,  0,  5,197, 85,  0,199, 85,
  0,199, 85,  0,195, 64, 80,195, 85,197,  0,
195, 85,195,  0,  1,  0,195, 85,194,  0,  1,
85,  0,195, 85,  0,  1, 85, 84,  0,195, 85,
  0,194, 85,194,  0,195, 85,  0,194, 85,194,
  0,195, 85,  0,194, 85,194,  0,195, 85,  0,
85,195,  0,195, 85,  0, 85,195,  0,195, 85,
  0, 85,195,  0,195, 85,  0, 64,195,  0,195,
85,  0,196,  3,195, 87,  3,199,192,193,255,
199,  0,193,255,199,  0,193,255,199,  0,193,
255,199,  0,193,255,199,  0,193,255,199,  0,
193,255,199,  0,193,255,199,  0,193,255,199,
  0,193,255,199,  0,193,255,199,  0,193,255,
199,  0,193,255,199,  0,193,255,199,  0,193,
255,199,  0,193,255,199,  0,193,255,199,  0,
193,255,199,  0,193,255,199,  0,193,255,199,
  0,193,255,199,  0,193,255,199,  0,193,255,
199,  0,193,255,199,  0,193,255,199,  0,193,
255,199,  0,193,255,199,  0,193,255,199,  0,
193,255,199,  0,193,255,199,  0,193,255,199,
  0,193,255,199,  0,193,255,199,  0,193,255,
199,  0,193,255,199,  0,193,255,199,  0,193,
255,199,  0,193,255,199,  0,193,255,199,  3,
193,255,
212,  0,  1,  4, 16, 64,  0,  5, 20, 64,  0,
194, 64, 76, 84, 64,197,  0,193,192,195,  4,
  0, 51,193,252, 48, 51,  5,196,  0,194,192,
  0, 64, 20,  1,196,  0, 12,194,  0, 64, 80,
20, 21, 17, 64,198,  0, 64, 80,216,  0,194,
  1,  4, 20, 16,195, 64,200,  0, 63,197, 12,
194,  0,198,192,194,  0, 51, 60, 63,199,  0,
193,192,197,  0, 60,197, 12,202,  0, 16,194,
  4,  1,200,  0,194, 64,194, 16,200,  0,194,
  1,195,  4,195, 16,194,  0, 79, 15,196,  3,
194,  0,193,240,197,204,242,  0, 48,193,204,
12,194, 48,193,192, 16, 20, 84,  4,195,  1,
200,  0, 64,194, 16,198, 64,  3,199,  0,193,
240,247,  0,193,252,207,  0,199, 64, 16, 64,
194, 67, 80,196, 64,193,240,194, 48,193,240,
194, 48,193,192,218,  0,  4,195, 21,  4,226,
  0,193,240,194, 48,193,241,194, 48,193,240,
  0,195, 16, 80,196, 16,197, 64,195, 16,199,
  0,  3,199,  0,193,192,255,  0,  0,200, 64,
194, 16,195,  4,194,  1,  0,196,  3, 67,  3,
  0, 64,194, 48,193,192,194, 48,193,192,242,
  0, 48,193,192,194,204,193,252,194, 12,  0,
195,  1,  4, 84, 20,194, 16,208,  0,194, 64,
16, 20,  4,194,  1,200,  0, 64, 63, 51,195,
  3,194, 12, 64,204,  0,194, 12, 48, 63,201,
  0, 60, 48, 60,195, 12, 60,199,  0, 64,195,
  0,  1,194,  4, 16, 80, 16,194, 64,221,  0,
16,  4,  1,197,  0,194, 64,  0, 64, 20,  5,
199,  0, 64, 84,  1,194, 51, 15,  0,195,  4,
85,198,  0,  5, 84,196,  0,  1, 20, 64,  0,
17, 21, 20, 80, 64,195,  0, 64,215,  0};


/* clock face to erase hands */
int clkrows = 9;
int clkcols = 12;
int clkrow = 6;
int clkcol = 9;
int clksize = 864;


char c640x = (char *)&t640x[2092];
char *clk = (char *)&t640x[0];
char *sback = (char *)&t640x[864]; /* reuse the packed buffer */
char *timebak = (char *)&t640x[1224];
/*
char timebak[48];
*/
/* spout stuff */
char sprow[9] = {3,6,8,10,12,14,16,18,20};

/*
int sp1rows = 17;
*/
int sp1cols = 3;
int sp2rows = 4;
int sp2cols = 14;

/* wave stuff */
int splrows = 10;
int splcols = 26;

/* musical array created from IBM snd file lubeyloo.snd */
/* array structure is midi note number, duration (18.2 ticks sec) */
/* these are song-parts created by sndfrag. I edited the output
   for readability. doing a song this way requires no particular
   musical knowledge, just counting skills. most programmers
   are pretty fair in this area. Note that the character
   255 in these arrays means a pause between notes, and the
   0, 0 pair indicates the end of a song.
   you can see the B64NAT.LIB sid.c source for more detail */

/* here we go lubey-loo */
char lub0[]={
62,   2,
255,  1,
62,   2,
255,  1,
62,   2,
255,  1,
66,   5,
255,  1,
62,   2,
255,  1,
69,   11,
0,    0};

/* here we go lubey-lie */
char lub1[]={
62,   2,
255,  1,
62,   2,
255,  1,
62,   2,
255,  1,
66,   5,
255,  1,
62,   2,
255,  1,
64,   11,
0,    0};

/* here we go lubey-loo
   same as lub0 so use lub0 twice.
char lub2[]={
62,   2,
255,  1,
62,   2,
255,  1,
62,  2,
255,  1,
66,  5,
255,  1,
62,  2,
255,  1,
69,  11,
0,   0};
*/

/* all on a saturday...
   all on a saturday...
   (repeated twice)  */
char lub3[]={
69,   2,
255,  1,
71,   2,
255,  1,
69,   2,
255,  1,
  67,  2,
255,  1,
66,   2,
255,  1,
64,   2,
0,    0};

/* all on a saturday night. */
char lub4[]={
69,   2,
255,  1,
71,   2,
255,  1,
69,   2,
255,  1,
  67,  2,
255,  1,
66,   2,
255,  1,
64,   2,
255,  1,
62,   11,
0,    0};


#define PUT 0
#define GET 1
#define P_AND 2



The Next Message contains the Code for this module.

Continued Next Message...

#9

"What Time Is It?" Main Menu Screen

"What Time Is It?" has 3 Learning Activities (Games) which can be selected from the Main Menu by moving the Snail Cursor with the Arrow Keys to the desired activity then started by pressing the [RETURN] Key. Each Learning activity is a Game based on a different type of analog clock formatted as a series of 20 screens presenting the time on the analog clock as a question and 3 or 5 multiple choice answers in digital clock format.

For the first 10 screens 3 digital clocks are displayed. This is "level 1". For the following 10 screens 5 digital clocks are displayed. This is "level 2". The student selects the answer for each screen, and when 10 screens are complete, the Student is presented with a musical reward. After the reward for completing 20 screens, the student is returned to the Main Menu.

Activities followed by musical rewards is the basic format of all the programs in the "Collection Les Petites espadrilles". The fourth Main Menu choice exits the Main Menu and ends the program and returns to BASIC. It is the equivalent of pressing the X Key. Sound can be toggled on or off at the Main Menu or during any of the activities by pressing S.


If you look below you can clearly see a large chunk of graphics array staring at you. When you read the source further lots of cursor manipulation and so forth is happening and you should be able to see what we use CURLIB for.


/* mainmenu.c (C) Copyright Bill Buckels 2008 */

#include <poke.h>
#include <time.h>

int crows[2] = { 6,14};
int ccols[2] = { 11,20};

/* pcx encoded array of C64 menu image */
char tmenu[2745] = {
85,199, 64, 85,199,  0, 85,199,  0, 85,199,
  0, 85,199,  0, 85,199,  0, 85,199,  0, 85,
199,  0, 85,199,  0, 85,199,  0, 85,199,  0,
85,199,  0, 85,199,  0, 85,199,  0, 85,199,
  0, 85,199,  0, 85,199,  0, 85,199,  0, 85,
199,  0, 85,199,  0, 85,199, 64, 85,199,  0,
85,199,  0, 85,199,  0, 85,199,  0, 85,199,
  0, 85,199,  0, 85,199,  0, 85,199,  0, 85,
199,  0, 85,199,  0, 85,199,  0, 85,199,  0,
85,199,  0, 85,199,  0, 85,199,  0, 85,199,
  0, 85,199,  0, 85,199,  0, 85,199,  1,200,
64,244,  0,  1,  4, 20, 17,  0,  1, 20, 80,
64,  0, 12, 63, 21, 80,194,  0,194,  3,194,
192, 85,194, 64,  0,194,252,194,236,  0, 84,
  5,196,  0,  3,195,  0, 64, 20,  4, 17,193,
192,199,  0, 64,240,  0,200, 64,244,  0,  1,
  4, 20, 17,  0,  1, 20, 80, 64,  0, 12, 63,
21, 80,194,  0,194,  3,194,192, 85,194, 64,
  0,194,252,193,204,193,236,  0, 84,  5,196,
  0,  3,195,  0, 64, 20,  4, 17,193,192,199,
  0, 64,232,  0,200,  1,200, 64,233,  0,194,
  1,194,  4, 16,194, 20, 64,197,  0,193,255,
193,252,196, 12,195,  0,197,192,196,  0,194,
160,172,197,160,  3,199,  0,198,192,  0,  3,
80, 16,194,  4,195,  1,193,196,199,  0, 64,
232,  0,200, 64,233,  0,194,  1,194,  4, 16,
194, 20, 64,197,  0,193,255,193,252,196, 12,
194,  0,  3,197,192,  0,193,255,194,204,194,
224,193,236,160,172,175,163,175,  3,196,  0,
193,252,193,243, 60,198,192,  0,  3, 80, 16,
194,  4,195,  1,193,196,199,  0, 64,224,  0,
200,  1,200, 64,228,  0,196,  1,196, 64,196,
  0,195, 60, 63,196,  0,195,192,205,  0,200,
160,200,  0,  3,194,  0,195,  3,194,  0,195,
192,194,  0,193,192,194,  0,194, 64,198, 16,
232,  0,200, 64,228,  0,196,  1,196, 64,196,
  0,195, 60, 63,196,  0,193,192,193,195,193,
192, 51,193,255,194, 51,193,255,193,207,193,
252,198,  0,163,199,160, 51, 60,  0,194, 15,
196,  3,194,  0,193,195,194,243,193,240, 48,
195,192,194,  0,193,192,194,  0,194, 64,198,
16,224,  0,200,  1,200, 64,224,  0,200,  1,
15,194, 12, 15, 64,194,  3,194,  0,196,192,
205,  0,197,  1,  0,194,160, 80,195, 86, 80,
196,  0,195,170,197,  0,128,168,128,195,  0,
60,194,  3, 12,194,  3, 60, 16,195,  4, 20,
195,  4,232,  0,200, 64,224,  0,200,  1, 15,
194, 12, 15, 64,194,  3,194,  0,193,204,193,
255,194,204, 60,195,  0,197,192,196,  0,197,
  1,  0,194,160, 80,195, 84, 80,160,202,  0,
194, 63, 15, 12, 15,194,  0, 60,194,  3, 12,
193,195,  3, 60, 16,195,  4, 20,195,  4,224,
  0,200,  1,200, 64,224,  0,197,  1,200,  0,
195, 64,194,  0,193,240,194,204,193,240,194,
204,227,  0,197,  3,197,  0,194,192,193,240,
199, 16, 64,232,  0,200, 64,224,  0,197,  1,
200,  0,195, 64,  3, 15,193,243,194,207,193,
240,194,204, 48,195,204, 48, 12, 63, 12,197,
  0,193,192, 48,193,243,197,160,194,163,160,
  0,  3, 15,194,  3,193,255,194,204,  0, 48,
193,192,193,243,193,207, 51,194,  3,197,  0,
194,192,193,240,199, 16, 64,224,  0,200,  1,
200, 64,232,  0, 64,194, 20, 16,194,  4,194,
  1,193,240,202,  0,193,252,195, 12, 48,199,
  0,  3,197,  0,194,192,196,  0,195,  3,197,
  0,193,192,  0,196,192,193,196,195,  1,194,
  4, 16,194, 64,238,  0,200, 64,232,  0, 64,
194, 20, 16,194,  4,194,  1,193,240,199,  0,
194, 12,  0,193,252,195, 12, 48, 63,193,195,
194,  3,195,  0,  3,172,160,193,204, 48,  0,
194,192,  0,194,240,  0,195,  3,197,  0,193,
192,  0,196,192,193,196,195,  1,194,  4, 16,
194, 64,230,  0,200,  1,200, 64,240,  0, 65,
194, 20,  4,  1,195,  0,194, 48,194,  0, 64,
80, 20,  1,195,  3,196,  0, 80,193,240,194,
48,193,240,194,  0,194, 64,  0,  3,196,  0,
  5, 84,194,196,  1,  4, 20, 64,194,  0, 80,
64,246,  0,200, 64,240,  0, 65,194, 20,  4,
  1,195,  0,194, 48,194,  0, 64, 80, 20,  1,
195,  3,196,  0, 80,193,240,194, 48,193,240,
194,  0,194, 64,  0,  3,196,  0,  5, 84,194,
196,  1,  4, 20, 64,194,  0, 80, 64,238,  0,
200,  1,200, 64,255,  0,  0, 21,199,  0, 85,
255,  0,208,  0,200, 64,255,  0,  0, 21,199,
  0, 85,255,  0,200,  0,200,  1,200, 64,255,
  0,255,  0,218,  0,200, 64,255,  0,255,  0,
210,  0,200,  1,195, 64,194, 85,198,  0,194,
85,198,  0,194, 85,198,  0,194, 85,194,240,
193,204,195,  0,194, 85,198,  0,194, 85,198,
  0,194, 85,198,  0,194, 85,198,  0,194, 85,
198,  0,194, 85,198,  0,194, 85,198,  0,194,
85,198,  0,194, 65,195,195,195,  0,194, 85,
198,  0,194, 85,198,  0,194, 85,198,  0,194,
85,198,  0,194, 85,198,  0,194, 85,198,  0,
194, 85,195,  0,195, 64,194, 85,198,  0,194,
85,198,  0,194, 85,198,  0,194, 85,198,  0,
194, 85,198,  0,194, 85,198,  0,194, 85,198,
  0,194, 85,198,  0,194, 85,198,  0,194, 85,
198,  0,194, 85,198,  0,194, 85,198,  0,194,
85,198,  0,194, 85,198,  0,194, 85,198,  0,
194, 85,198,  0,194, 85,198,  0,194, 85,198,
  0,194, 85,195,  0,195,  1,194, 85,204,  0,
199,  3,  0,193,255,197,  0,193,255,193,204,
193,195,  3,195,  0,  3,193,195,195,  0,193,
207,194,192, 15,194,  0, 15, 12,193,204, 15,
12,193,204, 12,  0,199,204,  0, 60,193,204,
194,192,194,204, 60,  0,195,204,193,252,195,
204,  0,193,252,198, 48,203,  0, 63,194, 12,
194,  3,196,195,199,  0,193,252,194, 48,194,
192,195,  0,193,252,194,  0,193,252,194,  0,
193,240,197,204,193,240,  0, 48,197,204, 48,
  0,197,195,193,255, 60,  0,195, 51,194, 63,
194, 51,225,  0,196,  3,  0,194,  3,  0,193,
195, 51,  3,193,195,194, 51,193,195,  0,193,
195,194, 51,193,195,195,  3,  0,193,195,194,
51,193,243,195, 51,  0,193,195, 51,195,  3,
51,193,195,  0,193,240,  0,  3,193,192,  0,
  3,193,240,  0,194,  3,193,243,  3,  0,193,
243,  3,  0,193,195, 51,  3,193,195,194, 51,
193,195,  0,193,243,194,  3,193,195,194,  3,
193,243,  0,198,  3,193,243,  0,193,243,194,
  3,193,195,194,  3,193,243,  0,193,195, 48,
195,  0, 48,193,192,  0,193,243,198,195,  0,
12,197, 51, 12,  0,194, 51,194, 63,195, 51,
222,  0,194,  3,  0, 12,194, 60,194,204, 12,
15,194,204,194,240,194,192,  0,193,255,199,
  0, 15,197,  0,194, 12,193,204,197,  0, 15,
194, 12,197,  0,193,207,194, 12,197,  0,193,
207,194,  3,197,  0,193,192,209,  0,  3,194,
195,195, 60,194,195,200,  0,193,192,199,  0,
193,252,197,  0,195,204,197,  0,193,240,194,
204,255,  0,205,  0,194, 60,194, 15,196,  0,
60,194,240,193,192,199,  0,  3,199,  0,193,
240,197,  0,194, 12, 15,197,  0, 51,194,243,
197,  0,193,243,194,  3,197,  0,195, 51,197,
  0,195, 48,240,  0,194, 12, 48,194, 12,194,
  3,198,  0, 15, 12,193,204,197,  3,193,255,
196,  0, 15,197,  0,194, 12,193,204, 15,196,
  0, 15,194, 12,193,207,196,  0, 15,194, 12,
193,204,196,  0,196,  3,212,  0,  3,194, 12,
63,199,  0,197,195,193,192,194, 48,193,252,
198,  0,193,252,197,  0,195,204,193,240,196,
  0,193,240,195,192,255,  0,205,  0,194,  3,
194, 15,194, 60,194,  0,195,192,194,240, 60,
196,  0,  3,199,  0,193,240,197,  0, 15,195,
12,196,  0,196, 51,196,  0,193,195,194,  3,
193,243,196,  0,194,243,194, 51,196,  0,195,
48,193,192,238,  0,194, 85,196, 64,194,  0,
194, 85,196,  0,193,204, 60,194, 85,198,  0,
194, 85,198,  0,194, 85,198,  0,194, 85,198,
  0,194, 85,198,  0,194, 85,198,  0,194, 85,
198,  0,194, 85,198,  0,194, 85,198,  0,194,
85,196,  0,194,195,194, 65,198,  0,194, 85,
198,  0,194, 85,198,  0,194, 85,198,  0,194,
85,198,  0,194, 85,198,  0,194, 85,198,  0,
194, 85,198,  0,194, 85,196, 64,194,  0,194,
85,198,  0,194, 85,198,  0,194, 85,198,  0,
194, 85,198,  0,194, 85,198,  0,194, 85,198,
  0,194, 85,198,  0,194, 85,198,  0,194, 85,
198,  0,194, 85,198,  0,194, 85,198,  0,194,
85,198,  0,194, 85,198,  0,194, 85,198,  0,
194, 85,198,  0,194, 85,198,  0,194, 85,198,
  0,194, 85,198,  0,194, 85,196,  1,200, 64,
237,  0,193,255,193,195,193,243,197,  0,193,
192,  0,193,192,200,  0,  3,194, 12, 15,194,
12, 15,  0, 60,195, 51,194,243, 60,206,  0,
195,  3,197,  0,193,240,  0,193,192,240,  0,
200, 64,255,  0,255,  0,210,  0,200,  1,200,
64,232,  0,195, 12,193,243,196,  0,196,192,
  0,  1,  4, 20,194,  0,  1, 20, 80, 64,  0,
12,  0, 21, 80,194,  0,194,  3,193,192,  0,
85,194, 64,  0,194,252,193,204,194,  0, 84,
  5,199,  0,  3, 64, 20,  4, 17,195, 48,193,
192,244,  0,200, 64,247,  0,  2,196,  0, 42,
194,128,197,  0,170,199,  0,170,199,  0,170,
200,  0,194,128, 32,240,  0,200,  1,200, 64,
217,  0, 15, 12, 15,195,  3, 15,  0, 60,197,
204, 60,194,  0,194,  1,194,  4, 16, 20, 17,
64,197,  0,193,255, 63,196, 12,195,  0,197,
192,195,  0,193,204,194,240,193,252,196,  0,
194,  3,198,  0,199,192,  0, 64, 80, 16,194,
  4,195,  1,  0, 12, 63,196, 15, 12,  0,193,
240,197, 48,193,240,224,  0,200, 64,239,  0,
194,  2,194,  8,194, 32,194,128,225,  0, 32,
194,  8,194,  2,200,  0,194,128, 32,232,  0,
200,  1,200, 64,229,  0,195,  1, 20,196, 64,
195,  0,193,252,195, 60, 63,195,  0,196,192,
211,  0,  2,195,  0, 10,194, 42,170,168,194,
  3,194,  0,195,  3,  0,193,196,195,192,194,
  0,193,192,  0,195, 64,197, 16,232,  0,200,
64,232,  0,  2,194,  8,197, 32,210,  0,  3,
12, 60,195,204,  0, 48,193,204,193,207,196,
204,196,  0,196,192,200,  0, 32,194,  8,197,
  2,232,  0,200,  1,200, 64,211,  0,195,  3,
195,  0,194,195, 51, 48,193,240, 48, 51,  1,
193,193,  1,197,193,  0, 15,194, 12, 15, 64,
194,  3,194,  0,196,192,205,  0,197,  1,  2,
10, 42, 90, 86,194, 84, 90,194,160,128,207,
  0, 60,194,  3, 12,194,  3,194, 16,  4,  7,
  4, 20,194,  4,194,  0,193,255,193,240,193,
252,195,195,224,  0,200, 64,232,  0,200, 32,
208,  0,196,204,196,192,195,204, 12,196,  0,
194,192,193,207,194,243,193,207, 12, 48,200,
  0,200,  2,232,  0,200,  1,200, 64,224,  0,
198,  1,200,  0,194, 64,195,  0,193,240,194,
204,193,240,193,204,208,  0,194, 42,195, 10,
195,  2,194,  0,194,128,195,160,168,196,  0,
196,  3, 60,197,  0,194,192,  4,199, 16,193,
252,231,  0,200, 64,232,  0,200, 32,208,  0,
198,192,194, 48,  0,194,192,195, 48,194,  0,
198, 48,194,192,200,  0,200,  2,232,  0,200,
  1,200, 64,220,  0,194,  3,194, 12,196,  0,
15, 51,194,243,194, 64,194, 20, 16,194,  4,
  1,193,204,193,240,202,  0,193,252,195, 12,
206,  0,194,192,194,168,195, 42, 10,  2,  0,
  3,195,  0,193,192,  0,194,192,193,240,193,
192,193,196,195,  1,194,  4,195, 64,  0,194,
15,194,  3,196,  0, 60,195,204,224,  0,200,
64,232,  0,195, 32,194,  8,194,  2,200,  0,
128,200,  0,197, 12,195,  0,196,  3,212,  0,
195,  2,194,  8,194, 32,128,232,  0,200,  1,
200, 64,216,  0, 15,199,  0,194,243,193,207,
197,  0,  1,200,  0, 65,194, 20,  4,  1,194,
  0,195, 48,194,  0, 64, 80, 20,196,  3,197,
  0,193,240,194, 48,193,240,194,  0, 64,194,
  0,  3,196,  0,  5,193,192,194,196,  1,  4,
20, 64,  0, 16, 80, 64,197,  0,194, 12, 15,
197,  0,194,204, 60,229,  0,200, 64,240,  0,
128,194, 32,194,  8,194,  2,200,  0,128,217,
  0,194,  2,194,  8,194, 32,194,128,239,  0,
200,  1,200, 64,232,  0, 15,194,  3, 15,194,
  3, 15,  0,193,252,193,192,193,240,195, 12,
193,240,  0,  1,199,  0, 80, 21,  0, 15,194,
  0,  3,  0, 64, 85,  0, 60,194,243, 51,193,
243, 84,199,  0,194, 15,194,  3,194, 12, 15,
  0,193,252,193,192,193,240,195, 12,193,240,
241,  0,200, 64,248,  0,128, 42,199,  0,170,
199,  0,170,199,  0,170,198,  0,128,247,  0,
200,  1,199, 64, 85,199,  0, 85,199,  0, 85,
199,  0, 85,199,  0, 85,199,  0, 85,199,  0,
85,199,  0, 85,199,  0, 85,  0, 15,197,  0,
85,193,243, 60,197,  0, 85,199,  0, 85,199,
  0, 85,199,  0, 85,199,  0, 85,199,  0, 85,
199,  0, 85,199,  0, 85,199,  0, 85,199,  0,
85,199, 64, 85,199,  0, 85,199,  0, 85,199,
  0, 85,199,  0, 85,199,  0, 85,199,  0, 85,
199,  0, 85,199,  0, 85,199,  0, 85,199,  0,
85,199,  0, 85,199,  0, 85,199,  0, 85,199,
  0, 85,199,  0, 85,199,  0, 85,199,  0, 85,
199,  0, 85,199,  1, 85};

char *sback = (char *)&tmenu[0]; /* reuse the screen buffer */

#define PUT 0
#define GET 1
#define P_AND 2

ovmain(name, choice)
int choice;
{

int c, crow, ccol;
char *ptr;

decode_scr(&tmenu[0],bmp,8000);

    putimage(snback,3,2,22,38,GET); /* save note area */
    /* display note if sound is on */
    if (sndflag == 1)putimage(snote,3,2,22,38,P_AND);

    while (kbhit()); /* wait for key release */
    kbflush();


    happy();
for (;;) {

switch(choice)
{
case 0:  crow = crows[0]; ccol = ccols[0]; ptr = sleft;  break;
case 1:  crow = crows[0]; ccol = ccols[1]; ptr = sright; break;
case 2:  crow = crows[1]; ccol = ccols[0]; ptr = sleft;  break;
case 3:
default: crow = crows[1]; ccol = ccols[1]; ptr = sright; break;


}
putimage(sback,srows,scols,crow,ccol,GET); /* save the screen */
putimage(ptr,srows,scols,crow,ccol,P_AND); /* put the cursor into position */

BEGIN:;

    c = toupper(getch());

    if (c == 13 || c == 32)  {
    if (choice == 3) sappy();
    else happy();
break;
}
    if (c == 'X') {
   choice = 3;
   sappy();
   break;
}
if (c == 'S') {
if (sndflag == 0) {
               putimage(snote,3,2,22,38,P_AND);
   sndflag = 1;
}
else {
sndflag = 0;
putimage(snback,3,2,22,38,PUT);
}
happy();
}
if (c == '3') {
multi = 3;
happy();
}
if (c == '5') {
multi = 5;
happy();
}


/*

#define UP_ARROW      145
#define DOWN_ARROW   17
#define LEFT_ARROW   157
#define RIGHT_ARROW   29

*/
        if (c != 145 && c != 17 && c != 157 && c != 29) goto BEGIN;

putimage(sback,srows,scols,crow,ccol,PUT); /* put the screen back */

    switch(c) {

   case 17:
   case 145: choice = choice + 2;
             if (choice > 3)choice = choice - 4;
             break;

   case 157: choice = choice - 1;
             if (choice < 0)choice = 3;
             break;

   case 29:  choice = choice + 1;
             if (choice > 3)choice = 0;
             break;
}

}

    /* don't waste any code cleaning-up */
    putimage(sback,srows,scols,crow,ccol,PUT); /* put the screen back */
return(choice);
}


Unpacking The Graphics

Just in case you thought this part would be hard... IT ISN'T! Here's the Aztec C64 library function that I wrote for the occasion.


/* (C) Copyright Bill Buckels 2008 */

/* decode screen arrays saved with pcx run-length ecoding */
/* decode full screen images onto screen */
/* decode fragments into buffers */

decode_scr(ptr, bptr, target)
char *ptr, *bptr;
int target;
{
int ctr=0, x, xcnt,ch;
    int offset=0;

do{

/* start with a seed count */
xcnt=1;
    ch=ptr[ctr];
    ctr++;

    /* check to see if its raw */
    /* if its not, run encoded */
    if(0xC0 == (ch & 0xc0)){
       xcnt = 0x3f & ch;
       ch = ptr[ctr];
       ctr++;
    }
    for(x=0;x<xcnt;x++){
if (offset < target) bptr[offset] = ch;
else break;

offset++;
}

     } while(offset<target);

}


Continued Next Message...
#10
The Crux of the Biscuit

Well kids, now here's where we see how to use all those pieces of graphics that we snagged over on the IBM-PC in our Aztec-C programs for the C64. The tools that we have been looking at work pretty well but we could also have written a bunch of C128 basic 7 programs to get these for us. I personally wouldn't bother as you can see...


"What Time Is It?" Title Screen

When the program loads the Title Screen will display during loading, then the Main Menu will appear when the program starts after it is loaded.


/* time.c (C) Copyright Bill Buckels 2008 */

/* this program is an expert level AztecC64 program */
/* it uses overlays and is just generally advanced */
/* if you haven't worked your way through the samples
   and other projects you may need to refer to those
   to really understand what is going-on here.

   then again, you may not. */



#define CMAIN 1

#include <poke.h>
#include <colors.h>
#include <math.h>
#include <time.h>
#include <sid.h>

main()
{
int c=0;

    scr_clear();

    /* background color, bordercolor */
    scr_back(tbk,C64_BLUE);

/* set multicolor mode 160 x 200 and display the logo */
/* this program uses a matched palette */

ovloader("CINIT",2,0);
    gclr(-1,tvram,tcram); /* keep this palette for the duration of the program */

    /* clear all keypresses */
    while (kbhit()); /* wait for key release */
    kbflush();

    /* start program by calling the menu */
    for (;;)
    {
       multi = 3;
       c = ovloader("MAINMENU",c);

       if (c == 3)break;


       switch(c) {
   case 0: ovloader("T640",0); break;
   case 1: ovloader("T641",0); break;
   case 2: ovloader("T642",0); break;

   }
       gclr(-1,tvram,tcram); /* reset default palette */

    }

    /* clean-up and exit */

    /* clear last palette and bitmap */
    gclr(0,0,0);
    ovloader("CINIT",0,2);
scr_clear();

    /* clear all keypressess */
    while (kbhit());
    kbflush();
    /* stuff something in the keyboard to make Aztec C happy */
    kbuf[0] = 'X';
    kbuflen[0]=1;
getchar();
scr_clear(); /* clear screen to erase the X */

exit(0);
}



libmain()
{
    /* dummy calls */
/* library functions that must be saved in main overlay */
/* add as required and careful about library functions
   that use other library functions.

   you will need to learn to balance your overlays for
   larger applications. put the common calls in
   the main application, and put the once-used or
   special calls in their own overlays.

   this speaks to the architecture of any overlay
   framework in any environment whether it is on the
   apple ][, C64, or old MS-DOS when memory was scarce.

   an exhaustive topic. 'nuff said.

*/

/* see note above. this code is never executed */
getpixel(0,0,2);
putimage(snote,3,2,22,38,2);
toupper(getch());
box(0, 0, 159, 199, 3, 2);
palset(vram,0,0,0,0,0,0);
decode_scr(bmp,bmp,0);
}

/* about 1/3 of a second */
happy()
{
if (sndflag  == 1) playnote(72,333,V_XYL,V_XYL,V_XYL);

}

/* about 1/3 of a second */
sappy()
{

if (sndflag  == 1) playnote(12,333,0,0,0);

}

/* randomize 5 sets of hours and 5 sets of minutes  */
/* return the selected answer from the group        */
/* we must make certain that there is no repetition */
/* in groups of 5 hours.                            */

/* jiffy clock */
int *jiffy = (int *)160;

randval()
{
    int i,temp,temp2, j;

   /* there are either 25 or 50 hours choices               */
   /* if we pick them sequentially there will be no repeats */
   /* they have been shuffled fairly well.                  */


   j = jiffy[0];
   if (j < 0)j = (j * -1);

   randseed = (j % 25);

   if(hrslimit==12) {
   temp=24;
   }
   else {
   randseed = randseed + 25;
       temp=49;
    }

   temp2=temp-24;

    for(i=0;i<5;i++)
    {
      randseed = (randseed + 1);
      if(randseed>temp)randseed=temp2;
      randhrs[i]=(int)hrseed[randseed];
      }


    /* get one of the 25 minute choices */
    randseed = (randseed + randhrs[0]);
    temp=24;

    for(i=0;i<5;i++)
    {
      randseed = (randseed + 1);
      if(randseed>temp)randseed=0;
      randmins[i]=(int)minseed[randseed];
      }

    /* return an answer within the range of questions */
    return randhrs[0]%multi;
}


circlepoints(x,y,baselength,fdegrees)
int *x, *y;
int baselength;
float fdegrees;
{
    float xtemp;
    float ytemp;
    int degrees = (int )fdegrees;
    float aspect_h, aspect_v;

    aspect_h = (float)1.16;
    aspect_v = (float)1;

/*  starting at 12 O'clock    */
/* use a switch for the break */
switch(degrees)
{


    default:

/* within range */
if(degrees<0 || degrees >359)degrees=0;

/*  0-45  sin */
if(degrees < 45)
{
xtemp = (float) sine_cosine[degrees][0];
ytemp = (float) sine_cosine[degrees][1];
ytemp = ytemp * -1;
break;
}

/* 45-90  cos */
if(degrees < 90)
{
xtemp = (float) sine_cosine[90-degrees][1];
ytemp = (float) sine_cosine[90-degrees][0];
ytemp = ytemp * -1;
break;
}

   /* 90 - 135 */
   if(degrees < 135)
   {
xtemp = (float) sine_cosine[degrees-90][1];
ytemp = (float) sine_cosine[degrees-90][0];
break;
}

/* 135 - 180 */
   if(degrees< 180)
   {
xtemp = (float) sine_cosine[180-degrees][0];
ytemp = (float) sine_cosine[180-degrees][1];
break;
}

   /* 180 - 225 */
   if(degrees< 225)
   {
xtemp = (float) sine_cosine[degrees-180][0];
xtemp = xtemp * -1;
ytemp = (float) sine_cosine[degrees-180][1];
break;
}

   /* 225 - 270 */
   if(degrees< 270)
   {
xtemp = (float) sine_cosine[270-degrees][1];
xtemp = xtemp * -1;
ytemp = (float) sine_cosine[270-degrees][0];
break;
}

   /*  270 - 315 */
   if(degrees< 315)
   {
xtemp = (float) sine_cosine[degrees-270][1];
xtemp = xtemp * -1;
ytemp = (float) sine_cosine[degrees-270][0];
ytemp = ytemp * -1;
break;
}

/* 315 - 360 */
xtemp = (float) sine_cosine[360-degrees][0];
xtemp = xtemp * -1;
ytemp = (float) sine_cosine[360-degrees][1];
ytemp = ytemp * -1;
    }

    ytemp = ytemp/32767;
    xtemp = xtemp/32767;

    xtemp *= (aspect_h*baselength);
    ytemp *= (aspect_v*baselength);

    *x += (int )xtemp;
    *y += (int )ytemp;

}


/* (C) Copyright 2008 Bill Buckels */
/* What Time is It - C64 Version by Bill Buckels */
/* screen mode initialization module */

ovmain(name, mode, prev)
int mode, prev;
{
       /* since this is called only twice during the program */
       /* it gets its own overlay */
       /* this allows more room for code in the main program */
       crtmode(prev);
       prev = setcrtmode(mode);
       return prev;
}



Continued Next Message...
#11

FRAGGLE
Continued from Curlib...

Well Jim henson was a Bearded Male and so am I but that and the fact that we both created something called "FRAGGLE" could well be the only resemblance.

Now in case someone gets the idea that I am a C snob or something, that's only one of my personnas and the reality is that "When In Rome"... so here's a little bit of BASIC from the IBM-PC side that also comes with the the Aztec C64 cross-compiler. This definetly is useful if you also use ClipShop to snag images in Windows XP and convert them to IBM-PC BASIC BSaved Images because then you can use FRAGGLE to chop them-up into little pieces and stick them in Aztec C64 programs (or whatever).


'FRAGGLE.BAS by Bill Buckels 1990
'Written in QuickBASIC Version 4.5
'produces and displays image fragments
'created from BASIC BSAVED MED RES CGA IMAGES
'Revised 2007 as a pure QuickBasic Program
'Removed PCX support because not written in QuickBasic
'Added resave back to BSaved Image
'Revised program structure for readability
'Increased error handling and added error messages
'Removed automatic naming from basename.
'Now using the .PUT extension when saving.
'Added 8 x 8 Block Based Fragments for C64 Style Saves

DEFINT A-Z
'allocate memory for picture buffer
DIM PIC(8002)                              'picture buffer
'constants for keypress values
NUL$ = CHR$(0)
UP$ = NUL$ + CHR$(72)
DN$ = NUL$ + CHR$(80)
LT$ = NUL$ + CHR$(75)
RT$ = NUL$ + CHR$(77)
ESC$ = CHR$(27)
ENTER$ = CHR$(13)
'constants for keypress status
FLAG = 0
ZERO = 0
ONE =  1
TWO =  2
DONE = 3
ABORT = 0

ERRORLEVEL = 0
ON ERROR GOTO ERRORHANDLE

SCREEN 1

DO

'bounds of the screen
X1 = 0: X2 = 319: Y1 = 0: Y2 = 199

GOSUB DRAWMENU 'Menu Routine
GOSUB GETCHOICE

IF ERRORLEVEL = 0 THEN
SELECT CASE PICTYPE%
CASE 1,5
'if we have been asked to fraggle
GOSUB VARFRAG
CASE 2
'if we're not fragging we're viewing so we stop and wait in that case
KEYPRESS$ = INPUT$(1)

CASE 3
'make a menu chip
GOSUB FIXEDFRAG 

CASE 4 'bsave fragment
GOSUB RESAVE

END SELECT
END IF

ABORT = ZERO
ERRORLEVEL = 0
LOOP UNTIL PICNAME$ = "FINISHED"
END


DRAWMENU:

CLS

LINE (2,2)-(317,102),2,b
LINE (0,0)-(319,102),1,b
LOCATE 2,2
PRINT " FRAGGLE(C)
LOCATE 3,2
PRINT " Copyright Bill Buckels 1990-2007"
LOCATE 5,2
PRINT "    1)   Fraggle a BSaved Image"
LOCATE 6,2
PRINT "    2)   Load an Image Fragment"
LOCATE 7,2
PRINT "    3)   Fraggle 88 x 52 from BSaved"
LOCATE 8, 2
PRINT "    4)   BSave a Fraggled Image"
LOCATE 9, 2
PRINT "    5)   Fraggle C64 Style from BSaved"
LOCATE 10,2
PRINT "    ESC  EXIT"

' menu explanations

LINE (2,104)-(317,197),1,b
LINE (0,104)-(319,199),2,b
LOCATE 15, 2
PRINT " Summary of Fraggle Hot Keys:"
LOCATE 17, 2
PRINT " R      - Reverse Video"
LOCATE 18, 2
PRINT " L      - Adjust Length By 1 pixel"
LOCATE 19, 2
PRINT " W      - Adjust Width By 1 pixel"
LOCATE 20, 2
PRINT " ESC    - Abandon Operation"
LOCATE 21, 2
PRINT " ENTER  - 1st and 2nd corners"
LOCATE 22, 2
PRINT "          Save Fragment"
LOCATE 23, 2
PRINT " ARROWS - Change Clip Position";

'get input
LOCATE 12,2
PRINT " Select from the above Menu options.";


RETURN


GETCHOICE:
  'menu input subroutine
  PICTYPE$ = INPUT$(1)
  PICTYPE% = VAL(PICTYPE$)
  SELECT CASE PICTYPE%
  CASE 1, 3, 5
        CLS
  PRINT "Raw Load"
FILES "*.BAS"
  CASE 2, 4
        CLS
PRINT "Image Fragment Load"
    FILES "*.PUT"
  CASE ELSE
      END
  END SELECT
 
  LINE(0,180)- (319,195),0,BF
  LINE(0,180)- (319,195),2,B
  LINE(2,182)- (317,193),1,B
  LOCATE 24,2
  SELECT CASE PICTYPE%
  CASE 1, 3, 5
  INPUT " PICTURE"; PICNAME$
  CASE 2, 4
  INPUT " FRAGMENT"; PICNAME$
  END SELECT
 
  IF PICNAME$ = "" THEN
  PICTYPE%=0
  ELSE
    CLS
    GOSUB LOADPIC
  END IF     

RETURN     


LOADPIC:
  ' picture loader subroutine
  SELECT CASE PICTYPE%

  CASE 1, 3, 5   'Raw Data
      SEGMENT = &HB800              'Use Screen Segment
      OFFSET = &H0
      DEF SEG = SEGMENT
      BLOAD PICNAME$, OFFSET        'Bload the Picture

  CASE 2, 4
      'load image fragments
      SEGMENT = VARSEG(PIC(0))
      OFFSET = VARPTR(PIC(0))

      DEF SEG = SEGMENT
      BLOAD PICNAME$, OFFSET
      XTAB = INT((640 - PIC(0)) / 4)   'center horizontally
      PUT (XTAB, 0), PIC, PSET         'put picture

  END SELECT
  DEF SEG  'Go back to original segment
 
  IF ERRORLEVEL > 0 THEN
      CLS
      LINE (0,0)-(319,24),0,BF
      LINE (0,0)-(319,24),1,B
      LOCATE 2,2
      PRINT PICNAME$ + " NOT loaded. Press a key..."
      A$ = INPUT$(1)     
  END IF
 
RETURN


VARFRAG:
  ' subroutine for saving variable size image fragments
  ' backup the picture
  GET (X1, Y1)-(X2, Y2), PIC
  'and do an elastic box with a DOTTED line in two colors
  LINE (X1, Y1)-(X2, Y2), 2, B, &HAAAA
  LINE (X1, Y1)-(X2, Y2), 3, B, &H5555

  IF PICTYPE% = 5 THEN
       INCR% = 8
  ELSE
       INCR% = 4
  END IF


  ENTER% = 1 'FRAG PART ONE- SET THE TOP LEFT CORNER
  FLAG = 0
  WHILE FLAG = 0
    KEYPRESS$ = INKEY$
    SELECT CASE KEYPRESS$
    CASE "R", "r" 'reverse video
PUT (0,0),PIC,PRESET
GET (0,0)-(319,199), PIC
PUT (0,0),PIC,PSET
FLAG=ONE
    CASE "L", "l" 'fine tuning
        IF INCR% = 4 THEN
  IF ENTER% = 1 THEN ' TOP LEFT CORNER
      IF NOT Y1 = 0 THEN
Y1 = Y1 - 1
PUT (0, 0), PIC, PSET
FLAG = ONE
      END IF
  ELSE  ' BOTTOM RIGHT CORNER
      IF Y2 > (Y1 + 4) THEN
Y2 = Y2 - 1
PUT (0, 0), PIC, PSET
FLAG = ONE
      END IF
  END IF
END IF
    CASE "W", "w"
        IF INCR% = 4 THEN
  IF ENTER% = 1 THEN ' TOP LEFT CORNER
      IF NOT X1 = 0 THEN
X1 = X1 - 1
PUT (0, 0), PIC, PSET
FLAG = ONE
      END IF
  ELSE  ' BOTTOM RIGHT CORNER
      IF X2 > (X1 + 4) THEN
X2 = X2 - 1
PUT (0, 0), PIC, PSET
FLAG = ONE
      END IF
  END IF
END IF
    CASE UP$ 'up arrow
IF ENTER% = 1 THEN ' TOP LEFT CORNER
      IF NOT Y1 = 0 THEN
Y1 = Y1 - INCR%
PUT (0, 0), PIC, PSET
FLAG = ONE
      END IF
ELSE  ' BOTTOM RIGHT CORNER
      IF Y2 > (Y1 + INCR%) THEN
Y2 = Y2 - INCR%
PUT (0, 0), PIC, PSET
FLAG = ONE
      END IF
END IF
    CASE DN$ 'down arrow
IF ENTER% = 1 THEN ' TOP LEFT CORNER
      IF NOT Y1 > Y2 - INCR% THEN
Y1 = Y1 + INCR%
PUT (0, 0), PIC, PSET
FLAG = ONE
      END IF
ELSE  ' BOTTOM RIGHT CORNER
      IF NOT Y2 = 199 THEN
Y2 = Y2 + INCR%
PUT (0, 0), PIC, PSET
FLAG = ONE
      END IF
END IF
    CASE LT$ 'left arrow
IF ENTER% = 1 THEN ' TOP LEFT CORNER
      IF NOT X1 = 0 THEN
X1 = X1 - INCR%
PUT (0, 0), PIC, PSET
FLAG = ONE
      END IF
ELSE  ' BOTTOM RIGHT CORNER
      IF X2 > (X1 + INCR%) THEN
X2 = X2 - INCR%
PUT (0, 0), PIC, PSET
FLAG = ONE
      END IF
END IF
    CASE RT$ 'right arrow
IF ENTER% = 1 THEN ' TOP LEFT CORNER
      IF NOT X1 > X2 - INCR% THEN
X1 = X1 + INCR%
PUT (0, 0), PIC, PSET
FLAG = ONE
      END IF
ELSE  ' BOTTOM RIGHT CORNER
      IF NOT X2 = 319 THEN
X2 = X2 + INCR%
PUT (0, 0), PIC, PSET
FLAG = ONE
      END IF
END IF
    CASE ESC$
ABORT = TWO
FLAG = DONE
    CASE ENTER$
ENTER% = ENTER% + 1 'FRAG PART TWO - SET THE BOTTOM RIGHT CORNER
IF ENTER% > 2 THEN FLAG = DONE
    END SELECT
    IF FLAG = ONE THEN
'change the position of the elastic box
'based on the last arrow or positional keypress
LINE (X1, Y1)-(X2, Y2), 2, B, &HAAAA
LINE (X1, Y1)-(X2, Y2), 3, B, &H5555
FLAG = 0
    END IF
  WEND

  IF ABORT = ZERO THEN
      GOSUB SAVEFRAG 'SAVE IF ESCAPE WAS NOT PRESSED
  END IF

RETURN



FIXEDFRAG:
  ' subroutine for saving 88 x 52 fixed size image fragments
  ' or 24 x 21 Double C4 Sprite
  ' backup the picture
  GET (X1, Y1)-(X2, Y2), PIC
  ' use a printshop compatible image size
  ' 88 x 52
  X1=0 : X2=87 : Y1 = 0 : Y2=51
 
 
  'and do an elastic box with a DOTTED line
  'in two colors to show-up regardless
  LINE (X1, Y1)-(X2, Y2), 2, B, &HAAAA
  LINE (X1, Y1)-(X2, Y2), 3, B, &H5555

  FLAG = 0

  WHILE FLAG = 0
    KEYPRESS$ = INKEY$
   
    SELECT CASE KEYPRESS$
    CASE "R", "r"  'reverse video
PUT (0,0),PIC,PRESET
GET (0,0)-(319,199), PIC
PUT (0,0),PIC,PSET
FLAG=ONE
    CASE UP$
              IF NOT Y1 = 0 THEN
Y1 = Y1 - 4
Y2 = Y2 - 4
PUT (0, 0), PIC, PSET
FLAG = ONE
              END IF
    CASE DN$  'down arrow
              IF NOT (Y2+4)>199 THEN
Y2 = Y2 + 4
Y1 = Y1 + 4
PUT (0, 0), PIC, PSET
FLAG = ONE
              END IF
    CASE LT$  'left arrow
              IF NOT X1 = 0 THEN
X1 = X1 - 4
X2 = X2 - 4
PUT (0, 0), PIC, PSET
FLAG = ONE
              END IF
    CASE RT$  'right arrow
              IF NOT (X2+4)>319 THEN
X1 = X1 + 4
X2 = X2 + 4
PUT (0, 0), PIC, PSET
FLAG = ONE
              END IF
    CASE ESC$
ABORT = TWO
FLAG = DONE
    CASE ENTER$
FLAG = DONE
    END SELECT
   
    IF FLAG = ONE THEN
'change the position of the elastic box
'based on the last arrow or positional keypress
LINE (X1, Y1)-(X2, Y2), 2, B, &HAAAA
LINE (X1, Y1)-(X2, Y2), 3, B, &H5555
FLAG = 0
    END IF
  WEND
 
  IF ABORT = ZERO THEN
  GOSUB SAVEFRAG 'SAVE IF ESCAPE WAS NOT PRESSED
  END IF

RETURN



SAVEFRAG:
  'subroutine for saving an image fragment
  'blot the screen one last time
  'give the file name from the a .PUT extension
  PUT (0, 0), PIC, PSET
  GET (X1, Y1)-(X2, Y2), PIC
  LINE (0,0)-(319,24),0,BF
  LINE (0,0)-(319,24),1,B
  LOCATE 2,2
  INPUT "FRAGMENT NAME"; NEWPIC$
  IF NEWPIC$ = "" THEN RETURN
 
  FRAG$ = NEWPIC$
  NEWPIC$ = ""
 
  A$ = ""
  A% = 1
  'parse until the period
  WHILE NOT A$ = "."
    IF A% < LEN(FRAG$)+1 THEN
      A$ = MID$(FRAG$, A%, 1)
    ELSE
      A$ = "."
    END IF
    NEWPIC$ = NEWPIC$ + A$
    A% = A% + 1
  WEND
  NEWPIC$ = NEWPIC$ + "PUT"
  'put the window into an array
  'then point to the array
  'and save it to disk
 
  SEGMENT = VARSEG(PIC(0))
  OFFSET = VARPTR(PIC(0))
  DEF SEG = SEGMENT
  'find the width and the height
  'and calculate the length of the array
  'raster lines break on byte boundaries
  'the array header is two words in length
  WIDE = INT((((X2 - X1) * 2) + 7) / 8)
  HIGH = (Y2 - Y1)+1
  PICSIZE = 4 + (WIDE * HIGH) +1
  BSAVE NEWPIC$, OFFSET, PICSIZE
  DEF SEG
 
  CLS
  LINE (0,0)-(319,24),0,BF
  LINE (0,0)-(319,24),1,B
  LOCATE 2,2
  IF ERRORLEVEL = 0 THEN
    PRINT NEWPIC$ + " saved. Press a key..."
  ELSE
    PRINT NEWPIC$ + " NOT saved. Press a key..."
  END IF
  A$ = INPUT$(1) 
     
RETURN             
 
RESAVE:
  'subroutine for saving a Bsaved Image
  'from an image fragment
  GET (X1, Y1)-(X2, Y2), PIC
  LINE (0,0)-(319,24),0,BF
  LINE (0,0)-(319,24),1,B
  LOCATE 2,2
  INPUT "NEW NAME"; NEWPIC$
  IF NEWPIC$ = "" THEN RETURN

  FRAG$ = NEWPIC$
  NEWPIC$ = ""

  A$ = ""
  A% = 1
  'parse until the period
  WHILE NOT A$ = "."
    IF A% < LEN(FRAG$)+1 THEN
      A$ = MID$(FRAG$, A%, 1)
    ELSE
      A$ = "."
    END IF
    NEWPIC$ = NEWPIC$ + A$
    A% = A% + 1
  WEND
  NEWPIC$ = NEWPIC$ + "BAS"

  'restore the screen
  'and save it to disk
  PUT (0, 0), PIC, PSET
  SEGMENT = &HB800              'Use Screen Segment
  OFFSET = &H0
  DEF SEG = SEGMENT
  PICSIZE = 16384
  BSAVE NEWPIC$, OFFSET, PICSIZE
  DEF SEG

  CLS
  LINE (0,0)-(319,24),0,BF
  LINE (0,0)-(319,24),1,B
  LOCATE 2,2
  IF ERRORLEVEL = 0 THEN
    PRINT NEWPIC$ + " saved. Press a key..."
  ELSE
    PRINT NEWPIC$ + " NOT saved. Press a key..."
  END IF
  A$ = INPUT$(1)
 
RETURN               

ERRORHANDLE:
     BEEP
     ERRORLEVEL = 1
     RESUME NEXT

MAKE.BAT

@echo off

IF NOT EXIST FRAGGLE.BAS GOTO ENDER

        BC FRAGGLE,,NUL /e/v/x
IF NOT EXIST FRAGGLE.OBJ GOTO ENDER

        LINK /NOD /NOE FRAGGLE,,NUL,BCOM45.LIB
        ERASE FRAGGLE.OBJ
IF NOT EXIST FRAGGLE.EXE GOTO ENDER
        echo FRAGGLE.exe Created !
        copy FRAGGLE.EXE ..\.
GOTO FINISH

:ENDER
        echo Sorry... Problem Encountered.
:FINISH


Continued Next Message...
#12
CURLIB

You may have noticed that the MAKEFILE for FRAG64X also builds a program called CURLIB. If you didn't it doesn't much matter because all that is done for you anyway and you only need to use curlib if you get fancy. But CURLIB does provide a utility for putting some little graphics fragments into a bloadable file. The problem you will have if you don't use Aztec C is that these need to be manipulated and you will in fact need to get fancy.


/* curlib.c (C) Copyright Bill Buckels 2008 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char curbuf[1000];

FILE *fp=NULL, *fp2=NULL, *fp3=NULL, *fp4=NULL;

main(int argc, char *argv[])
{
int ctr = 0,c;

/* this is a special purpose utility for
   creating cursor libraries that are embeded into
   aztec C programs instead of vram using up to 3 fragments
   or files named on the command line.

   the caveat is that you keep the maximum size
   of all 3 files to 1000 bytes total.

   You will generally want to create a cursor library using
   a left and right hand cursor and a musical note to indicate
   whether sound is in use or not.

   */

   if (argc < 2) {
      puts("Usage is \"Curlib [frag1] [frag2] [frag3]\"");
      exit(1);
   }


   fp = fopen("cursor.vhi","wb");
   fputc(0,fp);
   fputc(0x1C,fp);

   fp2 = fopen(argv[1],"rb");
   if (argc > 2) fp3 = fopen(argv[2],"rb");
   if (argc > 3) fp4 = fopen(argv[3],"rb");


   if (NULL != fp2) {
       while ((c = fgetc(fp2))!=EOF) {
   if (ctr < 1000)fputc(c,fp);
   ctr++;
   }

   }
   if (NULL != fp3) {
       while ((c = fgetc(fp3))!=EOF) {
   if (ctr < 1000)fputc(c,fp);
   ctr++;
   }

   }
   if (NULL != fp4) {
       while ((c = fgetc(fp4))!=EOF) {
   if (ctr < 1000)fputc(c,fp);
   ctr++;
   }

   }

   while (ctr < 1000) {
  fputc(0,fp);
  ctr++;
   }


   if (NULL!=fp)fclose(fp);
   if (NULL!=fp2)fclose(fp2);
   if (NULL!=fp3)fclose(fp3);
   if (NULL!=fp4)fclose(fp4);

   exit(0);

}


Note: The technical term "Fancy" means the same thing as the English term. Usually compilers don't come with much fancy stuff and also BASIC 2 certainly didn't... you needed to poke around alot. BASIC 7 on the C128 was quite an improvement but for doing graphics you really can't beat C for all around usability.

Now exactly where one gets these IBM-PC image fragments to make into CBM image fragments might surprise you especially if you haven't read the Wikipedia Article.

Continued Next Message...
#13
FRAG64X

Continued from previous message...

The following are the header comments from the frag64x source code... they explain alot.


/* this is an extended version of Frag64 which creates
   runlength encoded files and arrays in addition to
   the standard output of Frag64.

   The size improvement varies and can be minimal and
   may not be worth the effort of cluttering-up your disk,
   so I have left the simple version in place as well as
   this one for the more size conscious of you.

   For overlays that use graphics, embedding compressed
   graphics in the form of run-length encoded arrays
   can be very useful in terms of performance as well as
   space saving since the C64 disk drive access is slow
   when loading external files in addition to overlays,

   This version has other additional features that are
   not present in Frag64 and if clutter is not an issue
   use this one.

   */

/* converts from an IBM Bsaved PUT to a C64 image fragment */
/* fullscreen PIC's convert to BSAVED C64 Images with Colors */
/* extensions are fr2 or fr4 for fragments */
/* extensions are BHI or BMC for BSAVED C64 Images */
/* Color File Extensions are VHI or VMC and CMC */
/* The full screen files are in the Clipshop format */

/* The FRAGGLE.EXE utility will produce PUT format images from CGA
   4-Color BSaved Files which are freely available on the IBM-PC.
   Clipshop can be used to create 4 Color BSaved Files from the Windows
   Clipboard and other sources as can several old utilites.

   To learn more about all this visit my wikipedia page at

   http://en.wikipedia.org/wiki/BSAVE_(graphics_image_format)

   Generally speaking you are better-off to use FRAGGLE.EXE
   menu option 5 to create the PUT image fragments that you will
   be using in your C64 programs because these are saved in 8 x 8
   graphics blocks which is perfect for C64 conversion.

   Note that when converting from a 4 color image to a HIRES
   image on the C64, any color other than black is taken as white.

   Also note that when converting from a 4 color image to a
   Multicolor image on the C64, every second pixel is skipped
   since the horizontal resolution is only 160 pixels in Multicolor
   mode. This means that you should use lines of 2 pixels in
   width for your line elements and stay away from altrenating pixel
   pattern files. Solid color works best in colored areas.

   If you want to preserve detail in a Multicolor mode image
   you may need to draw it as a 160 x 100 picture on the
   IBM then scale it x 2 and BSAVE it before using FRAGGLE.EXE.

   Alernately just make sure your horizontal pixels are two wide
   and you will probably be ok in most cases.

   If you want your text and graphics to be near perfect in the
   horizontal axis in a Multicolor image that is what you must do,
   and for any menu screens that is what I would suggest. Your
   line elements in your artwork will be somewhat jagged but your
   results will be quite manageable for combining fragments
   with background screens and a common palette.

   I consider the sprites on a C64 a little small for my preferences
   on this type of programming, and I much prefer a clean image
   fragment instead even if I need to reduce to 4 colors.

   Lastly, this utility provides a command line override for
   mapping to your choice of each of the C64 colors 0-15 for
   your full screens.

   This gives you a choice of any 2-colors in your HIRES images
   and any 4-colors in your Multicolor images, which I feel provides
   a reasonable amount of flexibility in choosing a color scheme
   to combine fragments and screens.

   You have this source code if you want to customize this utility
   further. The 8 x 8 color block on a C64 makes converting a 4 color
   image a little tricky and as a programmer's tool I have gone about
   as far as I think is generally reasonable, but many more schemes
   are possible even with this lot. For example, widening your black
   lines or white lines on line-art in a multicolor image will
   guarantee that detail is not lost in some cases. In others it will
   destroy your graphics by creating blotches

   For these types of things hotkeys are used in this program.
   You can read the source to see what they are and try them
   for yourself. I stopped short of scaling and so forth and again
   you can add these functions yourself if you like.

   On a further note...

   Clipshop has more options for general purpose conversion of full
   screens but combining those with fragments will likely prove
   problematic, and even Clipshop conversions will prove problematic
   on their own, since color precedence is used to map the most used
   colors and colors are not what and where you might expect them
   from block to block and will be lost altogether if a complex
   image and no spot is available.

   Much better to deal with less colors and guaranteed results with
   this utility is my conclusion over the years of mucking with all
   this is what I think. Do your fancy stuff in a paint program
   first and use this utility to process the finished artwork is
   what I suggest.

   'Nuff Said.

   Download Clipshop at

   www.clipshop.ca

   */

MAKEFILE

# ---------------------------------------------------------
# Microsoft C 8 makefile by Bill Buckels 2008
# ---------------------------------------------------------
PRG=frag64X
PRG2=curlib
all: ..\$(PRG).exe ..\$(PRG2).exe

$(PRG).obj: $(PRG).c
      cl -c -AL -Zp1 $(PRG).c

$(PRG2).obj: $(PRG2).c
      cl -c -AL -Zp1 $(PRG2).c

..\$(PRG).exe: $(PRG).obj $(PRG).c MAKEFILE
     link $(PRG).obj,..\$(PRG).exe, NUL, /ST:8192 /NOE /NOD oldnames llibce graphics, NUL
     del $(PRG).obj
     
..\$(PRG2).exe: $(PRG2).obj $(PRG2).c MAKEFILE
     link $(PRG2).obj,..\$(PRG2).exe, NUL, /ST:8192 /NOE /NOD oldnames llibce graphics, NUL
     del $(PRG2).obj
   


#14
FRAG64X

This utility is one of many that I have provided (for FREE of course) with the Aztec C64 C Compiler, but guess what?, this can be used with whatever C compiler or whatever Computer Language you wish for both the C64 and the C128 to produce converted graphics from IBM-PC stuff to CBM stuff.

Amiga guys and Mac and Linux guys can adapt this if they wish. It was written for you too, so go ahead. You will however need to cut-in some screen stuff and would just probably be best running this in a DOS emulator and it's only a 16 bit MS-DOS program after all.


/* Frag64x (C) Copyright 2008 Bill Buckels */

#include <stdio.h>
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#include <dos.h>
#include <bios.h>
#include <malloc.h>
#include <string.h>
#include <graph.h>

#define bitsperbyte 8

unsigned int tempwidth, tempheight;

char buf1[66],buf2[66], buf3[66], buf4[66], ext[5],ext2[5];
char vhi[66], cmc[66], vmc[66];


int Color1, Color2, Color3, background;

/* poke values for colors */
/* not used - left here for reference */
#define C64_BLACK 0
#define C64_BWHITE 1
#define C64_RED 2
#define C64_CYAN 3
#define C64_PURPLE 4
#define C64_GREEN 5
#define C64_BLUE 6
#define C64_YELLOW 7
#define C64_ORANGE 8
#define C64_BROWN 9
#define C64_LRED 10
#define C64_DGRAY 11
#define C64_MGRAY 12
#define C64_LGREEN 13
#define C64_LBLUE 14
#define C64_LGRAY 15

/* return the color value of the pixel at x, y */
unsigned char getpixel(int x, int y)
{
    union REGS inregs, outregs;

    inregs.h.ah = '\x0d';
    inregs.x.cx = x;
    inregs.x.dx = y;

    int86(0x10, &inregs,&outregs);
    return outregs.h.al;
}

void putpixel(int x, int y,int pixelvalue)
{
    union REGS inregs, outregs;

    inregs.h.ah = '\x0c';
    inregs.h.al = pixelvalue;
    inregs.x.cx = x;
    inregs.x.dx = y;

    int86(0x10, &inregs,&outregs);
}

/* pcx encoder helper */
int encput(unsigned char byt,unsigned char cnt, FILE *pcxfile)       // the writer for the encline function
{
          if(cnt){
            if((cnt==1)&& (0xc0 != (0xc0 &byt))){
                if(EOF == fputc((int)byt,pcxfile))
                return(0);
                return(1);
            }
            else{
                if(EOF==fputc((int)0xc0|cnt,pcxfile))
                return(0);
                if(EOF==fputc((int)byt,pcxfile))
                return(0);
                return(2);
            }
        }
        return(0);

}

/* encode a line in pcxformat encoding */
int encline(unsigned char *inbuff,int inlen, FILE *pcxfile)  // encodes a raw line and writes it out to disk
{
    unsigned char this,last;
    int srcindex,i;
    int total;
    unsigned char runcount;
    total=0;
    last = *(inbuff); runcount=1;

for(srcindex=1;srcindex!=inlen;srcindex++){
    this= *(++inbuff);
    if(this==last){
        runcount++;
        if(runcount==63){
            if(!(i=encput(last,runcount,pcxfile)))
            return(0);
            total+=i;
            runcount=0;
        }
    }
    else{
        if(runcount){
            if(!(i=encput(last,runcount,pcxfile)))
            return(0);
            total+=i;
        }
        last=this;
        runcount=1;
      }
   }

   if(runcount){
    if(!(i=encput(last,runcount,pcxfile)))
    return(0);
    return(total+i);
    }
    return (total);

}


int fragin(char *fragment)
{

     FILE *fp;

     int fh,action,x,y,x1,y1,result;
     unsigned char far *buffer;
     unsigned char far *crt= (char *)0xb8000000l;
     unsigned int width, height;
     unsigned int buffersize,headerlength=7;
     unsigned char floodcolor;
     char c,d;

    fp=fopen(fragment,"rb");

    if (NULL == fp)return 1;


    buffersize=filelength(fileno(fp))-headerlength;
    fclose(fp);

    buffer=_fmalloc(buffersize);

    if (NULL == buffer)return 1;

    fh = open(fragment,O_RDONLY|O_BINARY);
    read(fh,buffer,7);

    /* minimal header check */
    if (buffer[0] != 0xfd) {
close(fh);
_ffree(buffer);
return 1;
}


    /* check for a fullscreen BSAVED image */
    /* the minimimum size for a BSAVED screen is larger than the maximum for a fullscreen PUT */
    if (buffersize > 16191) {
    read(fh,crt,16192);
    close(fh);
    _getimage(0,0,319,199,buffer);

}
    else {
read(fh,buffer,buffersize);
    close(fh);
}

    width=(buffer[0]|buffer[1]<<8) ;

    tempwidth=width/2;

    if((width%bitsperbyte)!=0)
    width=(width/bitsperbyte)+1;
    else
    width=(width/bitsperbyte) ;

    height=(buffer[2]|buffer[3]<<8);
    tempheight = height;

   /*
   floodcolor=buffer[4];
   memset(crt,floodcolor,0x4000);

   */

    _putimage(0,0,buffer,_GPSET);

    result = 0;
    while ((c = toupper(getch()))!=13) {

   if (c == 27) {
   result = 1;
   break;
   }

       if (c == 'B')floodcolor = 0;
       if (c == 'C')floodcolor = 1;
       if (c == 'M')floodcolor = 2;
       if (c == 'W')floodcolor = 3;

       if (c == 'A') action = _GAND;
       if (c == '0') action = _GOR;
       if (c == 'R') action = _GPRESET;
       if (c == 'N' || c == 'H' || c == 'H') action = _GPSET;
       if (c == 'X') action = _GXOR;

switch(c)
{
case 0:     getch(); break; /* fkeys are not valid here */
case 'H':
             _putimage(0,0,buffer,action);
            width = tempwidth / 2;
            for (y = 0; y < tempheight; y++) {
   x1 = tempwidth - 1;
                       for (x = 0; x < width; x++) {
        c =  getpixel(x,y);
        d =  getpixel(x1,y);
        putpixel(x,y,d);     /* swap horizontal pixels */
        putpixel(x1,y,c);
        x1--;
   }
}
x = tempwidth - 1;
y = tempheight - 1;
_getimage(0,0,x,y,buffer);
break;
case 'V':
             _putimage(0,0,buffer,action);
            height = tempheight / 2;
            y1 = tempheight - 1;
            for (y = 0; y < height; y++) {
                       for (x = 0; x < tempwidth; x++) {
        c =  getpixel(x,y);       /* swap vertical pixels */
        d =  getpixel(x,y1);
        putpixel(x,y,d);
        putpixel(x,y1,c);
   }
   y1--;
}
x = tempwidth - 1;
y = tempheight - 1;
_getimage(0,0,x,y,buffer);
break;




case 'X':
case 'R':
case 'N':
case 'O':
case 'A':
   _putimage(0,0,buffer,action);
   c=getch();
   if (c == 0)getch();
   if (c == 27) _putimage(0,0,buffer,_GPSET);
   break;
case 'S':  _putimage(1,0,buffer,_GPSET);
   c=getch();
   if (c == 0)getch();
   if (c == 27) _putimage(0,0,buffer,_GPSET);
   break;

            case 'B':
            case 'C':
case 'M':
case 'W':  for(y = 0; y < 200; y++)
for (x = 1; x < 320; x+=2)
   if (getpixel(x,y) == floodcolor)
  putpixel(x-1,y,floodcolor);

   c=getch();
   if (c == 0)getch();

   if (c == 27) _putimage(0,0,buffer,_GPSET);
   break;


}

    }

    _ffree(buffer);
    return result;

}


unsigned char bigbuf[8000];

/* saves a hires C64 image */
int savefrag64(char *name, int mode)
{

FILE *fp, *fp2=NULL,*fp3=NULL;
int x, y, x1, y1, rows, columns, row, col;
unsigned c, ch, ctr = 0, header = 0, idx;

if(tempwidth%8 !=0)
  tempwidth  = ((tempwidth/8)*8)+8; /* multiple of 8 */

if(tempheight%8 !=0)
  tempheight  = ((tempheight/8)*8)+8; /* multiple of 8 */

columns = tempwidth/8;
rows = tempheight/8;

fp = fopen(name,"wb");

if (NULL == fp) {
/* perror(name); */
return 1;
}

fp2 = fopen(buf3,"wb");
fp3 = fopen(buf4,"w");



   /* create a header */
   /* meaning is rows x columns if a fragment */

   /* image is block oriented */
   if (tempwidth == 320 && tempheight == 200) {
   fputc(0,fp);
   fputc(0x20,fp); /* if a full screen, image is bsaved with colors */
   }
   else {
   /* if a fragment, the image is saved without colors */
   /* fragments use the colors of the background image */
   /* the row and column info necessary to display is included */
   /* as the header instead of the load address. */
   fputc(rows,fp); /* this is oriented to how the loader works */
   fputc(columns,fp); /* and to how the C64 screen is arranged */
   if (NULL != fp2) {
    /* compressed fragments do not have color values */
    /* but they contain the row and column info necessary to unpack */
    header = 2;
    fputc(rows,fp2);
    fputc(columns,fp2);
   }
   }


   if (NULL != fp3) {
    /* the c array does not contain any positioning or color info, just data */
    fprintf(fp3,"/* %s.h Graphics Image Header Created by\n"
                "   Frag64x(C) Copyright Bill Buckels 2008 */\n\n",buf1);

    fprintf(fp3,"/* these arrays are suitable for embedding in Aztec C64 Programs */\n");
    fprintf(fp3,"/* remove or change the names of the following as required */\n");

    fprintf(fp3,"int %smode = %d;\n",buf1,mode);
    fprintf(fp3,"int %srows = %d;\n",buf1,rows);
    fprintf(fp3,"int %scols = %d;\n",buf1,columns);
   }



   for (row = 0; row < rows; row++) {
   for (col = 0; col < columns; col++) {

   y = row * 8;
   x = col * 8;

       for (y1 = y; y1 < (y+8); y1++) {
  c = 0;
      for (x1 = x; x1 < (x+8); x1+=mode) {
       c = c << mode;
       if (mode == 1) {
   if (getpixel(x1,y1) != 0)c = c|1; /* map colors to white */
   }
       else {
   ch = getpixel(x1,y1);
   c = c | ch;
   }
  }
  if (mode == 1)c = c^0xff;
  fputc(c,fp);
  if (NULL != fp2)bigbuf[ctr] = c;
  ctr++;
  }

   }
   }




   fclose(fp);

   if (NULL != fp3) {
   switch(mode) {
   case 2:

/* light blue and light red defaults */
c = (Color1 << 4 | Color2);
fprintf(fp3,"int %svram = %d;\n",buf1,c);

c = (background << 4 | Color3);
fprintf(fp3,"int %scram = %d;\n",buf1,c);
fprintf(fp3,"int %sbk = %d;\n",buf1,background);
fprintf(fp3,"int %sc1 = %d;\n",buf1,Color1);
fprintf(fp3,"int %sc2 = %d;\n",buf1,Color2);
fprintf(fp3,"int %sc3 = %d;\n",buf1,Color3);
break;


   default:

c = (Color2 << 4 | Color1);
fprintf(fp3,"int %svram = %d;\n",buf1,c);
fprintf(fp3,"int %sc1 = %d;\n",buf1,Color1);
fprintf(fp3,"int %sc2 = %d;\n",buf1,Color2);
break;


   }
   }

   /* if a full screen, save the colors */
   if (tempwidth == 320 && tempheight == 200) {
   switch(mode) {
       case 2:
                 fp = fopen(vmc,"wb");
                 if (NULL == fp) break;
                 fputc(0,fp);
fputc(0x1C,fp);
/* light blue and light red defaults */
                 c = (Color1 << 4 | Color2);
for (x = 0; x <1000; x++)fputc(c,fp);
                 fclose(fp);

                 /* fullscreen multicolor compressed is vram value
                    followed by cram value followed by encoded data */
                 if (NULL != fp2)fputc(c,fp2);

                     fp = fopen(cmc,"wb");
                 if (NULL == fp) break;
                 fputc(0,fp);
fputc(0xD8,fp);
             c = (background << 4 | Color3);
                 for (x = 0; x <1000; x++)fputc(c,fp); /* default white colormap */
                 fclose(fp);

             /* fullscreen multicolor compressed is vram value
                    followed by cram value followed by encoded data */
                 if (NULL != fp2){
fputc(c,fp2);
                  encline((unsigned char *)&bigbuf[0],8000,fp2);
                  fclose(fp2);
                  header = 2;
}
                     break;


       default:  fp = fopen(vhi,"wb");
                 if (NULL == fp) break;
                 fputc(0,fp);
fputc(0x1C,fp);
c = (Color2 << 4 | Color1);
for (x = 0; x <1000; x++)fputc(c,fp);
fclose(fp);

                     /* fullscreen hires compressed is vram value followed by encoded data */
                 if (NULL != fp2){
header = 1;
fputc(c,fp2);
                  encline((unsigned char *)&bigbuf[0],8000,fp2);
                  fclose(fp2);
}
break;


   }


   }
   else {
if (NULL != fp2){
encline((unsigned char *)&bigbuf[0],ctr,fp2);
fclose(fp2);
}

   }

   if (NULL != fp3){

       fp2 = fopen(buf3,"rb");

       fprintf(fp3,"#define RAW 1\n#ifdef RAW\n");
       fprintf(fp3,"/* raw array of C64 image */\n");
       fprintf(fp3,"char %s[%d] = {\n",buf1,ctr);

       c=0;
       for (idx = 0; idx < ctr; idx++) {
  x=bigbuf[idx];
      fprintf(fp3,"%3d",x);
      if(idx == (ctr-1))fprintf(fp3,"};");
      else fprintf(fp3,",");
          c++;
      if (c==11) {
  fprintf(fp3,"\n");
  c=0;
  }

   }
       fprintf(fp3,"\n#else\n");


       c=filelength(fileno(fp2))-header;
       fprintf(fp3,"/* pcx encoded array of C64 image */\n");
       fprintf(fp3,"char %sx[%d] = {\n",buf1,c);
       for (idx = 0; idx < header; idx++)fgetc(fp2);
       idx = 0;
       x= fgetc(fp2);
       fprintf(fp3,"%3d",x);
       do {
   x= fgetc(fp2);
   if (x== EOF) {
   fprintf(fp3,"};\n#endif\n");
   break;
   }
   fprintf(fp3,","); idx++;
   if (idx == 11) {
      fprintf(fp3,"\n");
      idx = 0;
   }
   fprintf(fp3,"%3d",x);

   }
       while (x!=EOF);
       fclose(fp2);
       fclose(fp3);
   }

   return 0;

}

main(int argc,char *argv[])
{
   int result,mode,idx;
   char *wordptr,c;

   if (argc < 2) {
      puts("Frag64X (C) Copyright 2008 Bill Buckels");
      puts("All Rights Reserved.");
      puts("Usage is \"FRAG64X MY.PUT\"");
      puts("Option   \"FRAG64X MY.PUT 2\"");
      puts("Option   \"FRAG64X MY.PUT 4\"");
      puts("Options   Number of Colors (2 or 4)");
      puts("Default   2 Colors");
      puts("Input     IBM-PC 4 Color CGA BSaved Image Fragment");
      puts("Output    Commodore 64 HIRES or Multi-Color Image Fragent");
      puts("Extension MY.fr2 (2 Color) or MY.fr4 (4 Color) for fragments");
      puts("Extension MY.BHI (2 Color) or MY.BMC (4 Color) for Full Screen");
      puts("Encoded   MY.f2x (2 Color) or MY.f4x (4 Color) for fragments");
      puts("Encoded   MY.BHX (2 Color) or MY.BMX (4 Color) for Full Screen");
      puts("Header    MY.h encoded static array option for Aztec C64 Programs");
      puts("Option 2  Color Mapping (Default is B&W (hires) or BRW on Black)");
      puts("          Color Map Values are in the range of 0-15");
      puts("Option 2  \"FRAG64X MY.PUT 2 Color1 background\"");
      puts("Option 2  \"FRAG64X MY.PUT 4 Color1 Color2 Color3 background\"");
      puts("          Color Mapping is for Fullscreen Only (320 x 200)");
      puts("Hotkeys   Enter=Save * Esc=Abort * H=Horizontal Flip * V=Vertical Flip");
      puts("          Widen Pixels - B=Black, C=Cyan, M=Magenta, W=White");
      puts("          Effects - A=AND, O=OR, X=XOR, R=REVERSE, N=NORMAL (reset)");
      exit(result);

   }

   /* if we are saving a hires fragment
      we encode every pixel.

      if we are saving a multicolor fragment
      we encode every second pixel.

      in either case the background is assumed
      to be black for the entire image.

      this makes CGA mode fragments ideal for
      encoding both screens and fragments.

      any palette that we wish to set in our
      programs can be mapped to each of the
      available colors in real time.

      a consistent palette needs to used anyway
      if we are combining screens and fragments.

      */

     strcpy(ext,".fr2");
     strcpy(ext2,".f2x");

     mode = 1;

     Color1 = 1;
     Color2 = 0;
     Color3 = 1;
     background = 0;


     if (argc > 2) {
if (argv[2][0] == '4') {
strcpy(ext,".fr4");
strcpy(ext2,".f4x");
mode = 2;
             Color1 = 14; /* lblue */
             Color2 = 10; /* lred  */
}
if (argc > 3) Color1 = atoi(argv[3])&0xf;
if (argc > 4) Color2 = atoi(argv[4])&0xf;
if (argc > 5) Color3 = atoi(argv[5])&0xf;
if (argc > 6) background = atoi(argv[6])&0xf;
}

_setvideomode(5); /* CGA 4 Color */
result = fragin(argv[1]);

if (result == 0) {

/* full screen */
if (tempwidth == 320 && tempheight == 200) {
if (mode == 1)  {
strcpy(ext,".bhi");
strcpy(ext2,".bhx");
}
else {
strcpy(ext,".bmc");
strcpy(ext2,".bmx");
}
}

strcpy(buf1,argv[1]);
wordptr=strtok(buf1,".");
sprintf(buf2,"%s%s",buf1,ext);
sprintf(buf3,"%s%s",buf1,ext2);
sprintf(vhi,"%s.vhi",buf1);
sprintf(cmc,"%s.cmc",buf1);
sprintf(vmc,"%s.vmc",buf1);
sprintf(buf4,"%s.h",buf1);

for (idx = 0; buf1[idx]!= 0; idx++)buf1[idx] = tolower(buf1[idx]);

result = savefrag64(buf2,mode);

    }
_setvideomode(3); /* CGA 80 Col Color Text */

    if (result == 0){
puts("Success!");
sprintf(buf2,"dir /O:D /b %s.???",buf1);
system(buf2);
}
    else {
puts("Unable to save C64 image!");
}

    exit(result);
}


Continued Next Message...
#15


CBINLODE - bitmapped graphics file loader

This is a bitmapped graphics viewer program for C64 HIRES and MultiColor BSaved screens. These screens can be created on the C64 if you are so inclined to write a program to do so, or from both IBM-PC and C64 Image Sources by using my ClipShop program for Windows XP.

The programming tools that I distribute with Aztec64 will also create these (and other C64 graphics) from IBM-PC graphics. This program also handles HIRES Doodle Draw and HIRES Art Studio and MultiColor Koala Painter Screen Images that can also be created in ClipShop as well as by a variety of other sources.


/* cbinlode.c (C) Copyright Bill Buckels 2008 */


/* a picture viewer for the Commodore 64   */
/* written in Manx Aztec C65 Version 1.05h */
/* runs under Commodore BASIC 2            */
/* displays BSaved HIRES and Multi-Color Images */
/* requires a text script called piclist   */



/*

Image Support

The images supported by this program are either split images of the type
created by my ClipShop program and require the file extensions that ClipShop
provides, or are Art Studio, Doodle Draw or Koala Paint uncompressed images,
with the file extensions of .ART, .DD, or .KOA that are supported by
ClipShop and other C64 image conversion utilities currently in use.

Images are read directly from disk into to their respective memory areas.

The images created by ClipShop store the palette(s) in a separate file from
the bitmap. Bitmaps are all 8002 bytes long and palette files are all 1002
bytes long. The first two bytes are a BSaved Header followed by data.

In the case of ClipShop's multicolor images, a third file (a second palette
file) contains the third color and background color. The background is in
the high nibble and is identical in all of the 1000 positions used by C64
palettes.

The first byte of the second palette is used to set the border (low nibble)
and background (high nibble) colors and then transferred to the first
multicolor position in memory, followed by reading the other 999 bytes
containing the rest of the third colors in the second palette directly to
the remaining 999 multicolor positions in memory.

In all cases, each ClipShop file is read in 2 passes, with the first pass
removing the header information and the second pass being read directly to
memory. Since I am doing a raw read, there probably isn't a more efficient
way to do this.

In the case of the ART, DD, and KOA images I do almost the same thing but
all bitmap and palette information comes from a single file.

Image Load Strategy

The image file extension drives the loader, but if a file name without an
extension is entered is typed-in I use the following strategy:

First I try to open a HIRES BSaved file with a single palette. I depend
entirely on naming convention so I expect an extension of ".BHI" for the
bitmap file paired with a palette file of ".VHI".

Second, if that fails, I try to open a Multi-Color BSaved File with an
extension of ".BMC" and 2 palette files with extensions of ".VMC" and ".CMC"
respectively again depending entirely on naming convention.

If both of those strategies fail, then I try for a .KOA, .ART, and .DD file
respectively.

If that fails, I just give-up and assume that whatever they are loading is a
HIRES BSaved image without a palette, so I set a black and white palette
manually and let them use whatever naming they like.

This part can be expanded to test for other image types that the C64
supports. The header and file information could have been used in the loader
to make it more robust in auto-detecting the many C64 graphics that exist,
as well as file length and load addresses stored in the image. It is only in
the interests of keeping this simple that I am using file extensions as "the
easy way out" in my loader routine and limiting my strategy to keep this
program smaller and more readable.

*/



/* memory map for creating C64 graphics programs in Aztec C

0x800 - (2048) - basic load address
0x810 - binary base address
0x4000 - data load address (advance as necessary if problems)
0x4400 - code load address (advance as necessary for more data)

for embedding a HIRES image
insert vram before bitmap

1000 bytes for vram storage
8000 bytes for bitmap

insert bitmap at default screen address when program loads
insert vram 1K before bitmap
0x2000
0x1c00

the bitmap is immediately displayed on the screen and vram
storage is then moved immediately to the actual vram address

for embedding a 1024 byte 8 x 8 fontset (characters 0-127)
insert fontset 2K before bitmap
0x1800

I have found in practice that no insertion of data can be done
below these areas.


*/
#define CMAIN 1

#include <poke.h>
#include <colors.h>
#include <stdio.h>

#define NONE 0
#define BHI 1
#define BMC 2
#define ART 3
#define DD  4
#define KOA 5

int itype = NONE;

char tmpbuf[3];

char image[40];
char *palette[40];
char *cmap[40];

/* since less than 25 C64 images can be placed on a CBINLODE disk
   the following pointer array is sufficient for memory
   storage of image names from the PICLIST.
   This allows the PICLIST to be opened once at the start of the
   program then to be read into memory referenced by this array */
char *inames[25];


nocr(ptr, cr)
char *ptr;
char cr;
{
int idx;

if (cr == '.')itype = NONE;

for (idx=0;ptr[idx] != 0; idx++) {
    if (ptr[idx] == cr) {
   ptr[idx] = 0;

   if (cr == '.') {
  if (ptr[idx+1] == 'B' && ptr[idx+2] == 'H' && ptr[idx+3] == 'I') {
  itype = BHI;
  break;
  }
  if (ptr[idx+1] == 'B' && ptr[idx+2] == 'M' && ptr[idx+3] == 'C') {
  itype = BMC;
  break;
  }
  if (ptr[idx+1] == 'A' && ptr[idx+2] == 'R' && ptr[idx+3] == 'T') {
  itype = ART;
  break;
  }
  if (ptr[idx+1] == 'D' && ptr[idx+2] == 'D') {
  itype = DD;
  break;
  }
  if (ptr[idx+1] == 'K' && ptr[idx+2] == 'O' && ptr[idx+3] == 'A') {
  itype = KOA;
  break;
  }
   }

   break;
}

}

}


FILE *fp = NULL;
char buffer[128];

int xkey = 90; /* exit = Z */

main()
{
int c,fh,idx,jdx;

    scr_clear();

    /* background color, bordercolor */
    scr_back(C64_LBLUE,C64_BLUE);

/* set to hires mode 320 x 200 and display the logo */
    setcrtmode(1);
    setlogo();

    pfont("Please Wait...",9,13,0,1,-1);

    /* open the piclist and read the images into the buffer */
    /* I am using a fixed field length of 40 characters in the buffer */
    for (idx = 0;idx < 25; idx++)inames[idx] = NULL;
    fp = fopen("PICLIST","r");
if (fp!=NULL) {
  idx = 0;
  jdx = 0;
  while (fgets(buffer,128,fp) != NULL) {
  if (idx > 24)break;
          nocr(buffer,'\n');
          buffer[39]=0;
          inames[idx] = (char *)&vstore[jdx];
          strcpy(inames[idx],buffer);
          idx++;
          jdx +=40; /* 40 character field length */

  }
  fclose(fp);

    }


    /* clear all keypressess */
    while (kbhit()); /* wait for key release */
    kbflush();

    pfont("Press Any Key.",9,13,0,1,-1); /* erase please wait */

    while (!kbhit()); /* wait for key press */
    /* clear last palette */
    gclr(-1,0,0);
    setcrtmode(0);
    scr_clear();

    /* clear bmp */
    gclr(0,-1,-1);
    while (kbhit()); /* wait for key release */
    /* clear the buffer */
    kbflush();

BEGERR:


    /* home cursor, clear screen */
    scr_clear();

    /* background color, bordercolor */
    scr_back(C64_LBLUE,C64_BLUE);

    scr_txtcolor(C64_BWHITE); /* bright white text */

    printf("CBINLOAD.PRG BY BILL BUCKELS 2007\n\nPICTURES:\n\n");

jdx = 65; /* ascii 'A' */
for (idx = 0; idx < 25; idx++) {
   if (inames[idx] == NULL)break;
   printf("  %c - %s\n",jdx, inames[idx]);
   jdx++;
}
printf("  %c - QUIT TO BASIC\n",xkey);


RENTER:

    printf("\nENTER PICTURE:");
    gets(buffer);
    if (buffer[0] == 0 || (buffer[1] == 0 && buffer[0] == xkey)) goto ENDERR;

    jdx=0;
    if (buffer[1] == 0) {
   jdx = 999;
   if (buffer[0] > 64 && buffer[0] < 90) {
        idx = buffer[0] - 65;
        if (inames[idx] != NULL){
strcpy(buffer,inames[idx]);
jdx = 0;
}
   }

}
if (jdx == 999) {
printf("INVALID MENU OPTION.");
goto RENTER;
}


    strcpy(image,buffer);
    nocr(image,'.');
    strcpy(palette,image);
    strcpy(cmap,image);


    switch(itype) {
   case KOA:
   case ART:
   case DD:
   case BMC:
   case BHI:
        fh = open(buffer,0); break;
   default:
        /* try to open as hires with palette */
        strcat(image,".BHI");
        fh = open(image,0);
        if (fh!= -1) {
itype = BHI; break;
}
        /* if that fails try to open as multicolor with palette and cmap */
        strcpy(image, palette);
strcat(image,".BMC");
        fh = open(image,0);
        if (fh!= -1) {
itype = BMC; break;
}
/* if that fails try to open as Koala Painter */
strcpy(image, palette);
strcat(image,".KOA");
        fh = open(image,0);
        if (fh!= -1) {
itype = KOA; break;
}
/* if that fails try to open as Art */
strcpy(image, palette);
strcat(image,".ART");
        fh = open(image,0);
        if (fh!= -1) {
itype = ART; break;
}
/* if that fails try to open as Doodle Draw */
strcpy(image, palette);
strcat(image,".DD");
        fh = open(image,0);
        if (fh!= -1) {
itype = DD; break;
}
/* if all fail assume hires without palette */
fh = open(buffer,0); break;

}

    if (fh == -1) {
printf("CAN'T OPEN %s",buffer);
goto RENTER;
}


scr_clear();

setcrtmode(1);

    switch(itype) {
case KOA:
/* Koala Painter */
/* second step required for multicolor graphics mode */
setcrtmode(2);

    palette[0] = 0;
    cmap[0] = 0;

    break;

    case ART:
    palette[0] = 0;
    cmap[0] = 0;
    break;

    case DD:
        /* doodle draw stores the palette before the bitmap */
        palette[0] = 0;
        cmap[0] = 0;
        read(fh,tmpbuf,2);
        read(fh,vram,1000);
        read(fh,buffer,22); /* padding - the last 2 bytes will be thrown away below */
        break;

case BMC:
    /* second step required for multicolor graphics mode */
            setcrtmode(2);

            strcat(palette,".VMC");
            strcat(cmap,".CMC");

            break;

case BHI:
default:
    strcat(palette,".VHI");
}

    read(fh,tmpbuf,2);
    read(fh,bmp,8000);
    if (itype == KOA || itype== ART)read(fh,vram,1000);
    if (itype == KOA) {
read(fh,cram,1000);
read(fh,buffer,1);
/* background color, bordercolor */
        scr_back((buffer[0] & 0xf),(cram[0] & 0xf));
}

    close(fh);

    if (palette[0] != 0) {
    fh = open(palette,0);
    if (fh != -1) {
read(fh,tmpbuf,2);
read(fh,vram,1000);
close(fh);
}
else {
for (idx = 0; idx < 1000; idx++)vram[idx] = C64_BWHITE;

}
}

    /* multicolor mode */
    if (itype == BMC) {
            fh = open(cmap,0);
if (fh != -1) {
read(fh,tmpbuf,3);
/* background color, bordercolor */
                scr_back((tmpbuf[2] >> 4),(tmpbuf[2] & 0xf));
                cram[0] = tmpbuf[2];
read(fh,&cram[1],999);
close(fh);
        }
}


    /* clear all keypressess */
    while (kbhit());
    kbflush();
    c = getch();

    /* clear last palette and bitmap */
    gclr(0,0,0);

    setcrtmode(0);

    if (c!=xkey) goto BEGERR;

ENDERR:

scr_reset();
exit(0);
}


MAKEFILE

# ---------------------------------------------
# Aztec C64 makefile by bill buckels 2007
# ---------------------------------------------

PRG=cbinlode

$(PRG).B64: $(PRG).asm
   as65 $(PRG).asm
   del $(PRG).asm
   copy $(CLIB65)B64NAT.LIB .
   copy $(CLIB65)C64NAT.LIB .
   ln65 $(PRG).rel B64NAT.LIB C64NAT.LIB -b 810 -d 4080 -c 4480
   del $(PRG).rel
   del C64NAT.LIB
   del B64NAT.LIB
   copy BAGGAGE\$(PRG).bhi .
   copy BAGGAGE\$(PRG).vhi .
   ADDLOGO $(PRG)
   MKBASIC $(PRG).sys $(PRG).prg
   del $(PRG)
   del $(PRG).sys
   del $(PRG).bhi
   del $(PRG).vhi
   
$(PRG).asm: $(PRG).c MAKEFILE
    copy $(INCL65)stdio.h .
    copy $(INCL65)poke.h .
    copy $(INCL65)colors.h .
    c65 $(PRG).c
    del stdio.h
    del poke.h
    del colors.h


#16
Libraries In General

To avoid typing so many object file names on the link line, libraries of object files were long ago dreamed-up so that linkers could just have a single library name reference for a bunch of these objects.

That doesn't sound very scientific does it? It'll do.

Here's something else you need to know.

Headers In General

If you include header files in a program and they describe functions in a library that doesn't mean that those functions will end-up linked in to your programs. It just means that the linker will use more memory to store all that useless information. So don't put a bunch of includes for headers that reference library functions that you don't use into your program.

Linking in General

I am talking about old-fashioned libraries and not DLL's like in Windows. These are statically bound at compile time and not dynamically bound at runtime with implied library references. If you don't understand what I said just know the following:

If you link to a library in Aztec C as in most if not all C compilers, only the library function modules that you use explictly and indirectly will be added to your finished program by the linker. No additional code will be added that is not called.

This IS the function of the linker. There's lots written on this topic if you want to go further.

I don't and I want to finish off by providing you with the source code for the library manager used with Aztec C64 and also Aztec-CZ80 which builds CP/M 80 programs that run on the C128.

Building Old Programs and Errors

I have even ported C-code from the 70's from PDP11's and an amazing amount of other old C-code which still compiles under Microsoft Visual Studio 2005. I know through experience what to change and what to do to make it all work. The main part of this process is to fix all the errors and also all the warnings. I take great pride in the fact that you can build anything that I put-out on the Internet and BBS's before it without either errors or warnings and also anything that I write anywhere else for that matter. So too should you always take great pride in doing so because then you haven't made a mess for someone else. The people that you can make a mess for starts with yourself and said mess can extend to erasing your entire hard disk and other major annoyances so listen up!

The following code compiles without warnings or errors and has been fully tested as with everything I do. It's not perfect but it is genuine vintage retro computing and it will do.

Libutil - Aztec C Library Utility

Quote from: Aztec C64 Documentation
libutil v1.05g fixups (C) Copyright Bill Buckels 2008. All Rights Reserved.
usage:  libutil [-artx] [-o libraryname.lib] name1.rel name2.rel ...
create: libutil [-o libraryname.lib] name1.rel name2.rel ...

-a add one or more object (.rel) modules into an existing library...
-r replace one or more object (.rel) modules into an existing library.
   add and replace are effectively and functionally the same command.
-t list all object (.rel) modules in a library.
-x extract one or more object (.rel) modules from a library.
   name1.rel name2.rel etc. (names must be as originally entered)

note: this utility has not been extended beyond its original capabilities.
      it is intended for use with Aztec C v1.0x and is not compatible with
      later versions that used lb.exe and its library format(s).

If you are using the x86 EXE, this was compiled under Aztec C86 v4.10d and is
for the Aztec C65 v1.06e MS-DOS C64 cross development environment using
the C II v1.05h compiler. The libutil source originated in Aztec C for CP/M80.
the output has been changed to default to the .rel object extension and
minor fixups were required for x86 OS (MS-DOS XP) and compiler compatibility.



#define C64 1

#ifdef UNIX
#include <stdio.h>
#define FNSIZE 100
#define EXTEND ".rel"
#else
#ifdef C64
#define EXTEND ".rel"
#else
#define EXTEND ".o"
#endif
#ifdef MPU6502
#include "/usr/xbin/mtuio.h"
#else
#include "stdio.h"
#define FNSIZE 20
#endif

#endif
#include "object.h"
#define MAXMOD 256
#define GRAIN 128 /* boundary to start new modules on within the file */
#define GRSHFT 7 /* log base 2 of GRAIN */

long ftell();
int append, extract, table;
FILE *libfp;

/* BB */
char *gets();
char *rindex();
char *index();

#define clear(addr,len,val) memset(addr,val,len)


char *usage = "libutil v1.05g fixups (C) Copyright Bill Buckels 2008. All Rights Reserved.\n"
"usage:  libutil [-artx] [-o libraryname.lib] name1.rel name2.rel ...\n"
"create: libutil [-o libraryname.lib] name1.rel name2.rel ...\n\n"
"-a add one or more object (.rel) modules into an existing library...\n"
"-r replace one or more object (.rel) modules into an existing library.\n"
"   add and replace are effectively and functionally the same command.\n"
"-t list all object (.rel) modules in a library.\n"
"-x extract one or more object (.rel) modules from a library.\n"
"   name1.rel name2.rel etc. (names must be as originally entered)\n\n"
"note: this utility has not been extended beyond its original capabilities.\n"
"      it is intended for use with Aztec C v1.0x and is not compatible with\n"
"      later versions that used lb.exe and its library format(s).\n\n"
"If you are using the x86 EXE, this was compiled under Aztec C86 v4.10d and is\n"
"for the Aztec C65 v1.06e MS-DOS C64 cross development environment using\n"
"the C II v1.05h compiler. The libutil source originated in Aztec C for CP/M80.\n"
"the output has been changed to default to the .rel object extension and\n"
"minor fixups were required for x86 OS (MS-DOS XP) and compiler compatibility.";

main(argc,argv)
int argc; char **argv;
{
FILE *fp, *outfp;
register char *cp, *tp;
char *libname, templib[FNSIZE];
struct header head;
unsigned i, size, lastone, global;
struct library lib;
struct l_item *item;
struct gbltab sym;
int count;
long next, origpos, lastdir;
struct {
char modname[10];
char filename[FNSIZE];
} modlist[MAXMOD], *modp, *maxmod;
char *bufp, cmdbuf[130];

libname = "libc.lib";
outfp = NULL;
if ( argc < 2 ) {
use:
        /* BB more usage information */
        puts(usage);
exit(4);
}

while (--argc) {
cp = *++argv;
if (*cp++ != '-')
break;
while (*cp) {
switch (*cp++) {
default:
printf("bad argument: %s\n",cp);
goto use;
case 'o': case 'O':
libname = *++argv;
--argc;
continue;
case 'a': case 'A':
append = 1;
continue;
case 'r': case 'R':
append = 1;
continue;
case 'x': case 'X':
extract = 1;
continue;
case 't': case 'T':
table = 1;
continue;
}
}
}

makename(templib, libname, ".$$$");
if (extract || table) {
if ((libfp = fopen(libname,"r")) == NULL) {
opnerr:
printf("Cannot open library: %s!\n",libname);
exit(4);
}
if (extract)
xtrct(argc,argv);
else
dir();
exit(0);
} else if (append) {
if ((libfp = fopen(libname, "r")) == NULL)
goto opnerr;
if ((outfp = fopen(templib, "w+")) == NULL)
goto opnerr;
} else {
if ((outfp = fopen(templib, "w+")) == NULL)
goto opnerr;
}

if ( argc < 1 )
goto use;
clear(&lib, sizeof lib, 0);
lib.lb_magic = H_LIBRARY;
item = lib.lb_items;
lastdir = 0;
fwrite(&lib, sizeof lib, 1, outfp);

modp = modlist;
bufp = cmdbuf;
*bufp = 0;
while ( argc ) {
if (strcmp(*argv, ".") == 0) {
for (;;) {
while (*bufp == ' ' || *bufp == '\t')
++bufp;
if (*bufp != 0)
break;
bufp = cmdbuf;
if (gets(cmdbuf)==NULL || *bufp==0 || strcmp(bufp, ".")==0) {
*bufp = 0;
--argc;
++argv;
goto nxtarg;
}
}
for (cp = modp->filename ; *bufp ; *cp++ = *bufp++)
if (*bufp == ' ' || *bufp == '\t')
break;
*cp = 0;
} else {
strcpy(modp->filename, *argv++);
--argc;
}
if ((cp = rindex(modp->filename,'/')) != NULL
|| (cp = rindex(modp->filename,':')) != NULL)
++cp;
else
cp = modp->filename;

clear(modp->modname, sizeof modp->modname, 0);
for (tp = modp->modname, i = 0 ; i < 8 ; ++i) {
if (*cp == 0 || *cp == '.')
break;
*tp++ = tolower(*cp++);
}

if (index(modp->filename,'.') == NULL)
strcat(modp->filename, EXTEND);
if (++modp >= modlist+MAXMOD) {
printf("too many module names!\n");
exit(4);
}
nxtarg: ;
}
maxmod = modp;
if (modp == modlist) {
printf("No modules to add or replace.\n");
fclose(outfp);
unlink(templib);
exit(4);
}

for (;;) {
if (libfp)
fp = libfp;
else {
for (modp = modlist ; modp < maxmod ; ++modp)
if (modp->filename[0])
goto fndmod;
break;

fndmod:
if ((fp = fopen(modp->filename,"r")) == NULL) {
printf("cannot open input: %s\n", modp->filename);
exit(4);
}
modp->filename[0] = 0;
if (libfp)
printf("replacing module: %s\n", modp->modname);
else
printf("adding module: %s\n", modp->modname);
}

while (fread(&head,sizeof(head),1,fp) == 1) {
if (head.h_magic == H_LIBRARY) {
fseek(fp, (long)(sizeof(struct library)-sizeof(head)), 1);
continue;
}
if (head.h_magic != H_MAGIC)
break;
origpos = ftell(fp) - sizeof head;
next = origpos + head.h_next;
lastone = ftell(outfp) >> GRSHFT;
if (head.h_name[0] == 0) {
strncpy(head.h_name, modp->modname, 8);
} else {
if (fp == libfp) {
for (modp = modlist ; modp < maxmod ; ++modp)
if (modp->filename[0] != 0 &&
strncmp(modp->modname,head.h_name,8) == 0) {
fseek(libfp, next, 0);
goto fndmod;
}
}
for (cp = head.h_name, i = 0 ; *cp && i < 8 ; ++i, ++cp)
*cp = tolower(*cp);
}
if ((global = head.h_global) != sizeof head) {
head.h_next = (head.h_end + GRAIN-1) & -GRAIN;
head.h_global = sizeof head;
head.h_local = sizeof head + head.h_local - global;
head.h_end = sizeof head + head.h_end - global;
}

if (fwrite(&head,sizeof(head),1,outfp) <= 0) {
ioerr:
printf("Error writting library!\n");
fclose(outfp);
unlink(templib);
exit(4);
}

if (global == sizeof head) {
if (copyfile(fp, outfp, head.h_next - sizeof head))
goto ioerr;
fseek(fp, origpos+global, 0);
} else {
fseek(fp, origpos+global, 0);
if (copyfile(fp, outfp, head.h_end - head.h_global))
goto ioerr;
fseek(fp, origpos+sizeof head, 0);
if (copyfile(fp, outfp, global-sizeof(head)))
goto ioerr;
}
padout(outfp, GRAIN);

count = (head.h_local - head.h_global) / sizeof (sym);
while ( count-- ) {
fread(&sym, sizeof sym, 1, fp);
if ((sym.g_flags&S_GLOBL) && sym.g_type != S_UND) {
if (item >= lib.lb_items+LBSIZE) {
padout(outfp, GRAIN);
lib.lb_next = ftell(outfp) >> GRSHFT;
fseek(outfp, lastdir, 0);
fwrite(&lib, sizeof lib, 1, outfp);
lastdir = lib.lb_next << GRSHFT;
fseek(outfp, lastdir, 0);
clear(&lib, sizeof lib, 0);
lib.lb_magic = H_LIBRARY;
fwrite(&lib, sizeof lib, 1, outfp);
item = lib.lb_items;
}
strncpy(item->li_name, sym.g_name, 8);
item->li_pos = lastone;
++item;
}
}
fseek(fp,next,0);
}
if (fp == libfp)
libfp = NULL;
fclose(fp);
}

fseek(outfp, lastdir, 0);
fwrite(&lib, sizeof lib, 1, outfp);
if (fclose(outfp) != 0)
goto ioerr;
    /* BB remove old library - otherwise rename cannot work */
unlink(libname);
rename(templib, libname);
exit(0);
}

padout(fp, bound)
unsigned bound; FILE *fp;
{
register unsigned i, next;

i = ftell(fp);
next = (i+bound-1) & -bound;
for ( ; i < next ; ++i )
putc(0,fp); /* pad out block */
}

dir()
{
struct header head;
register int i;

i = 6;
while (fread(&head,sizeof(head),1,libfp) == 1) {
if (head.h_magic == H_LIBRARY) {
fseek(libfp, (long)(sizeof(struct library)-sizeof(head)), 1);
continue;
}
if (head.h_magic != H_MAGIC)
break;
printf("%-12.8s", head.h_name);
if (--i == 0) {
putchar('\n');
i = 6;
}
fseek(libfp, (long)(head.h_next - sizeof(head)), 1);
}
if (i != 6)
putchar('\n');
fclose(libfp);
}

xtrct(argc,argv)
char **argv;
{
struct header head;
register int i;
long pos;

pos = 0;
for (pos = 0; fread(&head,sizeof(head),1,libfp) == 1; fseek(libfp,pos,0)) {
if (head.h_magic == H_LIBRARY) {
pos += sizeof(struct library);
continue;
}
if (head.h_magic != H_MAGIC)
break;
pos += head.h_next;
if (argc != 0) {
for (i = 0 ; i < argc ; ++i) {
if (strncmp(argv[i],head.h_name) == 0)
goto found;
}
continue;
}
found:
cpyout(&head);
}
fclose(libfp);
}

cpyout(hdr)
register struct header *hdr;
{
char name[20];
FILE *fp;
register int c;
int i, size;

if (hdr->h_name[0] == 0)
return;
size = hdr->h_next;
hdr->h_next = (hdr->h_next+255) & -256;
strncpy(name,hdr->h_name,8);
name[8] = 0;
strcat(name, EXTEND);
printf("Extracting: %s\n",name);
if ((fp = fopen(name,"w")) == NULL) {
printf("Cannot create %s\n",name);
exit(4);
}

if (fwrite(hdr, sizeof(struct header), 1, fp) != 1) {
ioerr:
printf("Error writing file: %s\n",name);
exit(4);
}

for (i = 0 ; i < size ; ++i)
#ifndef UNIX
if (putc(getc(libfp), fp) < 0)
goto ioerr;
#else
putc(getc(libfp), fp);
if (ferror(fp))
goto ioerr;
#endif

for ( ; i < hdr->h_next ; ++i)
putc(0,fp); /* pad out file */
if (fclose(fp) != 0)
goto ioerr;
}

copyfile(input, output, size)
FILE *input, *output;
{
while (size-- > 0)
#ifndef UNIX
if (putc(getc(input), output) < 0)
return -1;
#else
putc(getc(input), output);
if (ferror(output))
return -1;
#endif
return 0;
}

#ifdef UNIX
clear(cp, len, val)
register char *cp; register unsigned len;
{
while (len--)
*cp++ = val;
}

rename(onam, nnam)
register char *onam, *nnam;
{
unlink(nnam);
link(onam, nnam);
unlink(onam);
}

tolower(c)
register int c;
{
if (c >= 'A' && c <= 'Z')
return c - 'A' + 'a';
return c;
}

#endif

makename(dest,src,ext)
char *dest,*src,*ext;
{
register char *cp;

strcpy(dest,src);
if (cp = rindex(dest,'.'))
strcpy(cp,ext);
else
strcat(dest,ext);
}

MAKEFILE

# -------------------------------------------
# makefile by bill buckels 1997
# -------------------------------------------

libutil.exe: libutil.o
            ln libutil.o c.lib
            del libutil.o
            copy libutil.exe ..\libutil.exe
            del libutil.exe
            @echo All Done!

libutil.o: libutil.c
           cc libutil.c



#17
Adding Title Screen and Graphics Cursors to a Compiled Apple IIe ProDOS 8 Program

While off-topic to some degree, the C64 utility ADDLOGO was based on a similar program for Apple IIe programs.

Linking Aztec C Programs - General

When Aztec C cross-compilers were released, the linker provided several possible output format options (as a linker should and does). On the Apple IIe a BINARY program was Bloaded in DOS 3.3 (which is BASIC-ally the equivalent of the LOAD command on the C64).

However when the C64 program is produced, it needs a little bit of basic stuck on the beginning to BRUN the darned thing (that's not quite it but it'll do for an explanation). MKBASIC is used on the C64 to patch the beginning of the finished program (but this is hidden in MAKEFILE's that I have provided).

Anyway on the Apple IIe it is somewhat the opposite. The first 4 bytes are the BLOAD-able address of a linked BINARY program. Who needs BASIC in ProDOS anyway? So what we do when making a ProDOS program is use the little utility shown below to strip the BLOAD-able header from the SYS program and then embed whatever graphics artifacts we wish.

This then became the BASIS for my utility for the C64.



/* MAKEPRO2(C) Copyright Bill Buckels 1991-2008 */
/* All Rights Reserved. */

/* You have a royalty free right to use this program in any way
   you find useful provided that you agree that Bill Buckels
   has no Warranty Obligations or Liability in any way whatsoever. */

/* makes a prodos sys program with an embedded graphic */

/* removes the 4 byte BLOAD-able header from an Aztec C Apple IIe ProDOS Program */
/* adds a HIRES 6 Color Apple IIe Bitmap to an Aztec C Apple IIe ProDOS Program */
/* also adds a Bitmap CURSOR Library of bitmap graphics image fragments etc */

/* these are created by the designer independently using tools provided */

/* this is a 16 bit program compiled under MSC 8,00c */
/* 16 bit utility for compatibility with compiler environment. */

#include <malloc.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <io.h>
#include <fcntl.h>

int picfile=0;
int ribfile=0;
char *far screenbuffer;
int ribsize;

/* loads a lib */
int riblode(name)
char *name;
{
   int fh;
   fh = open(name,O_RDONLY|O_BINARY); /* open a binary file */
   ribsize = read(fh,(char *)&screenbuffer[0x2000],0x2000);
   close(fh);
   return ribsize;
}



int bitcopy(char *name1, char *name2)
{
    FILE *fp,*fp2;
    unsigned char c,d;

    long target,count=0;
    int piccount=0,ribcount=0;

    if((fp=fopen(name1,"rb"))==NULL){
                                     perror(name1);
                                     return -1;
                                     }
    fp2=fopen(name2,"wb");
    target=filelength(fileno(fp));

    while(count<target)
        {
        c=fgetc(fp);
        if(count>3)
        {
            if(count>0x2003 && (picfile!=0))
            {
             if(piccount<0x2000)c=screenbuffer[piccount];
             if(piccount>=0x2000 && ribfile!=0 && ribcount<ribsize)
             {
              c=screenbuffer[piccount];
              ribcount++;
             }
             piccount++;
            }
           fputc(c,fp2);

        }
        count++;
        }
    fclose(fp);
    fclose(fp2);

   return(0);
}


main(int argc, char *argv[])
{
    FILE *picture;
    char buf[66],buf2[66];

    if(argc==2 || argc ==3 || argc==4)
    {
    sprintf(buf,"%s.SYS",argv[1]);

    if(argc>2)
    {
     if((picture = fopen(argv[2],"rb"))!=NULL)
     {
        picfile++;
        fclose(picture);
        screenbuffer = _fmalloc(0x4000);
        memset(screenbuffer,0,0x4000);
        strcpy(buf2,argv[2]);
        preparepic(buf2);
      }
    }
    if(argc>3 && picfile!=0)
        ribfile = riblode(argv[3]);

    bitcopy(argv[1],buf);
    if(picfile)_ffree(screenbuffer);

    }
    else
    {
        printf(
        "Usage is [MANX C65 EXECUTABLE PRODOS SYS FILE- NO EXTENSION]\n");
        printf("Second Argument is Picture File Name\n");
        printf("Third Argument is Library File Name\n");
    }
    exit(0);
}

#define BOT 192
#define TOP 160
#define BIN 0

preparepic(char *picname)
{
   char c=0;
   int cflag=0;

   while(picname[c]!=0)
        {
            /* rudimentary check for type of screen that we are loading */
            if(picname[c]=='.')cflag=TOP;
            if(cflag==TOP)
            {
              if(picname[c]=='B'||picname[c]=='b')cflag=BOT;

             }
            if(cflag==BOT) {
  if(picname[c]=='I'||picname[c]=='i')cflag=BIN;
}
            if(picname[c]<' ')picname[c]=0;
            else c++;
        }

   piclode(picname,cflag);
}



piclode(name,type)
char *name;
int type;
{
   int fh,y,temp,packet=40,bos=type;
   char buffer[2];

   fh = open(name,O_RDONLY|O_BINARY); /* open a binary file */

   if (type == BIN) read(fh,(char *)&screenbuffer[0],0x2000);
   else {
   read(fh,buffer,2);
   for(y=0;y<bos;y++)
   {
     gethibase(y,&temp);
     read(fh,(char *)&screenbuffer[temp],packet);
     /* read each raster to the screenbuffer */
     }
   }
   close(fh);

}

/* provides base offset for hires scanlines         */
gethibase(currentline,currentbase)
int currentline;
int *currentbase;
{
  int ybase=0,z,a;

if(currentline >63)
   {
   if (currentline < 128)
       {
ybase+=0x28;
currentline-=64;
       }
   else
       {
       ybase+=0x50;
       currentline-=128;
       }
    }

    z=(currentline>>3);
    a = (z<<7)|ybase;
    *currentbase = (currentline - (z<<3))<<10 | a;
}



The following Memory Map shows how this works in practice (on an Apple IIe)

Memory arrangement in your program whether on the Apple IIe or C64 and C128 must avoid all the hardware areas and must not clobber the operating system. These programs that I wrote to embed screens use that to their advantage and when they load, just when they start to run, (or even while loading depending on initial video mode), since they load over the screen area the embedded screen title is displayed.


One of these days when I get more time I may create a drawing for the C64 that shows the equivalent but in the meantime the drawing that I created 18 years back gets the point across.
#18
Adding Graphics and Fonts to a Compiled C64 Program

Use the Source Luke!

This program is compiled in Microsoft 16 bit C and is provided with the Aztec C64 cross-compiler for Windows XP/MS-DOS. It is based on a similar program for the Aztec C Apple IIe ProDOS 8 cross-compiler for Windows XP/MS-DOS. Both Cross compilers are available from the Aztec C website.


/* ADDLOGO(C) Copyright Bill Buckels 2007 */
/* All Rights Reserved. */

/* You have a royalty free right to use this program in any way
   you find useful provided that you agree that Bill Buckels
   has no Warranty Obligations or Liability in any way whatsoever. */

/* adds a HIRES C64 Bitmap and Palette to an AztecC64 Program */
/* also adds a bitmap font for HIRES mode */
/* this is a 16 bit program compiled under MSC 8,00c */
/* 16 bit utility for compatibility with compiler environment. */

/* note: this utility is designed for use with LN65 output */
/*       with base 810 and code and data offset past default screen area */
/*       Also the LN65 output file must not have an extension */

/* this utility must be run before MKBASIC and after LN65 */
/* this utility does not overwrite the input file */
/* it creates an output file with a .SYS extension */

/* MKBASIC is then run on the SYS file to create a PRG */

/* this utility has also been extended to embed multicolor images
   and cursor libraries (cursor.vhi) and to use default naming of title.*
   as a convenient method of organizing a C64 aztec.c graphics project. */

/* I have stopped short of allowing the IBM OEM 256 character font set
   to be embedded. Multilingual programs using the OEM special characters
   are therefore not possible using this scheme but I have provided
   this source and those characters in case someone gets ambitious
   and wants to take this further. */


#include <malloc.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <io.h>
#include <fcntl.h>

char bmapbuffer[8000];
char vrambuffer[1000];

/* 1024 byte character array of IBM-PC 8 x 8 bitmapped rom font
   for ascii values 0-127 for static storage in C64 Aztec Programs.
   This will be inserted 3072 bytes below screen and will plot
   verbatim in HIRES mode. vram can be used to select colors. */
unsigned char fontbuffer[1024] = {
0,0,0,0,0,0,0,0,
126,129,165,129,189,153,129,126,
126,255,219,255,195,231,255,126,
108,254,254,254,124,56,16,0,
16,56,124,254,124,56,16,0,
56,124,56,254,254,124,56,124,
16,16,56,124,254,124,56,124,
0,0,24,60,60,24,0,0,
255,255,231,195,195,231,255,255,
0,60,102,66,66,102,60,0,
255,195,153,189,189,153,195,255,
15,7,15,125,204,204,204,120,
60,102,102,102,60,24,126,24,
63,51,63,48,48,112,240,224,
127,99,127,99,99,103,230,192,
153,90,60,231,231,60,90,153,
128,224,248,254,248,224,128,0,
2,14,62,254,62,14,2,0,
24,60,126,24,24,126,60,24,
102,102,102,102,102,0,102,0,
127,219,219,123,27,27,27,0,
62,99,56,108,108,56,204,120,
0,0,0,0,126,126,126,0,
24,60,126,24,126,60,24,255,
24,60,126,24,24,24,24,0,
24,24,24,24,126,60,24,0,
0,24,12,254,12,24,0,0,
0,48,96,254,96,48,0,0,
0,0,192,192,192,254,0,0,
0,36,102,255,102,36,0,0,
0,24,60,126,255,255,0,0,
0,255,255,126,60,24,0,0,
0,0,0,0,0,0,0,0,
48,120,120,120,48,0,48,0,
108,108,108,0,0,0,0,0,
108,108,254,108,254,108,108,0,
48,124,192,120,12,248,48,0,
0,198,204,24,48,102,198,0,
56,108,56,118,220,204,118,0,
96,96,192,0,0,0,0,0,
24,48,96,96,96,48,24,0,
96,48,24,24,24,48,96,0,
0,102,60,255,60,102,0,0,
0,48,48,252,48,48,0,0,
0,0,0,0,0,48,48,96,
0,0,0,252,0,0,0,0,
0,0,0,0,0,48,48,0,
6,12,24,48,96,192,128,0,
124,198,206,222,246,230,124,0,
48,112,48,48,48,48,252,0,
120,204,12,56,96,204,252,0,
120,204,12,56,12,204,120,0,
28,60,108,204,254,12,30,0,
252,192,248,12,12,204,120,0,
56,96,192,248,204,204,120,0,
252,204,12,24,48,48,48,0,
120,204,204,120,204,204,120,0,
120,204,204,124,12,24,112,0,
0,48,48,0,0,48,48,0,
0,48,48,0,0,48,48,96,
24,48,96,192,96,48,24,0,
0,0,252,0,0,252,0,0,
96,48,24,12,24,48,96,0,
120,204,12,24,48,0,48,0,
124,198,222,222,222,192,120,0,
48,120,204,204,252,204,204,0,
252,102,102,124,102,102,252,0,
60,102,192,192,192,102,60,0,
248,108,102,102,102,108,248,0,
126,96,96,120,96,96,126,0,
126,96,96,120,96,96,96,0,
60,102,192,192,206,102,62,0,
204,204,204,252,204,204,204,0,
120,48,48,48,48,48,120,0,
30,12,12,12,204,204,120,0,
230,102,108,120,108,102,230,0,
96,96,96,96,96,96,126,0,
198,238,254,254,214,198,198,0,
198,230,246,222,206,198,198,0,
56,108,198,198,198,108,56,0,
252,102,102,124,96,96,240,0,
120,204,204,204,220,120,28,0,
252,102,102,124,108,102,230,0,
120,204,224,112,28,204,120,0,
252,48,48,48,48,48,48,0,
204,204,204,204,204,204,252,0,
204,204,204,204,204,120,48,0,
198,198,198,214,254,238,198,0,
198,198,108,56,56,108,198,0,
204,204,204,120,48,48,120,0,
254,6,12,24,48,96,254,0,
120,96,96,96,96,96,120,0,
192,96,48,24,12,6,2,0,
120,24,24,24,24,24,120,0,
16,56,108,198,0,0,0,0,
0,0,0,0,0,0,0,255,
48,48,24,0,0,0,0,0,
0,0,120,12,124,204,118,0,
224,96,96,124,102,102,220,0,
0,0,120,204,192,204,120,0,
28,12,12,124,204,204,118,0,
0,0,120,204,252,192,120,0,
56,108,96,240,96,96,240,0,
0,0,118,204,204,124,12,248,
224,96,108,118,102,102,230,0,
48,0,112,48,48,48,120,0,
12,0,12,12,12,204,204,120,
224,96,102,108,120,108,230,0,
112,48,48,48,48,48,120,0,
0,0,204,254,254,214,198,0,
0,0,248,204,204,204,204,0,
0,0,120,204,204,204,120,0,
0,0,220,102,102,124,96,240,
0,0,118,204,204,124,12,30,
0,0,220,118,102,96,240,0,
0,0,124,192,120,12,248,0,
16,48,124,48,48,52,24,0,
0,0,204,204,204,204,118,0,
0,0,204,204,204,120,48,0,
0,0,198,214,254,254,108,0,
0,0,198,108,56,108,198,0,
0,0,204,204,204,124,12,248,
0,0,252,152,48,100,252,0,
28,48,48,224,48,48,28,0,
24,24,24,0,24,24,24,0,
224,48,48,28,48,48,224,0,
118,220,0,0,0,0,0,0,
0,16,56,108,198,198,254,0};


void stripext(char *ptr)
{
int idx, jdx = 999;

for (idx=0;ptr[idx] != 0; idx++) {
if (ptr[idx] == '.') jdx = idx;
}
if (jdx!=999)ptr[jdx]=0;

}

int blode(char *name)
{

   char fname[128];
   int fh, done1 = 0, done2 = 0;

   /* order of precedence here */
   /* if we have a cursor file we load this instead of the vram file */
   strcpy(fname,"cursor.vhi");
   fh = open(fname,O_RDONLY|O_BINARY); /* open a binary file */
   if (fh != -1) {
     read(fh,vrambuffer,2);
     read(fh,vrambuffer,1000);
     close(fh);
     done1 = 1;
   }

   /* if we don't have a cursor file we embed the vram file
      starting with the hires vram file and the multicolor
      vram file if a hires file is not found */

   /* to make this more straight forward we check for something called title.vhi */
   /* first, then title.vmc then on to the rest */

   if (done1 == 0) {
   strcpy(fname,"title.vhi");
   fh = open(fname,O_RDONLY|O_BINARY); /* open a binary file */
   if (fh != -1) {
read(fh,vrambuffer,2);
read(fh,vrambuffer,1000);
close(fh);
done1 = 1;
   }
   }
   if (done1 == 0) {
   strcpy(fname,"title.vmc");
   fh = open(fname,O_RDONLY|O_BINARY); /* open a binary file */
   if (fh != -1) {
read(fh,vrambuffer,2);
read(fh,vrambuffer,1000);
close(fh);
done1 = 1;
   }
    }
   if (done1 == 0) {
   strcpy(fname,name);
   stripext(fname);
   strcat(fname,".VHI");
   fh = open(fname,O_RDONLY|O_BINARY); /* open a binary file */
   if (fh != -1) {
read(fh,vrambuffer,2);
read(fh,vrambuffer,1000);
close(fh);
done1 = 1;
   }
   }
   if (done1 == 0) {
   strcpy(fname,name);
   stripext(fname);
   strcat(fname,".VMC");
   fh = open(fname,O_RDONLY|O_BINARY); /* open a binary file */
   if (fh != -1) {
read(fh,vrambuffer,2);
read(fh,vrambuffer,1000);
close(fh);
done1 = 1;
   }
   }


   /* we are done with the vram area now */
   /* we check for a hirea bitmap to embed as the title screen */
   /* to make this more straight forward we check for something called title.bhi */
   /* first, then title.bmc then on to the rest */

strcpy(fname,"title.bhi");
fh = open(fname,O_RDONLY|O_BINARY); /* open a binary file */
if (fh != -1) {
read(fh,bmapbuffer,2);
read(fh,bmapbuffer,8000);
close(fh);
done2 = 1;
}
    if (done2 == 0) {
   strcpy(fname,"title.bmc");
   fh = open(fname,O_RDONLY|O_BINARY); /* open a binary file */
   if (fh != -1) {
read(fh,bmapbuffer,2);
read(fh,bmapbuffer,8000);
close(fh);
done2 = 1;
   }
   }
   if (done2 == 0) {
   strcpy(fname,name);
   stripext(fname);
   strcat(fname,".BHI");
   fh = open(fname,O_RDONLY|O_BINARY); /* open a binary file */
   if (fh != -1) {
read(fh,bmapbuffer,2);
read(fh,bmapbuffer,8000);
close(fh);
done2 = 1;
   }
   }
   if (done2 == 0) {
strcpy(fname,name);
stripext(fname);
strcat(fname,".BHI");
fh = open(fname,O_RDONLY|O_BINARY); /* open a binary file */
if (fh != -1) {
read(fh,bmapbuffer,2);
read(fh,bmapbuffer,8000);
close(fh);
done2 = 1;
}
   }

   /* the programmer needs to provide some other way of
      populating colorram if the embedded title is
      a multicolor image.

      if the image has been created using frag64x the
      baggage files will be sufficient since
      the palette is identicalized and only a single
      value for each position in vram and cram are needed.

      doing it this way leaves the vstore available
      for other purposes as a static buffer. The cursor.vhi
      file is an example of that.

   */
   return 1;
}


/* action codes for inserting baggage files into program */
#define WRITE_PRG  0
#define WRITE_VRAM 1
#define WRITE_BMAP 2
#define WRITE_FONT 3

int bitcopy(char *name1, char *name2)
{
    FILE *fp,*fp2;
    unsigned char c;

    long target,count=0;
    int vcount=0,bcount=0,fcount=0, action=WRITE_PRG;

    if((fp=fopen(name1,"rb"))==NULL){
       perror(name1);
       return -1;
    }
    fp2=fopen(name2,"wb");
    target=filelength(fileno(fp));

    while(count<target)
        {
        c=fgetc(fp);
        action = WRITE_PRG;

        /* $2000 - $800 - $810 = 4080 (1024 byte storage area 2048 bytes
                                                              below screen) */
        /* font size = 1024 - 4080 to 5103 */
        /* add 4 bytes for LN65 header for insert range */
        if(count>4083 && count < 5108) action = WRITE_FONT;

        /* $2000 - $400 - $810 = 5104 (1024 byte storage area directly
                                                         below screen) */
        /* vram size = 1000 - 5104 to 6103 */
        /* add 4 bytes for LN65 header for insert range */
        if(count>5107 && count < 6108) action = WRITE_VRAM;

        /* $2000 - $810 = 6128 (base address of screen) */
        /* screen size = 8000 - 6128 to 14127 */
        /* add 4 bytes for LN65 header for insert range */
        if(count>6131 && count < 14132) action = WRITE_BMAP;

        switch(action)
        {
case WRITE_FONT: c = fontbuffer[fcount]; fcount++; break;
case WRITE_VRAM: c = vrambuffer[vcount]; vcount++; break;
case WRITE_BMAP: c = bmapbuffer[bcount]; bcount++; break;
}

        fputc(c,fp2);
        count++;
    }
    fclose(fp);
    fclose(fp2);

   return(0);
}


void main(int argc, char *argv[])
{
    char name1[128], name2[128];

    memset(bmapbuffer,0,8000);
    memset(vrambuffer,0,1000);

    if(argc==2)
    {
strcpy(name1, argv[1]);
stripext(name1);
strcpy(name2,name1);
strcat(name2,".SYS");
blode(argv[1]);
bitcopy(name1,name2);
}
    else
    {
printf("Purpose is to embed LOGO screens in AztecC64 programs.\n");
        printf("Usage is \"ADDLOGO MYC64\" (no extension).\n");
        printf("Output is MYC64.SYS with MYC64.BHI and MYC64.VHI embedded.\n");
        printf("All files in the set must use the same base name.\n");
   }
   /* deliberately exiting with zero regardless of outcome */
   exit(0);
}



MAKEFILE


# ---------------------------------------------------------
# Microsoft C 8 by Bill Buckels 2008
# ---------------------------------------------------------
PRG=addlogo
all: ..\$(PRG).exe


$(PRG).obj: $(PRG).c
      cl -c -AL -Zp1 $(PRG).c

..\$(PRG).exe: $(PRG).obj $(PRG).c MAKEFILE
     link $(PRG).obj,..\$(PRG).exe, NUL, /ST:8192 /NOE /NOD oldnames llibce graphics, NUL
     del $(PRG).obj

#19
General chat / Re: What's up with Canada post?
April 13, 2008, 10:35 AM
Quote from: airship on April 13, 2008, 03:56 AM
Andrew, make that like putting coins (or bills) into Coke (or Pepsi) machines anywhere. Our machines at work have about a 75% payout rate. The candy machines, too, though they're most often guilty of snagging the item you buy so you don't get anything but the next guy gets two... and I never seem to have enough change when my stuff gets snagged so that I can buy the next one. :(

Aha! I haven't had a coke or pepsi or a dr. pepper or even a gatorade for 6 weeks ever since my doc measured my fasting glucose and it had shot-up to triple what high normal is... so I would say that someone is probably watching-out for you by taking your money for nothing.

JUJYFRUITS

I managed to sneak some jujyfruits (actually several boxes) that we have imported special from south of the border (the Canadian Border not Chuck Norris's) but that is just recently.

That first week or 4 I got a little concerned and cut-out all carbs except for the brown rice that I ate with my baked fish...

Don't talk about coke... I want one. I gave-up cigarettes at about the same time and don't want one of those... but cola...

It is so hard to be healthy around this forum.

#20
I have added two more compilers to the Aztec C Website. These have been around awhile and you may have them, but if not fill yer hand bucko!

http://www.clipshop.ca/Aztec/index.htm#cpm8

Manx Aztec C80
Version 1.05f
Developer System
for CP/M-80
Target: Z80 and 8080 Native Code

CP/M-80 native mode development environment for Z80 and compatible computers. Comes with MyZ80 diskimage preconfigured with compiler and example.

az80105f.zip with MyZ80 .DSK Image

Manx Aztec C80
Version 1.06b
Developer System
for CP/M-80
Target: Z80 and 8080 Native Code

CP/M-80 native mode development environment for Z80 and compatible computers. Comes with MyZ80 diskimage preconfigured with compiler and example.

az80106b.zip with MyZ80 .DSK Image

This brings the total number of CP/M 80 compilers on the Aztec-C Website to Five (5)

I should also mention that each of these compilers comes with assemblers for generating Z80 binaries from Z80 assembler. As a matter of fact the Aztec C compiler was an "old school" compiler which produced an assembly language pass from C code and then used the assembler to produce the binary.

Anyone who really knows their way around the Z80 and the memory map and the ports on any specific Z80 platform including (of course:) the C128 could easily extend the Aztec C libraries using both C and Assembly Language. I am sorry to say that I won't have time to do so myself over the forseeable future.

I have a number of CP/M 86 and MS-DOS compilers to put on-line and then I want to focus on retro-fitting my Aztec C64 cross-compiler to the C128. This is an important part of my education that I neglected to indulge myself in when I was a youngster, and before I resurrect my C64 I am wondering if I shouldn't just put my effort into refurbishing a C128. Aztec C will show me the way.
#21
General chat / Re: What's up with Canada post?
April 09, 2008, 07:28 PM
Quote from: airship on April 08, 2008, 11:53 PM
They don't pay us to not grow Mary Jane, but farmers down here don't do that much anymore, anyway. It's much more profitable to set up a meth lab in the barn. Sometimes on the news we hear about one that has blown up real good.

Interestingly, the DOA (used to be DEA before they lost the War on Drugs) whose jurisdiction doesn't necessarily stop at the 49th paralell probably should have considered crimes of compassion before they dug and they burned and they burned and they dug. Despite my government's attempts about a decade ago to provide good quality hydro from underground bunkers in abandoned mine shafts right here in Friendly Manitoba our Ledain Commission ground to a screaming halt almost 40 years ago now leaving us with a less than satisfactory socio-economic framework for our own entreprenurial prairie farmers and other parties interested in crop diversification for a recreational or other market.

The farmers here too have adopted a more scientific and less organic approach in their own business plans.

Sadly, failing to learn from the days of Ken Kesey and the Merry Pranksters (and a lesson that many of us including long distance truck drivers should have been able to pass-on to posterity without the ubiquituous "Six Days On The Road" romanticisation) a resurgence of stimulants in the current generation has led to the same phenomenae here as well as there.

In my own time as a volunteer in various alley-patrols and other noble pursuits that attempted to keep our children safe from needle-sticks in the schoolyards of our urban centres in the name of a newer concept called "Harm Reduction" I too have witnessed this shift occurring in epidemic proportions in all sectors and not just in farming.

The issues are confusing to say the least whether there or here or by Bondi Pier and elsewhere around this planet.

Perhaps the "War on Terror" is not the only reason that Canada Post has become so slow, and perhaps other wars are being silently fought in the trenches of our fair Post Offices and it is not "working to rule" and all those time-honoured labour traditions that have created the obvious backlog. 

There are also obviously personal choices that need to be made on a community basis whether the official crop is corn and the unofficial crop hails back to the days of "Thunder Road" or a more contemporary underground economy that is reminiscent of the days of "Blow" and "Boston George".

Also in my own time as an activist in some areas, I have spent my fair share of time with folk heroes like Dean Wilson (a former IBM Salesman) sharing a plane on the way to Ottawa Canada's Capital in his bid to extend our own legislation to include other lucrative crops other than popcorn. Like most I have seen the folly of applying a "one size fits all" philosophy to crop selection and rotation.

Your observation is interesting and despite some obvious cultural differences between our two countries the choices are remarkably similar.

Recently a couple of idiots who are also both almost Senior Citizens in a small town close by the small town that I live in decided that since it was all contraband anyway, forgave themselves for lack of morals, and mixed-in illegal firearms with a Maryjane cash-crop and will probably die in jail.

How can we expect the children, many who are less well equipped to handle these choices by virtue of their own miserable parentage, lack of values, and peer pressure from losers to make good choices when so many poor examples exist in our own generation?

The values that I myself learned as a teenager and young adult were that the 3 parts of the whole person, the spirit, intellect, and "flesh" must be balanced. Each provides its own joy as well as sorrow and such is life. I suppose it is hard to transcend the reality of survival without making greedy choices when the opportunity of natural selection and those Darwinian principles provide such assuage and justification for cash crops other than corn.

However, the Joys of Playing with Computers, the "Hu-Manly Art of Programming", other literary pursuits and Fishing and other cool choices in life are perhaps all an individual can hope to inspire oneself and others with at the end of the day. Taking the Theologian's semantic view that Fate (like Faith) is immutable and cannot (or perhaps should not) be altered or tampered with by intellect or will is a complex lesson that is even hard for the smartest people that I know to understand (including myself:). The quiet place that belongs to all of us is very satisfying and doesn't need any enhancement, and one can disappear for years or a lifetime without missing a day with one's trusty compiler, favorite books, guitar and causes by one's side.

Having said all this, I appreciate your re-Mark. I almost understand why Norway does not show on the Map of Texas. Nor does Iceland show on the maps of Manitoba or North Dakota.

So it is perhaps also understandable that my knowledge of Iowa is limited and should remain that way, but surely Canada Post should also be capable of locating these exotic and far-off places more effectively despite the inpenetrable nature of the Corn Belt.   

 
#22
CP/M / Emulating CP/M 80 - MyZ80 instead of x128
April 07, 2008, 11:49 PM
An Overview of MyZ80

This could also be titled "An Underview of x128". I said x128 is "OK"... I am simply being polite and appreciative of the WinVICE Team's tremendous and great quality effort in C64 and C128 emulation modes etc. but think that the CP/M and Z80 stuff on the C128 might not have been all that great and if it was, it doesn't seem to be reflected by x128's emulation.

Depending on your goals of course, if you are a vintage computing fan you won't care as long as it is historically correct, and the vintage part of me also enjoys the rough and ready nature of x128's CP/M Z80 emulation with the long yawns between programs and the many repeated characters that stream in from a single key press.

"MYZ80 - Virtual Z80 Reality for today's computers."

For developing or running Z80 software, myZ80 is the best emulator that I could imagine. Even if your eventual development target is the C128, whatever you do in MyZ80 will work as efficiently as anything else you might do even today regardless of what your programming tools or target platform might be.

I just thought I should mention this. The rest of this missive is a portion of the text from MyZ80.DOC followed by a link to the rest of it. Yes it sounds like blatant advertising but even though this program is already quite dated it really does work as well as Simeon Says...

You can download MyZ80 from the following link and this is all I think I will say on the subject (unless asked).

Download MyZ80
MyZ80 Tutorial


Quote from: Simeon Cran (Author and designer of the MYZ80 package)



MicroFast Z80 Emulation Engine code,
MYZ80 API,
and The MYZ80 Emulator Package Versions 1.xx are each:
Copyright 1991,1992,1993,1994 Simeon Cran.

M Y Z 8 0

by Simeon Cran.


Welcome to MYZ80!

MYZ80 is a Z80/64180 emulator package. It was written to allow you to finally get rid of those old Z80 computers which  have done  so many fine years of service.  The new 80486, 80386 & 80286 machines with the fast hard drives and  the snazzy  OS/2 operating  systems are such a delight... but for many, the Z80 machines still have to be fired up from to time in order to develop code for CP/M and the Z80 chip. Well, not any more, thanks to MYZ80.

Other  emulators  on  the  market  are   less  than   satisfactory solutions.  Of  the small  number which  can actually  run without causing system errors under the later versions of  DOS, apparently none is capable of running real CP/M. Instead they use an emulated version of CP/M which is only as accurate  as the  developers have bothered to make it.

None can run CP/M  3.0, and  none can  run ZCPR  (which is  such a useful Z80 developer's environment).  Add to that their  less than perfect  Z80  emulation and  slow overall  performance, and  until MYZ80, the  'real' Z80  machines were  destined to  remain in  the office.

MYZ80 provides the solution being conceived, born and  nurtured to the point where it  is now  the most  useful Z80  emulator package ever!

MYZ80 features.

MYZ80 emulates the instruction set of the 8080, Z80 and Z180/64180 CPU chips. It does this with the "MicroFast Z80 Emulation  Engine" which is a very highly tuned piece of code designed to be as fast and as accurate as technically possible on 80286, 80386 and  80486 CPUs.

MYZ80 provides an interface (the MYZ80 API) to  the host  computer which allows real Z80 BDOSes to run in the MYZ80 environment. This interface provides disk and character I/O as well as two banks of 64k RAM (with common  area) and  a large  RAM disk.   These unique features allow MYZ80 to run 'real'  CP/M 2.2,  CP/M 3.0,  Z-System and ZPM3.

MYZ80  is  designed  for  the  latest  host computer  multitasking operating systems and makes Z80 programs  'host friendly'.   MYZ80 will  share  time  very  fairly  with  the  host.   Even  multiple instances of MYZ80 are supported.

MYZ80  can  take  advantage  of the  latest computer  hardware for increased performance. The Microfast Z80 Emulation Engine operates in either 16 (80286) or 32 (80386/80486/P5) bit mode depending  on the capabilities of the host computer.

MYZ80 runs beautifully on IBM AT compatible (or  better) computers under  DOS  3.3  compatible  (or later)  operating systems.   This includes running under OS/2 2.x, Desqview, and Windows 3.x.


Click Here for the Full Text of This Document


#23
CP/M / Re: Is there any reason to use CP/M ?
April 07, 2008, 10:04 PM
Quote from: Douglas on December 23, 2007, 05:09 PM
Hey everyone!

I have fun learning new (to me at least) computing systems, so I enjoy playing with CP/M, but is there any reason that you would need to use CP/M on the 128 where is does something that can't be done in native 128 mode?  Are there any programming languages that are available under CP/M that were never translated to 128 mode for example?  How about Database or Spreadsheet use.  Are the CP/M alternatives to the 128 versions of there programs more "Robust" or offer anything that a native 128 program didn't?

Just wondering aloud...

Douglas

:)

Your use of the word "Need" is much different than "Want". Like you I Want to have fun with vintage computers and emulators and learn about all of them. As far as "Would one need to?"... Others didn't, but some of us never even considered either choice a reasonable alternative.

Back to The Future in 1980

If you put yourself in "Back to the Future" mode and take a Quantum Leap back to the time of dark basements with dirty little boxes of diskettes copied from every conceivable direction... probably 1980 maybe a little earlier or later... there were all these camps of users... the SIG's (special interest groups) were happening... the "scene" came later... and there were main-frame operators who thought that programming was related to punch cards and young kids learning assembly language... and lots of business software running on Z80's with some guy named Gary Kildall selling his CP/M operating system for a huge sum of money which speaks back to his roots at IBM.

A Little Later On

Anyway, that's what I saw back then, and I also saw the C64 when it first came-out as being a fun toy for my cousin's 12 year old son as we sat and wrote music programs in BASIC 2 for an hour or so.

MESSY-DOS Had Already Taken-Over

If you examine the strategy behind all this and understand what Bil Herd was saying about the C128 being some kind of stalling technique while we waited for the Amiga (I didn't wait by the way, apologies to Carl Sassenrath and so forth), the CP/M thing was marketing and nothing more on the part of cbm. I don't mean the fellows (Engineers) like Bil Herd and consultants like Von Ertwine who were *NOT* what we have long called in this business "Managers" (and then washed our mouths out afterwards with soap when they left the room and we still do).

Herd and those fellows as far as I am concerned were in the trenches designing and building cool stuff that people enjoyed at home and could afford to buy and except for one point that I never liked about cbm... their disk drives were always too slow... this was good value.

This disk drive business in itself turned me off and I walked away much preferring to use cross-compilers for slow machines. But then I was already spoiled with real computers (not just PC's) and too impatient to play with toys because programming and CAD and so forth was all that I cared about and in the end the money was in the IBM-PC for me.

We had equal or better spreadsheets and word processors already on MS-DOS machines by the time cbm introduced this CP/M thing. And no business programmers that I knew were bothering much with anything but the IBM-PC running MS-DOS. The MAC was a favorite in the schools around here following the Apple II which by virtue of being around the schools a little longer had pushed the school market in the Apple-Sit direction (they were always going the wrong way just like the Appletalk Protocol).

In the late 80's our Amiga User's groups were a little like the Linux User's groups in the mid '90's (they were quite a religion) but for some reason I blinked and missed the C128. The Amiga by the way although having a faithful following and ham-e and 12 bit graphics and all that was still smoked by my IBM software using 16 bit TARGA board knockoffs by Everex. I once wrote some little songs using bars and pipes for a buddy who was doing a pacman for Blackbelt Systems so it's not like the Amiga wasn't there... our "Junior" version was offered on it... and when we developed our own digital speech board for talking Kiosk Systems before the Soundblaster we used the amiga to clean-up our recordings rather than write our own set of tools.

But I just skipped the C128. To me at that time it was just a C64 with more.

Why Bother Indeed?

Now I thought I'd best paint a different picture than many here would have to explain that all you would need CP/M for on a C128 would be to learn an MS-DOS like command line environment that was a little more unix-like than the BASIC 7 environment that a "real" C128 user would know back then...

Then using that knowledge, if you liked CP/M you might decide to give MS-DOS a try. Except that the poor way that CP/M was implemented on the C128 might discourage you from using CP/M.

What I really would like to ask Bil Herd and Von Ertwine is "Was a decision by the Managers at CBM made to make CP/M on the C128 so unusable that it would turn-off CBM home computer users from switching to MS-DOS and remain loyal to CBM until the Amiga could be produced?"

Because that's the way I see that CP/M on the C128 worked out. It was a hack as far as I can see and the reference to "native mode" about says it all... It reminds me of putting a 68030 motorola chip into a XT with a 4.77 mghz 8086 processor and 128K of ram on the motherboard and a 4 color CGA video card, then slowing down the 68030 to 9 MGHZ and disabling it to the point that it could properly use the bus and the RAM on the boards back then.

Just Wondering Aloud Myself,

Bill

Note: Any Resemblance To Anything Living or Dead in the preceding is purely coincidental since this version of history occurred in my mind and is just one of several versions that exists there that I dusted off to fit the occasion



   
#24
How MyZ80 Handles CP/M Disks

Quote from: hydrophilic on April 06, 2008, 12:12 PM
Anyway, knowing something about the way CP/M writes disks, I am amazed that MyZ80 is able to create an ever-expanding disk image.  I wonder how it does that.  Does it modify the Disk Parameter Block over time, or maybe it just creates a huge virtual disk at the start and only writes/expands the image file as needed?  (I'm guessing it's the latter.)

As I said in my previous reply "It is obviously the latter". However what is perfectly obvious to me is perfectly obvious to me so for your ongoing amusement and entertainment may I commend to you the following next installment in this; The Ancient Epistle of the Aztecs:

The following is excerpted from MYZ80.DOC written by Simeon Cran, the author of MyZ80. I have posted this document in its entirety in the CP/M forum which is where some of this discussion also probably belongs.

However since this discussion also relates heavily to configuring Aztec C to run under CP/M so you C128 guys can create CP/M programs that will run on a real C128 when done, I see no point in you torturing yourselves by testing your programs in the x128.exe emulator or even on a real C128 running in CP/M mode until you have finished your development cycle.

In order to make my point completely on this I have provided the necessary framework including x128 diskimages within my Aztec-C distribution for you to remember how bad the C128 really was when it came to writing and testing programs for CP/M, and have also provided MyZ80 disk images to provide you with a really good alternative. The rest is of course up to you.

Quote from: Simeon Cran. (Author and designer of the MYZ80 package)
DISK FILE

CP/M stores data on disks.  In  order to  satisfy CP/M's  need for particular  disk  formats,  MYZ80  emulates  the  real  CP/M  disk structure and stores the resultant data on your DOS disk. The data for each emulated CP/M disk is held in  a DISK  FILE. Usually  the disk files  are  called A.DSK,  B.DSK and  C.DSK, however  you may change the default names of the disk files with a  setting in  the DOS enironment block or by using the MyZ80 CHGDSK.COM utility.

SHRINKING

Because the MYZ80 virtual disks are able to hold over  8 megabytes of data, and because CP/M expects to be able to access all of that data at any time, disk files would normally have to be at  least 8 megabytes in size all the time. 

This would take up a lot  of your hard disk space and  would be  extremely wasteful  when your  disk files don't hold much useful data.  MYZ80 solves  this problem  by only storing useful data and returning dummy blank sectors to CP/M in return for any requests for data from unused parts of the disk.

As you add more data to your MYZ80 disk files  you will  find that they grow, however when you delete files from the MYZ80 disk files they will not shrink automatically. This is a feature, not  a bug! You can shrink disk files that have had data removed from them  so that MYZ80 will return the dummy blank sectors for the  previously used sectors  using the  SHRINK.COM utility.   

Note well  however, that disk files can only be shrunk down  to the  highest block  of data in use on the disk.  SHRINK.COM will tell you which file owns the highest block of data so that you can delete that file or move it  in  order  to  allow  further  shrinking  of  the  disk  file.  SHRINKING does  not "pack"  your disk  files, it  simply frees  up previously  allocated  blocks  that  are  no  longer  being  used.  SHRINKING is  not necessary,  except to  save space  on your  hard disk.

* MYZ80.DOC - Simeon Cran. (Author and designer of the MYZ80 package)
#25



Old 80 Revealed

The screenshots are of an earlier native mode compiler that I bundled with this cross-compiler. My main reason for doing so was to give you something else to play with if you got really bored with the other stuff!!!


ReadMe for OLD80

This directory contains Aztec CZ80 version 1.05 which amazingly fits on a
single sided C128 CPM 80 disk.

The down-side is that the C link library is pretty tiny:

**DIR**     supp8080    fprintf     fscanf      scan        fltlib     
fopen       fread       **DIR**     fseek       fgets       fputs       
getc        putc        ungetc      getbuff     setbuf      alloc       
format      callcpm     croot       open        read        write       
lseek       posit       **DIR**     blkio       rename      unlink     
atof        atol        atoi        block       atol        atoi       
block       string      toupper     closall     lsubs       fstub       

Two disk images are provided. AZ80105.DSK is for MyZ80 and AZ80105.D64 is
for the x128 Vice emulator.

Generally speaking you would not want to bother with a native mode cpm
compiler especially on the x128, however the MyZ80 emulator works pretty
well with this.

I am assuming you will have a SUBMIT command to use.

On the x128 emulator use the d81 diskimage also bundled with this lot to
boot cpm. Then put this d64 into drive B: Then to compile anything like
the exempl.c program that is on the d64 just type "A:SUBMIT CC EXMPL" and
press [Return]. Do yourself a favour and put the thing into WarpMode
directly after typing. However your keystrokes will repeat like crazy if
you try and run in warpmode during normal program execution.

On the MyZ80 emulator set the environment C.DSK=AZ80105.DSK and then start
MyZ80. Do this in a cmd window or in MS-DOS. Once inside MyZ80 type C: to
get on the C: drive that you have just assigned to AZ80105.DSK. Then type
"SUBMIT CC EXMPL" and press [Enter].

One more thing: This is pretty tight on disk space in x128 and you have a
copy of xdir on the image to determine just how tight. Use PIP to copy
part of your compiler to A: if you wish or the whole thing if you wish and
then copy it back to a d81 that you create on your own. To copy CII.COM
from B: to A: just type "PIP A:CII.COM=B:CII.COM" [Return] and when you
are done if you want to erase CII.COM from B: just "ERA CII.COM" [return].

Not wishing to write a book on the subject, please review all the
documentation I have provided on all of this and review the samples etc.
for further details.

Have Fun!

Bill Buckels April 2008


Quote from: hydrophilic on April 06, 2008, 12:12 PM
Ctools is a must for working with VICE and CP/M disk images as you stated.  CP/M is appearantly just another operating system (like GEOS or whatever) as far as VICE is concerned...

Understood, and also I understand ViceTEAM's POV. The thing works real well for what most people will ever use it for and it is pretty much a faithful hardware level emulator. I love it for that reason. I didn't want to start modifying anything either but admire anyone that is not as lazy as I am...

Quote
I modified VICE awhile back to support differnet disk images.  This allowed me to run some CP/M software released in TRS-80 disk images.  It work well enough for WordStar and Zork.  I don't remember what else I tried (it's been a while).

My Trash-80 days were pretty uninteresting. I used trs-80's with a program called ABACUS to program CNC punch coordinates for my drawing packages. One job for Ford Motor in Dearborn, MI for some brackets that I designed resulted in a paper tape 90 feet long, so I made two just in case. Sure enough when the Gal who operated it read the first one into the 16K ram bank on the Houdaille Strippit turret press, the reader tore the tape in the last two inches or so...  Murphy was an optimist. 

A little while later (years or so) our accountant was using one of those old Tandy 1000 DOS machines with the wierd 720K 5 1/4" drives and his hard-disk would get flaky sectors from the keyboard cable shorting out... that really did go into the trash... a very large dumpster.

And finally when Tandy made the DEC station 210 which was a 286 that ran at 10MGHZ but needed the processor slowed down to 8MGHZ so the bus could handle 16 bit edge connectors on our Targa Boards without losing data due to poor frequency tolerances on their bus... What Trash! Hardly even fit for the Kiosk systems that they were used for by us. The client insisted on DEC because of their reputation...




Quote
Anyway, knowing something about the way CP/M writes disks, I am amazed that MyZ80 is able to create an ever-expanding disk image.  I wonder how it does that.  Does it modify the Disk Parameter Block over time, or maybe it just creates a huge virtual disk at the start and only writes/expands the image file as needed?  (I'm guessing it's the latter.)




Well it is obviously the latter. I don't know if you even have the time or the inclination to play but the link that I have provided to Lee Bradley's distro of this thing gets you lots of goodies to put into the collection. It would also clear-up much of those questions and really highlight how extremely pitiful x128 really is when compared to something like this for cpm. Remember that I am a big fan on the C64 side of Vice...

MyZ80 - http://primepuzzle.com/mouse/maxz80.zip
Tutorial - http://primepuzzle.com/mouse/hints0.htm


On the CPM keyboard stuff especially x128 falls apart. Politely put there are timing issues, but since I never had a 128 and was once those guys with the 10 meg tandon external drives slung off the side of a 4.77 mghz Messydos box with a composite amber screen (at least it was a CGA so I could see snow and a BSaved Image or two) for all I know this is as good as the C128 got when it came to CP/M.

This guy Simeon Cran really did an amazing job on MyZ80... however like most things that are not worth anything in the business world including several hundred of my own programs (who counts eh?) he spent a lot of time and it looks like he walked away to Microsoft I think. Hope he makes some dough there anyway.

I was curious about one thing. I see that Bil Herd is still around. How about Von Ertwine? Imagine a time when an entire commercial OS could be written by a consultant at home! Or when a company would let him!

To me it really doesn't matter if I live to be 156 years old...  having lived through a time when I saw horse-drawn ice wagons in cities delivering to my neighbor's home in the days before everyone had a fridge, and through a time when one individual could do such a thing will stand-out in my memory to the end as long as it does not get flaky.

Bill