diff --git a/screenshot/dust3d_node_edge.png b/screenshot/dust3d_node_edge.png new file mode 100644 index 00000000..1ba38776 Binary files /dev/null and b/screenshot/dust3d_node_edge.png differ diff --git a/src/array.c b/src/array.c new file mode 100644 index 00000000..d678c9ce --- /dev/null +++ b/src/array.c @@ -0,0 +1,54 @@ +#include +#include +#include +#include "array.h" + +struct array { + int nodeSize; + int capacity; + int length; + char *nodes; +}; + +array *arrayCreate(int nodeSize) { + array *arr = (array *)calloc(1, sizeof(array)); + if (!arr) { + fprintf(stderr, "%s:Insufficient memory.\n", __FUNCTION__); + return 0; + } + arr->nodeSize = nodeSize; + return arr; +} + +int arraySetLength(array *arr, int length) { + if (length > arr->capacity) { + int newCapacity = (arr->capacity + 1) * 2; + char *newNodes = (char *)realloc(arr->nodes, arr->nodeSize * newCapacity); + if (!newNodes) { + fprintf(stderr, "%s:Insufficient memory.\n", __FUNCTION__); + return -1; + } + arr->capacity = newCapacity; + arr->nodes = newNodes; + } + arr->length = length; + return 0; +} + +void *arrayGetItem(array *arr, int index) { + if (index >= arr->length) { + return 0; + } + return arr->nodes + arr->nodeSize * index; +} + +int arrayGetLength(array *arr) { + return arr->length; +} + +void arrayDestroy(array *arr) { + if (arr) { + free(arr->nodes); + free(arr); + } +} diff --git a/src/array.h b/src/array.h new file mode 100644 index 00000000..0fa4fabe --- /dev/null +++ b/src/array.h @@ -0,0 +1,20 @@ +#ifndef ARRAY_H +#define ARRAY_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct array array; + +array *arrayCreate(int nodeSize); +void *arrayGetItem(array *arr, int index); +int arrayGetLength(array *arr); +int arraySetLength(array *arr, int length); +void arrayDestroy(array *arr); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/bmesh.c b/src/bmesh.c new file mode 100644 index 00000000..e90de4cc --- /dev/null +++ b/src/bmesh.c @@ -0,0 +1,75 @@ +#include +#include +#include +#include "bmesh.h" +#include "array.h" + +struct bmesh { + array *nodeArray; + array *edgeArray; +}; + +bmesh *bmeshCreate(void) { + bmesh *bm = (bmesh *)calloc(1, sizeof(bmesh)); + if (!bm) { + fprintf(stderr, "%s:Insufficient memory.\n", __FUNCTION__); + return 0; + } + bm->nodeArray = arrayCreate(sizeof(bmeshNode)); + if (!bm->nodeArray) { + fprintf(stderr, "%s:arrayCreate bmeshNode failed.\n", __FUNCTION__); + bmeshDestroy(bm); + return 0; + } + bm->edgeArray = arrayCreate(sizeof(bmeshEdge)); + if (!bm->edgeArray) { + fprintf(stderr, "%s:arrayCreate bmeshEdge failed.\n", __FUNCTION__); + bmeshDestroy(bm); + return 0; + } + return bm; +} + +void bmeshDestroy(bmesh *bm) { + arrayDestroy(bm->nodeArray); + arrayDestroy(bm->edgeArray); + free(bm); +} + +int bmeshGetNodeNum(bmesh *bm) { + return arrayGetLength(bm->nodeArray); +} + +int bmeshGetEdgeNum(bmesh *bm) { + return arrayGetLength(bm->edgeArray); +} + +bmeshNode *bmeshGetNode(bmesh *bm, int index) { + return (bmeshNode *)arrayGetItem(bm->nodeArray, index); +} + +bmeshEdge *bmeshGetEdge(bmesh *bm, int index) { + return (bmeshEdge *)arrayGetItem(bm->edgeArray, index); +} + +int bmeshAddNode(bmesh *bm, bmeshNode *node) { + int index = arrayGetLength(bm->nodeArray); + node->index = index; + if (0 != arraySetLength(bm->nodeArray, index + 1)) { + fprintf(stderr, "%s:arraySetLength failed.\n", __FUNCTION__); + return -1; + } + memcpy(arrayGetItem(bm->nodeArray, index), node, sizeof(bmeshNode)); + return index; +} + +int bmeshAddEdge(bmesh *bm, bmeshEdge *edge) { + int index = arrayGetLength(bm->edgeArray); + edge->index = index; + if (0 != arraySetLength(bm->edgeArray, index + 1)) { + fprintf(stderr, "%s:arraySetLength failed.\n", __FUNCTION__); + return -1; + } + memcpy(arrayGetItem(bm->edgeArray, index), edge, sizeof(bmeshEdge)); + return index; +} diff --git a/src/bmesh.h b/src/bmesh.h new file mode 100644 index 00000000..c7c22b32 --- /dev/null +++ b/src/bmesh.h @@ -0,0 +1,43 @@ +#ifndef B_MESH_H +#define B_MESH_H +#include "vector3d.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + BMESH_NODE_FLAG_KEY = 0x00000001, + BMESH_NODE_FLAG_INBETWEEN = 0x00000002, + BMESH_NODE_FLAG_ROOT = 0x00000010, +} bmeshNodeFlag; + +typedef struct bmesh bmesh; + +typedef struct { + int index; + vec3 position; + float radius; + unsigned int flag; +} bmeshNode; + +typedef struct { + int index; + int firstNode; + int secondNode; +} bmeshEdge; + +bmesh *bmeshCreate(void); +void bmeshDestroy(bmesh *bm); +int bmeshGetNodeNum(bmesh *bm); +int bmeshGetEdgeNum(bmesh *bm); +bmeshNode *bmeshGetNode(bmesh *bm, int index); +bmeshEdge *bmeshGetEdge(bmesh *bm, int index); +int bmeshAddNode(bmesh *bm, bmeshNode *node); +int bmeshAddEdge(bmesh *bm, bmeshEdge *edge); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/draw.cpp b/src/draw.cpp new file mode 100644 index 00000000..d6b91f2f --- /dev/null +++ b/src/draw.cpp @@ -0,0 +1,223 @@ +#include +#include +#include +#include +#include +#include "draw.h" + +/* + * This drawSphere 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]; + vec3 a, b, c; + + vec3Midpoint(&oldt->pt[0], &oldt->pt[2], &a); + vec3Midpoint(&oldt->pt[0], &oldt->pt[1], &b); + vec3Midpoint(&oldt->pt[1], &oldt->pt[2], &c); + + vec3Normalize(&a); + vec3Normalize(&b); + vec3Normalize(&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(vec3 *origin, float radius, 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; + } + + glPushMatrix(); + glTranslatef(origin->x, origin->y, origin->z); + glScalef(radius, radius, radius); + for (i = 0; i < newObj.npoly; ++i) { + drawTriangle(&newObj.poly[i]); + } + glPopMatrix(); + + free(newObj.poly); + + return 0; +} + +void drawTriangle(triangle *poly) { + int i; + glBegin(GL_TRIANGLES); + for (i = 0; i < 3; ++i) { + vec3 *pt = &poly->pt[i]; + glNormal3f(pt->x, pt->y, pt->z); + glVertex3f(pt->x, pt->y, pt->z); + } + glEnd(); +} + +int drawCylinder(vec3 *topOrigin, vec3 *bottomOrigin, float radius, int slices) { + float theta = (2.0 * M_PI) / (float)slices; + float a = 0.0f; + int lv; + float x, y, z; + vec3 zAxis = {0, 0, 1}; + vec3 p, t; + float height = 0; + float angle = 0; + + if (slices <= 0) { + fprintf(stderr, "%s:Invalid parameter(slices:%d).\n", __FUNCTION__, slices); + return -1; + } + + vec3Sub(topOrigin, bottomOrigin, &p); + vec3CrossProduct(&zAxis, &p, &t); + height = vec3Length(&p); + if (height > 0) { + angle = 180 / M_PI * acos(vec3DotProduct(&zAxis, &p) / height); + } + + glPushMatrix(); + + glTranslatef(bottomOrigin->x, bottomOrigin->y, + bottomOrigin->z); + glRotatef(angle, t.x, t.y, t.z); + + // strips + glBegin(GL_TRIANGLE_STRIP); + for (a = 0, lv = 0; lv <= slices; ++lv) { + float cosa = cos(a); + float sina = sin(a); + x = cosa * radius; + y = sina * radius; + z = 0; + glNormal3f(cosa, sina, 0); + glVertex3f(x, y, z); + z = height; + glNormal3f(cosa, sina, 0); + glVertex3f(x, y, z); + a += theta; + } + glEnd(); + + // bottom cap + z = 0; + glBegin(GL_TRIANGLE_FAN); + glNormal3f(0, 0, -1); + glVertex3f(0, 0, z); + for (a = 0, lv = 0; lv <= slices; ++lv) { + x = cos(a) * radius; + y = sin(a) * radius; + glNormal3f(0, 0, -1); + glVertex3f(x, y, z); + a += theta; + } + glEnd(); + + // top cap + z = height; + glBegin(GL_TRIANGLE_FAN); + glNormal3f(0, 0, 1); + glVertex3f(0, 0, z); + for (a = 0, lv = 0; lv <= slices; ++lv) { + x = cos(a) * radius; + y = sin(a) * radius; + glNormal3f(0, 0, 1); + glVertex3f(x, y, z); + a += theta; + } + glEnd(); + + glPopMatrix(); + + return 0; +} + +int drawGrid(float size, float step) { + glDisable(GL_LIGHTING); + + // x z plane + glBegin(GL_LINES); + for (GLfloat i = -size; i <= size; i += step) { + if (0 == i) { + glColor3f(0.0, 0.0, 1.0); + glVertex3f(i, 0, size); glVertex3f(i, 0, -size); + glColor3f(1.0, 0.0, 0.0); + glVertex3f(size, 0, i); glVertex3f(-size, 0, i); + } else { + glColor3f(0.39, 0.39, 0.39); + glVertex3f(i, 0, size); glVertex3f(i, 0, -size); + glVertex3f(size, 0, i); glVertex3f(-size, 0, i); + } + } + glEnd(); + + glEnable(GL_LIGHTING); + return 0; +} diff --git a/src/draw.h b/src/draw.h new file mode 100644 index 00000000..243c1d9d --- /dev/null +++ b/src/draw.h @@ -0,0 +1,27 @@ +#ifndef DRAW_SPHERE_H +#define DRAW_SPHERE_H +#include "vector3d.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + vec3 pt[3]; +} triangle; + +typedef struct { + int npoly; + triangle *poly; +} object; + +int drawSphere(vec3 *origin, float radius, int level); +void drawTriangle(triangle *poly); +int drawCylinder(vec3 *topOrigin, vec3 *bottomOrigin, float radius, int slices); +int drawGrid(float size, float step); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/drawcommon.h b/src/drawcommon.h index befdacc5..38de7647 100644 --- a/src/drawcommon.h +++ b/src/drawcommon.h @@ -1,18 +1,13 @@ #ifndef DRAW_COMMON_H #define DRAW_COMMON_H +#include "vector3d.h" #ifdef __cplusplus extern "C" { #endif typedef struct { - float x; - float y; - float z; -} point; - -typedef struct { - point pt[3]; + vec3 pt[3]; } triangle; typedef struct { @@ -20,8 +15,6 @@ typedef struct { triangle *poly; } object; -void normalize(point *p); -void midpoint(point *a, point *b, point *mid); void drawTriangle(triangle *poly); int drawCylinder(int slices, float radius, float height); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 47d849ad..163a14f4 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -2,29 +2,21 @@ #include #include #include "mainwindow.h" +#include "render.h" -MainWindow::MainWindow(void) -{ - glWidget = new GLWidget; - - resize(QDesktopWidget().availableGeometry(this).size() * 0.7); - +MainWindow::MainWindow(void) { + render = new Render; + resize(QDesktopWidget().availableGeometry(this).size() * 0.7); QHBoxLayout *mainLayout = new QHBoxLayout; - mainLayout->addWidget(glWidget); - setLayout(mainLayout); - - setWindowTitle(tr("DUST3D")); + mainLayout->addWidget(render); + setLayout(mainLayout); + setWindowTitle(tr("Dust3D Experiment")); } -void MainWindow::keyPressEvent(QKeyEvent *e) -{ - if (e->key() == Qt::Key_Escape) - { - close(); - } - else - { - QWidget::keyPressEvent(e); - } +void MainWindow::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Escape) { + close(); + } else { + QWidget::keyPressEvent(e); + } } - diff --git a/src/mainwindow.h b/src/mainwindow.h index dbcb3343..448f7bdb 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -2,20 +2,20 @@ #define MAINWINDOW_H #include -#include "glwidget.h" -class MainWindow : public QWidget -{ +class Render; + +class MainWindow : public QWidget { Q_OBJECT public: MainWindow(void); protected: - void keyPressEvent(QKeyEvent *event); + void keyPressEvent(QKeyEvent *event); private: - GLWidget *glWidget; + Render *render; }; #endif diff --git a/src/matrix.c b/src/matrix.c new file mode 100644 index 00000000..e28a5cad --- /dev/null +++ b/src/matrix.c @@ -0,0 +1,184 @@ +#include "matrix.h" +#include +#include + +#define DEG2RAD (M_PI / 180.0) + +matrix *matrixLoadIdentity(matrix *mat) { + memset(mat->data, 0, sizeof(mat->data)); + mat->data[0] = 1; + mat->data[5] = 1; + mat->data[10] = 1; + mat->data[15] = 1; + return mat; +} + +matrix *matrixTranslate(matrix *mat, float x, float y, float z) { + matrixLoadIdentity(mat); + mat->data[12] = x; + mat->data[13] = y; + mat->data[14] = z; + return mat; +} + +matrix *matrixRotateX(matrix *mat, float degree) { + float c; + float s; + + matrixLoadIdentity(mat); + + if (degree <= 0) { + return mat; + } + + c = cos(degree * DEG2RAD); + s = sin(degree * DEG2RAD); + + mat->data[5] = c; + mat->data[6] = s; + mat->data[9] = -s; + mat->data[10] = c; + + return mat; +} + +matrix *matrixRotateY(matrix *mat, float degree) { + float c; + float s; + + matrixLoadIdentity(mat); + + if (degree <= 0) { + return mat; + } + + c = cos(degree * DEG2RAD); + s = sin(degree * DEG2RAD); + + mat->data[0] = c; + mat->data[2] = -s; + mat->data[8] = s; + mat->data[10] = c; + + return mat; +} + +matrix *matrixRotateZ(matrix *mat, float degree) { + float c; + float s; + + matrixLoadIdentity(mat); + + if (degree <= 0) { + return mat; + } + + c = cos(degree * DEG2RAD); + s = sin(degree * DEG2RAD); + + mat->data[0] = c; + mat->data[1] = s; + mat->data[4] = -s; + mat->data[5] = c; + + return mat; +} + +matrix *matrixScale(matrix *mat, float x, float y, float z) { + matrixLoadIdentity(mat); + mat->data[0] = x; + mat->data[5] = y; + mat->data[10] = z; + return mat; +} + +float *matrixTransformVector(matrix *mat, float *vec) { + float x = (vec[0] * mat->data[0]) + + (vec[1] * mat->data[4]) + (vec[2] * mat->data[8]) + mat->data[12]; + float y = (vec[0] * mat->data[1]) + + (vec[1] * mat->data[5]) + (vec[2] * mat->data[9]) + mat->data[13]; + float z = (vec[0] * mat->data[2]) + + (vec[1] * mat->data[6]) + (vec[2] * mat->data[10]) + mat->data[14]; + vec[0] = x; + vec[1] = y; + vec[2] = z; + return vec; +} + +matrix *matrixAppend(matrix *mat, matrix *matB) { + matrix structMatA; + matrix *matA = &structMatA; + + memcpy(matA, mat, sizeof(matrix)); + + mat->data[0] = matA->data[0] * matB->data[0] + + matA->data[4] * matB->data[1] + + matA->data[8] * matB->data[2] + + matA->data[12] * matB->data[3]; + mat->data[4] = matA->data[0] * matB->data[4] + + matA->data[4] * matB->data[5] + + matA->data[8] * matB->data[6] + + matA->data[12] * matB->data[7]; + mat->data[8] = matA->data[0] * matB->data[8] + + matA->data[4] * matB->data[9] + + matA->data[8] * matB->data[10] + + matA->data[12] * matB->data[11]; + mat->data[12] = matA->data[0] * matB->data[12] + + matA->data[4] * matB->data[13] + + matA->data[8] * matB->data[14] + + matA->data[12] * matB->data[15]; + + mat->data[1] = matA->data[1] * matB->data[0] + + matA->data[5] * matB->data[1] + + matA->data[9] * matB->data[2] + + matA->data[13] * matB->data[3]; + mat->data[5] = matA->data[1] * matB->data[4] + + matA->data[5] * matB->data[5] + + matA->data[9] * matB->data[6] + + matA->data[13] * matB->data[7]; + mat->data[9] = matA->data[1] * matB->data[8] + + matA->data[5] * matB->data[9] + + matA->data[9] * matB->data[10] + + matA->data[13] * matB->data[11]; + mat->data[13] = matA->data[1] * matB->data[12] + + matA->data[5] * matB->data[13] + + matA->data[9] * matB->data[14] + + matA->data[13] * matB->data[15]; + + mat->data[2] = matA->data[2] * matB->data[0] + + matA->data[6] * matB->data[1] + + matA->data[10] * matB->data[2] + + matA->data[14] * matB->data[3]; + mat->data[6] = matA->data[2] * matB->data[4] + + matA->data[6] * matB->data[5] + + matA->data[10] * matB->data[6] + + matA->data[14] * matB->data[7]; + mat->data[10] = matA->data[2] * matB->data[8] + + matA->data[6] * matB->data[9] + + matA->data[10] * matB->data[10] + + matA->data[14] * matB->data[11]; + mat->data[14] = matA->data[2] * matB->data[12] + + matA->data[6] * matB->data[13] + + matA->data[10] * matB->data[14] + + matA->data[14] * matB->data[15]; + + mat->data[3] = matA->data[3] * matB->data[0] + + matA->data[7] * matB->data[1] + + matA->data[11] * matB->data[2] + + matA->data[15] * matB->data[3]; + mat->data[7] = matA->data[3] * matB->data[4] + + matA->data[7] * matB->data[5] + + matA->data[11] * matB->data[6] + + matA->data[15] * matB->data[7]; + mat->data[11] = matA->data[3] * matB->data[8] + + matA->data[7] * matB->data[9] + + matA->data[11] * matB->data[10] + + matA->data[15] * matB->data[11]; + mat->data[15] = matA->data[3] * matB->data[12] + + matA->data[7] * matB->data[13] + + matA->data[11] * matB->data[14] + + matA->data[15] * matB->data[15]; + + return mat; +} + diff --git a/src/matrix.h b/src/matrix.h new file mode 100644 index 00000000..87107f71 --- /dev/null +++ b/src/matrix.h @@ -0,0 +1,19 @@ +#ifndef __MATRIX_H__ +#define __MATRIX_H__ + +// Modified from http://wiki.unity3d.com/index.php?title=Matrix + +typedef struct matrix { + float data[16]; +} matrix; + +matrix *matrixLoadIdentity(matrix *mat); +matrix *matrixTranslate(matrix *mat, float x, float y, float z); +matrix *matrixRotateX(matrix *mat, float degree); +matrix *matrixRotateY(matrix *mat, float degree); +matrix *matrixRotateZ(matrix *mat, float degree); +matrix *matrixScale(matrix *mat, float x, float y, float z); +float *matrixTransformVector(matrix *mat, float *vec); +matrix *matrixAppend(matrix *mat, matrix *matB); + +#endif diff --git a/src/render.cpp b/src/render.cpp new file mode 100644 index 00000000..4293474c --- /dev/null +++ b/src/render.cpp @@ -0,0 +1,160 @@ +#include +#include +#include +#include +#include "render.h" +#include "draw.h" +#include "bmesh.h" +#include "matrix.h" + +static int drawBmeshNode(bmesh *bm, bmeshNode *node) { + float color1[3] = {1, 0, 0}; + glColor3fv(color1); + drawSphere(&node->position, node->radius, 3); + return 0; +} + +static int drawBmeshEdge(bmesh *bm, bmeshEdge *edge) { + float color2[3] = {0, 0, 1}; + glColor3fv(color2); + bmeshNode *firstNode = bmeshGetNode(bm, edge->firstNode); + bmeshNode *secondNode = bmeshGetNode(bm, edge->secondNode); + drawCylinder(&firstNode->position, &secondNode->position, 0.04, 40); + return 0; +} + +Render::Render(QWidget *parent) + : QGLWidget(QGLFormat(QGL::SampleBuffers), parent) { + QTimer *timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(update())); + timer->start(100); + + mouseX = 0; + mouseY = 0; + cameraAngleX = 50; + cameraAngleY = 70; + cameraDistance = 3; +} + +Render::~Render(void) { +} + +void Render::initializeGL() { + glShadeModel(GL_SMOOTH); + glEnable(GL_CULL_FACE); + glEnable(GL_BLEND); + + qglClearColor(QWidget::palette().color(QWidget::backgroundRole())); + glClearDepth(1.0f); + + GLfloat ambientLight[] = {0.0f, 0.0f, 0.0f, 1.0f}; + GLfloat diffuseLight[] = {0.9f, 0.9f, 0.9f, 1.0f}; + GLfloat specularLight[] = {1, 1, 1, 1}; + glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight); + glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight); + glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight); + + float lightDirection[4] = {0, 0, 1, 0}; + glLightfv(GL_LIGHT0, GL_POSITION, lightDirection); + + glEnable(GL_LIGHT0); + + float shininess = 64.0f; + float specularColor[] = {1.0, 1.0f, 1.0f, 1.0f}; + glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess); // range 0 ~ 128 + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specularColor); + + glClearStencil(0); + glClearDepth(1.0f); + glDepthFunc(GL_LEQUAL); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glEnable(GL_DEPTH_TEST); + glEnable(GL_LIGHTING); + glEnable(GL_CULL_FACE); + + glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); + glEnable(GL_COLOR_MATERIAL); +} + +void Render::paintGL() { + static bmesh *bm = 0; + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glPushMatrix(); + + glTranslatef(0, 0, -cameraDistance); + glRotatef(cameraAngleX, 1, 0, 0); + glRotatef(cameraAngleY, 0, 1, 0); + + drawGrid(10, 1); + + glEnable(GL_LIGHTING); + + if (0 == bm) { + bmeshNode node; + bmeshEdge edge; + bm = bmeshCreate(); + + memset(&node, 0, sizeof(node)); + node.position.x = -1.0; + node.position.y = 0.3; + node.position.z = 1.0; + node.radius = 0.45; + bmeshAddNode(bm, &node); + + memset(&node, 0, sizeof(node)); + node.position.x = -0.5; + node.position.y = 0.2; + node.position.z = 0.5; + node.radius = 0.1; + bmeshAddNode(bm, &node); + + memset(&edge, 0, sizeof(edge)); + edge.firstNode = 1; + edge.secondNode = 0; + bmeshAddEdge(bm, &edge); + } + + { + int index; + for (index = 0; index < bmeshGetNodeNum(bm); ++index) { + bmeshNode *node = bmeshGetNode(bm, index); + drawBmeshNode(bm, node); + } + for (index = 0; index < bmeshGetEdgeNum(bm); ++index) { + bmeshEdge *edge = bmeshGetEdge(bm, index); + drawBmeshEdge(bm, edge); + } + } + + glPopMatrix(); +} + +void Render::resizeGL(int w, int h) { + glViewport(0, 0, (GLsizei)w, (GLsizei)h); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum(-2, 2, -1.5, 1.5, 1, 1000); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); +} + +void Render::mousePressEvent(QMouseEvent *event) { + mouseX = event->x(); + mouseY = event->y(); +} + +void Render::mouseMoveEvent(QMouseEvent *event) { + cameraAngleY += (event->x() - mouseX); + cameraAngleX += (event->y() - mouseY); + update(); + mouseX = event->x(); + mouseY = event->y(); +} + +void Render::wheelEvent(QWheelEvent * event) { + cameraDistance -= event->delta() * 0.01f; +} diff --git a/src/render.h b/src/render.h new file mode 100644 index 00000000..ff2f9665 --- /dev/null +++ b/src/render.h @@ -0,0 +1,29 @@ +#ifndef RENDER_H +#define RENDER_H + +#include + +class Render : public QGLWidget { + Q_OBJECT + +public: + Render(QWidget *parent = 0); + ~Render(void); + +protected: + void initializeGL(void); + void paintGL(void); + void resizeGL(int width, int height); + void mousePressEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void wheelEvent(QWheelEvent * event); + +private: + int mouseX; + int mouseY; + float cameraAngleX; + float cameraAngleY; + float cameraDistance; +}; + +#endif diff --git a/src/vector3d.c b/src/vector3d.c new file mode 100644 index 00000000..1be5570f --- /dev/null +++ b/src/vector3d.c @@ -0,0 +1,40 @@ +#include "vector3d.h" + +float vec3Length(vec3 *p) { + double mag; + mag = p->x * p->x + p->y * p->y + p->z * p->z; + return sqrt(mag); +} + +void vec3Normalize(vec3 *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 vec3Midpoint(vec3 *a, vec3 *b, vec3 *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; +} + +void vec3Sub(vec3 *a, vec3 *b, vec3 *result) { + result->x = a->x - b->x; + result->y = a->y - b->y; + result->z = a->z - b->z; +} + +void vec3CrossProduct(vec3 *a, vec3 *b, vec3 *result) { + result->x = a->y * b->z - a->z * b->y; + result->y = a->z * b->x - a->x * b->z; + result->z = a->x * b->y - a->y * b->x; +} + +float vec3DotProduct(vec3 *a, vec3 *b) { + return a->x * b->x + a->y * b->y + a->z * b->z; +} diff --git a/src/vector3d.h b/src/vector3d.h new file mode 100644 index 00000000..67f8d5c3 --- /dev/null +++ b/src/vector3d.h @@ -0,0 +1,25 @@ +#ifndef VECTOR_3D_H +#define VECTOR_3D_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + float x; + float y; + float z; +} vec3; + +void vec3Normalize(vec3 *p); +void vec3Midpoint(vec3 *a, vec3 *b, vec3 *mid); +void vec3CrossProduct(vec3 *a, vec3 *b, vec3 *result); +void vec3Sub(vec3 *a, vec3 *b, vec3 *result); +float vec3DotProduct(vec3 *a, vec3 *b); +float vec3Length(vec3 *p); + +#ifdef __cplusplus +} +#endif + +#endif