📄 walker.c
字号:
#include <GL/glut.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#ifdef _WIN32
#include "win32_dirent.h"
/* Have to #undef LoadMenu or else Microsoft VC++ won't allow us to
redefine it. */
#undef LoadMenu
#else
#include <dirent.h>
#endif
#include <assert.h>
#include "walker.h"
#define MAX(x,y) ((x) > (y) ? (x) : (y))
#define MIN(x,y) ((x) < (y) ? (x) : (y))
#define CYCLE_SIZE 100
#define CYCLE_STEP 1.0/CYCLE_SIZE
#define OVERSAMPLE 10
#define MAX_CPOINTS 34 /* 2 end point ones and 10 in the middle */
#define MAX_CSETNAMELEN 25
#define NUM_JOINTS 5
#define CSET_EXT ".cset"
#define CSET_EXTLEN 5
#include "walkviewer.h"
typedef enum { CMENU_QUIT, CMENU_CURVE, CMENU_HORIZ, CMENU_RESET,
CMENU_WALK, CMENU_DONEEDIT, CMENU_SAVE, CMENU_LOAD,
CMENU_MIRROR
} CurveMenuChoices;
typedef enum { WIRECUBE, SOLIDCUBE, CYLINDER1, CYLINDER2 } ModelTypes;
int GuyModel = SOLIDCUBE;
/***************************************************************/
/*************************** GLOBALS ***************************/
/***************************************************************/
GLuint HorizontalList, AxesList, /* Display lists */
CurveLists, ControlPtsLists; /* Firsts of groups of display lists */
int CurveAsPoints = 0, /* Display curve as points? */
DrawHorizontals = 0, /* Draw horizontal lines? */
EditingCurve = -1; /* Editing what curve, -1 means none */
int CurveWindow, /* Glut window id's to two top level windows */
GuyWindow;
int MirrorLegs = 0;
int CurveMenu = -1,
CurveEditMenu = -1,
StepSizeMenu = -1,
LoadMenu = -1,
SaveMenu = -1;
char *CSetNames[MAX_CSETNAMELEN];
int CurrentCurve = -1; /* Curve loaded, index to CSetNames */
GLfloat Walk_cycle[2][NUM_JOINTS][CYCLE_SIZE]; /* array of computed angles */
int Step = CYCLE_SIZE/2; /* Position in cycle, start in middle */
float fStep = CYCLE_SIZE/2; /* floating point for non-integer steping */
float IncStep = 1.0;
typedef struct ControlPts {
int numpoints;
float xcoords[MAX_CPOINTS];
float angles[MAX_CPOINTS];
} tControlPts;
tControlPts RotCurve[NUM_JOINTS]; /* series of cntrl points for ea joint */
int Walking = 0, /* Guy is walking? */
ViewPerspective = 1, /* Perspective or orthographic views */
DrawAxes = 0; /* Draw axes for alignment */
int CurveWWidth, /* Dimensions of curve window */
CurveWHeight;
int CurveDownBtn = -1, /* mouse stuff, for editing curves */
WasWalking,
CurvePickedPoint = -1,
CurveLastX,
CurveLastY;
int CurveWindowVisible = 1;
/* prototypes */
void RedisplayBoth(void);
void IncrementStep(void);
void CurveCPointDrag(void);
void CurveHandleMenu(int value);
void StopWalking(void);
void CurveHandleEditMenu(int curve);
void ComputeCSetAndMakeLists(void);
int MakeLoadAndSaveMenus(void);
void CurveMenuInit(void);
void SetWindowTitles(char *csetname);
/***************************************************************/
/**************************** BEZIER ***************************/
/***************************************************************/
/* Matrix times a vector dest = m*v */
void MultMV(float m[3][4], float v[4], float dest[3])
{
int i, j;
for (i = 0; i < 3; i++) {
dest[i] = 0;
for (j = 0; j < 4; j++)
dest[i] += m[i][j] * v[j];
}
}
/* Matrix multiplication, dest = m1*m2 */
void MultM(float m1[3][4], float m2[4][4], float dest[3][4])
{
int i, j, k;
for (i = 0; i < 3; i++)
for (j = 0; j < 4; j++) {
dest[i][j] = 0;
for (k = 0; k < 4; k++)
dest[i][j] += (m1[i][k] * m2[k][j]);
}
}
void ComputeCurve(int joint)
{
float prod[3][4], tm[4], pos[3];
float t = 0, tinc = (float)CYCLE_STEP/OVERSAMPLE;
int ctlpoint, i;
float BBasis[4][4] = {{-1, 3, -3, 1}, {3, -6, 3, 0},
{-3, 3, 0, 0}, {1, 0, 0, 0}};
int lastindex, newindex;
float pointset[3][4];
for (i = 0; i < 4; i++) /* z's are always zero, only 2-d */
pointset[2][i] = 0;
lastindex = -1;
for(ctlpoint = 0; ctlpoint < RotCurve[joint].numpoints; ctlpoint += 3) {
t = 0;
for (i = 0; i < 4; i++)
pointset[0][i] = RotCurve[joint].xcoords[ctlpoint + i];
for (i = 0; i < 4; i++)
pointset[1][i] = RotCurve[joint].angles[ctlpoint + i];
MultM(pointset, BBasis, prod);
while (t <= 1) {
tm[0] = t*t*t;
tm[1] = t*t;
tm[2] = t;
tm[3] = 1;
MultMV(prod, tm, pos);
newindex = (int)(pos[0]*(CYCLE_SIZE-1));
if ((int)(newindex > lastindex)) { /* go at least one */
Walk_cycle[0][joint][newindex] = pos[1];
lastindex++;
}
t += tinc;
}
}
for (i = 0; i < CYCLE_SIZE; i++) { /* copy to other leg, out-o-phase */
if (MirrorLegs)
Walk_cycle[1][joint][i] =
Walk_cycle[0][joint][i];
else
Walk_cycle[1][joint][i] =
Walk_cycle[0][joint][(i+(CYCLE_SIZE/2))%CYCLE_SIZE];
}
}
/***************************************************************/
/************************* CURVE I/O ***************************/
/***************************************************************/
void FlatCSet(void)
{
int joint;
for (joint = 0; joint < NUM_JOINTS; joint++) {
RotCurve[joint].numpoints = 4;
RotCurve[joint].xcoords[0] = 0.0;
RotCurve[joint].angles[0] = 0.0;
RotCurve[joint].xcoords[1] = 0.2;
RotCurve[joint].angles[1] = 0.0;
RotCurve[joint].xcoords[2] = 0.8;
RotCurve[joint].angles[2] = 0.0;
RotCurve[joint].xcoords[3] = 1.0;
RotCurve[joint].angles[3] = 0.0;
}
}
int ReadCSetFromFile(char *filename)
{
FILE *infile = fopen(filename, "r");
int numjoints, numpoints, joint, point, mirrorlegs;
float value;
if (infile == NULL)
goto abort;
if (!fscanf(infile, " %d", &numjoints) || numjoints != NUM_JOINTS)
goto abort;
if (!fscanf(infile, " %d", &mirrorlegs) || (mirrorlegs != 0 &&
mirrorlegs != 1))
goto abort;
MirrorLegs = mirrorlegs;
for (joint = 0; joint < NUM_JOINTS; joint++) {
if (!fscanf(infile, " %d", &numpoints) || numpoints < 4 ||
numpoints > MAX_CPOINTS)
goto abort;
RotCurve[joint].numpoints = numpoints;
for (point = 0; point < numpoints; point++) {
if (!fscanf(infile, " %f", &value))
goto abort;
RotCurve[joint].xcoords[point] = value;
}
for (point = 0; point < numpoints; point++) {
if (!fscanf(infile, " %f", &value))
goto abort;
RotCurve[joint].angles[point] = value;
}
}
fclose(infile);
return 0;
abort:
fclose(infile);
fprintf(stderr, "Something went wrong while reading file %s\n", filename);
FlatCSet();
return -1;
}
void WriteCSetToFile(char *filename)
{
FILE *outfile = fopen(filename, "w+");
int joint, point;
if (outfile == NULL) {
fprintf(stderr, "Error: could not create file %s\n", filename);
return;
}
fprintf(outfile, "%d\n", NUM_JOINTS);
fprintf(outfile, "%d\n", MirrorLegs);
for (joint = 0; joint < NUM_JOINTS; joint++) {
fprintf(outfile, "%d\n", RotCurve[joint].numpoints);
for (point = 0; point < RotCurve[joint].numpoints; point++) {
fprintf(outfile, "%f ", RotCurve[joint].xcoords[point]);
}
fprintf(outfile, "\n");
for (point = 0; point < RotCurve[joint].numpoints; point++) {
fprintf(outfile, "%f ", RotCurve[joint].angles[point]);
}
fprintf(outfile, "\n");
}
fclose(outfile);
}
void HandleLoadMenu(int cset)
{
char filename[MAX_CSETNAMELEN + CSET_EXTLEN + 1];
if (cset == -1) {
MakeLoadAndSaveMenus();
CurveMenuInit();
} else {
(void)strcpy(filename, CSetNames[cset]);
(void)strcat(filename, CSET_EXT);
if (ReadCSetFromFile(filename) == 0) {
glutSetMenu(SaveMenu);
glutChangeToMenuEntry(1, CSetNames[cset], cset);
ComputeCSetAndMakeLists();
SetWindowTitles(CSetNames[cset]);
RedisplayBoth();
}
}
}
void HandleSaveMenu(int cset)
{
char filename[MAX_CSETNAMELEN + CSET_EXTLEN + 1];
(void)strcpy(filename, CSetNames[cset]);
(void)strcat(filename, CSET_EXT);
WriteCSetToFile(filename);
ComputeCSetAndMakeLists();
RedisplayBoth();
}
int MakeLoadAndSaveMenus(void)
{
DIR *dirp = opendir(".");
struct dirent *direntp;
int csetnum = 0;
char *newcsetname;
if (LoadMenu != -1)
glutDestroyMenu(LoadMenu);
if (SaveMenu != -1)
glutDestroyMenu(SaveMenu);
SaveMenu = glutCreateMenu(HandleSaveMenu);
LoadMenu = glutCreateMenu(HandleLoadMenu);
if (dirp == NULL) {
fprintf(stderr, "Error opening current dir in MakeLoadAndSaveMenus\n");
return(0);
}
while ((direntp = readdir(dirp)) != NULL) {
char *ext = direntp->d_name + (strlen(direntp->d_name) - CSET_EXTLEN);
if (!strcmp(ext, CSET_EXT)) {
newcsetname = malloc(strlen(direntp->d_name) - CSET_EXTLEN + 1);
strncpy(newcsetname, direntp->d_name,
strlen(direntp->d_name) - CSET_EXTLEN);
newcsetname[strlen(direntp->d_name) - CSET_EXTLEN] = 0;
CSetNames[csetnum] = newcsetname;
glutAddMenuEntry(newcsetname, csetnum++);
}
}
closedir(dirp);
glutSetMenu(LoadMenu);
glutAddMenuEntry("-> Rescan Directory <-", -1);
glutSetMenu(SaveMenu);
CSetNames[csetnum] = "NewCurve0";
glutAddMenuEntry("NewCurve0", csetnum++);
CSetNames[csetnum] = "NewCurve1";
glutAddMenuEntry("NewCurve1", csetnum++);
CSetNames[csetnum] = "NewCurve2";
glutAddMenuEntry("NewCurve2", csetnum++);
return (csetnum - 2); /* just indicate curves in Load menu */
}
/***************************************************************/
/********************* DISPLAY LISTS ***************************/
/***************************************************************/
void MakeCurveList(int joint)
{
int i;
glNewList(CurveLists+joint, GL_COMPILE);
glColor3f(1, 1, 1);
for (i = 0; i < CYCLE_SIZE; i++) {
glVertex3f((GLfloat)i/CYCLE_SIZE, Walk_cycle[0][joint][i]/180, 0);
}
glEndList();
}
void MakeCPointList(int joint)
{
int point;
glNewList(ControlPtsLists+joint, GL_COMPILE);
glColor3f(0, 0.4, 0);
glBegin(GL_LINE_STRIP);
for (point = 0; point < RotCurve[joint].numpoints; point++) {
if (!((point-2) % 3)) {
glEnd();
glBegin(GL_LINE_STRIP);
}
glVertex3f(RotCurve[joint].xcoords[point],
(RotCurve[joint].angles[point])/180.0, 0.0);
}
glEnd();
glBegin(GL_POINTS);
for (point = 0; point < RotCurve[joint].numpoints; point++) {
if (point % 3)
glColor3f(0, 0.7, 0);
else
glColor3f(0.7, 0.0, 0);
glVertex3f(RotCurve[joint].xcoords[point],
(RotCurve[joint].angles[point])/180, 0);
}
glEnd();
glEndList();
}
void MakeJointLists(int joint)
{
MakeCurveList(joint);
MakeCPointList(joint);
}
void ComputeCSetAndMakeLists(void)
{
int joint;
for(joint = 0; joint < NUM_JOINTS; joint++) {
ComputeCurve(joint);
MakeJointLists(joint);
}
}
void MakeLists(void)
{
HorizontalList = glGenLists(1);
glNewList(HorizontalList, GL_COMPILE);
{
float line1 = 25.0/180,
line2 = 35.0/180,
line3 = 45.0/180;
glColor3f(0, 0, 0.7);
glPushAttrib(GL_ENABLE_BIT);
glEnable(GL_LINE_STIPPLE);
glBegin(GL_LINES);
glVertex3f(0, 0, 0.5);
glVertex3f(1, 0, 0.5);
glVertex3f(0, line1, 0.5); glVertex3f(1, line1, 0.5);
glVertex3f(0, -line1, 0.5); glVertex3f(1, -line1, 0.5);
glVertex3f(0, line2, 0.5); glVertex3f(1, line2, 0.5);
glVertex3f(0, -line2, 0.5); glVertex3f(1, -line2, 0.5);
glVertex3f(0, line3, 0.5); glVertex3f(1, line3, 0.5);
glVertex3f(0, -line3, 0.5); glVertex3f(1, -line3, 0.5);
glEnd();
glPopAttrib();
}
glEndList();
CurveLists = glGenLists(NUM_JOINTS);
assert(CurveLists != 0);
ControlPtsLists = glGenLists(NUM_JOINTS);
assert(ControlPtsLists != 0);
ComputeCSetAndMakeLists();
}
/***************************************************************/
/********************* curve WINDOW ****************************/
/***************************************************************/
void CurveReshape(int w, int h)
{
glViewport(0,0,w,h);
CurveWWidth = w;
CurveWHeight = h;
glFlush();
}
void CurveDisplay(void)
{
int joint, otherlegstep;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glTranslatef(0, 0.5, 0);
for (joint = NUM_JOINTS-1; joint >= 0; joint--) {
if (DrawHorizontals)
glCallList(HorizontalList);
(CurveAsPoints) ?
glBegin(GL_POINTS) :
glBegin(GL_LINE_STRIP);
glCallList(CurveLists+joint);
glEnd();
if (joint == EditingCurve) {
glPointSize(5.0);
glCallList(ControlPtsLists+EditingCurve);
glPointSize(1.0);
}
glTranslatef(0, 1, 0);
}
glPopMatrix();
otherlegstep = (Step+50) % CYCLE_SIZE;
/* draw vertical line */
glColor3f(1, 1, 1);
glBegin(GL_LINES);
glVertex3f((GLfloat)Step/CYCLE_SIZE, 0, 0);
glVertex3f((GLfloat)Step/CYCLE_SIZE, NUM_JOINTS, 0);
if (!MirrorLegs) {
glVertex3f((GLfloat)otherlegstep/CYCLE_SIZE, 0, 0);
glVertex3f((GLfloat)otherlegstep/CYCLE_SIZE, NUM_JOINTS, 0);
}
glEnd();
glFlush();
glutSwapBuffers();
}
void CurveGLInit(void)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0,1,0,NUM_JOINTS,1,-1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glLineStipple(1, 0x00FF);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glFlush();
}
/* ARGSUSED2 */
void CurveHandleButton(int button, int state, int x, int y)
{
if (button == GLUT_RIGHT_BUTTON )
return;
if (state == GLUT_DOWN && CurveDownBtn == -1) {
if (button == GLUT_MIDDLE_BUTTON)
CurveHandleMenu(CMENU_WALK);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -