diff options
Diffstat (limited to 'demos/graphics_experiments/2.cpp')
-rw-r--r-- | demos/graphics_experiments/2.cpp | 312 |
1 files changed, 312 insertions, 0 deletions
diff --git a/demos/graphics_experiments/2.cpp b/demos/graphics_experiments/2.cpp new file mode 100644 index 00000000..d61dc9ea --- /dev/null +++ b/demos/graphics_experiments/2.cpp @@ -0,0 +1,312 @@ +// Code referred from +// https://www.geeksforgeeks.org/scan-line-polygon-filling-using-opengl-c/ + +#include "cru/platform/Color.hpp" +#include "cru/platform/bootstrap/Bootstrap.hpp" +#include "cru/platform/graphics/Factory.hpp" +#include "cru/platform/graphics/Painter.hpp" +#include "cru/platform/gui/UiApplication.hpp" +#include "cru/platform/gui/Window.hpp" + +#include <cmath> +#include <cstdio> +#include <functional> + +#define maxHt 800 +#define maxWd 600 +#define maxVer 10000 + +// Start from lower left corner +typedef struct edgebucket { + int ymax; // max y-coordinate of edge + float xofymin; // x-coordinate of lowest edge point updated only in aet + float slopeinverse; +} EdgeBucket; + +typedef struct edgetabletup { + // the array will give the scanline number + // The edge table (ET) with edges entries sorted + // in increasing y and x of the lower end + + int countEdgeBucket; // no. of edgebuckets + EdgeBucket buckets[maxVer]; +} EdgeTableTuple; + +EdgeTableTuple EdgeTable[maxHt], ActiveEdgeTuple; + +// Scanline Function +void initEdgeTable() { + int i; + for (i = 0; i < maxHt; i++) { + EdgeTable[i].countEdgeBucket = 0; + } + + ActiveEdgeTuple.countEdgeBucket = 0; +} + +void printTuple(EdgeTableTuple *tup) { + int j; + + if (tup->countEdgeBucket) printf("\nCount %d-----\n", tup->countEdgeBucket); + + for (j = 0; j < tup->countEdgeBucket; j++) { + printf(" %d+%.2f+%.2f", tup->buckets[j].ymax, tup->buckets[j].xofymin, + tup->buckets[j].slopeinverse); + } +} + +void printTable() { + int i, j; + + for (i = 0; i < maxHt; i++) { + if (EdgeTable[i].countEdgeBucket) printf("\nScanline %d", i); + + printTuple(&EdgeTable[i]); + } +} + +/* Function to sort an array using insertion sort*/ +void insertionSort(EdgeTableTuple *ett) { + int i, j; + EdgeBucket temp; + + for (i = 1; i < ett->countEdgeBucket; i++) { + temp.ymax = ett->buckets[i].ymax; + temp.xofymin = ett->buckets[i].xofymin; + temp.slopeinverse = ett->buckets[i].slopeinverse; + j = i - 1; + + while ((temp.xofymin < ett->buckets[j].xofymin) && (j >= 0)) { + ett->buckets[j + 1].ymax = ett->buckets[j].ymax; + ett->buckets[j + 1].xofymin = ett->buckets[j].xofymin; + ett->buckets[j + 1].slopeinverse = ett->buckets[j].slopeinverse; + j = j - 1; + } + ett->buckets[j + 1].ymax = temp.ymax; + ett->buckets[j + 1].xofymin = temp.xofymin; + ett->buckets[j + 1].slopeinverse = temp.slopeinverse; + } +} + +void storeEdgeInTuple(EdgeTableTuple *receiver, int ym, int xm, float slopInv) { + // both used for edgetable and active edge table.. + // The edge tuple sorted in increasing ymax and x of the lower end. + (receiver->buckets[(receiver)->countEdgeBucket]).ymax = ym; + (receiver->buckets[(receiver)->countEdgeBucket]).xofymin = (float)xm; + (receiver->buckets[(receiver)->countEdgeBucket]).slopeinverse = slopInv; + + // sort the buckets + insertionSort(receiver); + + (receiver->countEdgeBucket)++; +} + +void storeEdgeInTable(int x1, int y1, int x2, int y2) { + float m, minv; + int ymaxTS, xwithyminTS, scanline; // ts stands for to store + + if (x2 == x1) { + minv = 0.000000; + } else { + m = ((float)(y2 - y1)) / ((float)(x2 - x1)); + + // horizontal lines are not stored in edge table + if (y2 == y1) return; + + minv = (float)1.0 / m; + printf("\nSlope string for %d %d & %d %d: %f", x1, y1, x2, y2, minv); + } + + if (y1 > y2) { + scanline = y2; + ymaxTS = y1; + xwithyminTS = x2; + } else { + scanline = y1; + ymaxTS = y2; + xwithyminTS = x1; + } + // the assignment part is done..now storage.. + storeEdgeInTuple(&EdgeTable[scanline], ymaxTS, xwithyminTS, minv); +} + +void removeEdgeByYmax(EdgeTableTuple *Tup, int yy) { + int i, j; + for (i = 0; i < Tup->countEdgeBucket; i++) { + if (Tup->buckets[i].ymax == yy) { + printf("\nRemoved at %d", yy); + + for (j = i; j < Tup->countEdgeBucket - 1; j++) { + Tup->buckets[j].ymax = Tup->buckets[j + 1].ymax; + Tup->buckets[j].xofymin = Tup->buckets[j + 1].xofymin; + Tup->buckets[j].slopeinverse = Tup->buckets[j + 1].slopeinverse; + } + Tup->countEdgeBucket--; + i--; + } + } +} + +void updatexbyslopeinv(EdgeTableTuple *Tup) { + int i; + + for (i = 0; i < Tup->countEdgeBucket; i++) { + (Tup->buckets[i]).xofymin = + (Tup->buckets[i]).xofymin + (Tup->buckets[i]).slopeinverse; + } +} + +void ScanlineFill(const std::function<void(float x1, float y1, float x2, + float y2)> &draw_line) { + /* Follow the following rules: + 1. Horizontal edges: Do not include in edge table + 2. Horizontal edges: Drawn either on the bottom or on the top. + 3. Vertices: If local max or min, then count twice, else count + once. + 4. Either vertices at local minima or at local maxima are drawn.*/ + + int i, j, x1, ymax1, x2, ymax2, FillFlag = 0, coordCount; + + // we will start from scanline 0; + // Repeat until last scanline: + for (i = 0; i < maxHt; i++) // 4. Increment y by 1 (next scan line) + { + // 1. Move from ET bucket y to the + // AET those edges whose ymin = y (entering edges) + for (j = 0; j < EdgeTable[i].countEdgeBucket; j++) { + storeEdgeInTuple(&ActiveEdgeTuple, EdgeTable[i].buckets[j].ymax, + EdgeTable[i].buckets[j].xofymin, + EdgeTable[i].buckets[j].slopeinverse); + } + printTuple(&ActiveEdgeTuple); + + // 2. Remove from AET those edges for + // which y=ymax (not involved in next scan line) + removeEdgeByYmax(&ActiveEdgeTuple, i); + + // sort AET (remember: ET is presorted) + insertionSort(&ActiveEdgeTuple); + + printTuple(&ActiveEdgeTuple); + + // 3. Fill lines on scan line y by using pairs of x-coords from AET + j = 0; + FillFlag = 0; + coordCount = 0; + x1 = 0; + x2 = 0; + ymax1 = 0; + ymax2 = 0; + while (j < ActiveEdgeTuple.countEdgeBucket) { + if (coordCount % 2 == 0) { + x1 = (int)(ActiveEdgeTuple.buckets[j].xofymin); + ymax1 = ActiveEdgeTuple.buckets[j].ymax; + if (x1 == x2) { + /* three cases can arrive- + 1. lines are towards top of the intersection + 2. lines are towards bottom + 3. one line is towards top and other is towards bottom + */ + if (((x1 == ymax1) && (x2 != ymax2)) || + ((x1 != ymax1) && (x2 == ymax2))) { + x2 = x1; + ymax2 = ymax1; + } + + else { + coordCount++; + } + } + + else { + coordCount++; + } + } else { + x2 = (int)ActiveEdgeTuple.buckets[j].xofymin; + ymax2 = ActiveEdgeTuple.buckets[j].ymax; + + FillFlag = 0; + + // checking for intersection... + if (x1 == x2) { + /*three cases can arrive- + 1. lines are towards top of the intersection + 2. lines are towards bottom + 3. one line is towards top and other is towards bottom + */ + if (((x1 == ymax1) && (x2 != ymax2)) || + ((x1 != ymax1) && (x2 == ymax2))) { + x1 = x2; + ymax1 = ymax2; + } else { + coordCount++; + FillFlag = 1; + } + } else { + coordCount++; + FillFlag = 1; + } + + if (FillFlag) { + // drawing actual lines... + + draw_line(x1, i, x2, i); + + // printf("\nLine drawn from %d,%d to %d,%d",x1,i,x2,i); + } + } + + j++; + } + + // 5. For each nonvertical edge remaining in AET, update x for new y + updatexbyslopeinv(&ActiveEdgeTuple); + } + + printf("\nScanline filling complete"); +} + +int edges[] = {50, 50, 100, 40, 150, 150, 100, 80, 40, 90, 50, 50}; + +void drawPolyDino(const std::function<void(float x1, float y1, float x2, + float y2)> &draw_line) { + for (int i = 0; i < sizeof(edges) / sizeof(edges[0]) - 3; i += 2) { + draw_line(edges[i], edges[i + 1], edges[i + 2], edges[i + 3]); + storeEdgeInTable(edges[i], edges[i + 1], edges[i + 2], + edges[i + 3]); // storage of edges in edge table. + } +} + +void drawDino(const std::function<void(float x1, float y1, float x2, float y2)> + &draw_line) { + initEdgeTable(); + drawPolyDino(draw_line); + printf("\nTable"); + printTable(); + + ScanlineFill(draw_line); // actual calling of scanline filling.. +} + +int main(int argc, char **argv) { + auto application = cru::platform::bootstrap::CreateUiApplication(); + auto window = application->CreateWindow(); + + auto brush = application->GetGraphicsFactory()->CreateSolidColorBrush( + cru::platform::colors::black); + + window->SetClientSize(cru::platform::Size(400, 200)); + + window->PaintEvent()->AddHandler([window, &brush](nullptr_t) { + auto painter = window->BeginPaint(); + auto draw_line = [&painter, &brush](float x1, float y1, float x2, + float y2) { + painter->DrawLine({x1, y1}, {x2, y2}, brush.get(), 1); + }; + + drawDino(draw_line); + }); + + window->SetVisibility(cru::platform::gui::WindowVisibilityType::Show); + + return application->Run(); +} |