🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

1 total messages Started by prindle Tue, 21 Oct 1986 03:20
C-Power graphics package part 4 of 6 (grafpak1.c)
#2362
Author: prindle
Date: Tue, 21 Oct 1986 03:20
497 lines
13889 bytes
From: prindle@NADC

/* Graphics Package - Part 1
** Filename: grafpak1.c
** Author:   Mark R. Rinfret
** Date:     12/14/85
**
** Description:
**
** This package provides access to the
** hardware graphics capabilities of the
** Commodore 64 computer.  The routines
** are styled somewhat after the features
** provided by the Commodore Super Expander.
** The graphics area has been restricted to
** bank 2 (32768) for initial development.
**
** Routines in this package:
**   colors   - sets colors for pens 0-3
**   drawchar - puts a character on graphics screen
**   drawtext - puts string on graphics screen, with rotation
**   ginit    - initializes graphics routines
**   graphics - sets graphics mode
**   pset     - sets/clears a single pixel
**   line     - draws line segments
*/

#include <strings.h>
#include <math.h>
#include "grafpak.h"

/* Mask and bit value definitions.
** Mask arrays are selected by graphics mode (1 or 2) 
*/

static char gmask1[8] = {/* hi-res bit masks */
  0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};

static char gmask2[8] = {/* multi-color bit masks */
  0xfc,0xfc,0xf3,0xf3,0xcf,0xcf,0x3f,0x3f};

/* Bit value arrays are selected by pen number (1-3) */

static char hrbit1[8] = {/* pen 1 bit values */
  1,2,4,8,16,32,64,128};

static char mcbit1[8] = {/* pen 1 multicolor bit values */
  0x01,0x01,0x04,0x04,0x10,0x10,0x40,0x40};

static char mcbit2[8] = {/* pen 2 multicolor bit values */
  0x02,0x02,0x08,0x08,0x20,0x20,0x80,0x80};

static char mcbit3[8] = {/* pen 3 bit values */
  0x03,0x03,0x0c,0x0c,0x30,0x30,0xc0,0xc0};

/* Quick-lookup bitmap y-offset table */
static unsigned y_offset[25] = {
  0,320,640,960,1280,1600,1920,2240,2560,
  2880,3200,3520,3840,4160,4480,4800,
  5120,5440,5760,6080,6400,6720,7040,
  7360,7680
  };

/* Quick-lookup color memory y-offset table.  The index is expected to be
** adjusted to row number.  A y pixel coordinate can be converted to a row
** number simply by dividing by 8 (right shift 3)
**/
static unsigned y2color[25] = {
  0,40,80,120,160,200,240,280,
  320,360,400,440,480,520,560,
  600,640,680,720,760,800,840,
  880,920,960
  };

/* Set colors
** Parameters are:
**   border
**   background
**   pen 1
**   pen 2
**   pen 3
**
** Negative value => no change
 */
colors(bo,bg,p1,p2,p3)
int bo,bg,p1,p2,p3;
{
  if (bo>=0) poke(53280,bo);
  if (bg>=0) {
    pencolor[0]=bg;
    poke(53281,bg);
  }
  if (p1>=0) {
    pencolor[1] = p1;
    poke(COLOR,p1);
  }
  if (p2>=0) pencolor[2] = p2;
  if (p3>=0) pencolor[3] = p3;

}
  
/* Initialize Graphics Package */
ginit()
{
  gbank = 2;
  vbase = gbank * 16384; /* VIC-II base address */
  gbase = vbase + 8192;  /* only allowed location in bank 2 */
  sbase = vbase;
  gmode = 0;
  pencolor[0] = 1;       /* white background */
  pencolor[1] = 0;       /* black foreground */
  pencolor[2] = 5;       /* green multi-color 1 */
  pencolor[3] = 6;       /* blue multi-color 2 */
  cur_x = 0;
  cur_y = 0;
}

