FDF is a 3D wireframe graphics renderer, part of the 42 school curriculum. This project reads a file containing a 3D map and displays it in an isometric projection.
1. Reading the Map
this project is not a parsing project, (but that not mean our project can crash(Abort/SEGV..)), so all we need to verify is that the files extension is .fdf and the first line is the smallest line in the map!
2.Collect the points
the points collected from the map are the Z axis, and the Y axis is the number of line returned by get_next_line (staring from 0), while X axis is the string index returned by ft_split.
// Part of the function that collect point!!
static t_point *_get_points(char *line, int cols, int y)
{
char **spl;
t_point *pnt;
int x;
x = 0;
spl = split_w(line);
if (!spl || ft_split_size(spl) < cols)
return (ft_exit(), NULL);
pnt = malloc(sizeof(t_point) * cols);
if (!pnt)
return (ft_exit(), NULL);
while (spl[x] && x < cols)
{
pnt[x].x = x;
pnt[x].y = y;
pnt[x].z = ft_atoi(spl[x]);
x++;
}
return (ft_free_strs(spl), pnt);
}
3.Collect Colors
the colors can be in hexa (0x00FF00/0x00ff00) and can be in int, and always will be like this example: (27,0xff0000) in this example Z=27, and the color is the red,
I'm using split with ',' as separator to split the string and I take the second string if not NULL, then the following function handle the rest
static int _inbase(char c)
{
int i;
i = 0;
while (BASE1[i] && BASE2[i])
{
if (c == BASE1[i] || c == BASE2[i])
return (i + 1);
i++;
}
return (0);
}
uint32_t hexa2int(char *str)
{
uint32_t res;
int i;
i = 0;
if (!str)
return (i);
res = 0;
while (str[i] && _inbase(str[i]))
{
res = (res * 16) + _inbase(str[i]) - 1;
i++;
}
if (ft_strlen(str) == 8)
return (res);
return ((res << 8) | 0x000000FF);
}
Gridiant
A gradient transitions smoothly between two colors. The
gradient_color
function calculates an intermediate color between two given colors (col1
andcol2
) based on the current step and the total number of steps.
// (this function work as a part of dda functions)
uint32_t gradient_color(uint32_t col1, uint32_t col2, int step, int steps)
{
t_color color;
if (col1 == col2)
return (col1);
if (!steps)
return (col1);
color.r1 = col1 >> 24;
color.g1 = col1 >> 16;
color.b1 = col1 >> 8;
color.r2 = col2 >> 24;
color.g2 = col2 >> 16;
color.b2 = col2 >> 8;
if (color.r1 < color.r2)
color.r1 += step * (color.r2 - color.r1) / steps;
else
color.r1 -= step * (color.r1 - color.r2) / steps;
if (color.g1 < color.g2)
color.g1 += step * (color.g2 - color.g1) / steps;
else
color.g1 -= step * (color.g1 - color.g2) / steps;
if (color.b1 < color.b2)
color.b1 += step * (color.b2 - color.b1) / steps;
else
color.b1 -= step * (color.b1 - color.b2) / steps;
return (color.r1 << 24 | color.g1 << 16 | color.b1 << 8 | 0xFF);
}
4.Calcul isometric projection
for isometric projection I use the rotate matrix
to rotate my points 45deg on Z and X Axis,
5.Draw line
to draw a line between points A and B I have used dda algo to do that, it's not the good algo but it's the easest one,
void fdf_dda(t_point p1, t_point p2, mlx_image_t *img)
{
t_ddavars vars;
uint32_t color;
vars.dx = p2.u - p1.u;
vars.dy = p2.v - p1.v;
if (fabsf(vars.dx) > fabsf(vars.dy))
vars.steps = fabsf(vars.dx);
else
vars.steps = fabsf(vars.dy);
vars.x_inc = vars.dx / (float)vars.steps;
vars.y_inc = vars.dy / (float)vars.steps;
vars.x = p1.u;
vars.y = p1.v;
vars.i = 0;
while (vars.i <= vars.steps)
{
color = gradient_color(p1.color, p2.color, vars.i, vars.steps);
fdf_put_pixel(vars.x, vars.y, color, img);
vars.x += vars.x_inc;
vars.y += vars.y_inc;
vars.i++;
}
}
6.Render
now have to link my points and display them on the window, of course i have to center the shape , but after that all I need is to while loop on my points and draw them.
void fdf_link_points(t_point **pnts, t_dimensions dm, mlx_image_t *img)
{
int i;
int j;
i = 0;
while (pnts && pnts[i])
{
j = 0;
while (j < dm.cols - 1)
{
fdf_dda(pnts[i][j], pnts[i][j + 1], img);
j++;
}
i++;
}
j = 0;
while (j < dm.cols)
{
i = 0;
while (pnts && pnts[i + 1])
{
fdf_dda(pnts[i][j], pnts[i + 1][j], img);
i++;
}
j++;
}
}
the full code on my Github: