From 0492387cf1d104fe541bfa71681bd64721eb7f0f Mon Sep 17 00:00:00 2001 From: blobt <380255922@qq.com> Date: Sun, 9 Feb 2020 10:41:06 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=98=E5=88=B6=E4=B8=89=E8=A7=92=E5=BD=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/CMakeLists.txt | 3 + src/Raster.cc | 106 +++++++++++++++++++++++++++++ src/Raster.h | 61 +++++++++++++++++ src/Rgba.h | 3 + src/draw_triangle.cc | 159 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 332 insertions(+) create mode 100644 src/draw_triangle.cc diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2326cfb..564adb8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,3 +1,6 @@ +add_executable(draw_triangle draw_triangle.cc ${commom_src}) +target_link_libraries (draw_triangle ${FC_DEP_LIBS}) + add_executable(draw_rect draw_rect.cc ${commom_src}) target_link_libraries (draw_rect ${FC_DEP_LIBS}) diff --git a/src/Raster.cc b/src/Raster.cc index f80f406..9bc1c42 100644 --- a/src/Raster.cc +++ b/src/Raster.cc @@ -154,6 +154,105 @@ void Raster::drawLine(float2 p1, float2 p2, Rgba color1, Rgba color2) { } +/** + * 画一条平行于x轴的直线 + * @param span + */ +void Raster::drawSpan(const Span &span) { + //float length = tmax(span.xStart - span.xEnd, 1); //取保length不为0 + + Rgba color; + float length = span.xEnd - span.xStart; + for (int i = span.xStart; i <= span.xEnd; i++) { + color = colorLerp(span.color1, span.color2, (float) (i - span.xStart) / length); + setPixel(i, span.y, color); + } +} + +void Raster::drawEge(const Ege& e1, const Ege& e2) { + + float xOffset1 = fabs(e1.x2 - e1.x1); + float yOffset1 = fabs(e1.y2 - e1.y1); + float setp1 = 1 / yOffset1; + float scale1 = (e1.y2 - e2.y2) / yOffset1; //TODO:yOffset1 不能为0 + + float xOffset2 = fabs(e2.x2 - e2.x1); + float yOffset2 = fabs(e2.y2 - e2.y1); + float setp2 = 1 / yOffset2; //TODO:yOffset2 不能为0 + float scale2 = 0; + + + //优化2 不画三角形坐标y以为的部分 +// int startY = tmin(e2.y2, _height); +// int endY = tmax(e2.y1, 0); +// scale2 = (startY - _height) / yOffset2; + + + + Rgba colorE1; + Rgba colorE2; + for (int y = e2.y2; y > e2.y1; y--) { + + int x2; + if (e2.x2 < e2.x1) { + x2 = e2.x2 + xOffset2 * scale2; + } else { + x2 = e2.x2 - xOffset2 * scale2; + } + colorE2 = colorLerp(e2.color2, e2.color1, scale2); + scale2 += setp2; + //setPixel(x2, y, e2.color2); + + + int x1; + if (e1.x2 < e1.x1) { + x1 = e1.x2 + xOffset1 * scale1; + } else { + x1 = e1.x2 - xOffset1 * scale1; + } + colorE1 = colorLerp(e1.color2, e1.color1, scale1); + scale1 += setp1; + //setPixel(x1, y, e1.color2); + + Span span(x1, x2, y, colorE1, colorE2); + drawSpan(span); + } +} + +void Raster::drawTriangle(int2 p0, int2 p1, int2 p2, Rgba c0, Rgba c1, Rgba c2) { + + //优化1 不画3个点都不在坐标内的三角形 + if (!isIn(p0) && !isIn(p1) && !isIn(p2)) { + return; + } + + Ege eges[3] = { + Ege(p0.x, p0.y, p1.x, p1.y, c0, c1), + Ege(p1.x, p1.y, p2.x, p2.y, c1, c2), + Ege(p2.x, p2.y, p0.x, p0.y, c2, c0), + }; + + int iMax = 0; + int length = eges[0].y2 - eges[0].y1; + + int curLength = 0; + + for (int i = 1; i < 3; i++) { + curLength = eges[i].y2 - eges[i].y1; + if (curLength > length) { + iMax = i; + } + } + + int iShort1 = (iMax + 1) % 3; + int iShort2 = (iMax + 2) % 3; + + //printf("%d, %d, %d\n", iMax, iShort1, iShort2); + + drawEge(eges[iMax], eges[iShort1]); + drawEge(eges[iMax], eges[iShort2]); +} + void Raster::drawArray(DRAWMODE mode, const float2* points, size_t count) { switch (mode) { case DM_POINTS: @@ -242,4 +341,11 @@ bool Raster::setPixel(int x, int y, Rgba color) { } //行列是反的 buffer[ (_height - y) * _width + x] = color; +} + +bool Raster::isIn(int2 point) { + if (point.x >= 0 && point.x <= _width && point.y >= 0 && point.y < _height) { + return true; + } + return false; } \ No newline at end of file diff --git a/src/Raster.h b/src/Raster.h index ab2dab2..6d7eccb 100644 --- a/src/Raster.h +++ b/src/Raster.h @@ -15,6 +15,7 @@ #define RESTER_H #include "common.h" +#include "Rgba.h" enum DRAWMODE { DM_POINTS = 0, @@ -23,6 +24,62 @@ enum DRAWMODE { DM_LINES_TRIP = 3 }; +class Span { +public: + int xStart; + int xEnd; + int y; + + Rgba color1; + Rgba color2; + + Span(int xStart, int xEnd, int y, Rgba color1, Rgba color2) { + + if (xStart < xEnd) { + this->xStart = xStart; + this->xEnd = xEnd; + this->color1 = color1; + this->color2 = color2; + } else { + this->xStart = xEnd; + this->xEnd = xStart; + this->color1 = color2; + this->color2 = color1; + } + + this->y = y; + } +}; + +class Ege { +public: + int x1; + int y1; + Rgba color1; + + int x2; + int y2; + Rgba color2; + + Ege(int x1, int y1, int x2, int y2, Rgba color1, Rgba color2) { + if (y1 < y2) { + this->x1 = x1; + this->y1 = y1; + this->x2 = x2; + this->y2 = y2; + this->color1 = color1; + this->color2 = color2; + } else { + this->x1 = x2; + this->y1 = y2; + this->x2 = x1; + this->y2 = y1; + this->color1 = color2; + this->color2 = color1; + } + } +}; + class Raster { public: Rgba* buffer; @@ -31,12 +88,16 @@ public: void drawPoint(int x, int y, Rgba color = Rgba(255, 0, 0, 0), int pointSize = 1); void drawLine(float2 p1, float2 p2, Rgba color = Rgba(255, 0, 0, 0)); void drawLine(float2 p1, float2 p2, Rgba color1, Rgba color2); + void drawSpan(const Span &span); + void drawEge(const Ege& e1, const Ege& e2); + void drawTriangle(int2 p0, int2 p1, int2 p2, Rgba c0, Rgba c1, Rgba c2); void drawArray(DRAWMODE mode, const float2* points, size_t count); void drawFilledRect(int startX, int startY, int width, int height); void drawRect(const int2* points, const Rgba* colors); int size(); void clean(); bool setPixel(int x, int y, Rgba color); + bool isIn(int2 point); private: int _width; int _height; diff --git a/src/Rgba.h b/src/Rgba.h index 62ee425..1b20422 100644 --- a/src/Rgba.h +++ b/src/Rgba.h @@ -14,6 +14,8 @@ #ifndef RGBA_H #define RGBA_H +#include "stdio.h" + class Rgba { public: Rgba(unsigned char r = 0, unsigned char g = 0, unsigned char b = 0, unsigned char a = 0); @@ -40,5 +42,6 @@ inline Rgba colorLerp(const Rgba& color1, const Rgba& color2, float step) { return ret; } + #endif /* RGBA_H */ diff --git a/src/draw_triangle.cc b/src/draw_triangle.cc new file mode 100644 index 0000000..a2b7274 --- /dev/null +++ b/src/draw_triangle.cc @@ -0,0 +1,159 @@ +#include +#include +#include +#include +#include "Rgba.h" +#include "Raster.h" +#include "common.h" + +using namespace std; + + +gint height = 500; +gint width = 500; + +Raster raster(width, height); + +/** + * 使用drawSpan画线 + */ +void example1() { + Span span(100, 400, 250, Rgba(255, 0, 0, 0), Rgba(255, 0, 0, 0)); + + raster.drawSpan(span); + +} + +/** + * 使用斜率画斜线 + */ +void example2() { + + static int x = 0; + + if (x >= width) { + x = 0; + } + + Ege e2(x++, 50, 250, 250, Rgba(255, 0, 0, 0), Rgba(255, 0, 0, 0)); + + //计算跨度 + float xOffset = e2.x2 - e2.x1; + float yOffset = e2.y2 - e2.y1; + + //计算斜率 + float slope = xOffset / yOffset; + + //以跨度大 + for (float y = e2.y1; y < e2.y2; y++) { + float x; + // --> (x - e2.x1) / (y - e2.y1) = slope + // --> x - e2. x1 = slope * (y - e2.y1) + x = slope * (y - e2.y1) + e2.x1; + raster.setPixel(x, y, Rgba(255, 0, 0, 0)); + } +} + +void example3() { + //Ege e1(250, 250, 350, 50); + //Ege e2(250, 250, 100, 150); + + Ege e1(250, 250, 350, 50, Rgba(255, 0, 0, 0), Rgba(255, 0, 0, 0)); + Ege e2(100, 150, 350, 50, Rgba(255, 0, 0, 0), Rgba(255, 0, 0, 0)); + + raster.drawPoint(e1.x1, e1.y1, Rgba(255, 0, 0, 0), 3); + raster.drawPoint(e1.x2, e1.y2, Rgba(255, 0, 0, 0), 3); + + raster.drawPoint(e2.x1, e2.y1, Rgba(255, 0, 0, 0), 3); + raster.drawPoint(e2.x2, e2.y2, Rgba(255, 0, 0, 0), 3); + + raster.drawEge(e1, e2); +} + +void example4() { + + int2 p[3] = { + int2(50, 50), + int2(250, 250), + int2(300, 150) + }; + + // int2 p[3] = { + // int2(100, 150), + // int2(250, 250), + // int2(350, 50) + // }; + + Ege e0(p[0].x, p[0].y, p[1].x, p[1].y, Rgba(255, 0, 0, 0), Rgba(0, 255, 0, 0)); + Ege e1(p[1].x, p[1].y, p[2].x, p[2].y, Rgba(0, 255, 0, 0), Rgba(0, 0, 255, 0)); + Ege e2(p[2].x, p[2].y, p[0].x, p[0].y, Rgba(0, 0, 255, 0), Rgba(255, 0, 0, 0)); + + raster.drawPoint(e0.x1, e0.y1, Rgba(255, 0, 0, 0), 3); + raster.drawPoint(e0.x2, e0.y2, Rgba(255, 0, 0, 0), 3); + + raster.drawPoint(e2.x1, e2.y1, Rgba(255, 0, 0, 0), 3); + raster.drawPoint(e2.x2, e2.y2, Rgba(255, 0, 0, 0), 3); + + //raster.drawEge(e0, e1); + //raster.drawEge(e0, e2); + + + // raster.drawEge(e1, e0); + // raster.drawEge(e1, e2); + + + raster.drawTriangle(p[0], p[1], p[2], Rgba(255, 0, 0, 0), Rgba(0, 255, 0, 0), Rgba(0, 0, 255, 0)); +} + +unsigned char* makeBitmap() { + raster.clean(); + + example4(); + + return (unsigned char*) raster.buffer; +} + +void render(GtkWidget *widget) { + //允许窗口可以绘图 + gtk_widget_set_app_paintable(widget, TRUE); + gtk_widget_realize(widget); + gtk_widget_queue_draw(widget); + + //模拟一张图片 + unsigned char* data = makeBitmap(); + + GdkPixbuf *pixbuf = gdk_pixbuf_new_from_data(data, GDK_COLORSPACE_RGB, TRUE, 8, width, height, width * 4, NULL, NULL); + + GdkPixmap *pixmap = NULL; + + gdk_pixbuf_render_pixmap_and_mask(pixbuf, &pixmap, NULL, 128); + + gdk_window_set_back_pixmap(widget->window, pixmap, FALSE); + + g_object_unref(pixbuf); + g_object_unref(pixmap); + //delete data; +} + +int main(int argc, char* argv[]) { + + gtk_init(&argc, &argv); + + //创建窗口 + GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_widget_set_size_request(window, width, height); + + gtk_window_set_title(GTK_WINDOW(window), "Gtk testing"); + gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ALWAYS); + + //窗口关闭时候,关闭程序 + g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); + //设置渲染 + g_signal_connect(window, "expose-event", G_CALLBACK(render), window); + + + gtk_widget_show_all(window); + gtk_main(); + + return 0; +}