graphics(mode,clear)
unsigned mode,clear;
{
  if (mode<0 || mode>2) {
    textmode();
    printf("\nIllegal mode: %d\n",mode);
    exit();
  }
  gmode = mode;          /* save mode */
  if (mode==0) textmode();
  else {
    if (mode==1) hires();
    else multicolor();
  }
  if (clear) {
    if (mode==0) putchar(147);
    else {
      bmfill(0);
      cfill();   /* fill color memory */
    }
  }
}

/* Fill bit-map area with value */
bmfill(v)
unsigned v;
{
  register char *p;
  register char v1; /* local copy for speed */
  register unsigned i;

  v1 = v;           /* local copy to zero page */

  p = (char *) gbase;
  for (i=0;i<8000;i++)
    *p++ = v1;
}

/* Fill color memory with default colors. */
cfill()
{
  register char *p; /* Color memory pointer */
  register char c;
  register unsigned i;

  p = (char *) sbase; /* 1st, do screen memory */

/* Upper four bits are foreground, lower 4 bits are background */

  if (gmode==1)   
    c = (pencolor[1] << 4) | pencolor[0]; 
  else
    c = (pencolor[1] << 4) | pencolor[2];

  for (i=0;i<1000;i++)
    *p++ = c;

  if (gmode==2) { /* Multi-color mode? */
    p = (char *) COLORMEM; /* color ram */
    c = pencolor[3];
    for (i=0;i<1000;i++)
      *p++ = c;
  }
}
  
/* Set graphics screen base address */

unsigned vb,bb;
{
  register unsigned bank;

  bank = vb / 16384; /* calculate bank number */

  poke(C2DDRA,peek(C2DDRA) | 3); /* bits 0,1 are outputs */
  poke(CI2PRA,(peek(CI2PRA) & 252) | (3-bank));
  if (bb & 0x2000) { /* upper half of bank? */
    poke(VMCSB,peek(VMCSB) | 8);   /* set bit 3 */
  }
  else
    poke(VMCSB,peek(VMCSB) & 247); /* clear bit 3 */    
}

/* Set Screen Memory Location 
** In text mode, screen memory is where characters printed to the screen
** are displayed.  In bit-mapped mode, this area is used as another
** color memory area.  The value computed is the offset, a multiple of 1024,
** from the base address of the current bank being accessed by the VIC-II
** chip.
*/
setscreen(vb,sa)
unsigned vb,sa;
{
  register unsigned a;

  a = ((sa-vb)/64); /* (sa-vb)/1024 << 4 */
  poke(VMCSB,(peek(VMCSB) & 15) | a);
}

/* Set Text Graphics mode */
  setmap(0,1024);
  setscreen(0,1024);
  poke(VICCTL,peek(VICCTL) & 223);   
  poke(COLOR,pencolor[1]);
}

/* Set Multi-Color Graphics Mode */
multicolor()
{
  setmap(vbase,gbase);
  setscreen(vbase,sbase);
  poke(VICCTL,peek(VICCTL) | 32);
  poke(VICMC,peek(VICMC) | 16);
  poke(53281,pencolor[0]);
  aspect = 160.0 / 200.0;  /* compute aspect ratio */
}


