#include"line.h"#include"base_helpers.h"#include"cfbd_define.h"#include"cfbd_graphic_define.h"#include"device/graphic_device.h"#include"point.h"staticinlinevoidswap_int16(int16_t*val1,int16_t*val2){if(*val1==*val2)return;*val1^=*val2;*val2^=*val1;*val1^=*val2;}staticinlineuint16_tmax_uint16(uint16_tval1,uint16_tval2){returnval1>val2?val1:val2;}staticinlineuint16_tmin_uint16(uint16_tval1,uint16_tval2){returnval1<val2?val1:val2;}staticinlinevoidclearBounds(CFBD_GraphicDevice*handler,CFBDGraphic_Line*line){int32_tlx=asInt32_t(line->p_left.x);int32_trx=asInt32_t(line->p_right.x);int32_tty=asInt32_t(line->p_left.y);int32_tby=asInt32_t(line->p_right.y);if(lx>rx){int32_tt=lx;lx=rx;rx=t;}if(ty>by){int32_tt=ty;ty=by;by=t;}}/* draw the lines that matches the equal x*/staticvoid__on_handle_vertical_line(CFBD_GraphicDevice*handler,CFBDGraphic_Line*line){PointBaseTypemax_y=max_uint16(line->p_left.y,line->p_right.y);PointBaseTypemin_y=min_uint16(line->p_left.y,line->p_right.y);PointBaseTypex=line->p_left.x;PointBaseTypey;CFBD_Bool(*setpixel)(CFBD_GraphicDevice*device,uint16_tx,uint16_ty)=handler->ops->setPixel;for(PointBaseTypei=min_y;i<=max_y;i++){y=i;setpixel(handler,x,y);}}staticvoid__on_handle_horizental_line(CFBD_GraphicDevice*handler,CFBDGraphic_Line*line){CFBD_Bool(*setPixel)(CFBD_GraphicDevice*device,uint16_tx,uint16_ty)=handler->ops->setPixel;PointBaseTypemax_x=max_uint16(line->p_left.x,line->p_right.x);PointBaseTypemin_x=min_uint16(line->p_left.x,line->p_right.x);PointBaseTypex;PointBaseTypey=line->p_left.y;for(PointBaseTypei=min_x;i<=max_x;i++){x=i;setPixel(handler,x,y);}}// Bresenham's Line Algorithm, designed to avoid floating point calculations// References: https://www.cs.montana.edu/courses/spring2009/425/dslectures/Bresenham.pdf// https://www.bilibili.com/video/BV1364y1d7Lovoid__pvt_BresenhamMethod_line(CFBD_GraphicDevice*handler,CFBDGraphic_Line*line){CFBD_Bool(*setPixel)(CFBD_GraphicDevice*device,uint16_tx,uint16_ty)=handler->ops->setPixel;#define __pvt_fast_draw_point(X, Y) \ do { \ setPixel(handler, X, Y); \ } while (0)// Define initial points for the line: p_left and p_right represent the endpointsint16_tstartX=line->p_left.x;int16_tstartY=line->p_left.y;int16_tendX=line->p_right.x;int16_tendY=line->p_right.y;// Flags to indicate transformations of coordinatesuint8_tisYInverted=0,isXYInverted=0;{// If the start point's X coordinate is greater than the end point's X, swap the pointsif(startX>endX){// Swap the X and Y coordinates for the start and end pointsswap_int16(&startX,&endX);swap_int16(&startY,&endY);}// If the start point's Y coordinate is greater than the end point's Y, invert the Y// coordinatesif(startY>endY){// Invert Y coordinates to make the line direction consistent in the first quadrantstartY=-startY;endY=-endY;// Set the flag indicating Y coordinates were invertedisYInverted=1;}// If the line's slope (dy/dx) is greater than 1, swap X and Y coordinates for a shallower// slopeif(endY-startY>endX-startX){// Swap X and Y coordinates for both pointsswap_int16(&startX,&startY);swap_int16(&endX,&endY);// Set the flag indicating both X and Y coordinates were swappedisXYInverted=1;}// Calculate differences (dx, dy) and the decision variables for Bresenham's algorithmconstint16_tdx=endX-startX;constint16_tdy=endY-startY;constint16_tincrE=2*dy;// Increment for eastward movementconstint16_tincrNE=2*(dy-dx);// Increment for northeastward movementint16_tdecision=2*dy-dx;// Initial decision variableint16_tx=startX;// Starting X coordinateint16_ty=startY;// Starting Y coordinate// Draw the starting point and handle coordinate transformations based on flagsif(isYInverted&&isXYInverted){__pvt_fast_draw_point(y,-x);}elseif(isYInverted){__pvt_fast_draw_point(x,-y);}elseif(isXYInverted){__pvt_fast_draw_point(y,x);}else{__pvt_fast_draw_point(x,y);}// Iterate through the X-axis to draw the rest of the linewhile(x<endX){x++;// Increment X coordinateif(decision<0){decision+=incrE;// Move eastward if decision variable is negative}else{y++;// Move northeastward if decision variable is positive or zerodecision+=incrNE;}// Draw each point along the line with coordinate transformation as neededif(isYInverted&&isXYInverted){__pvt_fast_draw_point(y,-x);}elseif(isYInverted){__pvt_fast_draw_point(x,-y);}elseif(isXYInverted){__pvt_fast_draw_point(y,x);}else{__pvt_fast_draw_point(x,y);}}}}voidCFBDGraphic_DrawLine(CFBD_GraphicDevice*handler,CFBDGraphic_Line*line){clearBounds(handler,line);// test if the verticalif(line->p_left.x==line->p_right.x)__on_handle_vertical_line(handler,line);if(line->p_left.y==line->p_right.y)__on_handle_horizental_line(handler,line);__pvt_BresenhamMethod_line(handler,line);if(CFBDGraphic_DeviceRequestUpdateAtOnce(handler)){int32_tlx=asInt32_t(line->p_left.x);int32_trx=asInt32_t(line->p_right.x);int32_tty=asInt32_t(line->p_left.y);int32_tby=asInt32_t(line->p_right.y);if(lx>rx){int32_tt=lx;lx=rx;rx=t;}if(ty>by){int32_tt=ty;ty=by;by=t;}handler->ops->update_area(handler,clamp_u16_from_i32(lx),clamp_u16_from_i32(ty),clamp_u16_from_i32(rx-lx+1),clamp_u16_from_i32(by-ty+1));}}