//====================================================================
// clipper.v - 裁剪器
// 第10课：Sutherland-Hodgman裁剪算法
//====================================================================
module clipper #(
    parameter COORD_WIDTH = 16,
    parameter COLOR_WIDTH = 24,
    parameter FRAC_BITS  = 12
)(
    input  wire                          clk, rst_n,
    input  wire                          tri_in_valid,
    input  wire signed [COORD_WIDTH-1:0] tri_v0_x, tri_v0_y, tri_v0_z, tri_v0_w,
    input  wire signed [COORD_WIDTH-1:0] tri_v1_x, tri_v1_y, tri_v1_z, tri_v1_w,
    input  wire signed [COORD_WIDTH-1:0] tri_v2_x, tri_v2_y, tri_v2_z, tri_v2_w,
    input  wire [COLOR_WIDTH-1:0]        tri_v0_color, tri_v1_color, tri_v2_color,
    output reg                           tri_in_ready,
    output reg                           tri_out_valid,
    output reg  signed [COORD_WIDTH-1:0] out_v0_x, out_v0_y, out_v0_z, out_v0_w,
    output reg  signed [COORD_WIDTH-1:0] out_v1_x, out_v1_y, out_v1_z, out_v1_w,
    output reg  signed [COORD_WIDTH-1:0] out_v2_x, out_v2_y, out_v2_z, out_v2_w,
    output reg  [COLOR_WIDTH-1:0]        out_v0_color, out_v1_color, out_v2_color,
    output reg                           tri_clipped,  // 1=被裁剪
    input  wire                          tri_out_ready
);
/* 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
    // 判断顶点是否在裁剪面内: -w <= x <= w
    wire v0_inside = (tri_v0_x >= -tri_v0_w) && (tri_v0_x <= tri_v0_w) &&
                     (tri_v0_y >= -tri_v0_w) && (tri_v0_y <= tri_v0_w);
    wire v1_inside = (tri_v1_x >= -tri_v1_w) && (tri_v1_x <= tri_v1_w) &&
                     (tri_v1_y >= -tri_v1_w) && (tri_v1_y <= tri_v1_w);
    wire v2_inside = (tri_v2_x >= -tri_v2_w) && (tri_v2_x <= tri_v2_w) &&
                     (tri_v2_y >= -tri_v2_w) && (tri_v2_y <= tri_v2_w);
    localparam S_IDLE=2'd0, S_CLIP=2'd1, S_OUTPUT=2'd2;
    reg [1:0] state;
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin state<=S_IDLE; tri_in_ready<=1; tri_out_valid<=0; end
        else begin
            tri_out_valid <= 0;
            case (state)
                S_IDLE: begin
                    tri_in_ready <= 1;
                    if (tri_in_valid) begin
                        tri_in_ready <= 0; state <= S_CLIP;
                    end
                end
                S_CLIP: begin
                    if (v0_inside && v1_inside && v2_inside) begin
                        // 全部在内，直接透传
                        out_v0_x<=tri_v0_x; out_v0_y<=tri_v0_y; out_v0_z<=tri_v0_z; out_v0_w<=tri_v0_w;
                        out_v1_x<=tri_v1_x; out_v1_y<=tri_v1_y; out_v1_z<=tri_v1_z; out_v1_w<=tri_v1_w;
                        out_v2_x<=tri_v2_x; out_v2_y<=tri_v2_y; out_v2_z<=tri_v2_z; out_v2_w<=tri_v2_w;
                        out_v0_color<=tri_v0_color; out_v1_color<=tri_v1_color; out_v2_color<=tri_v2_color;
                        tri_clipped <= 0;
                    end else if (!v0_inside && !v1_inside && !v2_inside) begin
                        // 全部在外，丢弃
                        state <= S_IDLE; tri_in_ready <= 1;
                    end else begin
                        // 部分裁剪(简化：只做全内/全外判断)
                        out_v0_x<=tri_v0_x; out_v0_y<=tri_v0_y; out_v0_z<=tri_v0_z; out_v0_w<=tri_v0_w;
                        out_v1_x<=tri_v1_x; out_v1_y<=tri_v1_y; out_v1_z<=tri_v1_z; out_v1_w<=tri_v1_w;
                        out_v2_x<=tri_v2_x; out_v2_y<=tri_v2_y; out_v2_z<=tri_v2_z; out_v2_w<=tri_v2_w;
                        out_v0_color<=tri_v0_color; out_v1_color<=tri_v1_color; out_v2_color<=tri_v2_color;
                        tri_clipped <= 1;
                    end
                    if (v0_inside || v1_inside || v2_inside) state <= S_OUTPUT;
                end
                S_OUTPUT: begin tri_out_valid <= 1; state <= S_IDLE; tri_in_ready <= 1; end
                default: state <= S_IDLE;
            endcase
        end
    end
endmodule