Cube3d/render.c

141 lines
5.1 KiB
C

// render.c
#include "cub3d.h"
static int is_wall(t_app *a, int mx, int my) {
if (mx < 0 || my < 0 || mx >= a->map_w || my >= a->map_h) return 1;
return (a->map[my][mx] == '1');
}
static void move_player(t_app *a) {
double ms = a->move_speed;
double rs = a->rot_speed;
// forward/back
if (a->keys.w) {
double nx = a->px + a->dirx * ms;
double ny = a->py + a->diry * ms;
if (!is_wall(a, (int)nx, (int)a->py)) a->px = nx;
if (!is_wall(a, (int)a->px, (int)ny)) a->py = ny;
}
if (a->keys.s) {
double nx = a->px - a->dirx * ms;
double ny = a->py - a->diry * ms;
if (!is_wall(a, (int)nx, (int)a->py)) a->px = nx;
if (!is_wall(a, (int)a->px, (int)ny)) a->py = ny;
}
// strafe
if (a->keys.a) {
double nx = a->px - a->diry * ms;
double ny = a->py + a->dirx * ms;
if (!is_wall(a, (int)nx, (int)a->py)) a->px = nx;
if (!is_wall(a, (int)a->px, (int)ny)) a->py = ny;
}
if (a->keys.d) {
double nx = a->px + a->diry * ms;
double ny = a->py - a->dirx * ms;
if (!is_wall(a, (int)nx, (int)a->py)) a->px = nx;
if (!is_wall(a, (int)a->px, (int)ny)) a->py = ny;
}
// rotation
if (a->keys.left || a->keys.right) {
double angle = (a->keys.left ? -rs : rs);
double olddirx = a->dirx;
a->dirx = a->dirx * cos(angle) - a->diry * sin(angle);
a->diry = olddirx * sin(angle) + a->diry * cos(angle);
double oldplanex = a->planex;
a->planex = a->planex * cos(angle) - a->planey * sin(angle);
a->planey = oldplanex * sin(angle) + a->planey * cos(angle);
}
}
static void draw_vertical_line_tex(t_app *a, int x, int drawStart, int drawEnd,
t_tex *tex, int texX, double step, double texPos) {
if (drawStart < 0) drawStart = 0;
if (drawEnd >= WIN_H) drawEnd = WIN_H - 1;
// plafond (optionnel: couleur unie)
for (int y = 0; y < drawStart; ++y)
put_pixel(&a->frame, x, y, 0x0080A0); // bleu doux
for (int y = drawStart; y <= drawEnd; ++y) {
int texY = (int)texPos & (tex->h - 1); // textures power-of-two → masque ok
texPos += step;
int color = get_tex_color(tex, texX, texY);
put_pixel(&a->frame, x, y, color);
}
// sol
for (int y = drawEnd + 1; y < WIN_H; ++y)
put_pixel(&a->frame, x, y, 0x404040);
}
void render_frame(t_app *a) {
// clear: pas nécessaire si on redraw tout (plafond/sol + murs)
for (int x = 0; x < WIN_W; ++x) {
// camX dans [-1, 1]
double cameraX = 2.0 * x / (double)WIN_W - 1.0;
double rayDirX = a->dirx + a->planex * cameraX;
double rayDirY = a->diry + a->planey * cameraX;
int mapX = (int)a->px;
int mapY = (int)a->py;
double deltaDistX = (rayDirX == 0) ? 1e30 : fabs(1.0 / rayDirX);
double deltaDistY = (rayDirY == 0) ? 1e30 : fabs(1.0 / rayDirY);
double sideDistX, sideDistY;
int stepX, stepY;
if (rayDirX < 0) { stepX = -1; sideDistX = (a->px - mapX) * deltaDistX; }
else { stepX = 1; sideDistX = (mapX + 1.0 - a->px) * deltaDistX; }
if (rayDirY < 0) { stepY = -1; sideDistY = (a->py - mapY) * deltaDistY; }
else { stepY = 1; sideDistY = (mapY + 1.0 - a->py) * deltaDistY; }
int hit = 0, side = 0;
while (!hit) {
if (sideDistX < sideDistY) { sideDistX += deltaDistX; mapX += stepX; side = 0; }
else { sideDistY += deltaDistY; mapY += stepY; side = 1; }
if (is_wall(a, mapX, mapY)) hit = 1;
}
double perpWallDist = (side == 0)
? (mapX - a->px + (1 - stepX) / 2.0) / rayDirX
: (mapY - a->py + (1 - stepY) / 2.0) / rayDirY;
if (perpWallDist < 1e-6) perpWallDist = 1e-6;
int lineHeight = (int)(WIN_H / perpWallDist);
int drawStart = -lineHeight / 2 + WIN_H / 2;
int drawEnd = lineHeight / 2 + WIN_H / 2;
// texture selection: 0=N,1=E,2=S,3=W (à adapter selon ta map)
int tex_id;
if (side == 0 && rayDirX > 0) tex_id = 3; // W
else if (side == 0 && rayDirX < 0) tex_id = 1; // E
else if (side == 1 && rayDirY > 0) tex_id = 0; // N
else tex_id = 2; // S
t_tex *tex = &a->tex[tex_id];
// point d'impact sur le mur
double wallX = (side == 0) ? (a->py + perpWallDist * rayDirY)
: (a->px + perpWallDist * rayDirX);
wallX -= floor(wallX);
int texX = (int)(wallX * (double)tex->w);
if (side == 0 && rayDirX > 0) texX = tex->w - texX - 1;
if (side == 1 && rayDirY < 0) texX = tex->w - texX - 1;
double step = (double)tex->h / (double)lineHeight;
double texPos = (drawStart - WIN_H / 2 + lineHeight / 2) * step;
draw_vertical_line_tex(a, x, drawStart, drawEnd, tex, texX, step, texPos);
a->zbuf[x] = perpWallDist;
}
mlx_put_image_to_window(a->mlx, a->win, a->frame.ptr, 0, 0);
}
int update(t_app *a) {
move_player(a);
render_frame(a);
return 0;
}