aboutsummaryrefslogtreecommitdiff
path: root/src/render_state.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/render_state.c')
-rw-r--r--src/render_state.c205
1 files changed, 205 insertions, 0 deletions
diff --git a/src/render_state.c b/src/render_state.c
new file mode 100644
index 0000000..46fc7c5
--- /dev/null
+++ b/src/render_state.c
@@ -0,0 +1,205 @@
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* render_state.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: cacharle <marvin@42.fr> +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* Created: 2020/01/15 14:40:14 by cacharle #+# #+# */
+/* Updated: 2020/01/30 15:50:48 by cacharle ### ########.fr */
+/* */
+/* ************************************************************************** */
+
+#include "cub3d.h"
+
+/*
+** -1 0 1 <-- camera_x
+** v v v
+** ################
+** # | # <-- screen
+** # | #
+** ################
+**
+** camera_x is the x column from the camera percpective
+** scaling the plane vector and adding it to the direction vector
+** to create a vector in the *direction* of the column x.
+*/
+
+void rstate_ray(t_state *state, t_render_state *rstate)
+{
+ double camera_x;
+
+ camera_x = 2.0 * (double)rstate->x / (double)state->window.width - 1.0;
+ rstate->ray = vector_add(state->dir, vector_scale(state->plane, camera_x));
+}
+
+/*
+** delta between each grid unit form the vector percpective
+**
+** if we have a vector v = [2 3]:
+** dx = |v| / v_1
+** = sqrt(v_1^2 + v_2^2) / v_1
+** = (v_1^2 + v_2^2) / v_1^2
+** = 1 + v_2^2 / v_1^2
+** Same thing for dy
+** dy = |v| / v_2
+** = sqrt(v_1^2 + v_2^2) / v_1
+** = (v_1^2 + v_2^2) / v_2^2
+** = v_1^2 / v_2^2 + 1
+**
+** This can be simplified (for some obscure reason):
+** dx = |1 / v_1|
+** dy = |1 / v_2|
+*/
+
+void rstate_delta(t_render_state *rstate)
+{
+ rstate->delta.x = fabs(1 / rstate->ray.x); //vector_norm(rstate->ray) / rstate->ray.x;
+ rstate->delta.y = fabs(1 / rstate->ray.y); // vector_norm(rstate->ray) / rstate->ray.y;
+}
+
+/*
+** first delta between player position and first grid unit
+**
+** current x and y are the perpendicular distance to the nearest wall,
+** we multiply them by their corresponding delta.
+** 0 <= perpendicular distance <= 1 is a ratio, how much of the full delta we need to take.
+**
+** if (rstate->ray.x < 0)
+** rstate->probe.x = state->pos.x - rstate->map_pos.x;
+** else
+** rstate->probe.x = fabs(state->pos.x - rstate->map_pos.x + 1.0);
+** if (rstate->ray.y < 0)
+** rstate->probe.y = state->pos.y - rstate->map_pos.y;
+** else
+** rstate->probe.y = fabs(state->pos.y - rstate->map_pos.y + 1.0);
+** rstate->probe.x *= rstate->delta.x;
+** rstate->probe.y *= rstate->delta.y;
+*/
+
+void rstate_init_probe(t_state *state, t_render_state *rstate)
+{
+ if (rstate->ray.x < 0)
+ rstate->probe.x = (state->pos.x - rstate->map_pos.x) * rstate->delta.x;
+ else
+ rstate->probe.x = (rstate->map_pos.x + 1.0 - state->pos.x) * rstate->delta.x;
+ if (rstate->ray.y < 0)
+ rstate->probe.y = (state->pos.y - rstate->map_pos.y) * rstate->delta.y;
+ else
+ rstate->probe.y = (rstate->map_pos.y + 1.0 - state->pos.y) * rstate->delta.y;
+ /* rstate->probe = VECTOR_SUB(state->pos, rstate->map_pos); */
+ /* if (rstate->ray.x > 0) */
+ /* rstate->probe.x += 1.0; */
+ /* if (rstate->ray.y > 0) */
+ /* rstate->probe.y += 1.0; */
+ /* rstate->probe.x *= rstate->delta.x; */
+ /* rstate->probe.y *= rstate->delta.y; */
+}
+
+/*
+** Move the probe to it's next iteration by advancing to the nearest square unit
+** in the x or y direction.
+** This advance is represented both with the
+** player/ray percpective and the map pecpective.
+*/
+
+void rstate_next_probe(t_render_state *rstate)
+{
+ if (rstate->probe.x < rstate->probe.y)
+ {
+ rstate->probe.x += rstate->delta.x;
+ rstate->map_pos.x += rstate->map_step.x;
+ }
+ else
+ {
+ rstate->probe.y += rstate->delta.y;
+ rstate->map_pos.y += rstate->map_step.y;
+ }
+}
+
+/*
+** perpendicular distance between the wall hit and the camera plane.
+** We don't use euclidean distance because it would cause a fisheye effect.
+**
+** ====================X========== wall
+** | /|
+** | <------ / | -----+
+** | / | |
+** plane | / | <- perpendicular distance
+** | | / |
+** v | / |
+** <-------^----/----------------- camera plane
+** | /
+** dir -> | /
+** | / <- euclidean distance
+** |/
+** x <- pos
+**
+** In this case the perpendicular distance (p) is the difference
+** of the y-coord of the hit point and the y-coord of the pos + dir vector.
+** We use the y component because we hit the wall
+** from a south/north percepective,
+** if we had hit it form west/east, we would use the x component instead.
+*/
+
+void rstate_perp_dist(t_state *state, t_render_state *rstate)
+{
+ if (rstate->side == SIDE_WE)
+ rstate->perp_dist = (rstate->map_pos.x - state->pos.x + (1 - rstate->map_step.x) / 2) / rstate->ray.x;
+ else
+ rstate->perp_dist = (rstate->map_pos.y - state->pos.y + (1 - rstate->map_step.y) / 2) / rstate->ray.y;
+}
+
+/*
+** 0 <= 1 / perp_dist <= 1
+** height * (1 / perp_dist) is how much of the screen height do we take
+*/
+
+void rstate_line_height(t_state *state, t_render_state *rstate)
+{
+ rstate->line_height = (int)((double)state->window.height / rstate->perp_dist);
+}
+
+t_image *get_tex(t_state *state, t_render_state *rstate)
+{
+ if (rstate->side == SIDE_NS)
+ {
+ if (rstate->probe.y < state->pos.y)
+ return (state->textures + TEX_NORTH);
+ else
+ return (state->textures + TEX_SOUTH);
+ }
+ else if (rstate->side == SIDE_WE)
+ {
+ if (rstate->probe.x > state->pos.x)
+ return (state->textures + TEX_WEST);
+ else
+ return (state->textures + TEX_EAST);
+ }
+ return (NULL);
+}
+
+/*
+** Since we're drawing each column, all the texels we want to draw on the window
+** are on a single column of the texture.
+** First we find the x-coord relative to the wall we hit
+*/
+
+int get_tex_x(t_state *state, t_render_state *rstate, t_image *texture)
+{
+ int tex_x;
+ double wall_x;
+
+ if (rstate->side == SIDE_WE)
+ wall_x = state->pos.y + rstate->perp_dist * rstate->ray.y;
+ else
+ wall_x = state->pos.x + rstate->perp_dist * rstate->ray.x;
+ wall_x -= floor(wall_x);
+
+ tex_x = (int)(wall_x * (double)texture->width);
+ if (rstate->side == 0 && rstate->ray.x > 0)
+ tex_x = texture->width - tex_x - 1;
+ if (rstate->side == 1 && rstate->ray.y < 0)
+ tex_x = texture->width - tex_x - 1;
+ return (tex_x);
+}