Implement rotation on two connected bones.

master
Jeremy Hu 2016-12-25 15:30:02 +09:30
parent 3a5540324a
commit 0efbc668a3
9 changed files with 511 additions and 254 deletions

View File

@ -36,7 +36,7 @@ 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.
<img src="screenshot/dust3d_sphere_cylinder.png">
- [ ] Implement B-Mesh algorithm (Dec 18, 2016 ~ Dec 23, 2016)
- [ ] Implement B-Mesh algorithm (Dec 18, 2016 ~ Dec 25, 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.

View File

@ -1,4 +1,4 @@
const float bmeshTest1Nodes[][6] = {
const float bmeshTest1Balls[][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},
@ -6,7 +6,7 @@ const float bmeshTest1Nodes[][6] = {
{6, 0.01726, -0.88224, -2.87471, 0.2}
};
const int bmeshTest1Edges[][2] = {
const int bmeshTest1Bones[][2] = {
{0, 2}, {2, 4}, {4, 3}, {3, 1},
{4, 5}, {5, 6}
};

View File

@ -6,18 +6,21 @@
#include "bmesh.h"
#include "array.h"
#include "matrix.h"
#include "draw.h"
typedef struct bmeshNodeIndex {
int nodeIndex;
#define BMESH_STEP_DISTANCE 0.4
typedef struct bmeshBallIndex {
int ballIndex;
int nextChildIndex;
} bmeshNodeIndex;
} bmeshBallIndex;
struct bmesh {
array *nodeArray;
array *edgeArray;
array *ballArray;
array *boneArray;
array *indexArray;
array *quadArray;
int rootNodeIndex;
int rootBallIndex;
int roundColor;
};
@ -27,21 +30,21 @@ bmesh *bmeshCreate(void) {
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__);
bm->ballArray = arrayCreate(sizeof(bmeshBall));
if (!bm->ballArray) {
fprintf(stderr, "%s:arrayCreate bmeshBall failed.\n", __FUNCTION__);
bmeshDestroy(bm);
return 0;
}
bm->edgeArray = arrayCreate(sizeof(bmeshEdge));
if (!bm->edgeArray) {
fprintf(stderr, "%s:arrayCreate bmeshEdge failed.\n", __FUNCTION__);
bm->boneArray = arrayCreate(sizeof(bmeshBone));
if (!bm->boneArray) {
fprintf(stderr, "%s:arrayCreate bmeshBone failed.\n", __FUNCTION__);
bmeshDestroy(bm);
return 0;
}
bm->indexArray = arrayCreate(sizeof(bmeshNodeIndex));
bm->indexArray = arrayCreate(sizeof(bmeshBallIndex));
if (!bm->indexArray) {
fprintf(stderr, "%s:arrayCreate bmeshNodeIndex failed.\n", __FUNCTION__);
fprintf(stderr, "%s:arrayCreate bmeshBallIndex failed.\n", __FUNCTION__);
bmeshDestroy(bm);
return 0;
}
@ -51,125 +54,128 @@ bmesh *bmeshCreate(void) {
bmeshDestroy(bm);
return 0;
}
bm->rootNodeIndex = -1;
bm->rootBallIndex = -1;
bm->roundColor = 0;
return bm;
}
void bmeshDestroy(bmesh *bm) {
arrayDestroy(bm->nodeArray);
arrayDestroy(bm->edgeArray);
arrayDestroy(bm->ballArray);
arrayDestroy(bm->boneArray);
arrayDestroy(bm->indexArray);
arrayDestroy(bm->quadArray);
free(bm);
}
int bmeshGetNodeNum(bmesh *bm) {
return arrayGetLength(bm->nodeArray);
int bmeshGetBallNum(bmesh *bm) {
return arrayGetLength(bm->ballArray);
}
int bmeshGetEdgeNum(bmesh *bm) {
return arrayGetLength(bm->edgeArray);
int bmeshGetBoneNum(bmesh *bm) {
return arrayGetLength(bm->boneArray);
}
bmeshNode *bmeshGetNode(bmesh *bm, int index) {
return (bmeshNode *)arrayGetItem(bm->nodeArray, index);
bmeshBall *bmeshGetBall(bmesh *bm, int index) {
return (bmeshBall *)arrayGetItem(bm->ballArray, index);
}
bmeshEdge *bmeshGetEdge(bmesh *bm, int index) {
return (bmeshEdge *)arrayGetItem(bm->edgeArray, index);
bmeshBone *bmeshGetBone(bmesh *bm, int index) {
return (bmeshBone *)arrayGetItem(bm->boneArray, index);
}
int bmeshAddNode(bmesh *bm, bmeshNode *node) {
int index = arrayGetLength(bm->nodeArray);
node->index = index;
node->firstChildIndex = -1;
node->childrenIndices = 0;
if (0 != arraySetLength(bm->nodeArray, index + 1)) {
int bmeshAddBall(bmesh *bm, bmeshBall *ball) {
int index = arrayGetLength(bm->ballArray);
ball->index = index;
ball->firstChildIndex = -1;
ball->childrenIndices = 0;
if (0 != arraySetLength(bm->ballArray, index + 1)) {
fprintf(stderr, "%s:arraySetLength failed.\n", __FUNCTION__);
return -1;
}
memcpy(arrayGetItem(bm->nodeArray, index), node, sizeof(bmeshNode));
if (BMESH_NODE_TYPE_ROOT == node->type) {
bm->rootNodeIndex = index;
memcpy(arrayGetItem(bm->ballArray, index), ball, sizeof(bmeshBall));
if (BMESH_BALL_TYPE_ROOT == ball->type) {
bm->rootBallIndex = index;
}
return index;
}
static int bmeshAddChildNodeRelation(bmesh *bm, int parentNodeIndex,
int childNodeIndex) {
bmeshNode *parentNode = bmeshGetNode(bm, parentNodeIndex);
bmeshNodeIndex *indexItem;
static int bmeshAddChildBallRelation(bmesh *bm, int parentBallIndex,
int childBallIndex) {
bmeshBall *parentBall = bmeshGetBall(bm, parentBallIndex);
bmeshBallIndex *indexItem;
int newChildIndex = arrayGetLength(bm->indexArray);
if (0 != arraySetLength(bm->indexArray, newChildIndex + 1)) {
fprintf(stderr, "%s:arraySetLength failed.\n", __FUNCTION__);
return -1;
}
indexItem = (bmeshNodeIndex *)arrayGetItem(bm->indexArray, newChildIndex);
indexItem->nodeIndex = childNodeIndex;
indexItem->nextChildIndex = parentNode->firstChildIndex;
parentNode->firstChildIndex = newChildIndex;
parentNode->childrenIndices++;
indexItem = (bmeshBallIndex *)arrayGetItem(bm->indexArray, newChildIndex);
indexItem->ballIndex = childBallIndex;
indexItem->nextChildIndex = parentBall->firstChildIndex;
parentBall->firstChildIndex = newChildIndex;
parentBall->childrenIndices++;
return 0;
}
int bmeshAddEdge(bmesh *bm, bmeshEdge *edge) {
int index = arrayGetLength(bm->edgeArray);
edge->index = index;
if (0 != arraySetLength(bm->edgeArray, index + 1)) {
int bmeshAddBone(bmesh *bm, bmeshBone *bone) {
int index = arrayGetLength(bm->boneArray);
bone->index = index;
if (0 != arraySetLength(bm->boneArray, index + 1)) {
fprintf(stderr, "%s:arraySetLength failed.\n", __FUNCTION__);
return -1;
}
memcpy(arrayGetItem(bm->edgeArray, index), edge, sizeof(bmeshEdge));
if (0 != bmeshAddChildNodeRelation(bm, edge->firstNodeIndex,
edge->secondNodeIndex)) {
fprintf(stderr, "%s:bmeshAddChildNodeRelation failed.\n", __FUNCTION__);
memcpy(arrayGetItem(bm->boneArray, index), bone, sizeof(bmeshBone));
if (0 != bmeshAddChildBallRelation(bm, bone->firstBallIndex,
bone->secondBallIndex)) {
fprintf(stderr, "%s:bmeshAddChildBallRelation failed.\n", __FUNCTION__);
return -1;
}
if (0 != bmeshAddChildNodeRelation(bm, edge->secondNodeIndex,
edge->firstNodeIndex)) {
fprintf(stderr, "%s:bmeshAddChildNodeRelation failed.\n", __FUNCTION__);
if (0 != bmeshAddChildBallRelation(bm, bone->secondBallIndex,
bone->firstBallIndex)) {
fprintf(stderr, "%s:bmeshAddChildBallRelation failed.\n", __FUNCTION__);
return -1;
}
return index;
}
static int bmeshAddInbetweenNodeBetween(bmesh *bm,
bmeshNode *firstNode, bmeshNode *secondNode, float frac,
int parentNodeIndex) {
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);
if (-1 == bmeshAddNode(bm, &newNode)) {
fprintf(stderr, "%s:bmeshAddNode failed.\n", __FUNCTION__);
static int bmeshAddInbetweenBallBetween(bmesh *bm,
bmeshBall *firstBall, bmeshBall *secondBall, float frac,
int parentBallIndex) {
bmeshBall newBall;
memset(&newBall, 0, sizeof(newBall));
newBall.type = BMESH_BALL_TYPE_INBETWEEN;
newBall.radius = firstBall->radius * (1 - frac) +
secondBall->radius * frac;
vec3Lerp(&firstBall->position, &secondBall->position, frac,
&newBall.position);
if (-1 == bmeshAddBall(bm, &newBall)) {
fprintf(stderr, "%s:bmeshAddBall failed.\n", __FUNCTION__);
return -1;
}
if (-1 == bmeshAddChildNodeRelation(bm, parentNodeIndex, newNode.index)) {
fprintf(stderr, "%s:bmeshAddChildNodeRelation failed.\n", __FUNCTION__);
if (-1 == bmeshAddChildBallRelation(bm, parentBallIndex, newBall.index)) {
fprintf(stderr, "%s:bmeshAddChildBallRelation failed.\n", __FUNCTION__);
return -1;
}
return newNode.index;
return newBall.index;
}
static int bmeshGenerateNodeQuad(bmesh *bm, bmeshNode *node,
vec3 *localYaxis, vec3 *localZaxis, int connectWithQuad) {
int i;
quad q;
/*
static int bmeshGenerateBallCrossSection(bmesh *bm, bmeshBall *ball,
vec3 *boneDirection, vec3 *localYaxis, vec3 *localZaxis) {
//int i;
//quad q;
vec3 z, y;
vec3Scale(localYaxis, node->radius, &y);
vec3Scale(localZaxis, node->radius, &z);
vec3Sub(&node->position, &y, &q.pt[0]);
//vec3Scale(localYaxis, ball->radius, &y);
//vec3Scale(localZaxis, ball->radius, &z);
vec3Sub(&ball->position, &y, &q.pt[0]);
vec3Add(&q.pt[0], &z, &q.pt[0]);
vec3Sub(&node->position, &y, &q.pt[1]);
vec3Sub(&ball->position, &y, &q.pt[1]);
vec3Sub(&q.pt[1], &z, &q.pt[1]);
vec3Add(&node->position, &y, &q.pt[2]);
vec3Add(&ball->position, &y, &q.pt[2]);
vec3Sub(&q.pt[2], &z, &q.pt[2]);
vec3Add(&node->position, &y, &q.pt[3]);
vec3Add(&ball->position, &y, &q.pt[3]);
vec3Add(&q.pt[3], &z, &q.pt[3]);
ball->crossSection = q;
ball->boneDirection = *boneDirection;
if (-1 == bmeshAddQuad(bm, &q)) {
fprintf(stderr, "%s:meshAddQuad failed.\n", __FUNCTION__);
return -1;
@ -197,95 +203,110 @@ static int bmeshGenerateNodeQuad(bmesh *bm, bmeshNode *node,
}
}
return 0;
}
}*/
static int bmeshGenerateInbetweenNodesBetween(bmesh *bm,
int firstNodeIndex, int secondNodeIndex) {
float step = 0.5;
static int bmeshGenerateInbetweenBallsBetween(bmesh *bm,
int firstBallIndex, int secondBallIndex) {
float step;
float distance;
int parentNodeIndex = firstNodeIndex;
int parentBallIndex = firstBallIndex;
vec3 localZaxis;
vec3 localYaxis;
vec3 edgeDirection;
vec3 worldZaxis = {0, 0, 1};
int lastQuadIndex = -1;
bmeshNode *firstNode = bmeshGetNode(bm, firstNodeIndex);
bmeshNode *secondNode = bmeshGetNode(bm, secondNodeIndex);
bmeshNode *newNode;
if (secondNode->roundColor == bm->roundColor) {
vec3 boneDirection;
vec3 normalizedBoneDirection;
vec3 worldYaxis = {0, 1, 0};
bmeshBall *firstBall = bmeshGetBall(bm, firstBallIndex);
bmeshBall *secondBall = bmeshGetBall(bm, secondBallIndex);
bmeshBall *newBall;
if (secondBall->roundColor == bm->roundColor) {
return 0;
}
vec3Sub(&firstNode->position, &secondNode->position, &edgeDirection);
vec3CrossProduct(&worldZaxis, &edgeDirection, &localZaxis);
vec3Normalize(&localZaxis);
vec3CrossProduct(&localZaxis, &edgeDirection, &localYaxis);
vec3Normalize(&localYaxis);
distance = vec3Length(&edgeDirection);
if (distance > 0) {
float offset = step;
if (offset + step <= distance) {
while (offset + step <= distance) {
step = BMESH_STEP_DISTANCE;
vec3Sub(&firstBall->position, &secondBall->position, &boneDirection);
normalizedBoneDirection = boneDirection;
vec3Normalize(&normalizedBoneDirection);
vec3CrossProduct(&worldYaxis, &boneDirection, &localYaxis);
vec3Normalize(&localYaxis);
vec3CrossProduct(&localYaxis, &boneDirection, &localZaxis);
vec3Normalize(&localZaxis);
distance = vec3Length(&boneDirection);
if (distance > BMESH_STEP_DISTANCE) {
float offset;
int calculatedStepCount = (int)(distance / BMESH_STEP_DISTANCE);
float remaining = distance - BMESH_STEP_DISTANCE * calculatedStepCount;
step += remaining / calculatedStepCount;
offset = step;
if (offset < distance) {
while (offset < distance) {
float frac = offset / distance;
parentNodeIndex = bmeshAddInbetweenNodeBetween(bm,
firstNode, secondNode, frac, parentNodeIndex);
if (-1 == parentNodeIndex) {
parentBallIndex = bmeshAddInbetweenBallBetween(bm,
firstBall, secondBall, frac, parentBallIndex);
if (-1 == parentBallIndex) {
return -1;
}
newNode = bmeshGetNode(bm, parentNodeIndex);
bmeshGenerateNodeQuad(bm, newNode, &localYaxis, &localZaxis,
lastQuadIndex);
lastQuadIndex = -1 == lastQuadIndex ? bmeshGetQuadNum(bm) - 1 :
bmeshGetQuadNum(bm) - 5;
newBall = bmeshGetBall(bm, parentBallIndex);
newBall->localYaxis = localYaxis;
newBall->localZaxis = localZaxis;
newBall->boneDirection = normalizedBoneDirection;
offset += step;
}
} else if (distance > step) {
parentNodeIndex = bmeshAddInbetweenNodeBetween(bm, firstNode, secondNode,
0.5, parentNodeIndex);
if (-1 == parentNodeIndex) {
parentBallIndex = bmeshAddInbetweenBallBetween(bm, firstBall, secondBall,
0.5, parentBallIndex);
if (-1 == parentBallIndex) {
return -1;
}
newNode = bmeshGetNode(bm, parentNodeIndex);
bmeshGenerateNodeQuad(bm, newNode, &localYaxis, &localZaxis, lastQuadIndex);
lastQuadIndex = -1 == lastQuadIndex ? bmeshGetQuadNum(bm) - 1 :
bmeshGetQuadNum(bm) - 5;
newBall = bmeshGetBall(bm, parentBallIndex);
newBall->localYaxis = localYaxis;
newBall->localZaxis = localZaxis;
newBall->boneDirection = normalizedBoneDirection;
}
}
if (-1 == bmeshAddChildNodeRelation(bm, parentNodeIndex, secondNodeIndex)) {
fprintf(stderr, "%s:bmeshAddChildNodeRelation failed.\n", __FUNCTION__);
if (-1 == bmeshAddChildBallRelation(bm, parentBallIndex, secondBallIndex)) {
fprintf(stderr, "%s:bmeshAddChildBallRelation failed.\n", __FUNCTION__);
return -1;
}
return 0;
}
int bmeshGetNodeNextChild(bmesh *bm, bmeshNode *node, int *childIndex) {
int currentChildIndex = *childIndex;
bmeshNodeIndex *indexItem;
if (-1 == currentChildIndex) {
if (-1 == node->firstChildIndex) {
return -1;
}
currentChildIndex = node->firstChildIndex;
}
indexItem = (bmeshNodeIndex *)arrayGetItem(bm->indexArray, currentChildIndex);
*childIndex = indexItem->nextChildIndex;
return indexItem->nodeIndex;
}
bmeshNode *bmeshGetRootNode(bmesh *bm) {
if (-1 == bm->rootNodeIndex) {
bmeshBall *bmeshGetBallFirstChild(bmesh *bm, bmeshBall *ball,
bmeshBallIterator *iterator) {
if (-1 == ball->firstChildIndex) {
return 0;
}
return bmeshGetNode(bm, bm->rootNodeIndex);
*iterator = ball->firstChildIndex;
return bmeshGetBallNextChild(bm, ball, iterator);
}
static int bmeshGenerateInbetweenNodesFrom(bmesh *bm, int parentNodeIndex) {
int childIndex = -1;
int nodeIndex;
bmeshNode *parent;
bmeshBall *bmeshGetBallNextChild(bmesh *bm, bmeshBall *ball,
bmeshBallIterator *iterator) {
bmeshBallIndex *indexItem;
if (-1 == *iterator) {
return 0;
}
indexItem = (bmeshBallIndex *)arrayGetItem(bm->indexArray, *iterator);
*iterator = indexItem->nextChildIndex;
return bmeshGetBall(bm, indexItem->ballIndex);
}
parent = bmeshGetNode(bm, parentNodeIndex);
bmeshBall *bmeshGetRootBall(bmesh *bm) {
if (-1 == bm->rootBallIndex) {
return 0;
}
return bmeshGetBall(bm, bm->rootBallIndex);
}
static int bmeshGenerateInbetweenBallsFrom(bmesh *bm, int parentBallIndex) {
bmeshBallIterator iterator;
int ballIndex;
bmeshBall *parent;
bmeshBall *ball;
int oldChildrenIndices;
parent = bmeshGetBall(bm, parentBallIndex);
if (parent->roundColor == bm->roundColor) {
return 0;
}
@ -293,30 +314,30 @@ static int bmeshGenerateInbetweenNodesFrom(bmesh *bm, int parentNodeIndex) {
//
// Old indices came from user's input will be removed
// after the inbetween nodes are genereated, though
// after the inbetween balls are genereated, though
// the space occupied in indexArray will not been release.
//
childIndex = parent->firstChildIndex;
ball = bmeshGetBallFirstChild(bm, parent, &iterator);
parent->firstChildIndex = -1;
oldChildrenIndices = parent->childrenIndices;
parent->childrenIndices = 0;
while (-1 != childIndex) {
nodeIndex = bmeshGetNodeNextChild(bm, parent, &childIndex);
if (-1 == nodeIndex) {
break;
}
if (0 != bmeshGenerateInbetweenNodesBetween(bm, parentNodeIndex,
nodeIndex)) {
for (;
ball;
ball = bmeshGetBallNextChild(bm, parent, &iterator)) {
ballIndex = ball->index;
if (0 != bmeshGenerateInbetweenBallsBetween(bm, parentBallIndex,
ballIndex)) {
fprintf(stderr,
"%s:bmeshGenerateInbetweenNodesBetween failed(parentNodeIndex:%d).\n",
__FUNCTION__, parentNodeIndex);
"%s:bmeshGenerateInbetweenBallsBetween failed(parentBallIndex:%d).\n",
__FUNCTION__, parentBallIndex);
return -1;
}
if (0 != bmeshGenerateInbetweenNodesFrom(bm, nodeIndex)) {
if (0 != bmeshGenerateInbetweenBallsFrom(bm, ballIndex)) {
fprintf(stderr,
"%s:bmeshGenerateInbetweenNodesFrom failed(nodeIndex:%d).\n",
__FUNCTION__, nodeIndex);
"%s:bmeshGenerateInbetweenBallsFrom failed(ballIndex:%d).\n",
__FUNCTION__, ballIndex);
return -1;
}
}
@ -324,13 +345,13 @@ static int bmeshGenerateInbetweenNodesFrom(bmesh *bm, int parentNodeIndex) {
return 0;
}
int bmeshGenerateInbetweenNodes(bmesh *bm) {
if (-1 == bm->rootNodeIndex) {
fprintf(stderr, "%s:No root node.\n", __FUNCTION__);
int bmeshGenerateInbetweenBalls(bmesh *bm) {
if (-1 == bm->rootBallIndex) {
fprintf(stderr, "%s:No root ball.\n", __FUNCTION__);
return -1;
}
bm->roundColor++;
return bmeshGenerateInbetweenNodesFrom(bm, bm->rootNodeIndex);
return bmeshGenerateInbetweenBallsFrom(bm, bm->rootBallIndex);
}
int bmeshGetQuadNum(bmesh *bm) {
@ -351,4 +372,131 @@ int bmeshAddQuad(bmesh *bm, quad *q) {
return index;
}
static int bmeshSweepFrom(bmesh *bm, bmeshBall *parent, bmeshBall *ball) {
int result = 0;
vec3 worldYaxis = {0, 1, 0};
bmeshBallIterator iterator;
bmeshBall *child = 0;
if (BMESH_BALL_TYPE_KEY == ball->type) {
child = bmeshGetBallFirstChild(bm, ball, &iterator);
if (child) {
if (parent) {
float rotateAngle;
vec3 rotateAxis;
vec3CrossProduct(&parent->boneDirection, &child->boneDirection,
&rotateAxis);
vec3Normalize(&rotateAxis);
vec3Add(&rotateAxis, &ball->position, &rotateAxis);
rotateAngle = vec3Angle(&parent->boneDirection, &child->boneDirection);
rotateAngle *= 0.5;
/*
glColor3f(0.0, 0.0, 0.0);
drawDebugPrintf("<%f,%f,%f> <%f,%f,%f> rotateAngle:%f",
parent->boneDirection.x,
parent->boneDirection.y,
parent->boneDirection.z,
child->boneDirection.x,
child->boneDirection.y,
child->boneDirection.z,
rotateAngle);
glPushMatrix();
glTranslatef(parent->position.x, parent->position.y, parent->position.z);
glColor3f(1.0, 0.0, 1.0);
glBegin(GL_LINES);
glVertex3f(0, 0, 0);
glVertex3f(parent->boneDirection.x, parent->boneDirection.y,
parent->boneDirection.z);
glEnd();
glPopMatrix();
glPushMatrix();
glTranslatef(child->position.x, child->position.y, child->position.z);
glColor3f(0.0, 1.0, 1.0);
glBegin(GL_LINES);
glVertex3f(0, 0, 0);
glVertex3f(child->boneDirection.x, child->boneDirection.y,
child->boneDirection.z);
glEnd();
glPopMatrix();
*/
ball->boneDirection = parent->boneDirection;
vec3RotateAlong(&ball->boneDirection, rotateAngle, &rotateAxis,
&ball->boneDirection);
vec3CrossProduct(&worldYaxis, &ball->boneDirection, &ball->localYaxis);
vec3Normalize(&ball->localYaxis);
vec3CrossProduct(&ball->localYaxis, &ball->boneDirection,
&ball->localZaxis);
vec3Normalize(&ball->localZaxis);
} else {
// TODO:
}
} else {
ball->boneDirection = parent->boneDirection;
vec3CrossProduct(&worldYaxis, &ball->boneDirection, &ball->localYaxis);
vec3Normalize(&ball->localYaxis);
vec3CrossProduct(&ball->localYaxis, &ball->boneDirection,
&ball->localZaxis);
vec3Normalize(&ball->localZaxis);
}
}
for (child = bmeshGetBallFirstChild(bm, ball, &iterator);
child;
child = bmeshGetBallNextChild(bm, ball, &iterator)) {
result = bmeshSweepFrom(bm, ball, child);
if (0 != result) {
fprintf(stderr, "%s:bmeshSweepFrom failed.\n", __FUNCTION__);
return result;
}
}
return result;
}
int bmeshSweep(bmesh *bm) {
return bmeshSweepFrom(bm, 0, bmeshGetRootBall(bm));
}
static bmeshBall *bmeshFindBallForConvexHull(bmesh *bm, bmeshBall *root,
bmeshBall *ball) {
bmeshBallIterator iterator;
bmeshBall *child;
float distance = vec3Distance(&root->position, &ball->position);
if (distance >= root->radius) {
return ball;
}
child = bmeshGetBallFirstChild(bm, ball, &iterator);
if (!child) {
return ball;
}
return bmeshFindBallForConvexHull(bm, root, child);
}
static int bmeshStichFrom(bmesh *bm, bmeshBall *ball) {
int result = 0;
bmeshBallIterator iterator;
bmeshBall *child;
bmeshBall *ballForConvexHull;
if (BMESH_BALL_TYPE_ROOT == ball->type) {
for (child = bmeshGetBallFirstChild(bm, ball, &iterator);
child;
child = bmeshGetBallNextChild(bm, ball, &iterator)) {
ballForConvexHull = bmeshFindBallForConvexHull(bm, ball, child);
}
}
for (child = bmeshGetBallFirstChild(bm, ball, &iterator);
child;
child = bmeshGetBallNextChild(bm, ball, &iterator)) {
result = bmeshSweepFrom(bm, ball, child);
if (0 != result) {
fprintf(stderr, "%s:bmeshSweepFrom failed.\n", __FUNCTION__);
return result;
}
}
return result;
}
int bmeshStitch(bmesh *bm) {
return bmeshStichFrom(bm, bmeshGetRootBall(bm));
}

View File

@ -8,10 +8,10 @@ extern "C" {
#endif
typedef enum {
BMESH_NODE_TYPE_KEY = 0,
BMESH_NODE_TYPE_ROOT = 1,
BMESH_NODE_TYPE_INBETWEEN = 2,
} bmeshNodeType;
BMESH_BALL_TYPE_KEY = 0,
BMESH_BALL_TYPE_ROOT = 1,
BMESH_BALL_TYPE_INBETWEEN = 2,
} bmeshBallType;
typedef struct bmesh bmesh;
@ -22,29 +22,39 @@ typedef struct {
int type;
int childrenIndices;
int firstChildIndex;
vec3 boneDirection;
vec3 localYaxis;
vec3 localZaxis;
int roundColor;
} bmeshNode;
} bmeshBall;
typedef int bmeshBallIterator;
typedef struct {
int index;
int firstNodeIndex;
int secondNodeIndex;
} bmeshEdge;
int firstBallIndex;
int secondBallIndex;
} bmeshBone;
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);
int bmeshGenerateInbetweenNodes(bmesh *bm);
int bmeshGetNodeNextChild(bmesh *bm, bmeshNode *node, int *childIndex);
bmeshNode *bmeshGetRootNode(bmesh *bm);
int bmeshGetBallNum(bmesh *bm);
int bmeshGetBoneNum(bmesh *bm);
bmeshBall *bmeshGetBall(bmesh *bm, int index);
bmeshBone *bmeshGetBone(bmesh *bm, int index);
int bmeshAddBall(bmesh *bm, bmeshBall *ball);
int bmeshAddBone(bmesh *bm, bmeshBone *bone);
int bmeshGenerateInbetweenBalls(bmesh *bm);
bmeshBall *bmeshGetBallFirstChild(bmesh *bm, bmeshBall *node,
bmeshBallIterator *iterator);
bmeshBall *bmeshGetBallNextChild(bmesh *bm, bmeshBall *node,
bmeshBallIterator *iterator);
bmeshBall *bmeshGetRootBall(bmesh *bm);
int bmeshGetQuadNum(bmesh *bm);
quad *bmeshGetQuad(bmesh *bm, int index);
int bmeshAddQuad(bmesh *bm, quad *q);
int bmeshSweep(bmesh *bm);
int bmeshStitch(bmesh *bm);
#ifdef __cplusplus
}

View File

@ -97,3 +97,4 @@ int drawPrintf(int x, int y, const char *fmt, ...) {
vsnprintf(text, sizeof(text), fmt, args);
return drawText(x, y, text);
}

View File

@ -32,6 +32,7 @@ int drawCylinder(vec3 *topOrigin, vec3 *bottomOrigin, float radius, int slices,
int drawGrid(float size, float step);
int drawText(int x, int y, char *text);
int drawPrintf(int x, int y, const char *fmt, ...);
int drawDebugPrintf(const char *fmt, ...);
#ifdef __cplusplus
}

View File

@ -6,62 +6,108 @@
#include "draw.h"
#include "bmesh.h"
#include "matrix.h"
#include "vector3d.h"
static const float bmeshNodeColors[][3] {
static const float bmeshBallColors[][3] {
{0, 0.78, 1},
{1, 0, 0},
{1, 1, 1}
};
static const float bmeshEdgeColor[3] = {1, 1, 0};
static const float bmeshBoneColor[3] = {1, 1, 0};
static QGLWidget *_this = 0;
static int debugOutputTop = 0;
static int drawBmeshNode(bmesh *bm, bmeshNode *node) {
glColor3fv(bmeshNodeColors[node->type]);
drawSphere(&node->position, node->radius, 36, 24);
int drawDebugPrintf(const char *fmt, ...) {
int x = 0;
int y = debugOutputTop + 10;
va_list args;
char text[1024];
va_start(args, fmt);
vsnprintf(text, sizeof(text), fmt, args);
debugOutputTop += 9;
return drawText(x, y, text);
}
static int drawBmeshBall(bmesh *bm, bmeshBall *ball) {
glColor3fv(bmeshBallColors[ball->type]);
drawSphere(&ball->position, ball->radius, 36, 24);
return 0;
}
static void drawBmeshNodeRecursively(bmesh *bm, bmeshNode *node) {
int childIndex = node->firstChildIndex;
int childNodeIndex;
drawBmeshNode(bm, node);
while (-1 != childIndex) {
childNodeIndex = bmeshGetNodeNextChild(bm, node, &childIndex);
if (-1 == childNodeIndex) {
break;
}
drawBmeshNodeRecursively(bm, bmeshGetNode(bm, childNodeIndex));
static void drawBmeshBallRecursively(bmesh *bm, bmeshBall *ball) {
bmeshBallIterator iterator;
bmeshBall *child;
drawBmeshBall(bm, ball);
for (child = bmeshGetBallFirstChild(bm, ball, &iterator);
child;
child = bmeshGetBallNextChild(bm, ball, &iterator)) {
drawBmeshBallRecursively(bm, child);
}
}
static void drawBmeshNodeQuardRecursively(bmesh *bm, bmeshNode *node) {
int childIndex = node->firstChildIndex;
int childNodeIndex;
static int drawBmeshBallQuad(bmeshBall *ball) {
vec3 normal;
int j;
vec3 z, y;
quad q;
vec3Scale(&ball->localYaxis, ball->radius, &y);
vec3Scale(&ball->localZaxis, ball->radius, &z);
vec3Sub(&ball->position, &y, &q.pt[0]);
vec3Add(&q.pt[0], &z, &q.pt[0]);
vec3Sub(&ball->position, &y, &q.pt[1]);
vec3Sub(&q.pt[1], &z, &q.pt[1]);
vec3Add(&ball->position, &y, &q.pt[2]);
vec3Sub(&q.pt[2], &z, &q.pt[2]);
vec3Add(&ball->position, &y, &q.pt[3]);
vec3Add(&q.pt[3], &z, &q.pt[3]);
glColor4f(1.0f, 1.0f, 1.0f, 0.5);
glBegin(GL_QUADS);
vec3Normal(&q.pt[0], &q.pt[1], &q.pt[2], &normal);
for (j = 0; j < 4; ++j) {
glNormal3f(normal.x, normal.y, normal.z);
glVertex3f(q.pt[j].x, q.pt[j].y, q.pt[j].z);
}
glEnd();
glColor3f(0.0f, 0.0f, 0.0f);
glBegin(GL_LINE_STRIP);
for (j = 0; j < 4; ++j) {
glVertex3f(q.pt[j].x, q.pt[j].y, q.pt[j].z);
}
glVertex3f(q.pt[0].x, q.pt[0].y, q.pt[0].z);
glEnd();
}
static void drawBmeshBallQuadRecursively(bmesh *bm, bmeshBall *ball) {
bmeshBallIterator iterator;
bmeshBall *child;
/*
matrix matTmp;
matrix matCalc;
float quad[4][3] = {
{-node->radius, +node->radius, 0},
{-node->radius, -node->radius, 0},
{+node->radius, -node->radius, 0},
{+node->radius, +node->radius, 0},
{-ball->radius, +ball->radius, 0},
{-ball->radius, -ball->radius, 0},
{+ball->radius, -ball->radius, 0},
{+ball->radius, +ball->radius, 0},
};
matrixLoadIdentity(&matCalc);
matrixAppend(&matCalc,
matrixTranslate(&matTmp, node->position.x, node->position.y,
node->position.z));
matrixTranslate(&matTmp, ball->position.x, ball->position.y,
ball->position.z));
matrixAppend(&matCalc,
matrixRotate(&matTmp,
node->rotateAngle, node->rotateAround.x, node->rotateAround.y,
node->rotateAround.z));
ball->rotateAngle, ball->rotateAround.x, ball->rotateAround.y,
ball->rotateAround.z));
matrixTransformVector(&matCalc, quad[0]);
matrixTransformVector(&matCalc, quad[1]);
matrixTransformVector(&matCalc, quad[2]);
matrixTransformVector(&matCalc, quad[3]);
glVertex3fv(quad[0]);
glVertex3fv(quad[1]);
glVertex3fv(quad[2]);
@ -70,33 +116,33 @@ static void drawBmeshNodeQuardRecursively(bmesh *bm, bmeshNode *node) {
/*
glPushMatrix();
glTranslatef(node->position.x, node->position.y,
node->position.z);
glRotatef(node->rotateAngle, node->rotateAround.x, node->rotateAround.y,
node->rotateAround.z);
glTranslatef(ball->position.x, ball->position.y,
ball->position.z);
glRotatef(ball->rotateAngle, ball->rotateAround.x, ball->rotateAround.y,
ball->rotateAround.z);
glBegin(GL_QUADS);
glVertex3f(-node->radius, +node->radius, 0);
glVertex3f(-node->radius, -node->radius, 0);
glVertex3f(+node->radius, -node->radius, 0);
glVertex3f(+node->radius, +node->radius, 0);
glVertex3f(-ball->radius, +ball->radius, 0);
glVertex3f(-ball->radius, -ball->radius, 0);
glVertex3f(+ball->radius, -ball->radius, 0);
glVertex3f(+ball->radius, +ball->radius, 0);
glEnd();
glPopMatrix();
*/
while (-1 != childIndex) {
childNodeIndex = bmeshGetNodeNextChild(bm, node, &childIndex);
if (-1 == childNodeIndex) {
break;
}
drawBmeshNodeQuardRecursively(bm, bmeshGetNode(bm, childNodeIndex));
drawBmeshBallQuad(ball);
for (child = bmeshGetBallFirstChild(bm, ball, &iterator);
child;
child = bmeshGetBallNextChild(bm, ball, &iterator)) {
drawBmeshBallQuadRecursively(bm, child);
}
}
static int drawBmeshEdge(bmesh *bm, bmeshEdge *edge) {
glColor3fv(bmeshEdgeColor);
bmeshNode *firstNode = bmeshGetNode(bm, edge->firstNodeIndex);
bmeshNode *secondNode = bmeshGetNode(bm, edge->secondNodeIndex);
drawCylinder(&firstNode->position, &secondNode->position, 0.1, 36, 24);
static int drawBmeshBone(bmesh *bm, bmeshBone *bone) {
glColor3fv(bmeshBoneColor);
bmeshBall *firstBall = bmeshGetBall(bm, bone->firstBallIndex);
bmeshBall *secondBall = bmeshGetBall(bm, bone->secondBallIndex);
drawCylinder(&firstBall->position, &secondBall->position, 0.1, 36, 24);
return 0;
}
@ -137,7 +183,7 @@ void Render::initializeGL() {
qglClearColor(QWidget::palette().color(QWidget::backgroundRole()));
glClearStencil(0);
glClearDepth(1.0f);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
GLfloat ambientLight[] = {0.0f, 0.0f, 0.0f, 1.0f};
@ -166,9 +212,10 @@ void Render::initializeGL() {
#include "../data/bmesh_test_1.h"
void Render::paintGL() {
static bmesh *bm = 0;
bmesh *bm = 0;
_this = this;
debugOutputTop = 0;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@ -179,7 +226,7 @@ void Render::paintGL() {
glRotatef(cameraAngleY, 0, 1, 0);
glColor3f(0, 0, 0);
drawPrintf(0, 10, "cameraAngleX:%f cameraAngleY:%f cameraDistance:%f",
drawDebugPrintf("cameraAngleX:%f cameraAngleY:%f cameraDistance:%f",
cameraAngleX, cameraAngleY, cameraDistance);
drawGrid(10, 1);
@ -187,47 +234,48 @@ void Render::paintGL() {
glEnable(GL_LIGHTING);
if (0 == bm) {
bmeshNode node;
bmeshEdge edge;
bmeshBall ball;
bmeshBone bone;
int i;
bm = bmeshCreate();
for (i = 0; i < sizeof(bmeshTest1Nodes) / sizeof(bmeshTest1Nodes[0]); ++i) {
memset(&node, 0, sizeof(node));
node.position.x = bmeshTest1Nodes[i][1];
node.position.y = bmeshTest1Nodes[i][2];
node.position.z = bmeshTest1Nodes[i][3];
node.radius = bmeshTest1Nodes[i][4];
node.type = bmeshTest1Nodes[i][5];
bmeshAddNode(bm, &node);
for (i = 0; i < sizeof(bmeshTest1Balls) / sizeof(bmeshTest1Balls[0]); ++i) {
memset(&ball, 0, sizeof(ball));
ball.position.x = bmeshTest1Balls[i][1];
ball.position.y = bmeshTest1Balls[i][2];
ball.position.z = bmeshTest1Balls[i][3];
ball.radius = bmeshTest1Balls[i][4];
ball.type = bmeshTest1Balls[i][5];
bmeshAddBall(bm, &ball);
}
for (i = 0; i < sizeof(bmeshTest1Edges) / sizeof(bmeshTest1Edges[0]); ++i) {
memset(&edge, 0, sizeof(edge));
edge.firstNodeIndex = bmeshTest1Edges[i][0];
edge.secondNodeIndex = bmeshTest1Edges[i][1];
bmeshAddEdge(bm, &edge);
for (i = 0; i < sizeof(bmeshTest1Bones) / sizeof(bmeshTest1Bones[0]); ++i) {
memset(&bone, 0, sizeof(bone));
bone.firstBallIndex = bmeshTest1Bones[i][0];
bone.secondBallIndex = bmeshTest1Bones[i][1];
bmeshAddBone(bm, &bone);
}
bmeshGenerateInbetweenNodes(bm);
bmeshGenerateInbetweenBalls(bm);
bmeshSweep(bm);
}
drawBmeshNodeRecursively(bm, bmeshGetRootNode(bm));
drawBmeshBallRecursively(bm, bmeshGetRootBall(bm));
//glBegin(GL_QUADS);
//drawBmeshNodeQuardRecursively(bm, bmeshGetRootNode(bm));
drawBmeshBallQuadRecursively(bm, bmeshGetRootBall(bm));
//glEnd();
{
int index;
/*
for (index = 0; index < bmeshGetNodeNum(bm); ++index) {
bmeshNode *node = bmeshGetNode(bm, index);
drawBmeshNode(bm, node);
for (index = 0; index < bmeshGetBallNum(bm); ++index) {
bmeshBall *ball = bmeshGetBall(bm, index);
drawBmeshBall(bm, ball);
}*/
for (index = 0; index < bmeshGetEdgeNum(bm); ++index) {
bmeshEdge *edge = bmeshGetEdge(bm, index);
drawBmeshEdge(bm, edge);
for (index = 0; index < bmeshGetBoneNum(bm); ++index) {
bmeshBone *bone = bmeshGetBone(bm, index);
drawBmeshBone(bm, bone);
}
glColor4f(1.0f, 1.0f, 1.0f, 0.5);
glBegin(GL_QUADS);
@ -256,6 +304,11 @@ void Render::paintGL() {
}
glPopMatrix();
if (bm) {
bmeshDestroy(bm);
bm = 0;
}
}
void Render::resizeGL(int w, int h) {

View File

@ -1,5 +1,6 @@
#include <math.h>
#include "vector3d.h"
#include "matrix.h"
float vec3Length(vec3 *p) {
double mag;
@ -83,3 +84,44 @@ void vec3Normal(vec3 *a, vec3 *b, vec3 *c, vec3 *normal) {
normal->y = vr[1]/val;
normal->z = vr[2]/val;
}
void vec3RotateAlong(vec3 *a, float angle, vec3 *axis, vec3 *result) {
float vec[3];
matrix matRotate;
matrix matFinal;
matrixLoadIdentity(&matFinal);
matrixAppend(&matFinal, matrixRotate(&matRotate, angle,
axis->x, axis->y, axis->z));
vec[0] = a->x;
vec[1] = a->y;
vec[2] = a->z;
matrixTransformVector(&matFinal, vec);
result->x = vec[0];
result->y = vec[1];
result->z = vec[2];
}
float vec3Angle(vec3 *a, vec3 *b) {
float angle;
vec3 p;
float distance;
float dot;
float acosParam;
float acosVal;
vec3Sub(a, b, &p);
distance = vec3Length(&p);
if (0 == distance) {
return 0;
}
dot = vec3DotProduct(a, b);
acosParam = dot / distance;
if (acosParam < -1) {
acosParam = -1;
}
if (acosParam > 1) {
acosParam = 1;
}
acosVal = acos(acosParam);
angle = 180 / M_PI * acosVal;
return angle;
}

View File

@ -22,6 +22,8 @@ float vec3DotProduct(vec3 *a, vec3 *b);
float vec3Length(vec3 *p);
float vec3Distance(vec3 *a, vec3 *b);
void vec3Normal(vec3 *a, vec3 *b, vec3 *c, vec3 *normal);
void vec3RotateAlong(vec3 *a, float angle, vec3 *axis, vec3 *result);
float vec3Angle(vec3 *a, vec3 *b);
#ifdef __cplusplus
}