//====================================================================
// lighting_scene.v - 光照场景渲染器
// 第28课：多光源场景渲染
//====================================================================
module lighting_scene #(
    parameter COORD_WIDTH = 16,
    parameter COLOR_WIDTH = 24,
    parameter MAX_LIGHTS  = 4,
    parameter FRAC_BITS  = 12
)(
    input  wire                          clk, rst_n,
    // 片段输入
    input  wire                          frag_valid,
    input  wire [COLOR_WIDTH-1:0]        frag_base_color,
    input  wire signed [COORD_WIDTH-1:0] frag_nx, frag_ny, frag_nz,
    input  wire signed [COORD_WIDTH-1:0] frag_world_x, frag_world_y, frag_world_z,
    output reg                           frag_ready,
    // 光源参数(4个点光源)
    input  wire signed [COORD_WIDTH-1:0] light_pos_x [0:MAX_LIGHTS-1],
    input  wire signed [COORD_WIDTH-1:0] light_pos_y [0:MAX_LIGHTS-1],
    input  wire signed [COORD_WIDTH-1:0] light_pos_z [0:MAX_LIGHTS-1],
    input  wire [COLOR_WIDTH-1:0]        light_color_arr [0:MAX_LIGHTS-1],
    input  wire [7:0]                    light_intensity [0:MAX_LIGHTS-1],
    // 输出
    output reg                           result_valid,
    output reg  [COLOR_WIDTH-1:0]        result_color
);
/* 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 [1:0] light_idx;
    reg signed [COORD_WIDTH-1:0] dir_x, dir_y, dir_z;
    reg signed [2*COORD_WIDTH-1:0] dist_sq, dot_nl;
    reg [7:0] atten, diff;
    reg [15:0] acc_r, acc_g, acc_b;
    reg [7:0] base_r, base_g, base_b;
    localparam S_IDLE=3'd0, S_DIR=3'd1, S_DIST=3'd2, S_LIGHT=3'd3, S_ACCUM=3'd4, S_NEXT=3'd5, S_OUT=3'd6;
    reg [2:0] state;
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin state<=S_IDLE; frag_ready<=1; result_valid<=0; end
        else begin
            result_valid <= 0;
            case (state)
                S_IDLE: begin
                    frag_ready <= 1;
                    if (frag_valid) begin
                        frag_ready <= 0;
                        base_r <= frag_base_color[23:16]; base_g <= frag_base_color[15:8]; base_b <= frag_base_color[7:0];
                        acc_r <= 0; acc_g <= 0; acc_b <= 0;
                        light_idx <= 0; state <= S_DIR;
                    end
                end
                S_DIR: begin
                    dir_x <= light_pos_x[light_idx] - frag_world_x;
                    dir_y <= light_pos_y[light_idx] - frag_world_y;
                    dir_z <= light_pos_z[light_idx] - frag_world_z;
                    state <= S_DIST;
                end
                S_DIST: begin
                    dist_sq <= dir_x*dir_x + dir_y*dir_y + dir_z*dir_z;
                    dot_nl <= dir_x*frag_nx + dir_y*frag_ny + dir_z*frag_nz;
                    state <= S_LIGHT;
                end
                S_LIGHT: begin
                    atten <= light_intensity[light_idx] >> 2; // 简化衰减
                    diff <= (dot_nl > 0) ? ((dot_nl[19:12]>255)?8'd255:dot_nl[19:12]) : 8'd0;
                    state <= S_ACCUM;
                end
                S_ACCUM: begin
                    acc_r <= acc_r + (base_r * diff * atten) >> 16;
                    acc_g <= acc_g + (base_g * diff * atten) >> 16;
                    acc_b <= acc_b + (base_b * diff * atten) >> 16;
                    state <= S_NEXT;
                end
                S_NEXT: begin
                    if (light_idx < 2'd3) begin light_idx <= light_idx + 1; state <= S_DIR; end
                    else state <= S_OUT;
                end
                S_OUT: begin
                    result_color <= {(acc_r>255)?8'd255:acc_r[7:0], (acc_g>255)?8'd255:acc_g[7:0], (acc_b>255)?8'd255:acc_b[7:0]};
                    result_valid <= 1; state <= S_IDLE;
                end
                default: state <= S_IDLE;
            endcase
        end
    end
endmodule