⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 glpuzzle.c

📁 此书为Visual C++ 高级编程技术OpenGL篇
💻 C
📖 第 1 页 / 共 2 页
字号:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <malloc.h>
#include <time.h>
#include <math.h>
#include <GL/glaux.h>

#define WIDTH 4
#define HEIGHT 5
#define PIECES 10
#define OFFSETX -2
#define OFFSETY -2.5
#define OFFSETZ -0.5

typedef char Config[HEIGHT][WIDTH];

struct puzzle {
  struct puzzle *backptr;
  struct puzzle *solnptr;
  Config pieces;
  struct puzzle *next;
  unsigned hashvalue;
};

#define HASHSIZE 10691

struct puzzlelist {
  struct puzzle *puzzle;
  struct puzzlelist *next;
};

static char convert[PIECES + 1] = {0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 4};

static unsigned char colors[PIECES + 1][3] =
{
	{  0,   0,   0},{255, 255, 127},{255, 255, 127},{255, 255, 127},
	{255, 255, 127},{255, 127, 255},{255, 127, 255},{255, 127, 255},
	{255, 127, 255},{255, 127, 127},{255, 255, 255}
};

static struct puzzle *hashtable[HASHSIZE];
static struct puzzle *startPuzzle;
static struct puzzlelist *puzzles;
static struct puzzlelist *lastentry;

int curX, curY, visible;

#define MOVE_SPEED 0.2
static unsigned char movingPiece;
static float move_x, move_y;
static float curquat[4];
static int doubleBuffer = 1;
static int depth = 1;

static char xsize[PIECES + 1] = {0,1,1,1,1,1,1,1,1,2,2};
static char ysize[PIECES + 1] = {0,1,1,1,1,2,2,2,2,1,2};
static float zsize[PIECES + 1] = {0.0f,1.0f,1.0f,1.0f,1.0f,1.0f, 
                                  1.0f,1.0f,1.0f,1.0f,0.6f};

static Config startConfig =
{
  {8,10,10,7}, {8,10,10,7}, {6,9,9,5},{6,4,3,5}, {2,0,0,1}
};

static Config thePuzzle =
{
  {8,10,10,7},{8,10,10,7},{6,9,9,5},{6,4,3,5},{2,0,0,1}
};

static int xadds[4] = {-1, 0, 1, 0};
static int yadds[4] = {0, -1, 0, 1};
static long W = 400, H = 300;
static GLint viewport[4];

unsigned hash(Config config)
{
  int i, j, value;

  value = 0;
  for (i = 0; i < HEIGHT; i++) {
    for (j = 0; j < WIDTH; j++) {
      value = value + convert[config[i][j]];
      value *= 6;
    }
  }
  return (value);
}

float boxcoords[][3] =
{
  {0.2f, 0.2f, 0.9f},  {0.8f, 0.2f, 0.9f},
  {0.8f, 0.8f, 0.9f},  {0.2f, 0.8f, 0.9f},
  {0.2f, 0.1f, 0.8f},  {0.8f, 0.1f, 0.8f},
  {0.9f, 0.2f, 0.8f},  {0.9f, 0.8f, 0.8f},
  {0.8f, 0.9f, 0.8f},  {0.2f, 0.9f, 0.8f},
  {0.1f, 0.8f, 0.8f},  {0.1f, 0.2f, 0.8f},
  {0.2f, 0.1f, 0.2f},  {0.8f, 0.1f, 0.2f},
  {0.9f, 0.2f, 0.2f},  {0.9f, 0.8f, 0.2f},
  {0.8f, 0.9f, 0.2f},  {0.2f, 0.9f, 0.2f},
  {0.1f, 0.8f, 0.2f},  {0.1f, 0.2f, 0.2f},
  {0.2f, 0.2f, 0.1f},  {0.8f, 0.2f, 0.1f},
  {0.8f, 0.8f, 0.1f},  {0.2f, 0.8f, 0.1f},
};

