147 lines
4.7 KiB
C
147 lines
4.7 KiB
C
#include <fxengine/render/triangle.h>
|
|
#include <fxengine/render/buffer.h>
|
|
#include <fxengine/model/vertex.h>
|
|
#include <fxengine/model/bitmap.h>
|
|
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <gint/display.h>
|
|
|
|
void fe_display_triangle(const fe_triangle * face)
|
|
{
|
|
render_triangle(*face->s1, *face->s2, *face->s3, face->texture1, face->texture2, face->texture_half);
|
|
}
|
|
|
|
int render_triangle(fe_vertex const s1, fe_vertex const s2, fe_vertex const s3,
|
|
fe_bitmap const * side_0, fe_bitmap const * side_1, bool texture_half)
|
|
{
|
|
// Backface culling
|
|
const int32_t area = s1.x * s2.y
|
|
- s2.x * s1.y
|
|
+ s2.x * s3.y
|
|
- s3.x * s2.y
|
|
+ s3.x * s1.y
|
|
- s1.x * s3.y;
|
|
|
|
if (area < 0)
|
|
return render_triangle_nobfc(s1,s2,s3,side_0,texture_half);
|
|
else
|
|
return render_triangle_nobfc(s1,s2,s3,side_1,texture_half);
|
|
}
|
|
|
|
// Render Core
|
|
|
|
// Macros
|
|
#define min(x,y) (x<y?x:y)
|
|
#define max(x,y) (x>y?x:y)
|
|
#define abs(x) (x<0?-x:x)
|
|
|
|
// gestion des arètes
|
|
typedef struct
|
|
{
|
|
int32_t x,y,z;
|
|
int32_t dx,dy,dz;
|
|
int8_t no_line; // si les deux points sont confondus (se comporte comme un bool)
|
|
} line;
|
|
static void line_set(line* l,fe_vertex const * s1, fe_vertex 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 bool line_get_x(int32_t y, line const * l, int32_t * x) // retourne false si impossible, ou alors écrit dans 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;
|
|
}
|
|
|
|
|
|
int render_triangle_nobfc(fe_vertex const s1, fe_vertex const s2, fe_vertex const s3,
|
|
fe_bitmap const * side, bool texture_half)
|
|
{
|
|
if (!side) return RENDER_NOBMP;
|
|
|
|
// clipping (incomplete)
|
|
if (s1.x < 0 && s2.x < 0 && s3.x < 0) return RENDER_OUT_OF_SCREEN;
|
|
if (s1.x >= fe_width && s2.x >= fe_width && s3.x >= fe_width) return RENDER_OUT_OF_SCREEN;
|
|
if (s1.y < 0 && s2.y < 0 && s3.y < 0) return RENDER_OUT_OF_SCREEN;
|
|
if (s1.y >= fe_height && s2.y >= fe_height && s3.y >= fe_height) return RENDER_OUT_OF_SCREEN;
|
|
if (s1.z <= 0 && s2.z <= 0 && s3.z <= 0) return RENDER_OUT_OF_SCREEN;
|
|
|
|
line cotes[3];
|
|
line_set(&cotes[0], &s1, &s2);
|
|
line_set(&cotes[1], &s1, &s3);
|
|
line_set(&cotes[2], &s2, &s3);
|
|
if (cotes[0].no_line || cotes[1].no_line || cotes[2].no_line) return RENDER_INVISIBLE;
|
|
|
|
|
|
const int32_t ymin = max(min(s1.y, min(s2.y, s3.y)), 0);
|
|
const int32_t ymax = min(max(s1.y, max(s2.y, s3.y)), 63);
|
|
|
|
const int32_t xAB = s2.x - s1.x, yAB = s2.y - s1.y, zAB=s2.z-s1.z;
|
|
const int32_t xAC = s3.x - s1.x, yAC = s3.y - s1.y, zAC=s3.z-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++)
|
|
{
|
|
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 - s1.x, ycalc = y - s1.y;
|
|
// calcul de vx, vy
|
|
vx = (xcalc*fact_1 - ycalc*fact_2);
|
|
vy = (ycalc*fact_3 - xcalc*fact_4);
|
|
z = s1.z + (vx * zAB + vy * zAC)/32768;
|
|
if (z>0)
|
|
{
|
|
int32_t vx2= ( vx*side->size_px_x/s2.z ) / ((32768-vx)/s1.z + vx/s2.z);
|
|
int32_t vy2= ( vy*side->size_px_y/s3.z ) / ((32768-vy)/s1.z + vy/s3.z);
|
|
|
|
// Affichage du point
|
|
const uint8_t color = fe_bitmap_get_px(side, vx2, vy2);
|
|
|
|
if (color >> 1)
|
|
{
|
|
#ifdef RENDER_DEBUG_MODE
|
|
dpixel(x,y, C_BLACK);
|
|
#else
|
|
if (fe_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
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return RENDER_SUCCESSFULLY_RENDERED;
|
|
} |