/* Set Hi-Res Graphics Mode */
hires()
{
  setmap(vbase,gbase);
  setscreen(vbase,sbase);
  poke(VICCTL,peek(VICCTL) | 32);
  poke(VICMC,peek(VICMC) & 239); /* disable multi-color mode */
  poke(53281,pencolor[0]); /* background color reg */
  aspect = 320.0 / 200.0;  /* compute aspect ratio */

/* Convert pixel coordinate to byte offset.
** The BASIC formula from the PRG is:
**   row  = int(y/8)
**   char = int(x/8)
**   line = y and 7
**   loc  = base+row*320+char*8+line
**
** However, note that we can avoid the
** division and multiplication by using
** a table-lookup for row offset and by
** proper use of masking.
**
** IMPORTANT:  This routine only computes the OFFSET to the graphic byte,
** NOT its actual location.  You must add the graphics base address to 
** get the actual location.
*/
gofst(x,y)
unsigned x,y;
{
  register unsigned loc;
  
  loc = y_offset[y >> 3] + /* row offset */
    (x & 0xfff8) +         /* character offset */

  return loc;
}
 
/* Draw one pixel.
** Parameters:
**   0 <= xx  <= 319 (hi-res)
**   0 <= xx  <= 159 (multi-color)
**   0 <= yy  <= 199
**   0 <= pen <= 3
*/
pset(xx,yy,pen)
unsigned xx,yy,pen;
{
  register char bit,val,mask;
  register unsigned x,y;
  register unsigned loc,ofst;

  x=xx;  y=yy;
  if (gmode==2) x = x << 1; /* adjust for multi-color (x=x*2) */
  if (x<0 || x>319 || y<0 || y>199) return;

  cur_x = xx;               /* set current location */  
  cur_y = yy;
  ofst = gofst(x,y);        /* get pixel offset */
  loc = gbase + ofst;       /* true pixel byte address */
  bit = 7-(x & 7);          /* compute bit number */
  if (gmode==1) {           /* Hi-res */
    if (pen==0) val=0;      /* clearing bit */
    mask = gmask1[bit];     /* get pixel mask */
    poke(loc,(peek(loc) & mask) | val); /* set/clear bit */    
    y = y>>3;               /* divide by 8 */
    loc = sbase + y2color[y] + (x>>3);
    poke(loc,pencolor[0] + (pencolor[1] << 4));
  }
  else {                    /* Multi-color */ 
    switch(pen) {

    case 0: val=0;
            break;

    case 1: val=mcbit1[bit];
            break;

    case 2: val=mcbit2[bit];
            break;

    case 3: val=mcbit3[bit];
            break;

    default: val=0;
    }
  
    mask = gmask2[bit];
    poke(loc,(peek(loc) & mask) | val); /* set/clear bits */
    y = y>>3;               /* y = y/8 */
    x = x>>3;               /* x = x/8 */
    if (pen==3) {
      loc = COLORMEM + y2color[y] + x;
      poke(loc,pencolor[3]);
    }
    else if (pen>0){
      loc = sbase + y2color[y] + x;      
      poke(loc,(pencolor[1]<<4) | pencolor[2]);
    }
  }
      
}
/* Bresenham's line drawing algorithm.
** Draw a line between two coordinate pairs.
** This routine was adapted from an article appearing
** in the November '85 issue of BYTE Magazine.
*/
 
line(x1,y1,x2,y2,pen)
unsigned x1,y1,x2,y2,pen;
{
  register int x,y,z,a,b,d,dx,dy;
  register int deltap,deltaq;

  dx = abs(x2-x1);
  dy = abs(y2-y1);

  if (dy <= dx) {   /* Slope <= 1 */
    x = x1;              /* initialize x */
    y = y1;          /* initialize y */
    z = x2;          /* set sentinel in  x direction */
    
    if (x1 <= x2) a = 1; /* x increases */
    else a = -1;         /* x decreases */
    
    if (y <= y2) b = 1;  /* y increases */
    else b = -1;         /* y decreases */
    
    deltap = dy + dy;    /* initialize decision function and deltas */
    d = deltap - dx;
    deltaq = d - dx;
      
    /* Locate and plot points */
    pset(x,y,pen);
    for (;x != z;) {
      x += a;
      if (d < 0 ) d += deltap;
      else {
        y += b;
        d += deltaq;
      }
      pset(x,y,pen);
    }
  }
  else {                 /* dx <= dy so view x as function of y */
    y = y1;
    x = x1;
    z = y2;             /* set sentinel in y direction */
    
    /* Now set y increment */
    if (y1 <= y2) a = 1; /* y increases */
    else a = -1;         /* y decreases */

    /* Now set x increment */
    if (x1 <= x2) b = 1; /* x increases */
    else b = -1;         /* x decreases */
    
    /* Initialize decision function and its deltas */
    deltap = dx + dx;
    d = deltap - dy;
    deltaq = d - dy;
    
    /* Locate and plot points */
    pset(x,y,pen);        /* first point */
    for (;y != z;) {
      y += a;
      if (d < 0) d += deltap;
      else {
        x += b;
        d += deltaq;        
      }
      pset(x,y,pen);
    }
  }
}

/* Draw one character in any mode.
** Character ROM map:
---------------------------------------------------
            Set 1

**   53248: Upper-case & Misc.    0- 63  No SHIFT
**          Graphics/Graphics    64-127  SHIFT/CBM

**   54272  Upper-case & Misc.  128-191  No SHIFT    reverse
**          Graphics/Graphics   192-255  SHIFT/CBM   field
---------------------------------------------------
**   55296  Lower-case & Misc.    0- 63  No SHIFT
**          Upper-case/Graphics  64-127  SHIFT/CBM

**   56320  Lower-case & Misc.  128-191  No SHIFT    reverse
**          Upper-case/Graphics 192-255  SHIFT/CBM   field
---------------------------------------------------
**
** Note:  this routine currently only provides access to character set
** 2 and does not address reversed characters.  Its features should be
** expanded to provide both character sets (complete).
*/
drawchar(x,y,c,pen)
unsigned x,y,c,pen;
{
  register char c1;                /* translated character */
  register unsigned cbase;         /* base address of character set */
  register char *cp;
  register unsigned i,j;
  char pixels[8];                  /* matrix for one character */

  if (gmode==0) {                  /* text mode? */
    }
  else {                           /* hi-res or multi-color */
    cbase = 55296;                 /* Unconditional use of set 2 */
    c1=c;
    if (c1 < 32) c1 += 64;         /* translate to screen code */
    else if (c1>63 && c1<92) c1-=64;
    else if (c1>191 && c1<223) c1 -= 128;     
    cp = (char *) (cbase + c1*8);  /* compute rom location */

    poke(56334,peek(56334) & 254); /* disable timer (interrupts) */
    poke(1,peek(1) & 251);         /* map in character rom */

    for (i=0;i<8;i++) pixels[i] = *cp++;

    poke(1,peek(1) | 4);           /* map out character rom */
    poke(56334,peek(56334) | 1);   /* enable timer */

    for (i=0;i<8;i++) {            /* plot character */
      c1 = pixels[i];              /* get row of character */
      for (j=0;j<8;j++) {          /* do dots in row */
        if (c1 & 0x80)             /* pixel set? */
          pset(x+j,y+i,pen);
        c1 = c1 << 1;
      }
    }
  }
}

/* Output a complete text string in current mode.
** Text may be rotated by specifying a non-zero
** angle parameter. 
** Parameters:
**   x,y:   starting coordinate for top left of first character
**   s:     null terminated text string
**   angle: rotation angle, in degrees
**   pen:   pen number (0-3) to be used
*/
drawtext(x,y,s,angle,pen)
unsigned x,y; char *s; float angle; unsigned pen;
{
  register char c,*p;
  register unsigned xx,yy;
  float xradius,yradius,angl,fx,fy;

  xx=x; yy=y;
  fx=x; fy=y;              /* convert to floating point */
  yradius = 8.0;
  angl = angle / RADCON;   /* convert angle to radians */
  for (p=s;(c=*p++);) {    /* loop thru string */
    drawchar(xx,yy,c,pen); /* draw character */
    xradius = yradius * aspect;
    xx = fx + xradius * cos(angl);
    yy = fy + yradius * sin(angl);
    yradius += 8.0;         /* compute new radius */
  }
}
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads