diff --git a/README.md b/README.md index 1ce187cd..2890f0d7 100644 --- a/README.md +++ b/README.md @@ -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. -- [ ] 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. diff --git a/data/bmesh_test_1.h b/data/bmesh_test_1.h index 937b74fd..de88444f 100644 --- a/data/bmesh_test_1.h +++ b/data/bmesh_test_1.h @@ -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} }; diff --git a/src/bmesh.c b/src/bmesh.c index 57423e8b..767aa5ce 100644 --- a/src/bmesh.c +++ b/src/bmesh.c @@ -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)); +} diff --git a/src/bmesh.h b/src/bmesh.h index 838ad92f..329e804f 100644 --- a/src/bmesh.h +++ b/src/bmesh.h @@ -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 } diff --git a/src/draw.cpp b/src/draw.cpp index f685e90d..85dce4d4 100644 --- a/src/draw.cpp +++ b/src/draw.cpp @@ -97,3 +97,4 @@ int drawPrintf(int x, int y, const char *fmt, ...) { vsnprintf(text, sizeof(text), fmt, args); return drawText(x, y, text); } + diff --git a/src/draw.h b/src/draw.h index bfd524fc..e623c439 100644 --- a/src/draw.h +++ b/src/draw.h @@ -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 } diff --git a/src/render.cpp b/src/render.cpp index 01ef8023..e113d6ed 100644 --- a/src/render.cpp +++ b/src/render.cpp @@ -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) { diff --git a/src/vector3d.c b/src/vector3d.c index 4c29f0c1..35d4ea49 100644 --- a/src/vector3d.c +++ b/src/vector3d.c @@ -1,5 +1,6 @@ #include #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; +} diff --git a/src/vector3d.h b/src/vector3d.h index 2ec1d3a9..45cd8c39 100644 --- a/src/vector3d.h +++ b/src/vector3d.h @@ -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 }