diff --git a/README.md b/README.md index 7ee74b2..64f23dd 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,2 @@ # SpeeduinoGL -A work in progress library with basic graphical functions optimised for arm cortex m7. Tested on GIGA R1, with rasterization writing to registers between two lines, and basic shapes (triangles, circles and quadrilaterals).Support for processing arrays instead of pixels one by one is in progress. +A work in progress library with graphical functions optimised for arm cortex m7. Tested on GIGA R1, with rasterization writing to registers between two lines, and basic shapes (triangles, circles and quadrilaterals), but also transfer of one image to another with zoom shift and rotate transformations. Support for better examples, documentation, a whole display function fill and small changes to drawing function are in progress. The camera trasnfer takes about 30ms at 5x zoom, and while its slower at lower zoomes than each display pixel reading a camera ones, it progressively gets faster. diff --git a/examples/CameraToDisplaySquares/CameraToDisplaySquares.ino b/examples/CameraToDisplaySquares/CameraToDisplaySquares.ino new file mode 100644 index 0000000..08bc072 --- /dev/null +++ b/examples/CameraToDisplaySquares/CameraToDisplaySquares.ino @@ -0,0 +1,76 @@ +#include +#include "SpeeduinoGL.h" +#include "arducam_dvp.h" +#include "Arduino_H7_Video.h" +#include "dsi.h" +#include "SDRAM.h" + + +float ShiftH = -100; +float ShiftV = -400; +float zoom = 5; +float rotationRad = 0.3; + + + + +Rectangle sq1 = { + { 0, 0 }, + { 0, 480 }, + { 800, 0 }, + { 800, 480 } +}; + +uint16_t* DisplayFrameBuffer = (uint16_t*)SDRAM_START_ADDRESS; +FrameBuffer fb(1613300736); + +#include "OV7670/ov767x.h" +// OV7670 ov767x; +OV7675 ov767x; +Camera cam(ov767x); +#define IMAGE_MODE CAMERA_RGB565 + +Arduino_H7_Video Display(800, 480, GigaDisplayShield); + + + +void setup() { + // put your setup code here, to run once: + + if (!cam.begin(CAMERA_R320x240, IMAGE_MODE, 30)) { + } + SDRAM.begin(); + Display.begin(); + + + + dsi_lcdClear(0); + dsi_drawCurrentFrameBuffer(); + dsi_lcdClear(0); + dsi_drawCurrentFrameBuffer(); + + + FillRectangle(sq1, 0xFF00); + + +} + +void loop() { + // put your main code here, to run repeatedly: + + cam.grabFrame(fb, 3000); + + long t1 = micros(); + + TransferSquares(ShiftH, ShiftV, zoom, rotationRad); + + + Serial.println(micros() - t1); + + dsi_lcdDrawImage((void *)DisplayFrameBuffer, (void *)dsi_getCurrentFrameBuffer(), 480, 800, DMA2D_INPUT_RGB565); + dsi_drawCurrentFrameBuffer(); + +} + + + diff --git a/library.properties b/library.properties index 4621004..623f5dd 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=SpeeduinoGL -version=0.0.2 +version=0.0.4 author=Benjamin Gombala maintainer=Benjamin Gombala benjamin.gombala@gmail.com Bexin sentence=A library with basic graphical functions optimised for arm cortex m7. diff --git a/src/SpeeduinoGL.cpp b/src/SpeeduinoGL.cpp index a19bf5a..138cc47 100644 --- a/src/SpeeduinoGL.cpp +++ b/src/SpeeduinoGL.cpp @@ -5,6 +5,10 @@ uint32_t ImageAddress = 0x60000000; uint32_t ResV = 480; uint32_t ResH = 800; +uint16_t InputSizeH = 240; +uint16_t InputSizeV = 320; +uint32_t CameraAddress = 1613300736; + void ConfigBuffer(uint32_t Address, uint32_t ResolutionV, uint32_t ResolutionH) { ResV = ResolutionV; @@ -12,6 +16,12 @@ uint32_t ResH = 800; ResH = ResolutionH; } +void ConfigInput(uint32_t Address, uint32_t ResolutionV, uint32_t ResolutionH ) { + InputSizeV = ResolutionV; + CameraAddress = Address; + InputSizeH = ResolutionH; +} + void FillTriangle(Triangle triangle, uint16_t Colour) { // Sort points based on x-coordinates std::sort(&triangle.A, &triangle.C + 1, @@ -75,6 +85,7 @@ uint32_t ResH = 800; rectangle.A.h + gradAD * (ceil(rectangle.A.w) - rectangle.A.w), rectangle.A.h + gradAB * (ceil(rectangle.A.w) - rectangle.A.w), gradAB, gradAD, Colour, Polarized); + if (switched) { PolarizedTwoLineRasterizer(ceil(rectangle.B.w), ceil(rectangle.C.w), @@ -99,42 +110,90 @@ uint32_t ResH = 800; } } - void PolarizedTwoLineRasterizer(int32_t CellStartX, int32_t CellEndX, float PointerCoordinateH, float PointerEndH, float Gradient1, float Gradient2, uint16_t Colour, bool Polarity) { +DoubleFloat PolarizedTwoLineRasterizer(int32_t CellStartX, int32_t CellEndX, float PointerCoordinateH, float PointerEndH, float Gradient1, float Gradient2, uint16_t Colour, bool Polarity) { if (Polarity) { - TwoLineRasterizer(CellStartX, CellEndX, PointerCoordinateH, PointerEndH, Gradient1, Gradient2, Colour); + return(TwoLineRasterizer(CellStartX, CellEndX, PointerCoordinateH, PointerEndH, Gradient1, Gradient2, Colour)); } else { - TwoLineRasterizer(CellStartX, CellEndX, PointerEndH, PointerCoordinateH, Gradient2, Gradient1, Colour); + return(TwoLineRasterizer(CellStartX, CellEndX, PointerEndH, PointerCoordinateH, Gradient2, Gradient1, Colour)); } } - void TwoLineRasterizer(int32_t CellStartX, int32_t CellEndX, float PointerCoordinateH, float PointerEndH, float Gradient1, float Gradient2, uint16_t Colour) { - uint16_t* ImageBuffer = (uint16_t*)ImageAddress; +DoubleFloat TwoLineRasterizer(int32_t CellStartX, int32_t CellEndX, float PointerCoordinateH, float PointerEndH, float Gradient1, float Gradient2, uint16_t Colour) { + + + uint16_t* ImageBuffer = (uint16_t*)ImageAddress; + + if (CellStartX < 0) { - PointerCoordinateH -= Gradient2 * CellStartX; - PointerEndH -= Gradient1 * CellStartX; - } - + if (CellEndX < 0) { + PointerCoordinateH -= Gradient2 * (CellStartX-CellEndX); + PointerEndH -= Gradient1 * (CellStartX-CellEndX); + goto returnpoint; + } else { + PointerCoordinateH -= Gradient2 * CellStartX; + PointerEndH -= Gradient1 * CellStartX; + CellStartX = 0; + }; + }; + + + + + + + if (CellEndX > ResH) { CellEndX = ResH; - } + }; + for (uint32_t CurrentW = CellStartX; CellEndX > CurrentW; CurrentW++) { - uint32_t PointerCoorInt = ceil(PointerCoordinateH); - uint32_t PointerEndInt = ceil(PointerEndH); + int32_t PointerCoorInt = ceil(PointerCoordinateH); + int32_t PointerEndInt = ceil(PointerEndH); + + + + if (PointerEndInt < 0) { + PointerEndInt = 0; + }; + + if (PointerCoorInt < 0) { + PointerCoorInt = 0; + }; + + if (PointerEndInt > ResV) { PointerEndInt = ResV; - } + }; + + if (PointerCoorInt > ResV) { + PointerCoorInt = ResV; + }; + - for (int32_t CurrentH = PointerCoorInt; PointerEndInt > CurrentH; CurrentH++) { + for (uint32_t CurrentH = PointerCoorInt; PointerEndInt > CurrentH; CurrentH++) { ImageBuffer[ResV * (CurrentW) + (CurrentH)] = Colour; - } + }; PointerCoordinateH += Gradient2; PointerEndH += Gradient1; - } + }; + + + + returnpoint: + + DoubleFloat Retruner = {PointerCoordinateH, PointerEndH}; + + return(Retruner); + + + + + } void FillCircle(float Radius, uint16_t Colour, Point Centre) { @@ -174,3 +233,137 @@ uint32_t ResH = 800; } } + +void TransferSquares(float ShiftH, float ShiftV, float zoom, float rotationRad) { + + uint16_t* InputBuffer = (uint16_t*)CameraAddress; + + float gradient1 = cos(rotationRad); + float gradient2 = sin(rotationRad); + + + float HShift = zoom * gradient2; + float VShift = zoom * gradient1; + + gradient1 = abs(gradient1); + gradient2 = abs(gradient2); + + float grad1; + float grad2; + + + + bool Polarized = 0; + + if (sin(2 * rotationRad) <= 0) { + std::swap(gradient1, gradient2); + }; + + if (sin(4 * rotationRad) <= 0) { + Polarized = 1; + grad1 = gradient2 / gradient1; + grad2 = -gradient1 / gradient2; + } else { + grad1 = -gradient1 / gradient2; + grad2 = gradient2 / gradient1; + }; + + + + + float CellPointerH = ShiftH; + float CellPointerV = ShiftV; + + const float BoundStartH = 0 - zoom - abs(VShift); + const float BoundStartV = 0 - zoom - abs(HShift); + const float BoundEndH = ResH + zoom + abs(VShift); + const float BoundEndV = ResV + zoom + abs(HShift); + + + for (int16_t PosH = 0; PosH < InputSizeH; PosH++) { + + + float CellPointerHU = CellPointerH + VShift; + float CellPointerVU = CellPointerV + HShift; + + float EOCPTRH = CellPointerHU; + float EOCPTRV = CellPointerVU; + + float CellPointerH2 = CellPointerH - HShift; + float CellPointerV2 = CellPointerV + VShift; + float CellPointerHU2 = CellPointerHU - HShift; + float CellPointerVU2 = CellPointerVU + VShift; + + + + for (int16_t PosV = 0; PosV < InputSizeV; PosV++) { + + if (CellPointerH <= BoundEndH && CellPointerV <= BoundEndV && CellPointerH >= BoundStartH && CellPointerV >= BoundStartV) { + + + + Rectangle square = { + { CellPointerH, CellPointerV }, + { CellPointerHU, CellPointerVU }, + { CellPointerH2, CellPointerV2 }, + { CellPointerHU2, CellPointerVU2 } + }; + + + + + uint16_t Colour = InputBuffer[InputSizeV * PosH + PosV]; + Colour = (((Colour >> 8) & 0x00FF) | ((Colour << 8) & 0xFF00)); + + + + std::sort(&square.A, &square.C + 1, + [](const Point &a, const Point &b) { + return a.w < b.w; + }); + + if (square.A.w == square.B.w && square.A.h != square.D.h) { + std::swap(square.D.h, square.C.h); + }; + + + + + DoubleFloat WouldWork = + PolarizedTwoLineRasterizer(ceil(square.A.w), ceil(square.B.w), + square.A.h + grad2 * (ceil(square.A.w) - square.A.w), + square.A.h + grad1 * (ceil(square.A.w) - square.A.w), + grad1, grad2, Colour, Polarized); + + if (Polarized) { std::swap(WouldWork.Float1, WouldWork.Float2); }; + WouldWork = + PolarizedTwoLineRasterizer(ceil(square.B.w), ceil(square.D.w), + WouldWork.Float2, + square.B.h + grad2 * (ceil(square.B.w) - square.B.w), + grad2, grad2, Colour, Polarized); + + if (Polarized) { std::swap(WouldWork.Float1, WouldWork.Float2); }; + WouldWork = + PolarizedTwoLineRasterizer(ceil(square.D.w), ceil(square.C.w), + square.D.h + grad1 * (ceil(square.D.w) - square.D.w), + WouldWork.Float1, + grad2, grad1, Colour, Polarized); + }; + + CellPointerH = CellPointerH2; + CellPointerV = CellPointerV2; + + CellPointerHU = CellPointerHU2; + CellPointerVU = CellPointerVU2; + + CellPointerH2 -= HShift; + CellPointerV2 += VShift; + + CellPointerHU2 -= HShift; + CellPointerVU2 += VShift; + }; + + CellPointerH = EOCPTRH; + CellPointerV = EOCPTRV; + }; + } diff --git a/src/SpeeduinoGL.h b/src/SpeeduinoGL.h index c789447..2a8d688 100644 --- a/src/SpeeduinoGL.h +++ b/src/SpeeduinoGL.h @@ -8,6 +8,12 @@ float h; }; + +struct DoubleFloat { + float Float1; + float Float2; +}; + struct Triangle { Point A; Point B; @@ -21,12 +27,18 @@ Point C; }; + + + void ConfigBuffer(uint32_t address = 0x60000000, uint32_t ResolutionV = 480, uint32_t ResolutionH = 800); + void ConfigInput(uint32_t address = 1613300736, uint32_t ResolutionV = 320, uint32_t ResolutionH = 240); void FillTriangle(Triangle triangle, uint16_t Colour); void FillRectangle(Rectangle rectangle, uint16_t Colour); - void PolarizedTwoLineRasterizer(int32_t CellStartX, int32_t CellEndX, float PointerCoordinateH, float PointerEndH, float Gradient1, float Gradient2, uint16_t Colour, bool Polarity); - void TwoLineRasterizer(int32_t CellStartX, int32_t CellEndX, float PointerCoordinateH, float PointerEndH, float Gradient1, float Gradient2, uint16_t Colour); +DoubleFloat PolarizedTwoLineRasterizer(int32_t CellStartX, int32_t CellEndX, float PointerCoordinateH, float PointerEndH, float Gradient1, float Gradient2, uint16_t Colour, bool Polarity); +DoubleFloat TwoLineRasterizer(int32_t CellStartX, int32_t CellEndX, float PointerCoordinateH, float PointerEndH, float Gradient1, float Gradient2, uint16_t Colour); void FillCircle(float Radius, uint16_t Colour, Point Centre); +void TransferSquares(float ShiftH, float ShiftV, float zoom, float rotationRad); + #endif