/** 3DGPL *************************************************\
 * (8bit deep bitmap)                                     *
 * 2D graphics and 2D clipping.                           *
 *                                                        *
 *  Defines:                                              *
 *   G_init_graphics         initializing graphics;       *
 *   G_clear                 clearing the bitmap;         *
 *                                                        *
 *   G_dot                   dot into the bitmap;         *
 *   G_line                  line into a bitmap;          *
 *                                                        * 
 *  (6/1995) By Sergei Savhenko. (savs@cs.mcgill.ca).     *
 *  Copyright (c) 1995 Sergei Savchenko.                  *
 *  THIS SOURCE CODE CAN'T BE USED FOR COMERCIAL PURPOSES *
 *  WITHOUT AUTHORISATION                                 *
\**********************************************************/

#include <stdlib.h>                         /* malloc */
#include "../hardware/hardware.h"           /* hardware specific stuff */
#include "../clipper/clipper.h"             /* 2D clipping routines */
#include "../graphics/graphics.h"           /* graphics functions */

unsigned char *G_buffer;                    /* the bitmap's bits */

/**********************************************************\
 *  Allocating space for the colourmap.                   *
\**********************************************************/

unsigned char *G_init_graphics(void)
{
 return(G_buffer=(unsigned char*)malloc(HW_COLOURMAP_SIZE_CHAR));
}
   
/**********************************************************\
 *  Clearing the bitmap with the specified colour.        *
\**********************************************************/

void G_clear(void)
{
 HW_set_int((int*)G_buffer,HW_COLOURMAP_SIZE_INT,0x0);
}

/**********************************************************\
 *  Rendering a dot.                                      *
\**********************************************************/

void G_dot(int *vertex,unsigned char colour)
{
 if( (vertex[0]>=0)&&(vertex[0]<HW_SCREEN_X_SIZE) &&
     (vertex[1]>=0)&&(vertex[1]<HW_SCREEN_Y_SIZE) )
 {
  G_buffer[vertex[1]*HW_SCREEN_X_SIZE+vertex[0]]=colour;
 }
}

/**********************************************************\
 *  Rendering a line.                                     *
\**********************************************************/

void G_line(int *vertex1,int *vertex2,unsigned char colour)
{
 register int inc_ah,inc_al;                
 register int i;                            
 register unsigned char *adr=G_buffer;
 int *v1,*v2;
 int dx,dy,long_d,short_d;
 int d,add_dh,add_dl;
 int inc_xh,inc_yh,inc_xl,inc_yl;

 v1=vertex1;
 v2=vertex2;

 if(C_line_x_clipping(&v1,&v2,2))           /* horizontal clipping */
 {
  if(C_line_y_clipping(&v1,&v2,2))          /* vertical clipping */
  {
   dx=v2[0]-v1[0]; dy=v2[1]-v1[1];          /* ranges */

   if(dx<0){dx=-dx; inc_xh=-1; inc_xl=-1;}  /* making sure dx and dy >0 */
   else    {        inc_xh=1;  inc_xl=1; }  /* adjusting increments */

   if(dy<0){dy=-dy;inc_yh=-HW_SCREEN_X_SIZE;
                   inc_yl=-HW_SCREEN_X_SIZE;
           }                                /* to get to the neighboring */
   else    {       inc_yh= HW_SCREEN_X_SIZE;/* point along Y have to add */
                   inc_yl= HW_SCREEN_X_SIZE;/* or subtract this */
           }                               
   if(dx>dy){long_d=dx;short_d=dy;inc_yl=0;}/* long range,&making sure either */
   else     {long_d=dy;short_d=dx;inc_xl=0;}/* x or y is changed in L case */

   inc_ah=inc_xh+inc_yh;
   inc_al=inc_xl+inc_yl;                    /* increments for point address */
   adr+=v1[1]*HW_SCREEN_X_SIZE+v1[0];       /* address of first point */

   d=2*short_d-long_d;                      /* initial value of d */
   add_dl=2*short_d;                        /* d adjustment for H case */
   add_dh=2*short_d-2*long_d;               /* d adjustment for L case */

   for(i=0;i<=long_d;i++)                   /* for all points in longer range */
   {
    *adr=colour;                            /* rendering */
 
    if(d>=0){adr+=inc_ah; d+=add_dh;}       /* previous point was H type */
    else    {adr+=inc_al; d+=add_dl;}       /* previous point was L type */
   }
  }
 }
}

/**********************************************************/
