//====================================================================
// normal_mapper.v - 法线映射器
// 第17课：切线空间法线扰动
//====================================================================
module normal_mapper #(
    parameter COORD_WIDTH = 16,
    parameter COLOR_WIDTH = 24,
    parameter FRAC_BITS  = 12
)(
    input  wire                          clk, rst_n,
    input  wire                          frag_valid,
    input  wire signed [COORD_WIDTH-1:0] frag_nx, frag_ny, frag_nz,
    input  wire signed [COORD_WIDTH-1:0] frag_tx, frag_ty, frag_tz,
    input  wire signed [COORD_WIDTH-1:0] frag_bx, frag_by, frag_bz,
    input  wire [7:0]                    normal_r, normal_g, normal_b,
    output reg                           frag_ready,
    output reg                           result_valid,
    output reg  signed [COORD_WIDTH-1:0] out_nx, out_ny, out_nz
);
/* 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] map_nx, map_ny, map_nz;
    localparam S_IDLE=2'd0, S_REMAP=2'd1, S_OUT=2'd2;
    reg [1: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;
                        // 从[0,255]映射到[-1,1]的Q4.12
                        map_nx <= {1'b0, normal_r} * 16'sd32 - 16'sd4096; // (r/128-1)*4096
                        map_ny <= {1'b0, normal_g} * 16'sd32 - 16'sd4096;
                        map_nz <= {1'b0, normal_b} * 16'sd32 - 16'sd4096;
                        state <= S_REMAP;
                    end
                end
                S_REMAP: begin
                    // TBN矩阵变换: out = T*map_nx + B*map_ny + N*map_nz
                    out_nx <= qmul(frag_tx, map_nx) + qmul(frag_bx, map_ny) + qmul(frag_nx, map_nz);
                    out_ny <= qmul(frag_ty, map_nx) + qmul(frag_by, map_ny) + qmul(frag_ny, map_nz);
                    out_nz <= qmul(frag_tz, map_nx) + qmul(frag_bz, map_ny) + qmul(frag_nz, map_nz);
                    state <= S_OUT;
                end
                S_OUT: begin
                    result_valid <= 1; state <= S_IDLE;
                end
                default: state <= S_IDLE;
            endcase
        end
    end
endmodule