From a0ebc379b4cef52641debf58acbf147de99d1919 Mon Sep 17 00:00:00 2001 From: Jeremy Hu Date: Fri, 16 Dec 2016 22:15:11 +0930 Subject: [PATCH] Add Jon Leech's method to draw shpere --- .gitignore | 3 + build/dust3d.pro | 8 ++- src/drawcommon.c | 20 ++++++ src/drawcommon.h | 31 +++++++++ src/drawsphere.c | 106 +++++++++++++++++++++++++++++++ src/drawsphere.h | 14 +++++ src/glwidget.cpp | 161 +++++++++++++++-------------------------------- src/main.cpp | 16 +++-- 8 files changed, 243 insertions(+), 116 deletions(-) create mode 100644 .gitignore create mode 100644 src/drawcommon.c create mode 100644 src/drawcommon.h create mode 100644 src/drawsphere.c create mode 100644 src/drawsphere.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..295e4ee6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.* +*.o +build/* \ No newline at end of file diff --git a/build/dust3d.pro b/build/dust3d.pro index 815cf354..fd47d561 100644 --- a/build/dust3d.pro +++ b/build/dust3d.pro @@ -8,7 +8,11 @@ INCLUDEPATH += ../src SOURCES += main.cpp \ mainwindow.cpp \ - glwidget.cpp + glwidget.cpp \ + drawcommon.c \ + drawsphere.c HEADERS += mainwindow.h \ - glwidget.h \ No newline at end of file + glwidget.h \ + drawcommon.h \ + drawsphere.h \ No newline at end of file diff --git a/src/drawcommon.c b/src/drawcommon.c new file mode 100644 index 00000000..8f31acd8 --- /dev/null +++ b/src/drawcommon.c @@ -0,0 +1,20 @@ +#include "drawcommon.h" +#include + +void normalize(point *p) { + double mag; + mag = p->x * p->x + p->y * p->y + p->z * p->z; + if (mag != 0.0) { + mag = 1.0 / sqrt(mag); + p->x *= mag; + p->y *= mag; + p->z *= mag; + } +} + +void midpoint(point *a, point *b, point *mid) { + mid->x = (a->x + b->x) * 0.5; + mid->y = (a->y + b->y) * 0.5; + mid->z = (a->z + b->z) * 0.5; +} + diff --git a/src/drawcommon.h b/src/drawcommon.h new file mode 100644 index 00000000..10cb6167 --- /dev/null +++ b/src/drawcommon.h @@ -0,0 +1,31 @@ +#ifndef DRAW_COMMON_H +#define DRAW_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + float x; + float y; + float z; +} point; + +typedef struct { + point pt[3]; +} triangle; + +typedef struct { + int npoly; + triangle *poly; +} object; + +void normalize(point *p); +void midpoint(point *a, point *b, point *mid); +void drawTriangle(triangle *poly); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/drawsphere.c b/src/drawsphere.c new file mode 100644 index 00000000..02f825b1 --- /dev/null +++ b/src/drawsphere.c @@ -0,0 +1,106 @@ +#include "drawcommon.h" +#include "drawsphere.h" +#include +#include +#include + +/* + * This function modified from [Jon Leech's implementation of sphere](ftp://ftp.ee.lbl.gov/sphere.c) + * Jeremy HU (huxingyi@msn.com) 2016/12/16 +*/ + +#define XPLUS { 1, 0, 0 } /* X */ +#define XMIN { -1, 0, 0 } /* -X */ +#define YPLUS { 0, 1, 0 } /* Y */ +#define YMIN { 0, -1, 0 } /* -Y */ +#define ZPLUS { 0, 0, 1 } /* Z */ +#define ZMIN { 0, 0, -1 } /* -Z */ + +static const triangle octahedron[] = { + {{XPLUS, ZPLUS, YPLUS}}, + {{YPLUS, ZPLUS, XMIN}}, + {{XMIN, ZPLUS, YMIN}}, + {{YMIN, ZPLUS, XPLUS}}, + {{XPLUS, YPLUS, ZMIN}}, + {{YPLUS, XMIN, ZMIN}}, + {{XMIN, YMIN, ZMIN}}, + {{YMIN, XPLUS, ZMIN}}, +}; + +static void subdivide(object *old, object *subdivided) { + int i; + for (i = 0; i < old->npoly; ++i) { + triangle *oldt = &old->poly[i]; + triangle *newt = &subdivided->poly[i * 4]; + point a, b, c; + + midpoint(&oldt->pt[0], &oldt->pt[2], &a); + midpoint(&oldt->pt[0], &oldt->pt[1], &b); + midpoint(&oldt->pt[1], &oldt->pt[2], &c); + + normalize(&a); + normalize(&b); + normalize(&c); + + newt->pt[0] = oldt->pt[0]; + newt->pt[1] = b; + newt->pt[2] = a; + newt++; + + newt->pt[0] = b; + newt->pt[1] = oldt->pt[1]; + newt->pt[2] = c; + newt++; + + newt->pt[0] = a; + newt->pt[1] = b; + newt->pt[2] = c; + newt++; + + newt->pt[0] = a; + newt->pt[1] = c; + newt->pt[2] = oldt->pt[2]; + } +} + +int drawSphere(int level) { + int lv, i; + object oldObj, newObj; + + if (level < 1) { + fprintf(stderr, "%s:level max greater than 0.\n", __FUNCTION__); + return -1; + } + + oldObj.npoly = sizeof(octahedron) / sizeof(octahedron[0]); + oldObj.poly = (triangle *)malloc(oldObj.npoly * sizeof(triangle)); + if (!oldObj.poly) { + fprintf(stderr, "%s:insufficient memory.\n", __FUNCTION__); + return -1; + } + memcpy(oldObj.poly, octahedron, oldObj.npoly * sizeof(triangle)); + + for (lv = 0; lv < level; lv++) { + newObj.npoly = oldObj.npoly * 4; + newObj.poly = (triangle *)malloc(newObj.npoly * sizeof(triangle)); + if (!newObj.poly) { + fprintf(stderr, "%s:insufficient memory(levelLoop:%d).\n", + __FUNCTION__, lv); + free(oldObj.poly); + return -1; + } + + subdivide(&oldObj, &newObj); + + free(oldObj.poly); + oldObj = newObj; + } + + for (i = 0; i < newObj.npoly; ++i) { + drawTriangle(&newObj.poly[i]); + } + + free(newObj.poly); + + return 0; +} diff --git a/src/drawsphere.h b/src/drawsphere.h new file mode 100644 index 00000000..839dde5f --- /dev/null +++ b/src/drawsphere.h @@ -0,0 +1,14 @@ +#ifndef DRAW_SPHERE_H +#define DRAW_SPHERE_H + +#ifdef __cplusplus +extern "C" { +#endif + +int drawSphere(int level); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/glwidget.cpp b/src/glwidget.cpp index bce7e853..f2167858 100644 --- a/src/glwidget.cpp +++ b/src/glwidget.cpp @@ -1,132 +1,73 @@ #include #include #include - #include "glwidget.h" +#include "drawcommon.h" +#include "drawsphere.h" + +void drawTriangle(triangle *poly) { + int i; + glBegin(GL_TRIANGLES); + for (i = 0; i < 3; ++i) { + point *pt = &poly->pt[i]; + glNormal3f(pt->x, pt->y, pt->z); + glVertex3f(pt->x, pt->y, pt->z); + } + glEnd(); +} GLWidget::GLWidget(QWidget *parent) - : QGLWidget(QGLFormat(QGL::SampleBuffers), parent) -{ + : QGLWidget(QGLFormat(QGL::SampleBuffers), parent) { } -GLWidget::~GLWidget() -{ +GLWidget::~GLWidget() { } -void GLWidget::initializeGL() -{ - GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 }; - GLfloat mat_shininess[] = { 50.0 }; - GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 }; - GLfloat light[] = { 1.0, 0.2, 0.2 }; - GLfloat lmodel_ambient[] = { 0.1, 0.1, 0.1, 1.0 }; - glClearColor (0.0, 0.0, 0.0, 0.0); - glShadeModel (GL_SMOOTH); +void GLWidget::initializeGL() { + GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0}; + GLfloat mat_shininess[] = {50.0}; + GLfloat light_position[] = {1.0, 1.0, 1.0, 0.0}; + GLfloat light[] = {1.0, 0.2, 0.2}; + GLfloat lmodel_ambient[] = {0.1, 0.1, 0.1, 1.0}; - glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); - glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess); + glClearColor(0.0, 0.0, 0.0, 0.0); + glShadeModel(GL_SMOOTH); - glLightfv(GL_LIGHT0, GL_POSITION, light_position); - glLightfv(GL_LIGHT0, GL_DIFFUSE, light ); - glLightfv(GL_LIGHT0, GL_SPECULAR, light ); - glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient); + glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); + glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess); - glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - glEnable(GL_DEPTH_TEST); + glLightfv(GL_LIGHT0, GL_POSITION, light_position); + glLightfv(GL_LIGHT0, GL_DIFFUSE, light); + glLightfv(GL_LIGHT0, GL_SPECULAR, light); + glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient); + + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glEnable(GL_DEPTH_TEST); } -void normalize(float v[3]) -{ - GLfloat d = sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]); - if (d == 0.0) - { - return; - } - v[0] /= d; v[1] /= d; v[2] /= d; +void GLWidget::paintGL() { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + drawSphere(3); } -void drawtriangle(float *v1, float *v2, float *v3) -{ - glBegin(GL_TRIANGLES); - glNormal3fv(v1); glVertex3fv(v1); - glNormal3fv(v2); glVertex3fv(v2); - glNormal3fv(v3); glVertex3fv(v3); - glEnd(); +void GLWidget::resizeGL(int w, int h) { + glViewport(0, 0, (GLsizei)w, (GLsizei)h); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + if (w <= h) { + glOrtho(-1.5, 1.5, -1.5*(GLfloat)h/(GLfloat)w, + 1.5*(GLfloat)h/(GLfloat)w, -10.0, 10.0); + } else { + glOrtho(-1.5*(GLfloat)w/(GLfloat)h, + 1.5*(GLfloat)w/(GLfloat)h, -1.5, 1.5, -10.0, 10.0); + } + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); } -void subdivide(float *v1, float *v2, float *v3) -{ - GLfloat v12[3], v23[3], v31[3]; - GLint i; - - for (i = 0; i < 3; i++) - { - v12[i] = v1[i]+v2[i]; - v23[i] = v2[i]+v3[i]; - v31[i] = v3[i]+v1[i]; - } - normalize(v12); - normalize(v23); - normalize(v31); - drawtriangle(v1, v12, v31); - drawtriangle(v2, v23, v12); - drawtriangle(v3, v31, v23); - drawtriangle(v12, v23, v31); +void GLWidget::mousePressEvent(QMouseEvent *event) { } -// An example come from http://www.glprogramming.com/red/chapter02.html#name8 - -#define X .525731112119133606 -#define Z .850650808352039932 - -static GLfloat vdata[12][3] = { - {-X, 0.0, Z}, {X, 0.0, Z}, {-X, 0.0, -Z}, {X, 0.0, -Z}, - {0.0, Z, X}, {0.0, Z, -X}, {0.0, -Z, X}, {0.0, -Z, -X}, - {Z, X, 0.0}, {-Z, X, 0.0}, {Z, -X, 0.0}, {-Z, -X, 0.0} -}; -static GLuint tindices[20][3] = { - {0,4,1}, {0,9,4}, {9,5,4}, {4,5,8}, {4,8,1}, - {8,10,1}, {8,3,10}, {5,3,8}, {5,2,3}, {2,7,3}, - {7,10,3}, {7,6,10}, {7,11,6}, {11,0,6}, {0,1,6}, - {6,1,10}, {9,0,11}, {9,11,2}, {9,2,5}, {7,2,11} -}; - -void GLWidget::paintGL() -{ - GLint i; - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - for (i = 0; i < 20; i++) - { - subdivide(&vdata[tindices[i][0]][0], - &vdata[tindices[i][1]][0], - &vdata[tindices[i][2]][0]); - } -} - -void GLWidget::resizeGL(int w, int h) -{ - glViewport(0, 0, (GLsizei)w, (GLsizei)h); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - if (w <= h) - { - glOrtho(-1.5, 1.5, -1.5*(GLfloat)h/(GLfloat)w, - 1.5*(GLfloat)h/(GLfloat)w, -10.0, 10.0); - } - else - { - glOrtho(-1.5*(GLfloat)w/(GLfloat)h, - 1.5*(GLfloat)w/(GLfloat)h, -1.5, 1.5, -10.0, 10.0); - } - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); -} - -void GLWidget::mousePressEvent(QMouseEvent *event) -{ -} - -void GLWidget::mouseMoveEvent(QMouseEvent *event) -{ +void GLWidget::mouseMoveEvent(QMouseEvent *event) { } diff --git a/src/main.cpp b/src/main.cpp index dd64252e..68e39bbb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,11 +1,19 @@ #include +#include +#include #include "mainwindow.h" int main(int argc, char *argv[]) { - QApplication a(argc, argv); - MainWindow w; - w.show(); + QApplication a(argc, argv); + MainWindow w; - return a.exec(); + assert(0 != freopen((a.applicationDirPath() + + "/dust3d.log").toUtf8(), "w", stdout)); + assert(0 != freopen((a.applicationDirPath() + + "/dust3d_error.log").toUtf8(), "w", stderr)); + + w.show(); + + return a.exec(); }