//====================================================================
// geometry_shader.v - 几何着色器
// 第24课：图元生成与变换
//====================================================================
module geometry_shader #(
    parameter COORD_WIDTH = 16,
    parameter COLOR_WIDTH = 24,
    parameter FRAC_BITS  = 12
)(
    input  wire                          clk, rst_n,
    input  wire                          prim_valid,
    input  wire signed [COORD_WIDTH-1:0] in_v0_x, in_v0_y, in_v0_z,
    input  wire signed [COORD_WIDTH-1:0] in_v1_x, in_v1_y, in_v1_z,
    input  wire signed [COORD_WIDTH-1:0] in_v2_x, in_v2_y, in_v2_z,
    input  wire [COLOR_WIDTH-1:0]        in_v0_color, in_v1_color, in_v2_color,
    input  wire [1:0]                    emit_mode,   // 0=PASS, 1=NORMAL_VIS, 2=EXPAND
    output reg                           prim_ready,
    output reg                           out_valid,
    output reg  signed [COORD_WIDTH-1:0] out_x, out_y, out_z,
    output reg  [COLOR_WIDTH-1:0]        out_color,
    output reg  [1:0]                    out_vertex_idx, // 输出图元的顶点索引
    output reg                           out_prim_last
);
/* 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] face_nx, face_ny, face_nz;
    localparam S_IDLE=3'd0, S_NORMAL=3'd1, S_EMIT0=3'd2, S_EMIT1=3'd3, S_EMIT2=3'd4, S_EMIT_N0=3'd5, S_EMIT_N1=3'd6, S_DONE=3'd7;
    reg [2:0] state;
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin state<=S_IDLE; prim_ready<=1; out_valid<=0; out_prim_last<=0; end
        else begin
            out_valid <= 0; out_prim_last <= 0;
            case (state)
                S_IDLE: begin
                    prim_ready <= 1;
                    if (prim_valid) begin
                        prim_ready <= 0;
                        if (emit_mode == 2'd0) state <= S_EMIT0; // 透传
                        else state <= S_NORMAL;
                    end
                end
                S_NORMAL: begin
                    // 计算面法线 = (V1-V0) × (V2-V0)
                    face_nx <= qmul(in_v1_y-in_v0_y, in_v2_z-in_v0_z) - qmul(in_v1_z-in_v0_z, in_v2_y-in_v0_y);
                    face_ny <= qmul(in_v1_z-in_v0_z, in_v2_x-in_v0_x) - qmul(in_v1_x-in_v0_x, in_v2_z-in_v0_z);
                    face_nz <= qmul(in_v1_x-in_v0_x, in_v2_y-in_v0_y) - qmul(in_v1_y-in_v0_y, in_v2_x-in_v0_x);
                    state <= S_EMIT_N0;
                end
                S_EMIT0: begin out_x<=in_v0_x; out_y<=in_v0_y; out_z<=in_v0_z; out_color<=in_v0_color; out_vertex_idx<=0; out_valid<=1; state<=S_EMIT1; end
                S_EMIT1: begin out_x<=in_v1_x; out_y<=in_v1_y; out_z<=in_v1_z; out_color<=in_v1_color; out_vertex_idx<=1; out_valid<=1; state<=S_EMIT2; end
                S_EMIT2: begin out_x<=in_v2_x; out_y<=in_v2_y; out_z<=in_v2_z; out_color<=in_v2_color; out_vertex_idx<=2; out_valid<=1; out_prim_last<=1; state<=S_DONE; end
                S_EMIT_N0: begin
                    out_x <= (in_v0_x+in_v1_x+in_v2_x)/3; out_y <= (in_v0_y+in_v1_y+in_v2_y)/3;
                    out_z <= (in_v0_z+in_v1_z+in_v2_z)/3;
                    out_color <= 24'h00ff00; out_vertex_idx <= 0; out_valid <= 1; state <= S_EMIT_N1;
                end
                S_EMIT_N1: begin
                    out_x <= (in_v0_x+in_v1_x+in_v2_x)/3 + face_nx; out_y <= (in_v0_y+in_v1_y+in_v2_y)/3 + face_ny;
                    out_z <= (in_v0_z+in_v1_z+in_v2_z)/3 + face_nz;
                    out_color <= 24'h00ff00; out_vertex_idx <= 1; out_valid <= 1; out_prim_last <= 1; state <= S_DONE;
                end
                S_DONE: begin state <= S_IDLE; end
                default: state <= S_IDLE;
            endcase
        end
    end
endmodule