Implement rotation on two connected bones.
parent
3a5540324a
commit
0efbc668a3
|
@ -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.
|
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.
|
Now, for just beginning, I think it's a not bad start.
|
||||||
<img src="screenshot/dust3d_sphere_cylinder.png">
|
<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*
|
*Drawing Skeletal Shape Balls*
|
||||||
Draw shape ball is easy, no need to rotate, I just need scale it along the ball's radius.
|
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.
|
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.
|
||||||
|
|
|
@ -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},
|
{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},
|
{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},
|
{4, 0, 0, 0, 0.8, 1},
|
||||||
|
@ -6,7 +6,7 @@ const float bmeshTest1Nodes[][6] = {
|
||||||
{6, 0.01726, -0.88224, -2.87471, 0.2}
|
{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},
|
{0, 2}, {2, 4}, {4, 3}, {3, 1},
|
||||||
{4, 5}, {5, 6}
|
{4, 5}, {5, 6}
|
||||||
};
|
};
|
||||||
|
|
468
src/bmesh.c
468
src/bmesh.c
|
@ -6,18 +6,21 @@
|
||||||
#include "bmesh.h"
|
#include "bmesh.h"
|
||||||
#include "array.h"
|
#include "array.h"
|
||||||
#include "matrix.h"
|
#include "matrix.h"
|
||||||
|
#include "draw.h"
|
||||||
|
|
||||||
typedef struct bmeshNodeIndex {
|
#define BMESH_STEP_DISTANCE 0.4
|
||||||
int nodeIndex;
|
|
||||||
|
typedef struct bmeshBallIndex {
|
||||||
|
int ballIndex;
|
||||||
int nextChildIndex;
|
int nextChildIndex;
|
||||||
} bmeshNodeIndex;
|
} bmeshBallIndex;
|
||||||
|
|
||||||
struct bmesh {
|
struct bmesh {
|
||||||
array *nodeArray;
|
array *ballArray;
|
||||||
array *edgeArray;
|
array *boneArray;
|
||||||
array *indexArray;
|
array *indexArray;
|
||||||
array *quadArray;
|
array *quadArray;
|
||||||
int rootNodeIndex;
|
int rootBallIndex;
|
||||||
int roundColor;
|
int roundColor;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -27,21 +30,21 @@ bmesh *bmeshCreate(void) {
|
||||||
fprintf(stderr, "%s:Insufficient memory.\n", __FUNCTION__);
|
fprintf(stderr, "%s:Insufficient memory.\n", __FUNCTION__);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
bm->nodeArray = arrayCreate(sizeof(bmeshNode));
|
bm->ballArray = arrayCreate(sizeof(bmeshBall));
|
||||||
if (!bm->nodeArray) {
|
if (!bm->ballArray) {
|
||||||
fprintf(stderr, "%s:arrayCreate bmeshNode failed.\n", __FUNCTION__);
|
fprintf(stderr, "%s:arrayCreate bmeshBall failed.\n", __FUNCTION__);
|
||||||
bmeshDestroy(bm);
|
bmeshDestroy(bm);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
bm->edgeArray = arrayCreate(sizeof(bmeshEdge));
|
bm->boneArray = arrayCreate(sizeof(bmeshBone));
|
||||||
if (!bm->edgeArray) {
|
if (!bm->boneArray) {
|
||||||
fprintf(stderr, "%s:arrayCreate bmeshEdge failed.\n", __FUNCTION__);
|
fprintf(stderr, "%s:arrayCreate bmeshBone failed.\n", __FUNCTION__);
|
||||||
bmeshDestroy(bm);
|
bmeshDestroy(bm);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
bm->indexArray = arrayCreate(sizeof(bmeshNodeIndex));
|
bm->indexArray = arrayCreate(sizeof(bmeshBallIndex));
|
||||||
if (!bm->indexArray) {
|
if (!bm->indexArray) {
|
||||||
fprintf(stderr, "%s:arrayCreate bmeshNodeIndex failed.\n", __FUNCTION__);
|
fprintf(stderr, "%s:arrayCreate bmeshBallIndex failed.\n", __FUNCTION__);
|
||||||
bmeshDestroy(bm);
|
bmeshDestroy(bm);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -51,125 +54,128 @@ bmesh *bmeshCreate(void) {
|
||||||
bmeshDestroy(bm);
|
bmeshDestroy(bm);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
bm->rootNodeIndex = -1;
|
bm->rootBallIndex = -1;
|
||||||
bm->roundColor = 0;
|
bm->roundColor = 0;
|
||||||
return bm;
|
return bm;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bmeshDestroy(bmesh *bm) {
|
void bmeshDestroy(bmesh *bm) {
|
||||||
arrayDestroy(bm->nodeArray);
|
arrayDestroy(bm->ballArray);
|
||||||
arrayDestroy(bm->edgeArray);
|
arrayDestroy(bm->boneArray);
|
||||||
arrayDestroy(bm->indexArray);
|
arrayDestroy(bm->indexArray);
|
||||||
arrayDestroy(bm->quadArray);
|
arrayDestroy(bm->quadArray);
|
||||||
free(bm);
|
free(bm);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bmeshGetNodeNum(bmesh *bm) {
|
int bmeshGetBallNum(bmesh *bm) {
|
||||||
return arrayGetLength(bm->nodeArray);
|
return arrayGetLength(bm->ballArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bmeshGetEdgeNum(bmesh *bm) {
|
int bmeshGetBoneNum(bmesh *bm) {
|
||||||
return arrayGetLength(bm->edgeArray);
|
return arrayGetLength(bm->boneArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
bmeshNode *bmeshGetNode(bmesh *bm, int index) {
|
bmeshBall *bmeshGetBall(bmesh *bm, int index) {
|
||||||
return (bmeshNode *)arrayGetItem(bm->nodeArray, index);
|
return (bmeshBall *)arrayGetItem(bm->ballArray, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
bmeshEdge *bmeshGetEdge(bmesh *bm, int index) {
|
bmeshBone *bmeshGetBone(bmesh *bm, int index) {
|
||||||
return (bmeshEdge *)arrayGetItem(bm->edgeArray, index);
|
return (bmeshBone *)arrayGetItem(bm->boneArray, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bmeshAddNode(bmesh *bm, bmeshNode *node) {
|
int bmeshAddBall(bmesh *bm, bmeshBall *ball) {
|
||||||
int index = arrayGetLength(bm->nodeArray);
|
int index = arrayGetLength(bm->ballArray);
|
||||||
node->index = index;
|
ball->index = index;
|
||||||
node->firstChildIndex = -1;
|
ball->firstChildIndex = -1;
|
||||||
node->childrenIndices = 0;
|
ball->childrenIndices = 0;
|
||||||
if (0 != arraySetLength(bm->nodeArray, index + 1)) {
|
if (0 != arraySetLength(bm->ballArray, index + 1)) {
|
||||||
fprintf(stderr, "%s:arraySetLength failed.\n", __FUNCTION__);
|
fprintf(stderr, "%s:arraySetLength failed.\n", __FUNCTION__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
memcpy(arrayGetItem(bm->nodeArray, index), node, sizeof(bmeshNode));
|
memcpy(arrayGetItem(bm->ballArray, index), ball, sizeof(bmeshBall));
|
||||||
if (BMESH_NODE_TYPE_ROOT == node->type) {
|
if (BMESH_BALL_TYPE_ROOT == ball->type) {
|
||||||
bm->rootNodeIndex = index;
|
bm->rootBallIndex = index;
|
||||||
}
|
}
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bmeshAddChildNodeRelation(bmesh *bm, int parentNodeIndex,
|
static int bmeshAddChildBallRelation(bmesh *bm, int parentBallIndex,
|
||||||
int childNodeIndex) {
|
int childBallIndex) {
|
||||||
bmeshNode *parentNode = bmeshGetNode(bm, parentNodeIndex);
|
bmeshBall *parentBall = bmeshGetBall(bm, parentBallIndex);
|
||||||
bmeshNodeIndex *indexItem;
|
bmeshBallIndex *indexItem;
|
||||||
int newChildIndex = arrayGetLength(bm->indexArray);
|
int newChildIndex = arrayGetLength(bm->indexArray);
|
||||||
if (0 != arraySetLength(bm->indexArray, newChildIndex + 1)) {
|
if (0 != arraySetLength(bm->indexArray, newChildIndex + 1)) {
|
||||||
fprintf(stderr, "%s:arraySetLength failed.\n", __FUNCTION__);
|
fprintf(stderr, "%s:arraySetLength failed.\n", __FUNCTION__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
indexItem = (bmeshNodeIndex *)arrayGetItem(bm->indexArray, newChildIndex);
|
indexItem = (bmeshBallIndex *)arrayGetItem(bm->indexArray, newChildIndex);
|
||||||
indexItem->nodeIndex = childNodeIndex;
|
indexItem->ballIndex = childBallIndex;
|
||||||
indexItem->nextChildIndex = parentNode->firstChildIndex;
|
indexItem->nextChildIndex = parentBall->firstChildIndex;
|
||||||
parentNode->firstChildIndex = newChildIndex;
|
parentBall->firstChildIndex = newChildIndex;
|
||||||
parentNode->childrenIndices++;
|
parentBall->childrenIndices++;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bmeshAddEdge(bmesh *bm, bmeshEdge *edge) {
|
int bmeshAddBone(bmesh *bm, bmeshBone *bone) {
|
||||||
int index = arrayGetLength(bm->edgeArray);
|
int index = arrayGetLength(bm->boneArray);
|
||||||
edge->index = index;
|
bone->index = index;
|
||||||
if (0 != arraySetLength(bm->edgeArray, index + 1)) {
|
if (0 != arraySetLength(bm->boneArray, index + 1)) {
|
||||||
fprintf(stderr, "%s:arraySetLength failed.\n", __FUNCTION__);
|
fprintf(stderr, "%s:arraySetLength failed.\n", __FUNCTION__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
memcpy(arrayGetItem(bm->edgeArray, index), edge, sizeof(bmeshEdge));
|
memcpy(arrayGetItem(bm->boneArray, index), bone, sizeof(bmeshBone));
|
||||||
if (0 != bmeshAddChildNodeRelation(bm, edge->firstNodeIndex,
|
if (0 != bmeshAddChildBallRelation(bm, bone->firstBallIndex,
|
||||||
edge->secondNodeIndex)) {
|
bone->secondBallIndex)) {
|
||||||
fprintf(stderr, "%s:bmeshAddChildNodeRelation failed.\n", __FUNCTION__);
|
fprintf(stderr, "%s:bmeshAddChildBallRelation failed.\n", __FUNCTION__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (0 != bmeshAddChildNodeRelation(bm, edge->secondNodeIndex,
|
if (0 != bmeshAddChildBallRelation(bm, bone->secondBallIndex,
|
||||||
edge->firstNodeIndex)) {
|
bone->firstBallIndex)) {
|
||||||
fprintf(stderr, "%s:bmeshAddChildNodeRelation failed.\n", __FUNCTION__);
|
fprintf(stderr, "%s:bmeshAddChildBallRelation failed.\n", __FUNCTION__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bmeshAddInbetweenNodeBetween(bmesh *bm,
|
static int bmeshAddInbetweenBallBetween(bmesh *bm,
|
||||||
bmeshNode *firstNode, bmeshNode *secondNode, float frac,
|
bmeshBall *firstBall, bmeshBall *secondBall, float frac,
|
||||||
int parentNodeIndex) {
|
int parentBallIndex) {
|
||||||
bmeshNode newNode;
|
bmeshBall newBall;
|
||||||
memset(&newNode, 0, sizeof(newNode));
|
memset(&newBall, 0, sizeof(newBall));
|
||||||
newNode.type = BMESH_NODE_TYPE_INBETWEEN;
|
newBall.type = BMESH_BALL_TYPE_INBETWEEN;
|
||||||
newNode.radius = firstNode->radius * (1 - frac) +
|
newBall.radius = firstBall->radius * (1 - frac) +
|
||||||
secondNode->radius * frac;
|
secondBall->radius * frac;
|
||||||
vec3Lerp(&firstNode->position, &secondNode->position, frac,
|
vec3Lerp(&firstBall->position, &secondBall->position, frac,
|
||||||
&newNode.position);
|
&newBall.position);
|
||||||
if (-1 == bmeshAddNode(bm, &newNode)) {
|
if (-1 == bmeshAddBall(bm, &newBall)) {
|
||||||
fprintf(stderr, "%s:bmeshAddNode failed.\n", __FUNCTION__);
|
fprintf(stderr, "%s:bmeshAddBall failed.\n", __FUNCTION__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (-1 == bmeshAddChildNodeRelation(bm, parentNodeIndex, newNode.index)) {
|
if (-1 == bmeshAddChildBallRelation(bm, parentBallIndex, newBall.index)) {
|
||||||
fprintf(stderr, "%s:bmeshAddChildNodeRelation failed.\n", __FUNCTION__);
|
fprintf(stderr, "%s:bmeshAddChildBallRelation failed.\n", __FUNCTION__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return newNode.index;
|
return newBall.index;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bmeshGenerateNodeQuad(bmesh *bm, bmeshNode *node,
|
/*
|
||||||
vec3 *localYaxis, vec3 *localZaxis, int connectWithQuad) {
|
static int bmeshGenerateBallCrossSection(bmesh *bm, bmeshBall *ball,
|
||||||
int i;
|
vec3 *boneDirection, vec3 *localYaxis, vec3 *localZaxis) {
|
||||||
quad q;
|
//int i;
|
||||||
|
//quad q;
|
||||||
vec3 z, y;
|
vec3 z, y;
|
||||||
vec3Scale(localYaxis, node->radius, &y);
|
//vec3Scale(localYaxis, ball->radius, &y);
|
||||||
vec3Scale(localZaxis, node->radius, &z);
|
//vec3Scale(localZaxis, ball->radius, &z);
|
||||||
vec3Sub(&node->position, &y, &q.pt[0]);
|
vec3Sub(&ball->position, &y, &q.pt[0]);
|
||||||
vec3Add(&q.pt[0], &z, &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]);
|
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]);
|
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]);
|
vec3Add(&q.pt[3], &z, &q.pt[3]);
|
||||||
|
ball->crossSection = q;
|
||||||
|
ball->boneDirection = *boneDirection;
|
||||||
if (-1 == bmeshAddQuad(bm, &q)) {
|
if (-1 == bmeshAddQuad(bm, &q)) {
|
||||||
fprintf(stderr, "%s:meshAddQuad failed.\n", __FUNCTION__);
|
fprintf(stderr, "%s:meshAddQuad failed.\n", __FUNCTION__);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -197,95 +203,110 @@ static int bmeshGenerateNodeQuad(bmesh *bm, bmeshNode *node,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
static int bmeshGenerateInbetweenNodesBetween(bmesh *bm,
|
static int bmeshGenerateInbetweenBallsBetween(bmesh *bm,
|
||||||
int firstNodeIndex, int secondNodeIndex) {
|
int firstBallIndex, int secondBallIndex) {
|
||||||
float step = 0.5;
|
float step;
|
||||||
float distance;
|
float distance;
|
||||||
int parentNodeIndex = firstNodeIndex;
|
int parentBallIndex = firstBallIndex;
|
||||||
vec3 localZaxis;
|
vec3 localZaxis;
|
||||||
vec3 localYaxis;
|
vec3 localYaxis;
|
||||||
vec3 edgeDirection;
|
vec3 boneDirection;
|
||||||
vec3 worldZaxis = {0, 0, 1};
|
vec3 normalizedBoneDirection;
|
||||||
int lastQuadIndex = -1;
|
vec3 worldYaxis = {0, 1, 0};
|
||||||
|
bmeshBall *firstBall = bmeshGetBall(bm, firstBallIndex);
|
||||||
bmeshNode *firstNode = bmeshGetNode(bm, firstNodeIndex);
|
bmeshBall *secondBall = bmeshGetBall(bm, secondBallIndex);
|
||||||
bmeshNode *secondNode = bmeshGetNode(bm, secondNodeIndex);
|
bmeshBall *newBall;
|
||||||
bmeshNode *newNode;
|
if (secondBall->roundColor == bm->roundColor) {
|
||||||
if (secondNode->roundColor == bm->roundColor) {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
vec3Sub(&firstNode->position, &secondNode->position, &edgeDirection);
|
|
||||||
vec3CrossProduct(&worldZaxis, &edgeDirection, &localZaxis);
|
|
||||||
vec3Normalize(&localZaxis);
|
|
||||||
vec3CrossProduct(&localZaxis, &edgeDirection, &localYaxis);
|
|
||||||
vec3Normalize(&localYaxis);
|
|
||||||
|
|
||||||
distance = vec3Length(&edgeDirection);
|
step = BMESH_STEP_DISTANCE;
|
||||||
if (distance > 0) {
|
|
||||||
float offset = step;
|
vec3Sub(&firstBall->position, &secondBall->position, &boneDirection);
|
||||||
if (offset + step <= distance) {
|
normalizedBoneDirection = boneDirection;
|
||||||
while (offset + step <= distance) {
|
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;
|
float frac = offset / distance;
|
||||||
parentNodeIndex = bmeshAddInbetweenNodeBetween(bm,
|
parentBallIndex = bmeshAddInbetweenBallBetween(bm,
|
||||||
firstNode, secondNode, frac, parentNodeIndex);
|
firstBall, secondBall, frac, parentBallIndex);
|
||||||
if (-1 == parentNodeIndex) {
|
if (-1 == parentBallIndex) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
newNode = bmeshGetNode(bm, parentNodeIndex);
|
newBall = bmeshGetBall(bm, parentBallIndex);
|
||||||
bmeshGenerateNodeQuad(bm, newNode, &localYaxis, &localZaxis,
|
newBall->localYaxis = localYaxis;
|
||||||
lastQuadIndex);
|
newBall->localZaxis = localZaxis;
|
||||||
lastQuadIndex = -1 == lastQuadIndex ? bmeshGetQuadNum(bm) - 1 :
|
newBall->boneDirection = normalizedBoneDirection;
|
||||||
bmeshGetQuadNum(bm) - 5;
|
|
||||||
offset += step;
|
offset += step;
|
||||||
}
|
}
|
||||||
} else if (distance > step) {
|
} else if (distance > step) {
|
||||||
parentNodeIndex = bmeshAddInbetweenNodeBetween(bm, firstNode, secondNode,
|
parentBallIndex = bmeshAddInbetweenBallBetween(bm, firstBall, secondBall,
|
||||||
0.5, parentNodeIndex);
|
0.5, parentBallIndex);
|
||||||
if (-1 == parentNodeIndex) {
|
if (-1 == parentBallIndex) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
newNode = bmeshGetNode(bm, parentNodeIndex);
|
newBall = bmeshGetBall(bm, parentBallIndex);
|
||||||
bmeshGenerateNodeQuad(bm, newNode, &localYaxis, &localZaxis, lastQuadIndex);
|
newBall->localYaxis = localYaxis;
|
||||||
lastQuadIndex = -1 == lastQuadIndex ? bmeshGetQuadNum(bm) - 1 :
|
newBall->localZaxis = localZaxis;
|
||||||
bmeshGetQuadNum(bm) - 5;
|
newBall->boneDirection = normalizedBoneDirection;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (-1 == bmeshAddChildNodeRelation(bm, parentNodeIndex, secondNodeIndex)) {
|
if (-1 == bmeshAddChildBallRelation(bm, parentBallIndex, secondBallIndex)) {
|
||||||
fprintf(stderr, "%s:bmeshAddChildNodeRelation failed.\n", __FUNCTION__);
|
fprintf(stderr, "%s:bmeshAddChildBallRelation failed.\n", __FUNCTION__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bmeshGetNodeNextChild(bmesh *bm, bmeshNode *node, int *childIndex) {
|
bmeshBall *bmeshGetBallFirstChild(bmesh *bm, bmeshBall *ball,
|
||||||
int currentChildIndex = *childIndex;
|
bmeshBallIterator *iterator) {
|
||||||
bmeshNodeIndex *indexItem;
|
if (-1 == ball->firstChildIndex) {
|
||||||
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) {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return bmeshGetNode(bm, bm->rootNodeIndex);
|
*iterator = ball->firstChildIndex;
|
||||||
|
return bmeshGetBallNextChild(bm, ball, iterator);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bmeshGenerateInbetweenNodesFrom(bmesh *bm, int parentNodeIndex) {
|
bmeshBall *bmeshGetBallNextChild(bmesh *bm, bmeshBall *ball,
|
||||||
int childIndex = -1;
|
bmeshBallIterator *iterator) {
|
||||||
int nodeIndex;
|
bmeshBallIndex *indexItem;
|
||||||
bmeshNode *parent;
|
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) {
|
if (parent->roundColor == bm->roundColor) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -293,30 +314,30 @@ static int bmeshGenerateInbetweenNodesFrom(bmesh *bm, int parentNodeIndex) {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Old indices came from user's input will be removed
|
// 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.
|
// the space occupied in indexArray will not been release.
|
||||||
//
|
//
|
||||||
|
|
||||||
childIndex = parent->firstChildIndex;
|
ball = bmeshGetBallFirstChild(bm, parent, &iterator);
|
||||||
parent->firstChildIndex = -1;
|
parent->firstChildIndex = -1;
|
||||||
|
oldChildrenIndices = parent->childrenIndices;
|
||||||
parent->childrenIndices = 0;
|
parent->childrenIndices = 0;
|
||||||
|
|
||||||
while (-1 != childIndex) {
|
for (;
|
||||||
nodeIndex = bmeshGetNodeNextChild(bm, parent, &childIndex);
|
ball;
|
||||||
if (-1 == nodeIndex) {
|
ball = bmeshGetBallNextChild(bm, parent, &iterator)) {
|
||||||
break;
|
ballIndex = ball->index;
|
||||||
}
|
if (0 != bmeshGenerateInbetweenBallsBetween(bm, parentBallIndex,
|
||||||
if (0 != bmeshGenerateInbetweenNodesBetween(bm, parentNodeIndex,
|
ballIndex)) {
|
||||||
nodeIndex)) {
|
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"%s:bmeshGenerateInbetweenNodesBetween failed(parentNodeIndex:%d).\n",
|
"%s:bmeshGenerateInbetweenBallsBetween failed(parentBallIndex:%d).\n",
|
||||||
__FUNCTION__, parentNodeIndex);
|
__FUNCTION__, parentBallIndex);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (0 != bmeshGenerateInbetweenNodesFrom(bm, nodeIndex)) {
|
if (0 != bmeshGenerateInbetweenBallsFrom(bm, ballIndex)) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"%s:bmeshGenerateInbetweenNodesFrom failed(nodeIndex:%d).\n",
|
"%s:bmeshGenerateInbetweenBallsFrom failed(ballIndex:%d).\n",
|
||||||
__FUNCTION__, nodeIndex);
|
__FUNCTION__, ballIndex);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -324,13 +345,13 @@ static int bmeshGenerateInbetweenNodesFrom(bmesh *bm, int parentNodeIndex) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bmeshGenerateInbetweenNodes(bmesh *bm) {
|
int bmeshGenerateInbetweenBalls(bmesh *bm) {
|
||||||
if (-1 == bm->rootNodeIndex) {
|
if (-1 == bm->rootBallIndex) {
|
||||||
fprintf(stderr, "%s:No root node.\n", __FUNCTION__);
|
fprintf(stderr, "%s:No root ball.\n", __FUNCTION__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
bm->roundColor++;
|
bm->roundColor++;
|
||||||
return bmeshGenerateInbetweenNodesFrom(bm, bm->rootNodeIndex);
|
return bmeshGenerateInbetweenBallsFrom(bm, bm->rootBallIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bmeshGetQuadNum(bmesh *bm) {
|
int bmeshGetQuadNum(bmesh *bm) {
|
||||||
|
@ -351,4 +372,131 @@ int bmeshAddQuad(bmesh *bm, quad *q) {
|
||||||
return index;
|
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));
|
||||||
|
}
|
||||||
|
|
44
src/bmesh.h
44
src/bmesh.h
|
@ -8,10 +8,10 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
BMESH_NODE_TYPE_KEY = 0,
|
BMESH_BALL_TYPE_KEY = 0,
|
||||||
BMESH_NODE_TYPE_ROOT = 1,
|
BMESH_BALL_TYPE_ROOT = 1,
|
||||||
BMESH_NODE_TYPE_INBETWEEN = 2,
|
BMESH_BALL_TYPE_INBETWEEN = 2,
|
||||||
} bmeshNodeType;
|
} bmeshBallType;
|
||||||
|
|
||||||
typedef struct bmesh bmesh;
|
typedef struct bmesh bmesh;
|
||||||
|
|
||||||
|
@ -22,29 +22,39 @@ typedef struct {
|
||||||
int type;
|
int type;
|
||||||
int childrenIndices;
|
int childrenIndices;
|
||||||
int firstChildIndex;
|
int firstChildIndex;
|
||||||
|
vec3 boneDirection;
|
||||||
|
vec3 localYaxis;
|
||||||
|
vec3 localZaxis;
|
||||||
int roundColor;
|
int roundColor;
|
||||||
} bmeshNode;
|
} bmeshBall;
|
||||||
|
|
||||||
|
typedef int bmeshBallIterator;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int index;
|
int index;
|
||||||
int firstNodeIndex;
|
int firstBallIndex;
|
||||||
int secondNodeIndex;
|
int secondBallIndex;
|
||||||
} bmeshEdge;
|
} bmeshBone;
|
||||||
|
|
||||||
bmesh *bmeshCreate(void);
|
bmesh *bmeshCreate(void);
|
||||||
void bmeshDestroy(bmesh *bm);
|
void bmeshDestroy(bmesh *bm);
|
||||||
int bmeshGetNodeNum(bmesh *bm);
|
int bmeshGetBallNum(bmesh *bm);
|
||||||
int bmeshGetEdgeNum(bmesh *bm);
|
int bmeshGetBoneNum(bmesh *bm);
|
||||||
bmeshNode *bmeshGetNode(bmesh *bm, int index);
|
bmeshBall *bmeshGetBall(bmesh *bm, int index);
|
||||||
bmeshEdge *bmeshGetEdge(bmesh *bm, int index);
|
bmeshBone *bmeshGetBone(bmesh *bm, int index);
|
||||||
int bmeshAddNode(bmesh *bm, bmeshNode *node);
|
int bmeshAddBall(bmesh *bm, bmeshBall *ball);
|
||||||
int bmeshAddEdge(bmesh *bm, bmeshEdge *edge);
|
int bmeshAddBone(bmesh *bm, bmeshBone *bone);
|
||||||
int bmeshGenerateInbetweenNodes(bmesh *bm);
|
int bmeshGenerateInbetweenBalls(bmesh *bm);
|
||||||
int bmeshGetNodeNextChild(bmesh *bm, bmeshNode *node, int *childIndex);
|
bmeshBall *bmeshGetBallFirstChild(bmesh *bm, bmeshBall *node,
|
||||||
bmeshNode *bmeshGetRootNode(bmesh *bm);
|
bmeshBallIterator *iterator);
|
||||||
|
bmeshBall *bmeshGetBallNextChild(bmesh *bm, bmeshBall *node,
|
||||||
|
bmeshBallIterator *iterator);
|
||||||
|
bmeshBall *bmeshGetRootBall(bmesh *bm);
|
||||||
int bmeshGetQuadNum(bmesh *bm);
|
int bmeshGetQuadNum(bmesh *bm);
|
||||||
quad *bmeshGetQuad(bmesh *bm, int index);
|
quad *bmeshGetQuad(bmesh *bm, int index);
|
||||||
int bmeshAddQuad(bmesh *bm, quad *q);
|
int bmeshAddQuad(bmesh *bm, quad *q);
|
||||||
|
int bmeshSweep(bmesh *bm);
|
||||||
|
int bmeshStitch(bmesh *bm);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,3 +97,4 @@ int drawPrintf(int x, int y, const char *fmt, ...) {
|
||||||
vsnprintf(text, sizeof(text), fmt, args);
|
vsnprintf(text, sizeof(text), fmt, args);
|
||||||
return drawText(x, y, text);
|
return drawText(x, y, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@ int drawCylinder(vec3 *topOrigin, vec3 *bottomOrigin, float radius, int slices,
|
||||||
int drawGrid(float size, float step);
|
int drawGrid(float size, float step);
|
||||||
int drawText(int x, int y, char *text);
|
int drawText(int x, int y, char *text);
|
||||||
int drawPrintf(int x, int y, const char *fmt, ...);
|
int drawPrintf(int x, int y, const char *fmt, ...);
|
||||||
|
int drawDebugPrintf(const char *fmt, ...);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
201
src/render.cpp
201
src/render.cpp
|
@ -6,62 +6,108 @@
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "bmesh.h"
|
#include "bmesh.h"
|
||||||
#include "matrix.h"
|
#include "matrix.h"
|
||||||
|
#include "vector3d.h"
|
||||||
|
|
||||||
static const float bmeshNodeColors[][3] {
|
static const float bmeshBallColors[][3] {
|
||||||
{0, 0.78, 1},
|
{0, 0.78, 1},
|
||||||
{1, 0, 0},
|
{1, 0, 0},
|
||||||
{1, 1, 1}
|
{1, 1, 1}
|
||||||
};
|
};
|
||||||
|
|
||||||
static const float bmeshEdgeColor[3] = {1, 1, 0};
|
static const float bmeshBoneColor[3] = {1, 1, 0};
|
||||||
|
|
||||||
static QGLWidget *_this = 0;
|
static QGLWidget *_this = 0;
|
||||||
|
static int debugOutputTop = 0;
|
||||||
|
|
||||||
static int drawBmeshNode(bmesh *bm, bmeshNode *node) {
|
int drawDebugPrintf(const char *fmt, ...) {
|
||||||
glColor3fv(bmeshNodeColors[node->type]);
|
int x = 0;
|
||||||
drawSphere(&node->position, node->radius, 36, 24);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drawBmeshNodeRecursively(bmesh *bm, bmeshNode *node) {
|
static void drawBmeshBallRecursively(bmesh *bm, bmeshBall *ball) {
|
||||||
int childIndex = node->firstChildIndex;
|
bmeshBallIterator iterator;
|
||||||
int childNodeIndex;
|
bmeshBall *child;
|
||||||
drawBmeshNode(bm, node);
|
drawBmeshBall(bm, ball);
|
||||||
while (-1 != childIndex) {
|
for (child = bmeshGetBallFirstChild(bm, ball, &iterator);
|
||||||
childNodeIndex = bmeshGetNodeNextChild(bm, node, &childIndex);
|
child;
|
||||||
if (-1 == childNodeIndex) {
|
child = bmeshGetBallNextChild(bm, ball, &iterator)) {
|
||||||
break;
|
drawBmeshBallRecursively(bm, child);
|
||||||
}
|
|
||||||
drawBmeshNodeRecursively(bm, bmeshGetNode(bm, childNodeIndex));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drawBmeshNodeQuardRecursively(bmesh *bm, bmeshNode *node) {
|
static int drawBmeshBallQuad(bmeshBall *ball) {
|
||||||
int childIndex = node->firstChildIndex;
|
vec3 normal;
|
||||||
int childNodeIndex;
|
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 matTmp;
|
||||||
matrix matCalc;
|
matrix matCalc;
|
||||||
float quad[4][3] = {
|
float quad[4][3] = {
|
||||||
{-node->radius, +node->radius, 0},
|
{-ball->radius, +ball->radius, 0},
|
||||||
{-node->radius, -node->radius, 0},
|
{-ball->radius, -ball->radius, 0},
|
||||||
{+node->radius, -node->radius, 0},
|
{+ball->radius, -ball->radius, 0},
|
||||||
{+node->radius, +node->radius, 0},
|
{+ball->radius, +ball->radius, 0},
|
||||||
};
|
};
|
||||||
matrixLoadIdentity(&matCalc);
|
matrixLoadIdentity(&matCalc);
|
||||||
matrixAppend(&matCalc,
|
matrixAppend(&matCalc,
|
||||||
matrixTranslate(&matTmp, node->position.x, node->position.y,
|
matrixTranslate(&matTmp, ball->position.x, ball->position.y,
|
||||||
node->position.z));
|
ball->position.z));
|
||||||
matrixAppend(&matCalc,
|
matrixAppend(&matCalc,
|
||||||
matrixRotate(&matTmp,
|
matrixRotate(&matTmp,
|
||||||
node->rotateAngle, node->rotateAround.x, node->rotateAround.y,
|
ball->rotateAngle, ball->rotateAround.x, ball->rotateAround.y,
|
||||||
node->rotateAround.z));
|
ball->rotateAround.z));
|
||||||
matrixTransformVector(&matCalc, quad[0]);
|
matrixTransformVector(&matCalc, quad[0]);
|
||||||
matrixTransformVector(&matCalc, quad[1]);
|
matrixTransformVector(&matCalc, quad[1]);
|
||||||
matrixTransformVector(&matCalc, quad[2]);
|
matrixTransformVector(&matCalc, quad[2]);
|
||||||
matrixTransformVector(&matCalc, quad[3]);
|
matrixTransformVector(&matCalc, quad[3]);
|
||||||
|
|
||||||
glVertex3fv(quad[0]);
|
glVertex3fv(quad[0]);
|
||||||
glVertex3fv(quad[1]);
|
glVertex3fv(quad[1]);
|
||||||
glVertex3fv(quad[2]);
|
glVertex3fv(quad[2]);
|
||||||
|
@ -70,33 +116,33 @@ static void drawBmeshNodeQuardRecursively(bmesh *bm, bmeshNode *node) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
glTranslatef(node->position.x, node->position.y,
|
glTranslatef(ball->position.x, ball->position.y,
|
||||||
node->position.z);
|
ball->position.z);
|
||||||
glRotatef(node->rotateAngle, node->rotateAround.x, node->rotateAround.y,
|
glRotatef(ball->rotateAngle, ball->rotateAround.x, ball->rotateAround.y,
|
||||||
node->rotateAround.z);
|
ball->rotateAround.z);
|
||||||
glBegin(GL_QUADS);
|
glBegin(GL_QUADS);
|
||||||
glVertex3f(-node->radius, +node->radius, 0);
|
glVertex3f(-ball->radius, +ball->radius, 0);
|
||||||
glVertex3f(-node->radius, -node->radius, 0);
|
glVertex3f(-ball->radius, -ball->radius, 0);
|
||||||
glVertex3f(+node->radius, -node->radius, 0);
|
glVertex3f(+ball->radius, -ball->radius, 0);
|
||||||
glVertex3f(+node->radius, +node->radius, 0);
|
glVertex3f(+ball->radius, +ball->radius, 0);
|
||||||
glEnd();
|
glEnd();
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
*/
|
*/
|
||||||
|
|
||||||
while (-1 != childIndex) {
|
drawBmeshBallQuad(ball);
|
||||||
childNodeIndex = bmeshGetNodeNextChild(bm, node, &childIndex);
|
|
||||||
if (-1 == childNodeIndex) {
|
for (child = bmeshGetBallFirstChild(bm, ball, &iterator);
|
||||||
break;
|
child;
|
||||||
}
|
child = bmeshGetBallNextChild(bm, ball, &iterator)) {
|
||||||
drawBmeshNodeQuardRecursively(bm, bmeshGetNode(bm, childNodeIndex));
|
drawBmeshBallQuadRecursively(bm, child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int drawBmeshEdge(bmesh *bm, bmeshEdge *edge) {
|
static int drawBmeshBone(bmesh *bm, bmeshBone *bone) {
|
||||||
glColor3fv(bmeshEdgeColor);
|
glColor3fv(bmeshBoneColor);
|
||||||
bmeshNode *firstNode = bmeshGetNode(bm, edge->firstNodeIndex);
|
bmeshBall *firstBall = bmeshGetBall(bm, bone->firstBallIndex);
|
||||||
bmeshNode *secondNode = bmeshGetNode(bm, edge->secondNodeIndex);
|
bmeshBall *secondBall = bmeshGetBall(bm, bone->secondBallIndex);
|
||||||
drawCylinder(&firstNode->position, &secondNode->position, 0.1, 36, 24);
|
drawCylinder(&firstBall->position, &secondBall->position, 0.1, 36, 24);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,7 +183,7 @@ void Render::initializeGL() {
|
||||||
qglClearColor(QWidget::palette().color(QWidget::backgroundRole()));
|
qglClearColor(QWidget::palette().color(QWidget::backgroundRole()));
|
||||||
glClearStencil(0);
|
glClearStencil(0);
|
||||||
glClearDepth(1.0f);
|
glClearDepth(1.0f);
|
||||||
|
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
GLfloat ambientLight[] = {0.0f, 0.0f, 0.0f, 1.0f};
|
GLfloat ambientLight[] = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||||
|
@ -166,9 +212,10 @@ void Render::initializeGL() {
|
||||||
#include "../data/bmesh_test_1.h"
|
#include "../data/bmesh_test_1.h"
|
||||||
|
|
||||||
void Render::paintGL() {
|
void Render::paintGL() {
|
||||||
static bmesh *bm = 0;
|
bmesh *bm = 0;
|
||||||
|
|
||||||
_this = this;
|
_this = this;
|
||||||
|
debugOutputTop = 0;
|
||||||
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
|
@ -179,7 +226,7 @@ void Render::paintGL() {
|
||||||
glRotatef(cameraAngleY, 0, 1, 0);
|
glRotatef(cameraAngleY, 0, 1, 0);
|
||||||
|
|
||||||
glColor3f(0, 0, 0);
|
glColor3f(0, 0, 0);
|
||||||
drawPrintf(0, 10, "cameraAngleX:%f cameraAngleY:%f cameraDistance:%f",
|
drawDebugPrintf("cameraAngleX:%f cameraAngleY:%f cameraDistance:%f",
|
||||||
cameraAngleX, cameraAngleY, cameraDistance);
|
cameraAngleX, cameraAngleY, cameraDistance);
|
||||||
|
|
||||||
drawGrid(10, 1);
|
drawGrid(10, 1);
|
||||||
|
@ -187,47 +234,48 @@ void Render::paintGL() {
|
||||||
glEnable(GL_LIGHTING);
|
glEnable(GL_LIGHTING);
|
||||||
|
|
||||||
if (0 == bm) {
|
if (0 == bm) {
|
||||||
bmeshNode node;
|
bmeshBall ball;
|
||||||
bmeshEdge edge;
|
bmeshBone bone;
|
||||||
int i;
|
int i;
|
||||||
bm = bmeshCreate();
|
bm = bmeshCreate();
|
||||||
|
|
||||||
for (i = 0; i < sizeof(bmeshTest1Nodes) / sizeof(bmeshTest1Nodes[0]); ++i) {
|
for (i = 0; i < sizeof(bmeshTest1Balls) / sizeof(bmeshTest1Balls[0]); ++i) {
|
||||||
memset(&node, 0, sizeof(node));
|
memset(&ball, 0, sizeof(ball));
|
||||||
node.position.x = bmeshTest1Nodes[i][1];
|
ball.position.x = bmeshTest1Balls[i][1];
|
||||||
node.position.y = bmeshTest1Nodes[i][2];
|
ball.position.y = bmeshTest1Balls[i][2];
|
||||||
node.position.z = bmeshTest1Nodes[i][3];
|
ball.position.z = bmeshTest1Balls[i][3];
|
||||||
node.radius = bmeshTest1Nodes[i][4];
|
ball.radius = bmeshTest1Balls[i][4];
|
||||||
node.type = bmeshTest1Nodes[i][5];
|
ball.type = bmeshTest1Balls[i][5];
|
||||||
bmeshAddNode(bm, &node);
|
bmeshAddBall(bm, &ball);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < sizeof(bmeshTest1Edges) / sizeof(bmeshTest1Edges[0]); ++i) {
|
for (i = 0; i < sizeof(bmeshTest1Bones) / sizeof(bmeshTest1Bones[0]); ++i) {
|
||||||
memset(&edge, 0, sizeof(edge));
|
memset(&bone, 0, sizeof(bone));
|
||||||
edge.firstNodeIndex = bmeshTest1Edges[i][0];
|
bone.firstBallIndex = bmeshTest1Bones[i][0];
|
||||||
edge.secondNodeIndex = bmeshTest1Edges[i][1];
|
bone.secondBallIndex = bmeshTest1Bones[i][1];
|
||||||
bmeshAddEdge(bm, &edge);
|
bmeshAddBone(bm, &bone);
|
||||||
}
|
}
|
||||||
|
|
||||||
bmeshGenerateInbetweenNodes(bm);
|
bmeshGenerateInbetweenBalls(bm);
|
||||||
|
bmeshSweep(bm);
|
||||||
}
|
}
|
||||||
|
|
||||||
drawBmeshNodeRecursively(bm, bmeshGetRootNode(bm));
|
drawBmeshBallRecursively(bm, bmeshGetRootBall(bm));
|
||||||
|
|
||||||
//glBegin(GL_QUADS);
|
//glBegin(GL_QUADS);
|
||||||
//drawBmeshNodeQuardRecursively(bm, bmeshGetRootNode(bm));
|
drawBmeshBallQuadRecursively(bm, bmeshGetRootBall(bm));
|
||||||
//glEnd();
|
//glEnd();
|
||||||
|
|
||||||
{
|
{
|
||||||
int index;
|
int index;
|
||||||
/*
|
/*
|
||||||
for (index = 0; index < bmeshGetNodeNum(bm); ++index) {
|
for (index = 0; index < bmeshGetBallNum(bm); ++index) {
|
||||||
bmeshNode *node = bmeshGetNode(bm, index);
|
bmeshBall *ball = bmeshGetBall(bm, index);
|
||||||
drawBmeshNode(bm, node);
|
drawBmeshBall(bm, ball);
|
||||||
}*/
|
}*/
|
||||||
for (index = 0; index < bmeshGetEdgeNum(bm); ++index) {
|
for (index = 0; index < bmeshGetBoneNum(bm); ++index) {
|
||||||
bmeshEdge *edge = bmeshGetEdge(bm, index);
|
bmeshBone *bone = bmeshGetBone(bm, index);
|
||||||
drawBmeshEdge(bm, edge);
|
drawBmeshBone(bm, bone);
|
||||||
}
|
}
|
||||||
glColor4f(1.0f, 1.0f, 1.0f, 0.5);
|
glColor4f(1.0f, 1.0f, 1.0f, 0.5);
|
||||||
glBegin(GL_QUADS);
|
glBegin(GL_QUADS);
|
||||||
|
@ -256,6 +304,11 @@ void Render::paintGL() {
|
||||||
}
|
}
|
||||||
|
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
|
|
||||||
|
if (bm) {
|
||||||
|
bmeshDestroy(bm);
|
||||||
|
bm = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Render::resizeGL(int w, int h) {
|
void Render::resizeGL(int w, int h) {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "vector3d.h"
|
#include "vector3d.h"
|
||||||
|
#include "matrix.h"
|
||||||
|
|
||||||
float vec3Length(vec3 *p) {
|
float vec3Length(vec3 *p) {
|
||||||
double mag;
|
double mag;
|
||||||
|
@ -83,3 +84,44 @@ void vec3Normal(vec3 *a, vec3 *b, vec3 *c, vec3 *normal) {
|
||||||
normal->y = vr[1]/val;
|
normal->y = vr[1]/val;
|
||||||
normal->z = vr[2]/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;
|
||||||
|
}
|
||||||
|
|
|
@ -22,6 +22,8 @@ float vec3DotProduct(vec3 *a, vec3 *b);
|
||||||
float vec3Length(vec3 *p);
|
float vec3Length(vec3 *p);
|
||||||
float vec3Distance(vec3 *a, vec3 *b);
|
float vec3Distance(vec3 *a, vec3 *b);
|
||||||
void vec3Normal(vec3 *a, vec3 *b, vec3 *c, vec3 *normal);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue