42 fdf

42 fdf

a 42 school project

·

4 min read

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 and col2) 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: