bouncy fpga game
www.youtube.com/watch?v=IiLWF3GbV7w
1-- ========================================================================
2-- Renderer (scrolling world)
3-- world_col = pixel_column + cam_x
4-- world_row = pixel_row + cam_y
5-- All comparisons in world-space (11-bit).
6-- Obstacles imported from level package (use work.level.all).
7--
8-- Color priority:
9-- Arrow = White (111) > Char = Red (100) > Obs = Yellow (110)
10-- > Ground/Ceil/Walls = Green (010) > Trail = Magenta (101) > Sky = Black (000)
11-- ========================================================================
12
13library IEEE;
14use IEEE.STD_LOGIC_1164.all;
15use IEEE.STD_LOGIC_ARITH.all;
16use IEEE.STD_LOGIC_UNSIGNED.all;
17use work.level.all;
18
19entity renderer is
20 port(
21 pixel_row : in std_logic_vector(9 downto 0);
22 pixel_column : in std_logic_vector(9 downto 0);
23 char_x : in std_logic_vector(10 downto 0);
24 char_y : in std_logic_vector(10 downto 0);
25 char_width : in std_logic_vector(9 downto 0);
26 char_height : in std_logic_vector(9 downto 0);
27 cam_x : in std_logic_vector(10 downto 0);
28 cam_y : in std_logic_vector(10 downto 0);
29 vel_x_in : in std_logic_vector(9 downto 0);
30 vel_y_in : in std_logic_vector(9 downto 0);
31 trail_on_in : in std_logic;
32 red : out std_logic;
33 green : out std_logic;
34 blue : out std_logic
35 );
36end renderer;
37
38architecture behavior of renderer is
39
40 -- World boundaries (11-bit)
41 constant GROUND_TOP : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1488, 11);
42 constant CEIL_BOT : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(8, 11);
43 constant LEFT_WALL : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(8, 11);
44 constant RIGHT_WALL : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1492, 11);
45
46 -- World-space pixel coordinates (shared between processes)
47 signal wc : std_logic_vector(10 downto 0);
48 signal wr : std_logic_vector(10 downto 0);
49
50 signal char_on, ground_on, wall_on, ceiling_on, obs_on, arrow_on : std_logic;
51
52begin
53
54 -- Convert screen coordinates to world coordinates
55 wc <= ('0' & pixel_column) + cam_x;
56 wr <= ('0' & pixel_row) + cam_y;
57
58 -- ----------------------------------------------------------------
59 -- Scene geometry: character, world edges, obstacles
60 -- ----------------------------------------------------------------
61 render : process(wc, wr, char_x, char_y, char_width, char_height)
62 begin
63 char_on <= '0';
64 ground_on <= '0';
65 wall_on <= '0';
66 ceiling_on <= '0';
67 obs_on <= '0';
68
69 -- Character
70 if wc >= char_x - ('0' & char_width) and
71 wc <= char_x + ('0' & char_width) and
72 wr >= char_y - ('0' & char_height) and
73 wr <= char_y + ('0' & char_height) then
74 char_on <= '1';
75 end if;
76
77 -- World edges
78 if wr >= GROUND_TOP then ground_on <= '1'; end if;
79 if wr <= CEIL_BOT then ceiling_on <= '1'; end if;
80 if wc < LEFT_WALL or wc > RIGHT_WALL then wall_on <= '1'; end if;
81
82 -- Obstacles (loop over level_pkg arrays)
83 for obs_i in 0 to OBS_COUNT-1 loop
84 if wc >= OBS_L(obs_i) and wc <= OBS_R(obs_i) and
85 wr >= OBS_T(obs_i) and wr <= OBS_B(obs_i) then
86 obs_on <= '1';
87 end if;
88 end loop;
89
90 end process render;
91
92 -- ----------------------------------------------------------------
93 -- Velocity vector arrow
94 -- Line from (char_x, char_y) to (char_x + 3*vx, char_y + 3*vy).
95 -- Uses cross-product line-segment test:
96 -- pixel on segment iff |dy*(px-x0) - dx*(py-y0)| <= max(|dx|,|dy|)
97 -- and dx*(px-x0) + dy*(py-y0) in [0, dx^2+dy^2]
98 -- ----------------------------------------------------------------
99 arrow_proc : process(wc, wr, char_x, char_y, vel_x_in, vel_y_in)
100 variable wci, wri : integer;
101 variable cx, cy : integer;
102 variable vxi, vyi : integer;
103 variable dx, dy : integer;
104 variable cross : integer;
105 variable dot_p : integer;
106 variable len_sq : integer;
107 variable maxd : integer;
108 begin
109 wci := CONV_INTEGER(wc);
110 wri := CONV_INTEGER(wr);
111 cx := CONV_INTEGER(char_x);
112 cy := CONV_INTEGER(char_y);
113
114 -- Convert 10-bit 2's complement velocity to signed integer
115 if vel_x_in(9) = '1' then vxi := CONV_INTEGER(vel_x_in) - 1024;
116 else vxi := CONV_INTEGER(vel_x_in); end if;
117 if vel_y_in(9) = '1' then vyi := CONV_INTEGER(vel_y_in) - 1024;
118 else vyi := CONV_INTEGER(vel_y_in); end if;
119
120 -- Scale arrow by 3 for visibility
121 dx := vxi * 3;
122 dy := vyi * 3;
123
124 -- Precompute line metrics
125 cross := dy * (wci - cx) - dx * (wri - cy);
126 dot_p := dx * (wci - cx) + dy * (wri - cy);
127 len_sq := dx * dx + dy * dy;
128
129 -- Chebyshev thickness (~1-2 world-pixels wide)
130 maxd := dx; if maxd < 0 then maxd := -maxd; end if;
131 if dy > maxd then maxd := dy;
132 elsif -dy > maxd then maxd := -dy; end if;
133
134 arrow_on <= '0';
135 if maxd > 4 then -- skip arrow when velocity is negligible
136 if cross >= -maxd and cross <= maxd and
137 dot_p >= 0 and dot_p <= len_sq then
138 arrow_on <= '1';
139 end if;
140 end if;
141 end process arrow_proc;
142
143 -- ----------------------------------------------------------------
144 -- Color output with priority
145 -- ----------------------------------------------------------------
146 color : process(char_on, ground_on, wall_on, ceiling_on,
147 obs_on, arrow_on, trail_on_in)
148 begin
149 if arrow_on = '1' then
150 red <= '1'; green <= '1'; blue <= '1'; -- White
151 elsif char_on = '1' then
152 red <= '1'; green <= '0'; blue <= '0'; -- Red
153 elsif obs_on = '1' then
154 red <= '1'; green <= '1'; blue <= '0'; -- Yellow
155 elsif ground_on = '1' or ceiling_on = '1' then
156 red <= '0'; green <= '1'; blue <= '0'; -- Green
157 elsif wall_on = '1' then
158 red <= '0'; green <= '1'; blue <= '0'; -- Green
159 elsif trail_on_in = '1' then
160 red <= '1'; green <= '0'; blue <= '1'; -- Magenta
161 else
162 red <= '0'; green <= '0'; blue <= '0'; -- Black (sky)
163 end if;
164 end process color;
165
166end behavior;