float boxnormals[][3] =
{
  {0.0f, 0.0f, 1.0f},  {0.0f, 1.0f, 0.0f},
  {1.0f, 0.0f, 0.0f},  {0.0f, 0.0f, -1.0f},
  {0.0f, -1.0f, 0.0f}, {-1.0f, 0.0f, 0.0f},
  {0.7071f, 0.7071f, 0.0000f},  {0.7071f, -0.7071f, 0.0000f},
  {-0.7071f, 0.7071f, 0.0000f}, {-0.7071f, -0.7071f, 0.0000f},
  {0.7071f, 0.0000f, 0.7071f},  {0.7071f, 0.0000f, -0.7071f},
  {-0.7071f, 0.0000f, 0.7071f}, {-0.7071f, 0.0000f, -0.7071f},
  {0.0000f, 0.7071f, 0.7071f},  {0.0000f, 0.7071f, -0.7071f},
  {0.0000f, -0.7071f, 0.7071f}, {0.0000f, -0.7071f, -0.7071f},
  {0.5774f, 0.5774f, 0.5774f},  {0.5774f, 0.5774f, -0.5774f},
  {0.5774f, -0.5774f, 0.5774f}, {0.5774f, -0.5774f, -0.5774f},
  {-0.5774f, 0.5774f, 0.5774f}, {-0.5774f, 0.5774f, -0.5774f},
  {-0.5774f, -0.5774f, 0.5774f},{-0.5774f, -0.5774f, -0.5774f},
};

int boxfaces[][4] =
{
  {0, 1, 2, 3},   {9, 8, 16, 17},
  {6, 14, 15, 7}, {20, 23, 22, 21},
  {12, 13, 5, 4}, {19, 11, 10, 18},
  {7, 15, 16, 8}, {13, 14, 6, 5},
  {18, 10, 9, 17},{19, 12, 4, 11},
  {1, 6, 7, 2},   {14, 21, 22, 15},
  {11, 0, 3, 10}, {20, 19, 18, 23},
  {3, 2, 8, 9},   {17, 16, 22, 23},
  {4, 5, 1, 0},   {20, 21, 13, 12},
  {2, 7, 8, -1},  {16, 15, 22, -1},
  {5, 6, 1, -1},  {13, 21, 14, -1},
  {10, 3, 9, -1}, {18, 17, 23, -1},
  {11, 4, 0, -1}, {20, 12, 19, -1},
};

#define NBOXFACES (sizeof(boxfaces)/sizeof(boxfaces[0]))

/* Draw a box.  Bevel as desired. */
void drawBox(int piece, float xoff, float yoff)
{
  int xlen, ylen;
  int i, k;
  float x, y, z;
  float zlen;
  float *v;

  xlen = xsize[piece];
  ylen = ysize[piece];
  zlen = zsize[piece];

  glColor3ubv(colors[piece]);
  glBegin(GL_QUADS);
  for (i = 0; i < 18; i++) {
    glNormal3fv(boxnormals[i]);
    for (k = 0; k < 4; k++) {
      if (boxfaces[i][k] == -1)
        continue;
      v = boxcoords[boxfaces[i][k]];
      x = v[0] + OFFSETX;
      if (v[0] > 0.5)
        x += xlen - 1;
      y = v[1] + OFFSETY;
      if (v[1] > 0.5)
        y += ylen - 1;
      z = v[2] + OFFSETZ;
      if (v[2] > 0.5)
        z += zlen - 1;
      glVertex3f(xoff + x, yoff + y, z);
    }
  }
  glEnd();
  glBegin(GL_TRIANGLES);
  for (i = 18; i < NBOXFACES; i++) {
    glNormal3fv(boxnormals[i]);
    for (k = 0; k < 3; k++) {
      if (boxfaces[i][k] == -1)
        continue;
      v = boxcoords[boxfaces[i][k]];
      x = v[0] + OFFSETX;
      if (v[0] > 0.5)
        x += xlen - 1;
      y = v[1] + OFFSETY;
      if (v[1] > 0.5)
        y += ylen - 1;
      z = v[2] + OFFSETZ;
      if (v[2] > 0.5)
        z += zlen - 1;
      glVertex3f(xoff + x, yoff + y, z);
    }
  }
  glEnd();
}

