fxengine/src/render/triangle.c

227 lines
6.2 KiB
C

#include <render/triangle.h>
#include <render/bitmap.h>
#include <render/translate.h>
#include <render/zbuffer.h>
#ifdef USE_LIBPROF
#include <libprof.h>
#endif
#include <gint/display.h>
#include <gint/clock.h>
#ifdef USE_LIBPROF
static uint32_t frame_interval_min=1000000;
static uint32_t frame_interval_max=1;
#endif
void render_update(const uint32_t libprof_channel)
{
//dupdate();
#ifdef USE_LIBPROF
// gestion du temps avec libprof
if (prof_elapsed)
{
prof_leave(libprof_channel);
uint32_t frame_interval = prof_time(libprof_channel);
//sleep_us(0, MINIMUM_FRAME_DELAY-frame_interval);
if (frame_interval<frame_interval_min)
frame_interval_min = frame_interval;
if (frame_interval>frame_interval_max)
frame_interval_max = frame_interval;
}
else
{
prof_init(libprof_channel+1, 0);
}
//dupdate();
prof_clear(libprof_channel);
prof_enter(libprof_channel);
#endif
render_zbuffer_clear();
///render_set(dh, dv, roulis, camera);
//dclear(C_WHITE);
}
/**
* @brief Orientation of the face
*
* @param face The face
*
* @return if it is true the it is clockwised else it isn't clockwised
*/
static bool is_colckwised(render_triangle const * face)
{
int32_t area = 0;
area += face->s1->x * face->s2->y;
area -= face->s2->x * face->s1->y;
area += face->s2->x * face->s3->y;
area -= face->s3->x * face->s2->y;
area += face->s3->x * face->s1->y;
area -= face->s1->x * face->s3->y;
return (area < 0);
}
// gestion locale des arètes
typedef struct line line;
struct line
{
int32_t x,y,z;
int32_t dx,dy,dz;
int32_t no_line; // si les deux points sont confondus (se comporte comme un bool)
};
/**
* @brief Sets up a line with 2 points
*
* @param l The line
* @param s1 The s 1
* @param s2 The s 2
*/
static void line_set(line* l,render_integer_position const * s1, render_integer_position const * s2)
{
l->x = s1->x;
l->y = s1->y;
l->z = s1->z;
l->dx = s2->x - s1->x;
l->dy = s2->y - s1->y;
l->dz = s2->z - s1->z;
l->no_line = (l->dx==0 && l->dy==0);
}
static int32_t max(int32_t x, int32_t y)
{
return (x>y ? x : y);
}
static int32_t min(int32_t x, int32_t y)
{
return (x<y ? x : y);
}
static int32_t abs(int32_t x)
{
return(x<0 ? -x : x);
}
/**
* @brief get the corresponding x from the y coordinate
*
* @param[in] y the y coordinate
* @param l the line
* @param x address where x is written
*
* @return if given point coordinate belongs to the l
*/
static bool line_get_x(int32_t y, line const * l, int32_t * x)
{
y -= l->y;
if (y < 0 && l->dy > 0)
return false;
if (y > 0 && l->dy < 0)
return false;
if (abs(y) > abs(l->dy))
return false;
if (l->dy != 0)
*x = l->x + (y * l->dx) / l->dy;
else if (y==0)
*x = l->x + l->dx;
else
return false;
return true;
}
void render_display_triangle(const render_triangle * face)
{
// backface culling
if (is_colckwised(face) != face->clockwised)
return;
// incomplete clipping
if (face->s1->x < 0 && face->s2->x < 0 && face->s3->x < 0)
return;
if (face->s1->x >= render_width && face->s2->x >= render_width && face->s3->x >= render_width)
return;
if (face->s1->y < 0 && face->s2->y < 0 && face->s3->y < 0)
return;
if (face->s1->y >= render_height && face->s2->y >= render_height && face->s3->y >= render_height)
return;
if (face->s1->z <= 0 && face->s2->z <= 0 && face->s3->z <= 0)
return;
line cotes[3];
line_set(&cotes[0], face->s1, face->s2);
line_set(&cotes[1], face->s1, face->s3);
line_set(&cotes[2], face->s2, face->s3);
if (cotes[0].no_line || cotes[1].no_line || cotes[2].no_line)
return;
const int32_t ymin = max(min(face->s1->y, min(face->s2->y, face->s3->y)), 0);
const int32_t ymax = min(max(face->s1->y, max(face->s2->y, face->s3->y)), 63);
const int32_t xAB = face->s2->x - face->s1->x, yAB = face->s2->y - face->s1->y, zAB=face->s2->z-face->s1->z;
const int32_t xAC = face->s3->x - face->s1->x, yAC = face->s3->y - face->s1->y, zAC=face->s3->z-face->s1->z;
const int32_t diviseur_commun = (xAB * yAC - yAB * xAC);
const int32_t fact_1= (32768 * yAC) / diviseur_commun, fact_2 = (32768 * xAC) / diviseur_commun;
const int32_t fact_3= (32768 * xAB) / diviseur_commun, fact_4 = (32768 * yAB) / diviseur_commun;
for (int32_t y = ymin; y <= ymax; y++)
{
// xmin and xmax determination
int32_t tx1,tx2;
for (int t=0;t<3;t++)
{
if (line_get_x(y,&cotes[t],&tx1))
break;
}
for (int32_t t=0;t<3;t++)
{
if (line_get_x(y,&cotes[t],&tx2) && tx1!=tx2)
break;
}
const int32_t txmin=max(min(tx1,tx2),0), txmax=min(max(tx1,tx2),127);
for (int32_t x=txmin; x<=txmax; x++)
{
int32_t vx, vy, z;
const int32_t xcalc = x - face->s1->x, ycalc = y - face->s1->y;
// calcul de vx, vy
vx = (xcalc*fact_1 - ycalc*fact_2);
vy = (ycalc*fact_3 - xcalc*fact_4);
z = face->s1->z + (vx * zAB + vy * zAC)/32768;
int32_t vx2= ( vx*face->texture->size_px_x/face->s2->z ) / ((32768-vx)/face->s1->z + vx/face->s2->z);
int32_t vy2= ( vy*face->texture->size_px_y/face->s3->z ) / ((32768-vy)/face->s1->z + vy/face->s3->z);
/* Perspective correction
vx /= (double) face->s2->z / ((1 - vx) / face->s1->z + vx / (double) face->s2->z);
vy /= (double) face->s3->z / ((1 - vy) / face->s1->z + vy / (double) face->s3->z);
*/
// Affichage du point
const uint8_t color = bitmap_get_pixel_r(face->texture, vx2, vy2);
if (color >> 1)
{
//dpixel(x,y, C_BLACK);
if (render_zbuffer_set_px(x,y,z))
dpixel(x, y, 3 * (color % 2)); // 3* means cast to black and white, and vx,and vy casted between 0 and 7
}
}
}
}