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. 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.

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}, {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}
}; };

View File

@ -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));
}

View File

@ -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
} }

View File

@ -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);
} }

View File

@ -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
} }

View File

@ -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) {

View File

@ -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;
}

View File

@ -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
} }