diff --git a/README.md b/README.md
index 6de8f926..50fd1ccd 100644
--- a/README.md
+++ b/README.md
@@ -21,18 +21,20 @@ Two caps and many strips composites a cylinder.
Almost all 3D editor have a infinite grid ground, I just made a finite one, in the future, I should expand the grid outside of the screen to make it infinite.
Now, for just beginning, I think it's a not bad start.
-- [ ] Implement B-Mesh algorithm (Dec 18, 2016 ~ Dec 19, 2016)
+- [ ] Implement B-Mesh algorithm (Dec 18, 2016 ~ Dec 20, 2016)
*Drawing Skeletal Shape Balls*
Draw shape ball is easy, no need to rotate, I just need scale it along the ball's radius.
Draw the cylinder which connects two shape balls is more difficult, I need do some math to rotate it. [Here](http://www.thjsmith.com/40/cylinder-between-two-points-opengl-c) described it.
*Camera Control*
Camera rotate/zoom implemented, [here](http://www.songho.ca/opengl/gl_transform.html) is a good article which explained the theory of OpenGL Transformation. Most important is that the demo app is very beautiful.
Added x,z axis, looks better than last screenshot.
-I have to use the GLU library, the previous implementation of drawSphere and drawCylinder looks not good, and take too much time to debug.
-
+I have to use the GLU library, the previous implementation of drawSphere and drawCylinder looks not good, and take too much time to debug.
+
*B-Mesh data struct*
-I created the test nodes's geometry information from Blender. Here is the render result of `data/bmesh_test_1.h`
-
+I created the test nodes's geometry information from Blender. Here is the render result of `data/bmesh_test_1.h`
+
+*Generate Inbetween Nodes*
+
- [ ] Export Wavefront .obj
- [ ] Render B-Mesh result
- [ ] Design UI for monster parts configuration
diff --git a/data/bmesh_test_1.h b/data/bmesh_test_1.h
index 32df44ff..937b74fd 100644
--- a/data/bmesh_test_1.h
+++ b/data/bmesh_test_1.h
@@ -1,9 +1,9 @@
-const float bmeshTest1Nodes[][4] = {
- {0, -2.07575, 1.53902, 0.04122}, {1, 2.40837, 2.34882, 0.48585},
- {2, -0.91403, 0.77069, 0.62299}, {3, 2.25224, 0.74973, 0.85115},
- {4, 0, 0, 0},
- {5, 0.00920, -0.66115, -2.04601},
- {6, 0.01726, -0.88224, -2.87471}
+const float bmeshTest1Nodes[][6] = {
+ {0, -2.07575, 1.53902, 0.04122, 0.25}, {1, 2.40837, 2.34882, 0.48585, 0.3},
+ {2, -0.91403, 0.77069, 0.62299, 0.5}, {3, 2.25224, 0.74973, 0.85115, 0.5},
+ {4, 0, 0, 0, 0.8, 1},
+ {5, 0.00920, -0.66115, -2.04601, 0.5},
+ {6, 0.01726, -0.88224, -2.87471, 0.2}
};
const int bmeshTest1Edges[][2] = {
diff --git a/screenshot/dust3d_bmesh_inbetween.png b/screenshot/dust3d_bmesh_inbetween.png
new file mode 100644
index 00000000..af9b9885
Binary files /dev/null and b/screenshot/dust3d_bmesh_inbetween.png differ
diff --git a/screenshot/dust3d_bmesh_skeleton.png b/screenshot/dust3d_bmesh_skeleton.png
new file mode 100644
index 00000000..ab281741
Binary files /dev/null and b/screenshot/dust3d_bmesh_skeleton.png differ
diff --git a/src/bmesh.c b/src/bmesh.c
index e90de4cc..f136b9b4 100644
--- a/src/bmesh.c
+++ b/src/bmesh.c
@@ -73,3 +73,39 @@ int bmeshAddEdge(bmesh *bm, bmeshEdge *edge) {
memcpy(arrayGetItem(bm->edgeArray, index), edge, sizeof(bmeshEdge));
return index;
}
+
+static int bmeshAddInbetweenNodeBetween(bmesh *bm,
+ bmeshNode *firstNode, bmeshNode *secondNode, float frac) {
+ bmeshNode newNode;
+ memset(&newNode, 0, sizeof(newNode));
+ newNode.type = BMESH_NODE_TYPE_INBETWEEN;
+ newNode.radius = firstNode->radius * (1 - frac) +
+ secondNode->radius * frac;
+ vec3Lerp(&firstNode->position, &secondNode->position, frac,
+ &newNode.position);
+ return bmeshAddNode(bm, &newNode);
+}
+
+int bmeshGenerateInbetweenNodes(bmesh *bm) {
+ int edgeIdx;
+ for (edgeIdx = 0; edgeIdx < bmeshGetEdgeNum(bm); ++edgeIdx) {
+ bmeshEdge *edge = bmeshGetEdge(bm, edgeIdx);
+ bmeshNode *firstNode = bmeshGetNode(bm, edge->firstNode);
+ bmeshNode *secondNode = bmeshGetNode(bm, edge->secondNode);
+ float step = 0.5;
+ float distance = vec3Distance(&firstNode->position, &secondNode->position);
+ if (distance > 0) {
+ float offset = step;
+ if (offset + step <= distance) {
+ while (offset + step <= distance) {
+ float frac = offset / distance;
+ bmeshAddInbetweenNodeBetween(bm, firstNode, secondNode, frac);
+ offset += step;
+ }
+ } else if (distance > step) {
+ bmeshAddInbetweenNodeBetween(bm, firstNode, secondNode, 0.5);
+ }
+ }
+ }
+ return 0;
+}
diff --git a/src/bmesh.h b/src/bmesh.h
index c7c22b32..83b8de8b 100644
--- a/src/bmesh.h
+++ b/src/bmesh.h
@@ -7,10 +7,10 @@ extern "C" {
#endif
typedef enum {
- BMESH_NODE_FLAG_KEY = 0x00000001,
- BMESH_NODE_FLAG_INBETWEEN = 0x00000002,
- BMESH_NODE_FLAG_ROOT = 0x00000010,
-} bmeshNodeFlag;
+ BMESH_NODE_TYPE_KEY = 0,
+ BMESH_NODE_TYPE_ROOT = 1,
+ BMESH_NODE_TYPE_INBETWEEN = 2,
+} bmeshNodeType;
typedef struct bmesh bmesh;
@@ -18,7 +18,7 @@ typedef struct {
int index;
vec3 position;
float radius;
- unsigned int flag;
+ int type;
} bmeshNode;
typedef struct {
@@ -35,6 +35,7 @@ bmeshNode *bmeshGetNode(bmesh *bm, int index);
bmeshEdge *bmeshGetEdge(bmesh *bm, int index);
int bmeshAddNode(bmesh *bm, bmeshNode *node);
int bmeshAddEdge(bmesh *bm, bmeshEdge *edge);
+int bmeshGenerateInbetweenNodes(bmesh *bm);
#ifdef __cplusplus
}
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 163a14f4..ce4872ae 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -6,7 +6,8 @@
MainWindow::MainWindow(void) {
render = new Render;
- resize(QDesktopWidget().availableGeometry(this).size() * 0.7);
+ int size = QDesktopWidget().availableGeometry(this).size().height() * 0.7;
+ resize(QSize(size, size));
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addWidget(render);
setLayout(mainLayout);
diff --git a/src/render.cpp b/src/render.cpp
index 9fd51405..4c7a6cda 100644
--- a/src/render.cpp
+++ b/src/render.cpp
@@ -7,18 +7,24 @@
#include "bmesh.h"
#include "matrix.h"
+static const float bmeshNodeColors[][3] {
+ {0, 0.78, 1},
+ {1, 0, 0},
+ {1, 1, 1}
+};
+
+static const float bmeshEdgeColor[3] = {1, 1, 0};
+
static QGLWidget *_this = 0;
static int drawBmeshNode(bmesh *bm, bmeshNode *node) {
- float color1[3] = {1, 0, 0};
- glColor3fv(color1);
+ glColor3fv(bmeshNodeColors[node->type]);
drawSphere(&node->position, node->radius, 36, 24);
return 0;
}
static int drawBmeshEdge(bmesh *bm, bmeshEdge *edge) {
- float color2[3] = {1, 1, 0};
- glColor3fv(color2);
+ glColor3fv(bmeshEdgeColor);
bmeshNode *firstNode = bmeshGetNode(bm, edge->firstNode);
bmeshNode *secondNode = bmeshGetNode(bm, edge->secondNode);
drawCylinder(&firstNode->position, &secondNode->position, 0.1, 36, 24);
@@ -26,7 +32,10 @@ static int drawBmeshEdge(bmesh *bm, bmeshEdge *edge) {
}
int drawText(int x, int y, char *text) {
- _this->renderText(x, y, QString(text));
+ QFont font = QFont("Arial");
+ font.setPointSize(9);
+ font.setBold(false);
+ _this->renderText(x, y, QString(text), font);
return 0;
}
@@ -40,7 +49,7 @@ Render::Render(QWidget *parent)
mouseY = 0;
cameraAngleX = 20;
cameraAngleY = -225;
- cameraDistance = 3;
+ cameraDistance = 7;
}
Render::~Render(void) {
@@ -99,8 +108,8 @@ void Render::paintGL() {
glRotatef(cameraAngleY, 0, 1, 0);
glColor3f(0, 0, 0);
- drawPrintf(0, 10, "cameraAngleX:%f cameraAngleY:%f", cameraAngleX,
- cameraAngleY);
+ drawPrintf(0, 10, "cameraAngleX:%f cameraAngleY:%f cameraDistance:%f",
+ cameraAngleX, cameraAngleY, cameraDistance);
drawGrid(10, 1);
@@ -117,7 +126,8 @@ void Render::paintGL() {
node.position.x = bmeshTest1Nodes[i][1];
node.position.y = bmeshTest1Nodes[i][2];
node.position.z = bmeshTest1Nodes[i][3];
- node.radius = 0.35;
+ node.radius = bmeshTest1Nodes[i][4];
+ node.type = bmeshTest1Nodes[i][5];
bmeshAddNode(bm, &node);
}
@@ -127,6 +137,8 @@ void Render::paintGL() {
edge.secondNode = bmeshTest1Edges[i][1];
bmeshAddEdge(bm, &edge);
}
+
+ bmeshGenerateInbetweenNodes(bm);
}
{
@@ -149,7 +161,7 @@ void Render::resizeGL(int w, int h) {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
- gluPerspective(60.0f, w/(h/2.0f), 1, 100);
+ gluPerspective(60.0f, w/h, 1, 100);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
diff --git a/src/vector3d.c b/src/vector3d.c
index 1be5570f..c8cb9845 100644
--- a/src/vector3d.c
+++ b/src/vector3d.c
@@ -1,3 +1,4 @@
+#include
#include "vector3d.h"
float vec3Length(vec3 *p) {
@@ -18,9 +19,13 @@ void vec3Normalize(vec3 *p) {
}
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;
+ vec3Lerp(a, b, 0.5, mid);
+}
+
+void vec3Lerp(vec3 *a, vec3 *b, float frac, vec3 *result) {
+ result->x = a->x + (b->x - a->x) * frac;
+ result->y = a->y + (b->y - a->y) * frac;
+ result->z = a->z + (b->z - a->z) * frac;
}
void vec3Sub(vec3 *a, vec3 *b, vec3 *result) {
@@ -38,3 +43,9 @@ void vec3CrossProduct(vec3 *a, vec3 *b, vec3 *result) {
float vec3DotProduct(vec3 *a, vec3 *b) {
return a->x * b->x + a->y * b->y + a->z * b->z;
}
+
+float vec3Distance(vec3 *a, vec3 *b) {
+ vec3 p;
+ vec3Sub(a, b, &p);
+ return vec3Length(&p);
+}
diff --git a/src/vector3d.h b/src/vector3d.h
index 67f8d5c3..eea3d7fe 100644
--- a/src/vector3d.h
+++ b/src/vector3d.h
@@ -13,10 +13,12 @@ typedef struct {
void vec3Normalize(vec3 *p);
void vec3Midpoint(vec3 *a, vec3 *b, vec3 *mid);
+void vec3Lerp(vec3 *a, vec3 *b, float frac, vec3 *result);
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);
+float vec3Distance(vec3 *a, vec3 *b);
#ifdef __cplusplus
}