Routines de tracé de lignes et de polygones

Introduction

Ces routines sont celles étudiées en cours. Il manque pas mal de choses pour qu'elles deviennent vraiment utiles :

Exemples de routines (à placer dans un fichier séparé)

Voici les routines que je vous ai présenté :

Tracé de lignes (utile pour tester les XImages)

#include <stdio.h>
#include <math.h>
#include <limits.h>                         /* INT_MAX/INT_MIN */

#include "object.h"

char *G_buffer;
int HW_SCREEN_X_SIZE;
int HW_SCREEN_Y_SIZE;


/*-------------------------------*/
void SetImageBuffer(Camera *cam)
/*-------------------------------*/
/* Initialisation du buffer camera. DOIT ETRE APPELEE AVANT TOUTES LES AUTRES ! */
{
  G_buffer = cam->image;
  HW_SCREEN_X_SIZE=cam->resX;
  HW_SCREEN_Y_SIZE=cam->resY;
   /* Allocation du tableau pour le trace des polygones */
  AllocateTableau();
}

/*----------------------------------------------------------*/
void G_line(int x,int y,int x2,int y2,unsigned char colour)
/*----------------------------------------------------------*/
/* Trace de ligne de type Bresenham, version optimisee pour l'utilisation 
   d'une XImage */
{
 int dx,dy,long_d,short_d;
 int d,add_dh,add_dl;
 int inc_xh,inc_yh,inc_xl,inc_yl;
 register int inc_ah,inc_al;          
 register int i;                      
 register unsigned char *adr=G_buffer;

 dx=x2-x; dy=y2-y;                          /* 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 adress */
 adr+=y*HW_SCREEN_X_SIZE+x;                 /* 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 */
 }
}
Tracé de polygones
int *G_start;
int *G_end;
int G_miny,G_maxy;                          /* vertical boundaries */

void AllocateTableau() {
  /* Allocation du tableau des lignes */
  G_start = (int *) malloc(HW_SCREEN_Y_SIZE * sizeof(int));
  G_end = (int *) malloc(HW_SCREEN_Y_SIZE * sizeof(int));
}


void GI_scan(int x1, int y1, int x2, int y2)
/* Balayage de l'arete et remplissage des tableaux G_start et G_end */
{
 int dx,dy,long_d,short_d;
 int d,add_dh,add_dl;
 int inc_xh,inc_yh,inc_xl,inc_yl;
 register int i; 

 dx=x2-x1; dy=y2-y1;                          /* ranges */

  if(y1<G_miny) G_miny=y1;
  if(y1>G_maxy) G_maxy=y1;
  if(y2<G_miny) G_miny=y2;
  if(y2>G_maxy) G_maxy=y2;                  /* updating vertical size */


  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=-1; inc_yl=-1;}
  else    {        inc_yh=1;  inc_yl=1; }

  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 */

  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 */
    if(x1<G_start[y1])                         /* further then rightmost */
      G_start[y1]=x1;                           /* the begining of scan line */

   if(G_end[y1]<x1)                           /* further the leftmost */
     G_end[y1]=x1;                             /* the end of scan line */

   if(d>=0){x1+=inc_xh;y1+=inc_yh;d+=add_dh;} /* previous point was H type */
   else    {x1+=inc_xl;y1+=inc_yl;d+=add_dl;} /* previous point was L type */
  }
}

void GI_boarder_array_init(void)
{
 G_miny=INT_MAX;                            /* polygon starts here */
 G_maxy=INT_MIN;                            /* polygon ends here */

 G_start = (int *) memset((char *)G_start, 127, HW_SCREEN_Y_SIZE*sizeof(char*));
 G_end =(int *)  memset((char *)G_end, 0, HW_SCREEN_Y_SIZE*sizeof(char*));
}

void G_ambient_polygon(Tri* tri, Object *obj, unsigned char colour)
{
 register unsigned char *l_adr,*adr; 
 register int beg,end,i;
 int i0, i1, i2;

 /* Initialisation du tableau */
 GI_boarder_array_init();                   /* initializing the arrays */


 /* Parcours des faces */
 i0 = tri->PtVertex[0];
 i1 = tri->PtVertex[1];
 i2 = tri->PtVertex[2];

 GI_scan(obj->Vertex[i0].ScreenVertex.x,
         obj->Vertex[i0].ScreenVertex.y,
         obj->Vertex[i1].ScreenVertex.x,
         obj->Vertex[i1].ScreenVertex.y); 

 GI_scan(obj->Vertex[i1].ScreenVertex.x,
         obj->Vertex[i1].ScreenVertex.y,
         obj->Vertex[i2].ScreenVertex.x,
         obj->Vertex[i2].ScreenVertex.y); 

 GI_scan(obj->Vertex[i2].ScreenVertex.x,
         obj->Vertex[i2].ScreenVertex.y,
         obj->Vertex[i0].ScreenVertex.x,
         obj->Vertex[i0].ScreenVertex.y); 


  /* nothing to do? */
 if(G_miny<=G_maxy)  {
  l_adr=G_buffer+G_miny*HW_SCREEN_X_SIZE;   /* addr of 1st byte of 1st line */

  /* rendering all lines */
  for(; G_miny<=G_maxy; G_miny++, l_adr+=HW_SCREEN_X_SIZE) {
    adr=l_adr+(beg=G_start[G_miny]);         /* addr of the current line */
    end=G_end[G_miny]-beg+1;                 /* ends here */

    memset((char *) adr, colour, end);
  }
 }
}