1v13d/src/FxEngine/face.c

138 lines
4.4 KiB
C

#include "face.h"
#include "zbuffer.h"
#include <stdbool.h>
#include <gint/display.h>
#define min(x,y) (x<y?x:y)
#define max(x,y) (x>y?x:y)
#define abs(x) (x>0?x:-x)
static bool sens_horaire(FE_face const * face)
{
int area = 0;
area+=face->s1->translated.x*face->s2->translated.y;
area-=face->s2->translated.x*face->s1->translated.y;
area+=face->s2->translated.x*face->s3->translated.y;
area-=face->s3->translated.x*face->s2->translated.y;
area+=face->s3->translated.x*face->s1->translated.y;
area-=face->s1->translated.x*face->s3->translated.y;
return (area < 0);
}
// gestion des lignes
typedef struct line line;
struct line
{
int x,y,z;
int dx,dy,dz;
bool no_line; // si les deux points sont confondus
};
static void set_line(line* segment,FE_point const * s1, FE_point const * s2)
{
segment->x=s1->translated.x;
segment->y=s1->translated.y;
segment->z=s1->translated.z;
segment->dx=s2->translated.x-s1->translated.x;
segment->dy=s2->translated.y-s1->translated.y;
segment->dz=s2->translated.z-s1->translated.z;
segment->no_line=(segment->dx==0&&segment->dy==0);
}
static bool get_x(int y, line const * segment, int * x)
{
y-=segment->y;
if (y<0 && segment->dy>0)
return false;
if (y>0 && segment->dy<0)
return false;
if (abs(y)>abs(segment->dy))
return false;
if (segment->dy!=0)
*x=segment->x+(y*segment->dx)/segment->dy;
else if (y==0)
*x=segment->x+segment->dx;
else
return false;
return true;
}
void FE_draw_face(FE_face const * face)
{
if (sens_horaire(face)!=face->visible)
return;
if (face->s1->translated.x<0 && face->s2->translated.x<0 && face->s3->translated.x<0)
return;
if (face->s1->translated.x>127 && face->s2->translated.x>127 && face->s3->translated.x>127)
return;
if (face->s1->translated.y<0 && face->s2->translated.y<0 && face->s3->translated.y<0)
return;
if (face->s1->translated.y>63 && face->s2->translated.y>63 && face->s3->translated.y>63)
return;
if (face->s1->translated.z<=0 && face->s2->translated.z<=0 && face->s3->translated.z<=0)
return;
line cotes[3];
set_line(&cotes[0],face->s1,face->s2);
set_line(&cotes[1],face->s1,face->s3);
set_line(&cotes[2],face->s2,face->s3);
if (cotes[0].no_line||cotes[1].no_line||cotes[2].no_line)
return;
const int xmin=min(face->s1->translated.x,min(face->s2->translated.x,face->s3->translated.x));
const int xmax=max(face->s1->translated.x,max(face->s2->translated.x,face->s3->translated.x));
const int ymin=max(min(face->s1->translated.y,min(face->s2->translated.y,face->s3->translated.y)),0);
const int ymax=min(max(face->s1->translated.y,max(face->s2->translated.y,face->s3->translated.y)),63);
const int xAB=face->s2->translated.x-face->s1->translated.x, yAB=face->s2->translated.y-face->s1->translated.y;
const int xAC=face->s3->translated.x-face->s1->translated.x, yAC=face->s3->translated.y-face->s1->translated.y;
const int diviseur_commun=(xAB*yAC-yAB*xAC); //(multiplier par 10000)
const int fact_1=(10000*yAC)/diviseur_commun, fact_2=(10000*xAC)/diviseur_commun;
const int fact_3=(10000*xAB)/diviseur_commun, fact_4=(10000*yAB)/diviseur_commun;
for (int ty=ymin; ty<=ymax; ty++)
{
int tx1,tx2;
// tx1
for (int t=0;t<3;t++)
{if (get_x(ty,&cotes[t],&tx1)) break;}
for (int t=0;t<3;t++)
{if (get_x(ty,&cotes[t],&tx2)&&tx1!=tx2) break;}
const int txmin=max(min(tx1,tx2),0), txmax=min(max(tx1,tx2),127);
for (int tx=txmin; tx<=txmax; tx++)
{
int vx,vy,vz;
int xcalc=tx-face->s1->translated.x, ycalc=ty-face->s1->translated.y;
vx=(xcalc*fact_1-ycalc*fact_2)/1250;
vy=(ycalc*fact_3-xcalc*fact_4)/1250;
vz=face->s1->translated.z + (vx*cotes[0].dz + vy*cotes[1].dz)/8;
if (FE_zbuffer_set_dist(tx,ty,vz))
dpixel(tx,ty,3*FE_get_pixel(face->texturenum,vx,vy));
}
}
// x=Det(AM,AC)/det(AB,AC)
// y=det(AM,AB)/det(AC,AB)
// x=(xAM*yAC-yAM*xAC)/(xAB*yAC-yAB*xAC)
// y=(xAM*yAB-yAM*xAB)/(xAC*yAB-yAC*xAB)
// soit diviseur_commun = (xAB*yAC-yAB*xAC)
// x=xAM*yAC/diviseur_commun-yAM*xAC/diviseur_commun
// y=yAM*xAB/diviseur_commun-xAM*yAB/diciseur_commun
}