//====================================================================
// shadow_renderer.v - 阴影渲染器
// 第29课：完整阴影映射管线
//====================================================================
module shadow_renderer #(
    parameter COORD_WIDTH = 16,
    parameter COLOR_WIDTH = 24,
    parameter SHADOW_RES  = 256,
    parameter FRAC_BITS  = 12
)(
    input  wire                          clk, rst_n,
    // 控制接口
    input  wire                          frame_start,
    input  wire [1:0]                    render_pass, // 0=shadow, 1=color
    output reg                           frame_done,
    // 光源参数
    input  wire signed [COORD_WIDTH-1:0] light_pos_x, light_pos_y, light_pos_z,
    input  wire signed [COORD_WIDTH-1:0] light_dir_x, light_dir_y, light_dir_z,
    // 场景顶点输入
    input  wire                          vert_valid,
    input  wire signed [COORD_WIDTH-1:0] vert_x, vert_y, vert_z,
    input  wire [COLOR_WIDTH-1:0]        vert_color,
    output reg                           vert_ready,
    // 帧缓冲输出
    output reg                           fb_wen,
    output reg  [COORD_WIDTH-1:0]        fb_x, fb_y,
    output reg  [COLOR_WIDTH-1:0]        fb_color,
    // 阴影图SRAM接口
    output reg  [17:0]                   smap_addr,
    output reg  signed [COORD_WIDTH-1:0] smap_wdata,
    output reg                           smap_wen,
    input  wire signed [COORD_WIDTH-1:0] smap_rdata,
    output reg                           smap_ren,
    input  wire                          smap_valid
);
/* verilator lint_off WIDTHEXPAND */
/* verilator lint_off WIDTHTRUNC */
/* verilator lint_off CASEOVERLAP */
/* verilator lint_off CMPCONST */
/* verilator lint_off UNSIGNED */
/* verilator lint_off WIDTHCONCAT */

    function signed [COORD_WIDTH-1:0] qmul;
        input signed [COORD_WIDTH-1:0] a, b;
        reg signed [2*COORD_WIDTH-1:0] prod;
        begin prod = a * b; qmul = prod[2*COORD_WIDTH-FRAC_BITS-1:COORD_WIDTH-FRAC_BITS]; end
    endfunction
    // 光源空间变换后的坐标
    reg signed [COORD_WIDTH-1:0] light_space_x, light_space_y, light_space_z;
    // 阴影测试结果
    reg in_shadow;
    reg signed [COORD_WIDTH-1:0] stored_depth;
    reg [COLOR_WIDTH-1:0] stored_color;
    localparam S_SHADOW_XFORM=3'd0, S_SHADOW_WRITE=3'd1,
               S_COLOR_XFORM=3'd2, S_SHADOW_READ=3'd3, S_SHADOW_TEST=3'd4,
               S_LIGHTING=3'd5, S_FB_WRITE=3'd6, S_DONE=3'd7;
    reg [2:0] state;
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin state<=S_SHADOW_XFORM; vert_ready<=1; frame_done<=0; fb_wen<=0; smap_wen<=0; smap_ren<=0; end
        else begin
            fb_wen <= 0; smap_wen <= 0; smap_ren <= 0; frame_done <= 0;
            case (state)
                S_SHADOW_XFORM: begin
                    vert_ready <= 1;
                    if (vert_valid && render_pass == 2'd0) begin
                        vert_ready <= 0;
                        // 变换到光源空间(简化)
                        light_space_x <= vert_x - light_pos_x;
                        light_space_y <= vert_y - light_pos_y;
                        light_space_z <= vert_z - light_pos_z;
                        state <= S_SHADOW_WRITE;
                    end else if (vert_valid && render_pass == 2'd1) begin
                        vert_ready <= 0; stored_color <= vert_color;
                        light_space_x <= vert_x - light_pos_x;
                        light_space_y <= vert_y - light_pos_y;
                        light_space_z <= vert_z - light_pos_z;
                        state <= S_SHADOW_READ;
                    end
                end
                S_SHADOW_WRITE: begin
                    // 写入阴影图
                    smap_addr <= light_space_y[COORD_WIDTH-1:4] * SHADOW_RES + light_space_x[COORD_WIDTH-1:4];
                    smap_wdata <= light_space_z;
                    smap_wen <= 1;
                    state <= S_SHADOW_XFORM;
                end
                S_SHADOW_READ: begin
                    smap_addr <= light_space_y[COORD_WIDTH-1:4] * SHADOW_RES + light_space_x[COORD_WIDTH-1:4];
                    smap_ren <= 1;
                    state <= S_SHADOW_TEST;
                end
                S_SHADOW_TEST: begin
                    if (smap_valid) begin
                        stored_depth <= smap_rdata;
                        in_shadow <= (light_space_z > smap_rdata + 16'd8); // 深度偏移
                        state <= S_LIGHTING;
                    end
                end
                S_LIGHTING: begin
                    if (in_shadow) fb_color <= {stored_color[23:17], stored_color[15:9], stored_color[7:1]};
                    else fb_color <= stored_color;
                    state <= S_FB_WRITE;
                end
                S_FB_WRITE: begin
                    fb_wen <= 1; fb_x <= light_space_x; fb_y <= light_space_y;
                    state <= S_SHADOW_XFORM;
                end
                default: state <= S_SHADOW_XFORM;
            endcase
        end
    end
endmodule