//====================================================================
// viewport_transform.v - 视口变换单元
// 第09课：NDC到屏幕坐标映射
//====================================================================
module viewport_transform #(
    parameter COORD_WIDTH = 16,
    parameter FB_WIDTH    = 640,
    parameter FB_HEIGHT   = 480,
    parameter FRAC_BITS  = 12
)(
    input  wire                          clk, rst_n,
    // 视口参数
    input  wire [COORD_WIDTH-1:0]        vp_x, vp_y,     // 视口左下角
    input  wire [COORD_WIDTH-1:0]        vp_width, vp_height,
    // NDC输入
    input  wire                          ndc_valid,
    input  wire signed [COORD_WIDTH-1:0] ndc_x, ndc_y, ndc_z,
    output reg                           ndc_ready,
    // 屏幕坐标输出
    output reg                           screen_valid,
    output reg  [COORD_WIDTH-1:0]        screen_x, screen_y,
    output reg  signed [COORD_WIDTH-1:0] screen_z
);
/* 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
    localparam HALF_Q12 = 16'h0800; // 0.5 in Q4.12
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin screen_valid <= 0; ndc_ready <= 1; end
        else begin
            screen_valid <= 0;
            ndc_ready <= 1;
            if (ndc_valid) begin
                ndc_ready <= 0;
                // screen_x = vp_x + (ndc_x + 1) * vp_width / 2
                // screen_y = vp_y + (ndc_y + 1) * vp_height / 2
                // 简化: 使用移位近似除法
                screen_x <= vp_x + qmul(ndc_x + 16'h1000, vp_width >> 1);
                screen_y <= vp_y + qmul(ndc_y + 16'h1000, vp_height >> 1);
                screen_z <= ndc_z; // 深度直接传递
                screen_valid <= 1;
            end
        end
    end
endmodule