float containercoords[][3] =
{
  {-0.1f, -0.1f, 1.0f}, {-0.1f, -0.1f, -0.1f},
  {4.1f, -0.1f, -0.1f}, {4.1f, -0.1f, 1.0f},
  {1.0f, -0.1f, 0.6f},  {3.0f, -0.1f, 0.6f},
  {1.0f, -0.1f, 0.0f},  {3.0f, -0.1f, 0.0f},
  {1.0f, 0.0f, 0.0f},   {3.0f, 0.0f, 0.0f},
  {3.0f, 0.0f, 0.6f},   {1.0f, 0.0f, 0.6f},
  {0.0f, 0.0f, 1.0f},   {4.0f, 0.0f, 1.0f},
  {4.0f, 0.0f, 0.0f},   {0.0f, 0.0f, 0.0f},
  {0.0f, 5.0f, 0.0f},   {0.0f, 5.0f, 1.0f},
  {4.0f, 5.0f, 1.0f},   {4.0f, 5.0f, 0.0f},
  {-0.1f, 5.1f, -0.1f}, {4.1f, 5.1f, -0.1f},
  {4.1f, 5.1f, 1.0f},   {-0.1f, 5.1f, 1.0f},
};

float containernormals[][3] =
{
  {0.0f, -1.0f, 0.0f},  {0.0f, -1.0f, 0.0f},
  {0.0f, -1.0f, 0.0f},  {0.0f, -1.0f, 0.0f},
  {0.0f, -1.0f, 0.0f},  {0.0f, 1.0f, 0.0f},
  {0.0f, 1.0f, 0.0f},   {0.0f, 1.0f, 0.0f},
  {1.0f, 0.0f, 0.0f},   {1.0f, 0.0f, 0.0f},
  {1.0f, 0.0f, 0.0f},   {-1.0f, 0.0f, 0.0f},
  {-1.0f, 0.0f, 0.0f},  {-1.0f, 0.0f, 0.0f},
  {0.0f, 1.0f, 0.0f},   {0.0f, 0.0f, -1.0f},
  {0.0f, 0.0f, -1.0f},  {0.0f, 0.0f, 1.0f},
  {0.0f, 0.0f, 1.0f},   {0.0f, 0.0f, 1.0f},
  {0.0f, 0.0f, 1.0f},   {0.0f, 0.0f, 1.0f},
  {0.0f, 0.0f, 1.0f},   {0.0f, 0.0f, 1.0f},
};

int containerfaces[][4] =
{
  {1, 6, 4, 0},     {0, 4, 5, 3},
  {1, 2, 7, 6},     {7, 2, 3, 5},
  {16, 19, 18, 17}, {23, 22, 21, 20},
  {12, 11, 8, 15},  {10, 13, 14, 9},
  {15, 16, 17, 12}, {2, 21, 22, 3},
  {6, 8, 11, 4},    {1, 0, 23, 20},
  {14, 13, 18, 19}, {9, 7, 5, 10},
  {12, 13, 10, 11}, {1, 20, 21, 2},
  {4, 11, 10, 5},   {15, 8, 19, 16},
  {19, 8, 9, 14},   {8, 6, 7, 9},
  {0, 3, 13, 12},   {13, 3, 22, 18},
  {18, 22, 23, 17}, {17, 23, 0, 12},
};

#define NCONTFACES (sizeof(containerfaces)/sizeof(containerfaces[0]))

/* Draw the container */
void drawContainer(void)
{
  int i, k;
  float *v;

  /* Y is reversed here because the model has it reversed */
  /* Arbitrary bright wood-like color */
  glColor3ub(209, 103, 23);
  glBegin(GL_QUADS);
  for (i = 0; i < NCONTFACES; i++) {
    v = containernormals[i];
    glNormal3f(v[0], -v[1], v[2]);
    for (k = 3; k >= 0; k--) {
      v = containercoords[containerfaces[i][k]];
      glVertex3f(v[0] + OFFSETX, -(v[1] + OFFSETY), v[2] + OFFSETZ);
    }
  }
  glEnd();
}

