Browse Source

绘制三角形

master
blobt 5 years ago
parent
commit
0492387cf1
  1. 3
      src/CMakeLists.txt
  2. 106
      src/Raster.cc
  3. 61
      src/Raster.h
  4. 3
      src/Rgba.h
  5. 159
      src/draw_triangle.cc

3
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})

106
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<int>(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<int>(e2.y2, _height);
// int endY = tmax<int>(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;
}

61
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;

3
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 */

159
src/draw_triangle.cc

@ -0,0 +1,159 @@
#include <iostream>
#include <math.h>
#include <cairo.h>
#include <gtk/gtk.h>
#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;
}
Loading…
Cancel
Save