/*
 * Seven-segment LED emulator
 *
 * Stephen A. Edwards, Columbia University
 *
 */

module VGA_LED_Emulator(
 input logic 	    clk50, reset,
 input logic [7:0]  hex0, hex1, hex2, hex3, hex4, hex5, hex6, hex7,
 output logic [7:0] VGA_R, VGA_G, VGA_B,
 output logic 	    VGA_CLK, VGA_HS, VGA_VS, VGA_BLANK_n, VGA_SYNC_n);

/*
 * 640 X 480 VGA timing for a 50 MHz clock: one pixel every other cycle
 * 
 *HCOUNT 1599 0             1279       1599 0
 *            _______________              ________
 * __________|    Video      |____________|  Video
 * 
 * 
 * |SYNC| BP |<-- HACTIVE -->|FP|SYNC| BP |<-- HACTIVE
 *       _______________________      _____________
 * |____|       VGA_HS          |____|
 */

 	parameter radius_square = 20'd 1024;
 
   parameter HACTIVE      = 11'd 1280,
             HFRONT_PORCH = 11'd 32,
             HSYNC        = 11'd 192,
             HBACK_PORCH  = 11'd 96,   
             HTOTAL       = HACTIVE + HFRONT_PORCH + HSYNC + HBACK_PORCH; //1600

   parameter VACTIVE      = 10'd 480,
             VFRONT_PORCH = 10'd 10,
             VSYNC        = 10'd 2,
             VBACK_PORCH  = 10'd 33,
             VTOTAL       = VACTIVE + VFRONT_PORCH + VSYNC + VBACK_PORCH; //525

   logic [10:0]			     hcount; // Horizontal counter
   logic 			     endOfLine;
   
   always_ff @(posedge clk50 or posedge reset)
     if (reset)          hcount <= 0;
     else if (endOfLine) hcount <= 0;
     else  	         hcount <= hcount + 11'd 1;

   assign endOfLine = hcount == HTOTAL - 1;

	
   // Vertical counter
   logic [9:0] 			     vcount;
	logic[9:0]			vcount_plus1;
   logic 			     endOfField;
   
   always_ff @(posedge clk50 or posedge reset)
     if (reset)          vcount <= 0;
     else if (endOfLine)
       if (endOfField)   vcount <= 0;
       else              vcount <= vcount + 10'd 1;

   assign endOfField = vcount == VTOTAL - 1;

   // Horizontal sync: from 0x520 to 0x57F
   // 101 0010 0000 to 101 0111 1111
   assign VGA_HS = !( (hcount[10:7] == 4'b1010) & (hcount[6] | hcount[5]));
   assign VGA_VS = !( vcount[9:1] == (VACTIVE + VFRONT_PORCH) / 2);

   assign VGA_SYNC_n = 1; // For adding sync to video signals; not used for VGA
   
   // Horizontal active: 0 to 1279     Vertical active: 0 to 479
   // 101 0000 0000  1280	       01 1110 0000  480	       
   // 110 0011 1111  1599	       10 0000 1100  524        
   assign VGA_BLANK_n = !( hcount[10] & (hcount[9] | hcount[8]) ) &
			!( vcount[9] | (vcount[8:5] == 4'b1111) );   

   assign VGA_CLK = hcount[0]; // 25 MHz clock: pixel latched on rising edge
 





 
  
		/*added by cong*/
		logic					inEdge;
//		logic					in_b1;	

		logic					fb_wren;
		logic[31:0]			fb_out;
		integer  			fb_addr;
		integer  			fb_waddr;
		integer  			fb_raddr;
//		logic					fb_odd_wren;
//		logic					fb_even_wren;
//		logic[63:0]			fb_odd_out;
//		logic[63:0]			fb_even_out;
//		integer				fb_odd_waddr;
//		integer				fb_odd_raddr;
//		integer				fb_odd_addr;
//		integer				fb_even_waddr;
//		integer				fb_even_raddr;
//		integer				fb_even_addr;


//////////////////////////
//  Space  information  //
//////////////////////////		
		integer				x;
		integer 				y;
		integer 				z;
		integer 				x_r1;
		integer 				y_r1;
		integer	 			z_r1;
		integer 				x_r2;
		integer 				y_r2;
		integer	 			z_r2;
		integer				x0;
		
//		integer 				x_r2_s;
//		integer 				y_r2_s;
//		integer 				z_r2_s;
				
		integer				sin__x;
		integer				cos__x;
		integer				sin__y;
		integer				cos__y;

		integer				scan_count;
		integer				vcount_integer;
		integer 				hcount_pack;
		integer				hcount_plus;
		
		reg [15:0][1:0]	plane;  //[x][color]
		reg [29:0]			counter;
		reg [3:0]			section_sel = 4'b0;
		
//////////////////////////
//  object information  //
//////////////////////////


//  square one
		integer	x1_s1 = -100;
		integer	x2_s1 = -80;
		integer	y1_s1 = 80;
		integer	y2_s1 = 100;
		integer	z1_s1 = -100;
		integer	z2_s1 = 100;
		
//  square two
		integer	x1_s2 = -80;
		integer	x2_s2 = 100;
		integer	y1_s2 = -100;
		integer	y2_s2 = -80;
		integer	z1_s2 = -100;
		integer	z2_s2 = -80;
		
//  square three
		integer	x1_s3 = 80;
		integer	x2_s3 = 100;
		integer	y1_s3 = -60;
		integer	y2_s3 = -40;
		integer	z1_s3 = -80;
		integer	z2_s3 = 100;
		
//  square four
		integer	x1_s4 = 0;
		integer	x2_s4 = 80;
		integer	y1_s4 = -20;
		integer	y2_s4 = 0;
		integer	z1_s4 = 80;
		integer	z2_s4 = 100;
		
//  square five
		integer	x1_s5 = -100;
		integer	x2_s5 = -80;
		integer	y1_s5 = -100;
		integer	y2_s5 = -80;
		integer	z1_s5 = -80;
		integer	z2_s5 = 100;
		
//  ball one
		integer	x_b1 = 0;
		integer	y_b1 = 0;
		integer	z_b1 = -30;
		
		integer 	dx_b1;
		integer 	dy_b1;
		integer 	dz_b1;
		
		integer  dr_b1;
/////////////////////////////////////////////////////
//                                                 //
/////////////////////////////////////////////////////		
//		assign fb_odd_wren = !vcount[0] && hcount == 11'd1280;
//		assign fb_even_wren = vcount[0] && hcount == 11'd1280;
//		assign				fb_odd_waddr  = {section_sel, vcount[8:1]};
//		assign				fb_odd_raddr  = {hcount[8:5], vcount[8:1]};
//		assign				fb_even_waddr = {section_sel, vcount_plus1[8:1]};
//		assign				fb_even_raddr = {hcount[8:5], vcount_plus1[8:1]};
//		assign				fb_odd_addr   = fb_odd_wren  ? fb_odd_waddr  : fb_odd_raddr;
//		assign				fb_even_addr  = fb_even_wren ? fb_even_waddr : fb_even_raddr;
				
//		assign vcount_plus1 = vcount + 1'b1;
		assign hcount_pack = {hcount[5:2], 1'b0}; 
		assign hcount_plus = hcount_pack + 1;
		assign inEdge = fb_out[hcount_plus];
//		assign inEdge = vcount[0] ? fb_odd_out[hcount_plus]/* && fb_odd_out[hcount_pack]*/ : fb_even_out[hcount_plus]/* && fb_even_out[hcount_pack]*/;






		
		assign fb_wren = hcount == 11'd300 || hcount == 11'd600 || hcount == 11'd900 || hcount == 11'd1200;
		assign fb_waddr = {section_sel, vcount[8:1] + 8'd1};
		assign fb_raddr = {hcount[9:6], vcount[8:1]};
		assign fb_addr = fb_wren ? fb_waddr : fb_raddr;
		
		
		
		always_ff @(posedge clk50) begin
		//initial 
			if (hcount == 11'd 0 || hcount == 11'd300 || hcount == 11'd600 || hcount == 11'd900) begin 
				scan_count <= 0;
				section_sel[2:0] <= section_sel[2:0] + 3'b1;
				for (x = 0; x < 16; x++) plane[x] <= 2'b0;
			end
			
			if (endOfLine && endOfField) begin
				section_sel[3] <= !section_sel[3];
			end 
			
			if (scan_count != 256) begin
				scan_count <= scan_count + 1;		
				for (x = 0; x < 16; x++) begin
						x0 = {section_sel, x[3:0]} - 128;

						/*
						x_r1 = ((-sin__y*z + cos__y*x0)>>>12);//>>>12
						y_r1 = y;
						z_r1 = ((cos__y*z + sin__y*x0)>>>12);//>>>12
						
						x_r2 = x_r1;
						y_r2 = ((cos__x*y_r1 + sin__x*z_r1)>>>12);//>>>12
						z_r2 = ((-sin__x*y_r1 + cos__x*z_r1)>>>12);//>>>12
						*/
						
						x_r1 = x0;
						y_r1 = ((cos__x*y + sin__x*z)>>>12);//>>>12
						z_r1 = ((-sin__x*y + cos__x*z)>>>12);//>>>12
						
						x_r2 = ((-sin__y*z_r1 + cos__y*x_r1)>>>12);//>>>12
						y_r2 = y_r1;
						z_r2 = ((cos__y*z_r1 + sin__y*x_r1)>>>12);//>>>12
						
						
						
						if (plane[x] == 2'b0) plane[x][0] <= 	(x_r2 == x1_s1 || x_r2 == x2_s1) && y_r2 >= y1_s1 && y_r2 <= y2_s1 && z_r2 >= z1_s1 && z_r2 <= z2_s1 ||
																			(y_r2 == y1_s1 || y_r2 == y2_s1) && z_r2 >= z1_s1 && z_r2 <= z2_s1 && x_r2 >= x1_s1 && x_r2 <= x2_s1 ||
																			(z_r2 == z1_s1 || z_r2 == z2_s1) && x_r2 >= x1_s1 && x_r2 <= x2_s1 && y_r2 >= y1_s1 && y_r2 <= y2_s1 ||
																			(x_r2 == x1_s2 || x_r2 == x2_s2) && y_r2 >= y1_s2 && y_r2 <= y2_s2 && z_r2 >= z1_s2 && z_r2 <= z2_s2 ||
																			(y_r2 == y1_s2 || y_r2 == y2_s2) && z_r2 >= z1_s2 && z_r2 <= z2_s2 && x_r2 >= x1_s2 && x_r2 <= x2_s2 ||
																			(z_r2 == z1_s2 || z_r2 == z2_s2) && x_r2 >= x1_s2 && x_r2 <= x2_s2 && y_r2 >= y1_s2 && y_r2 <= y2_s2 ||
																			(x_r2 == x1_s3 || x_r2 == x2_s3) && y_r2 >= y1_s3 && y_r2 <= y2_s3 && z_r2 >= z1_s3 && z_r2 <= z2_s3 ||
																			(y_r2 == y1_s3 || y_r2 == y2_s3) && z_r2 >= z1_s3 && z_r2 <= z2_s3 && x_r2 >= x1_s3 && x_r2 <= x2_s3 ||
																			(z_r2 == z1_s3 || z_r2 == z2_s3) && x_r2 >= x1_s3 && x_r2 <= x2_s3 && y_r2 >= y1_s3 && y_r2 <= y2_s3 ||
																			(x_r2 == x1_s4 || x_r2 == x2_s4) && y_r2 >= y1_s4 && y_r2 <= y2_s4 && z_r2 >= z1_s4 && z_r2 <= z2_s4 ||
																			(y_r2 == y1_s4 || y_r2 == y2_s4) && z_r2 >= z1_s4 && z_r2 <= z2_s4 && x_r2 >= x1_s4 && x_r2 <= x2_s4 ||
																			(z_r2 == z1_s4 || z_r2 == z2_s4) && x_r2 >= x1_s4 && x_r2 <= x2_s4 && y_r2 >= y1_s4 && y_r2 <= y2_s4 ||
																			(x_r2 == x1_s5 || x_r2 == x2_s5) && y_r2 >= y1_s5 && y_r2 <= y2_s5 && z_r2 >= z1_s5 && z_r2 <= z2_s5 ||
																			(y_r2 == y1_s5 || y_r2 == y2_s5) && z_r2 >= z1_s5 && z_r2 <= z2_s5 && x_r2 >= x1_s5 && x_r2 <= x2_s5 ||
																			(z_r2 == z1_s5 || z_r2 == z2_s5) && x_r2 >= x1_s5 && x_r2 <= x2_s5 && y_r2 >= y1_s5 && y_r2 <= y2_s5;
						
						if (plane[x] == 2'b0) plane[x][0] <= 	(x_r2 == x1_s1 || x_r2 == x2_s1) && y_r2 >= y1_s1 && y_r2 <= y2_s1 && z_r2 >= z1_s1 && z_r2 <= z2_s1 ||
																			(y_r2 == y1_s1 || y_r2 == y2_s1) && z_r2 >= z1_s1 && z_r2 <= z2_s1 && x_r2 >= x1_s1 && x_r2 <= x2_s1 ||
																			(z_r2 == z1_s1 || z_r2 == z2_s1) && x_r2 >= x1_s1 && x_r2 <= x2_s1 && y_r2 >= y1_s1 && y_r2 <= y2_s1 ||
																			(x_r2 == x1_s2 || x_r2 == x2_s2) && y_r2 >= y1_s2 && y_r2 <= y2_s2 && z_r2 >= z1_s2 && z_r2 <= z2_s2 ||
																			(y_r2 == y1_s2 || y_r2 == y2_s2) && z_r2 >= z1_s2 && z_r2 <= z2_s2 && x_r2 >= x1_s2 && x_r2 <= x2_s2 ||
																			(z_r2 == z1_s2 || z_r2 == z2_s2) && x_r2 >= x1_s2 && x_r2 <= x2_s2 && y_r2 >= y1_s2 && y_r2 <= y2_s2 ||
																			(x_r2 == x1_s3 || x_r2 == x2_s3) && y_r2 >= y1_s3 && y_r2 <= y2_s3 && z_r2 >= z1_s3 && z_r2 <= z2_s3 ||
																			(y_r2 == y1_s3 || y_r2 == y2_s3) && z_r2 >= z1_s3 && z_r2 <= z2_s3 && x_r2 >= x1_s3 && x_r2 <= x2_s3 ||
																			(z_r2 == z1_s3 || z_r2 == z2_s3) && x_r2 >= x1_s3 && x_r2 <= x2_s3 && y_r2 >= y1_s3 && y_r2 <= y2_s3 ||
																			(x_r2 == x1_s4 || x_r2 == x2_s4) && y_r2 >= y1_s4 && y_r2 <= y2_s4 && z_r2 >= z1_s4 && z_r2 <= z2_s4 ||
																			(y_r2 == y1_s4 || y_r2 == y2_s4) && z_r2 >= z1_s4 && z_r2 <= z2_s4 && x_r2 >= x1_s4 && x_r2 <= x2_s4 ||
																			(z_r2 == z1_s4 || z_r2 == z2_s4) && x_r2 >= x1_s4 && x_r2 <= x2_s4 && y_r2 >= y1_s4 && y_r2 <= y2_s4 ||
																			(x_r2 == x1_s5 || x_r2 == x2_s5) && y_r2 >= y1_s5 && y_r2 <= y2_s5 && z_r2 >= z1_s5 && z_r2 <= z2_s5 ||
																			(y_r2 == y1_s5 || y_r2 == y2_s5) && z_r2 >= z1_s5 && z_r2 <= z2_s5 && x_r2 >= x1_s5 && x_r2 <= x2_s5 ||
																			(z_r2 == z1_s5 || z_r2 == z2_s5) && x_r2 >= x1_s5 && x_r2 <= x2_s5 && y_r2 >= y1_s5 && y_r2 <= y2_s5;
//						
//						if (plane[x] == 2'b0) plane[x][0] <= 	(x_r2 == x1 || x_r2 == x2) && y_r2 >= y1 && y_r2 <= y2 && z_r2 >= z1 && z_r2 <= z2 ||
//																			(y_r2 == y1 || y_r2 == y2) && z_r2 >= z1 && z_r2 <= z2 && x_r2 >= x1 && x_r2 <= x2 ||
//																			(z_r2 == z1 || z_r2 == z2) && x_r2 >= x1 && x_r2 <= x2 && y_r2 >= y1 && y_r2 <= y2;
//						
//						if (plane[x] == 2'b0) plane[x][1] <= 	(x_r2 == x1 || x_r2 == x2) && (y_r2 == y1 || y_r2 == y2) && z_r2 >= z1 && z_r2 <= z2 ||
//																			(y_r2 == y1 || y_r2 == y2) && (z_r2 == z1 || z_r2 == z2) && x_r2 >= x1 && x_r2 <= x2 ||
//																			(z_r2 == z1 || z_r2 == z2) && (x_r2 == x1 || x_r2 == x2) && y_r2 >= y1 && y_r2 <= y2;// ||
//																			//(x_r2 - x_b1)*(x_r2 - x_b1) + (y_r2 - y_b1)*(y_r2 - y_b1) + (z_r2 - z_b1)*(z_r2 - z_b1) == 100;																									
				end
			end
		end
		
		always_ff @(posedge clk50)
			counter <= counter + 30'd1;
			
//		sin_x sinx(.address(counter[29:18]), .clock(clk50), .q(sin__x));
//		cos_x cosx(.address(counter[29:18]), .clock(clk50), .q(cos__x));
//		sin_y siny(.address(counter[29:18]), .clock(clk50), .q(sin__y));
//		cos_y cosy(.address(counter[29:18]), .clock(clk50), .q(cos__y));
		
		sin_x sinx(.address({hex3[3:0],hex2}), .clock(clk50), .q(sin__x));
		cos_x cosx(.address({hex3[3:0],hex2}), .clock(clk50), .q(cos__x));
		sin_y siny(.address({hex1[3:0],hex0}), .clock(clk50), .q(sin__y));
		cos_y cosy(.address({hex1[3:0],hex0}), .clock(clk50), .q(cos__y));

//		sin_x sinx(.address(0), .clock(clk50), .q(sin__x));
//		cos_x cosx(.address(0), .clock(clk50), .q(cos__x));
//		sin_y siny(.address(0), .clock(clk50), .q(sin__y));
//		cos_y cosy(.address(0), .clock(clk50), .q(cos__y));

		FrameBuffer framebuffer(	.address(fb_addr), 
											.clock(clk50),
											.data(plane), 
											.wren(fb_wren), 
											.q(fb_out));
		
//		FrameBuffer fb_odd(	.address(fb_odd_addr), 
//									.clock(clk50), 
//									.data(plane), 
//									.wren(fb_odd_wren), 
//									.q(fb_odd_out));
//									
//		FrameBuffer fb_even(	.address(fb_even_addr), 
//									.clock(clk50),
//									.data(plane), 
//									.wren(fb_even_wren), 
//									.q(fb_even_out));
		
		
		always_comb begin		
			vcount_integer = vcount[9:1];	
			y = vcount_integer - 128;
			z = scan_count - 128;
			
			{VGA_R, VGA_G, VGA_B} = {8'h0, 8'h0, 8'h0}; // black	
			if (inEdge)
				{VGA_R, VGA_G, VGA_B} = {8'h56, 8'hca, 8'h32}; // green
		end  
   
endmodule // VGA_LED_Emulator