void drawAll(void)
{
  int i, j;
  int piece;
  char done[PIECES + 1];

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  glTranslatef(0, 0, -10);
  glRotatef(180, 0, 0, 1);

  if (depth) {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  } else {
    glClear(GL_COLOR_BUFFER_BIT);
  }
  for (i = 1; i <= PIECES; i++) {
    done[i] = 0;
  }
  glLoadName(0);
  drawContainer();
  for (i = 0; i < HEIGHT; i++) {
    for (j = 0; j < WIDTH; j++) {
      piece = thePuzzle[i][j];
      if (piece == 0)
        continue;
      if (done[piece])
        continue;
      done[piece] = 1;
      glLoadName(piece);
      if (piece == movingPiece) {
        drawBox(piece, move_x, move_y);
      } else {
        drawBox(piece, j, i);
      }
    }
  }
}

void CALLBACK redraw(void)
{
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(45, 1.0, 0.1, 100.0);

  drawAll();

  if (doubleBuffer)
    auxSwapBuffers();
  else
    glFinish();
}

/* Checks if a space can move */
int canmove0(Config pieces, int x, int y, int dir, Config newpieces)
{
  char piece;
  int xadd, yadd;
  int l, m;

  xadd = xadds[dir];
  yadd = yadds[dir];

  if (x + xadd < 0 || x + xadd >= WIDTH ||
    y + yadd < 0 || y + yadd >= HEIGHT)
    return 0;
  piece = pieces[y + yadd][x + xadd];
  if (piece == 0)
    return 0;
  memcpy(newpieces, pieces, HEIGHT * WIDTH);
  for (l = 0; l < WIDTH; l++) {
    for (m = 0; m < HEIGHT; m++) {
      if (newpieces[m][l] == piece)
        newpieces[m][l] = 0;
    }
  }
  xadd = -xadd;
  yadd = -yadd;
  for (l = 0; l < WIDTH; l++) {
    for (m = 0; m < HEIGHT; m++) {
      if (pieces[m][l] == piece) {
        int newx, newy;

        newx = l + xadd;
        newy = m + yadd;
        if (newx < 0 || newx >= WIDTH ||
          newy < 0 || newy >= HEIGHT)
          return 0;
        if (newpieces[newy][newx] != 0)
          return 0;
        newpieces[newy][newx] = piece;
      }
    }
  }
  return 1;
}

/* Checks if a piece can move */
int canmove(Config pieces, int x, int y, int dir, Config newpieces)
{
  int xadd, yadd;

  xadd = xadds[dir];
  yadd = yadds[dir];

  if (x + xadd < 0 || x + xadd >= WIDTH ||
    y + yadd < 0 || y + yadd >= HEIGHT)
    return 0;
  if (pieces[y + yadd][x + xadd] == pieces[y][x]) {
    return canmove(pieces, x + xadd, y + yadd, dir, newpieces);
  }
  if (pieces[y + yadd][x + xadd] != 0)
    return 0;
  return canmove0(pieces, x + xadd, y + yadd, (dir + 2) % 4, newpieces);
}

int selectPiece(int mousex, int mousey)
{
  long hits;
  GLuint selectBuf[1024];
  GLuint closest;
  GLuint dist;

  glSelectBuffer(1024, selectBuf);
  (void) glRenderMode(GL_SELECT);
  glInitNames();

  /* Because LoadName() won't work with no names on the stack */
  glPushName(-1);

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPickMatrix(mousex, H - mousey, 4, 4, viewport);
  gluPerspective(45, 1.0, 0.1, 100.0);

  drawAll();

  hits = glRenderMode(GL_RENDER);
  if (hits <= 0) {
    return 0;
  }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -