Blame projects/jigsaw/puzzle.chunk.c

Ivan Mahonin fdbd7d
Ivan Mahonin fdbd7d
#include "puzzle.h"
Ivan Mahonin fdbd7d
Ivan Mahonin fdbd7d
Ivan Mahonin fdbd7d
Ivan Mahonin fdbd7d
unsigned int chunkCalcEdges(Chunk *c) {
Ivan Mahonin fdbd7d
  unsigned int edges = 0;
Ivan Mahonin fdbd7d
  if (c->c   <= 0           || c->pz->chunks[c->r][c->c-1].parent != c->parent) edges |= PF_BORDER_L;
Ivan Mahonin fdbd7d
  if (c->c+1 >= c->pz->cols || c->pz->chunks[c->r][c->c+1].parent != c->parent) edges |= PF_BORDER_R;
Ivan Mahonin fdbd7d
  if (c->r   <= 0           || c->pz->chunks[c->r-1][c->c].parent != c->parent) edges |= PF_BORDER_T;
Ivan Mahonin fdbd7d
  if (c->r+1 >= c->pz->rows || c->pz->chunks[c->r+1][c->c].parent != c->parent) edges |= PF_BORDER_B;
Ivan Mahonin fdbd7d
  return edges;
Ivan Mahonin fdbd7d
}
Ivan Mahonin fdbd7d
Ivan Mahonin fdbd7d
Ivan Mahonin fdbd7d
void chunkDrawBase(Chunk *c, unsigned int edges) {
Ivan Mahonin fdbd7d
  int levels = 4;
Ivan Mahonin fdbd7d
  Vec gp = chunkGroupPos(c);
Ivan Mahonin fdbd7d
  
Ivan Mahonin fdbd7d
  saveState();
Ivan Mahonin fdbd7d
  noFill();
Ivan Mahonin fdbd7d
  strokeWidth( mind(c->pz->cs.x, c->pz->cs.y)*0.025 );
Ivan Mahonin fdbd7d
  translate(-gp.x, -gp.y);
Ivan Mahonin fdbd7d
  if (edges & PF_BORDER_T) lineDraw(c->pz->hlines[c->r + 0] + (c->c + 0)*LN_SEGS,  1, levels);
Ivan Mahonin fdbd7d
  if (edges & PF_BORDER_R) lineDraw(c->pz->vlines[c->c + 1] + (c->r + 0)*LN_SEGS,  1, levels);
Ivan Mahonin fdbd7d
  if (edges & PF_BORDER_B) lineDraw(c->pz->hlines[c->r + 1] + (c->c + 1)*LN_SEGS, -1, levels);
Ivan Mahonin fdbd7d
  if (edges & PF_BORDER_L) lineDraw(c->pz->vlines[c->c + 0] + (c->r + 1)*LN_SEGS, -1, levels);
Ivan Mahonin fdbd7d
  restoreState();
Ivan Mahonin fdbd7d
Ivan Mahonin fdbd7d
  saveState();
Ivan Mahonin fdbd7d
  translate(-gp.x, -gp.y);
Ivan Mahonin fdbd7d
  /*strokeWidth( mind(c->pz->cs.x, c->pz->cs.y)*0.1 );
Ivan Mahonin fdbd7d
  stroke(COLOR_WHITE);
Ivan Mahonin fdbd7d
  strokeTexture(c->pz->image, 0, 0, c->pz->cols*c->pz->cs.x, c->pz->rows*c->pz->cs.x, FALSE);
Ivan Mahonin fdbd7d
  if (edges & PF_BORDER_T)    lineDraw(c->pz->hlines[c->r + 0] + (c->c + 0)*LN_SEGS,  1, levels);
Ivan Mahonin fdbd7d
  if (edges & PF_BORDER_R)  lineDraw(c->pz->vlines[c->c + 1] + (c->r + 0)*LN_SEGS,  1, levels);
Ivan Mahonin fdbd7d
  if (edges & PF_BORDER_B) lineDraw(c->pz->hlines[c->r + 1] + (c->c + 1)*LN_SEGS, -1, levels);
Ivan Mahonin fdbd7d
  if (edges & PF_BORDER_L)   lineDraw(c->pz->vlines[c->c + 0] + (c->r + 1)*LN_SEGS, -1, levels);*/
Ivan Mahonin fdbd7d
  noStroke();
Ivan Mahonin fdbd7d
  fill(COLOR_WHITE);
Ivan Mahonin fdbd7d
  fillTexture(c->pz->image, 0, 0, c->pz->cols*c->pz->cs.x, c->pz->rows*c->pz->cs.y, FALSE);
Ivan Mahonin fdbd7d
  linePut(c->pz->hlines[c->r + 0] + (c->c + 0)*LN_SEGS,  1, levels);
Ivan Mahonin fdbd7d
  linePut(c->pz->vlines[c->c + 1] + (c->r + 0)*LN_SEGS,  1, levels);
Ivan Mahonin fdbd7d
  linePut(c->pz->hlines[c->r + 1] + (c->c + 1)*LN_SEGS, -1, levels);
Ivan Mahonin fdbd7d
  linePut(c->pz->vlines[c->c + 0] + (c->r + 1)*LN_SEGS, -1, levels);
Ivan Mahonin fdbd7d
  closePath();
Ivan Mahonin fdbd7d
  restoreState();
Ivan Mahonin fdbd7d
}
Ivan Mahonin fdbd7d
Ivan Mahonin fdbd7d
Ivan Mahonin fdbd7d
void chunkDraw(Chunk *c) {
Ivan Mahonin fdbd7d
  saveState();
Ivan Mahonin fdbd7d
  Vec p = chunkWorldPos(c);
Ivan Mahonin fdbd7d
  translate(p.x, p.y);
Ivan Mahonin fdbd7d
  rotate(vangled(c->parent->dx));
Ivan Mahonin fdbd7d
  if (c->t.tex && c->t.ts > 1e-5 && (c->flags & PF_RENDERED)) {
Ivan Mahonin fdbd7d
    translate(-c->t.s/2, -c->t.s/2);
Ivan Mahonin fdbd7d
    noStroke();
Ivan Mahonin fdbd7d
    double k = c->t.s/c->t.ts;
Ivan Mahonin fdbd7d
    fillTexture(c->t.tex, -c->t.tp.x*k, -c->t.tp.y*k, k, k, FALSE);
Ivan Mahonin fdbd7d
    rect(0, 0, c->t.s, c->t.s);
Ivan Mahonin fdbd7d
  } else {
Ivan Mahonin fdbd7d
    chunkDrawBase(c, chunkCalcEdges(c));
Ivan Mahonin fdbd7d
  }
Ivan Mahonin fdbd7d
  restoreState();
Ivan Mahonin fdbd7d
}
Ivan Mahonin fdbd7d
Ivan Mahonin fdbd7d
Ivan Mahonin fdbd7d
void chunkDrawDebug(Chunk *c) {
Ivan Mahonin fdbd7d
  saveState();
Ivan Mahonin fdbd7d
  Vec p = chunkWorldPos(c);
Ivan Mahonin fdbd7d
  translate(p.x, p.y);
Ivan Mahonin fdbd7d
  rotate(vangled(c->parent->dx));
Ivan Mahonin fdbd7d
  stroke(randColorPtr(c->parent));
Ivan Mahonin fdbd7d
  Vec hs = vdiv(c->pz->cs, 2);
Ivan Mahonin fdbd7d
  if (c->flags & PF_HANDLE_L) line(-hs.x, -hs.y, -hs.x,  hs.y);
Ivan Mahonin fdbd7d
  if (c->flags & PF_HANDLE_R) line( hs.x, -hs.y,  hs.x,  hs.y);
Ivan Mahonin fdbd7d
  if (c->flags & PF_HANDLE_T) line(-hs.x, -hs.y,  hs.x, -hs.y);
Ivan Mahonin fdbd7d
  if (c->flags & PF_HANDLE_B) line(-hs.x,  hs.y,  hs.x,  hs.y);
Ivan Mahonin fdbd7d
  restoreState();
Ivan Mahonin fdbd7d
}
Ivan Mahonin fdbd7d
Ivan Mahonin fdbd7d
Ivan Mahonin fdbd7d
void chunkRender(Chunk *c) {
Ivan Mahonin fdbd7d
  if (!c->t.fb || !(c->t.ts > 1e-5)) return;
Ivan Mahonin fdbd7d
Ivan Mahonin fdbd7d
  unsigned int edges = PF_RENDERED | chunkCalcEdges(c);
Ivan Mahonin fdbd7d
  if ((c->flags & PF_RENDERING) == edges) return;
Ivan Mahonin fdbd7d
  
Ivan Mahonin fdbd7d
  saveState();
Ivan Mahonin fdbd7d
  target(c->t.fb);
Ivan Mahonin fdbd7d
  resetStateEx(STATE_TRANSFORM);
Ivan Mahonin fdbd7d
Ivan Mahonin fdbd7d
  int ix = (int)round(c->t.tp.x*TM_SIZE);
Ivan Mahonin fdbd7d
  int iy = (int)round(c->t.tp.y*TM_SIZE);
Ivan Mahonin fdbd7d
  int s = (int)round(c->t.ts*TM_SIZE);
Ivan Mahonin fdbd7d
  background(COLOR_TRANSPARENT);
Ivan Mahonin fdbd7d
  glEnable(GL_SCISSOR_TEST);
Ivan Mahonin fdbd7d
  glScissor(ix, iy, s, s);
Ivan Mahonin fdbd7d
  clear();
Ivan Mahonin fdbd7d
  glScissor(0, 0, TM_SIZE, TM_SIZE);
Ivan Mahonin fdbd7d
  glDisable(GL_SCISSOR_TEST);
Ivan Mahonin fdbd7d
Ivan Mahonin fdbd7d
  double k = c->t.s/c->t.ts;
Ivan Mahonin fdbd7d
  zoom(TM_SIZE/k);
Ivan Mahonin fdbd7d
  translate(c->t.tp.x*k + c->t.s/2, c->t.tp.y*k + c->t.s/2);
Ivan Mahonin fdbd7d
  cliprect(-c->t.s/2, -c->t.s/2, c->t.s, c->t.s);
Ivan Mahonin fdbd7d
  chunkDrawBase(c, edges);
Ivan Mahonin fdbd7d
  c->flags |= edges;
Ivan Mahonin fdbd7d
Ivan Mahonin fdbd7d
  restoreState();
Ivan Mahonin fdbd7d
}
Ivan Mahonin fdbd7d
Ivan Mahonin dcf1b6
Ivan Mahonin fdbd7d
void chunkMerge(Chunk *a, Chunk *b) {
Ivan Mahonin fdbd7d
  if (a->parent == b->parent) return;
Ivan Mahonin fdbd7d
  Puzzle *pz = a->pz;
Ivan Mahonin fdbd7d
  PhGroup *pa = a->parent, *pb = b->parent;
Ivan Mahonin fdbd7d
  phGroupMerge(pa, pb);
Ivan Mahonin f8c4ae
  phGroupFix(pa, !pz->turn);
Ivan Mahonin fdbd7d
  
Ivan Mahonin fdbd7d
  for(int r = 0; r < pz->rows; ++r)
Ivan Mahonin fdbd7d
  for(int c = 0; c < pz->cols; ++c) {
Ivan Mahonin fdbd7d
    Chunk *chunk = &pz->chunks[r][c];
Ivan Mahonin fdbd7d
    if (chunk->parent == pa || chunk->parent == pb) chunk->flags &= ~PF_HANDLES;
Ivan Mahonin fdbd7d
    if (chunk->parent != pb) continue;
Ivan Mahonin fdbd7d
    chunk->parent = pa;
Ivan Mahonin fdbd7d
    chunkRender(chunk);
Ivan Mahonin fdbd7d
    if (c   > 0       ) chunkRender(&pz->chunks[r][c-1]);
Ivan Mahonin fdbd7d
    if (c+1 < pz->cols) chunkRender(&pz->chunks[r][c+1]);
Ivan Mahonin fdbd7d
    if (r   > 0       ) chunkRender(&pz->chunks[r-1][c]);
Ivan Mahonin fdbd7d
    if (r+1 < pz->rows) chunkRender(&pz->chunks[r+1][c]);
Ivan Mahonin fdbd7d
  }
Ivan Mahonin fdbd7d
  
Ivan Mahonin fdbd7d
  int c0 = pz->cols-1, c1 = 0;
Ivan Mahonin fdbd7d
  for(int r = 0; r < pz->rows; ++r) {
Ivan Mahonin fdbd7d
    Chunk *first = NULL, *last = NULL;
Ivan Mahonin fdbd7d
    for(int c = 0; c < pz->cols; ++c) {
Ivan Mahonin fdbd7d
      Chunk *chunk = &pz->chunks[r][c];
Ivan Mahonin fdbd7d
      if (chunk->parent != pa) continue;
Ivan Mahonin fdbd7d
      if (c <= c0) { first = chunk; c0 = c; }
Ivan Mahonin fdbd7d
      if (c >= c1) { last  = chunk; c1 = c; }
Ivan Mahonin fdbd7d
    }
Ivan Mahonin fdbd7d
    if (first) first->flags |= PF_HANDLE_L;
Ivan Mahonin fdbd7d
    if (last)  last->flags  |= PF_HANDLE_R;
Ivan Mahonin fdbd7d
  }
Ivan Mahonin fdbd7d
Ivan Mahonin fdbd7d
  c0 = pz->cols-1, c1 = 0;
Ivan Mahonin fdbd7d
  for(int r = pz->rows-1; r >= 0; --r) {
Ivan Mahonin fdbd7d
    Chunk *first = NULL, *last = NULL;
Ivan Mahonin fdbd7d
    for(int c = 0; c < pz->cols; ++c) {
Ivan Mahonin fdbd7d
      Chunk *chunk = &pz->chunks[r][c];
Ivan Mahonin fdbd7d
      if (chunk->parent != pa) continue;
Ivan Mahonin fdbd7d
      if (c <= c0) { first = chunk; c0 = c; }
Ivan Mahonin fdbd7d
      if (c >= c1) { last  = chunk; c1 = c; }
Ivan Mahonin fdbd7d
    }
Ivan Mahonin fdbd7d
    if (first) first->flags |= PF_HANDLE_L;
Ivan Mahonin fdbd7d
    if (last)  last->flags  |= PF_HANDLE_R;
Ivan Mahonin fdbd7d
  }
Ivan Mahonin fdbd7d
  
Ivan Mahonin fdbd7d
  int r0 = pz->rows-1, r1 = 0;
Ivan Mahonin fdbd7d
  for(int c = 0; c < pz->cols; ++c) {
Ivan Mahonin fdbd7d
    Chunk *first = NULL, *last = NULL;
Ivan Mahonin fdbd7d
    for(int r = 0; r < pz->rows; ++r) {
Ivan Mahonin fdbd7d
      Chunk *chunk = &pz->chunks[r][c];
Ivan Mahonin fdbd7d
      if (chunk->parent != pa) continue;
Ivan Mahonin fdbd7d
      if (r <= r0) { first = chunk; r0 = r; }
Ivan Mahonin fdbd7d
      if (r >= r1) { last  = chunk; r1 = r; }
Ivan Mahonin fdbd7d
    }
Ivan Mahonin fdbd7d
    if (first) first->flags |= PF_HANDLE_T;
Ivan Mahonin fdbd7d
    if (last)  last->flags  |= PF_HANDLE_B;
Ivan Mahonin fdbd7d
  }
Ivan Mahonin fdbd7d
Ivan Mahonin fdbd7d
  r0 = pz->rows-1, r1 = 0;
Ivan Mahonin fdbd7d
  for(int c = pz->cols-1; c >= 0; --c) {
Ivan Mahonin fdbd7d
    Chunk *first = NULL, *last = NULL;
Ivan Mahonin fdbd7d
    for(int r = 0; r < pz->rows; ++r) {
Ivan Mahonin fdbd7d
      Chunk *chunk = &pz->chunks[r][c];
Ivan Mahonin fdbd7d
      if (chunk->parent != pa) continue;
Ivan Mahonin fdbd7d
      if (r <= r0) { first = chunk; r0 = r; }
Ivan Mahonin fdbd7d
      if (r >= r1) { last  = chunk; r1 = r; }
Ivan Mahonin fdbd7d
    }
Ivan Mahonin fdbd7d
    if (first) first->flags |= PF_HANDLE_T;
Ivan Mahonin fdbd7d
    if (last)  last->flags  |= PF_HANDLE_B;
Ivan Mahonin fdbd7d
  }
Ivan Mahonin fdbd7d
}
Ivan Mahonin fdbd7d
Ivan Mahonin fdbd7d
Ivan Mahonin fdbd7d
void chunkTryMerge(Chunk *a, int dr, int dc) {
Ivan Mahonin fdbd7d
  int r = a->r + dr;
Ivan Mahonin fdbd7d
  int c = a->c + dc;
Ivan Mahonin fdbd7d
  Puzzle *pz = a->pz;
Ivan Mahonin fdbd7d
  if (r < 0 || c < 0 || r >= pz->rows || c >= pz->cols) return;
Ivan Mahonin fdbd7d
  
Ivan Mahonin fdbd7d
  Chunk *b = &pz->chunks[r][c];
Ivan Mahonin fdbd7d
  if (a->parent == b->parent) return;
Ivan Mahonin fdbd7d
  
Ivan Mahonin fdbd7d
  Vec gp = vadd( chunkGroupPos(a), vdiv(vec(dc,dr), 2));
Ivan Mahonin fdbd7d
  Vec pa = phGroupTrans(a->parent, gp);
Ivan Mahonin fdbd7d
  Vec pb = phGroupTrans(b->parent, gp);
Ivan Mahonin fdbd7d
  double d2 = vdist2(pb, pa);
Ivan Mahonin fdbd7d
Ivan Mahonin fdbd7d
  if (d2 < pz->cs.x*pz->cs.y/16)
Ivan Mahonin fdbd7d
    chunkMerge(a, b);
Ivan Mahonin fdbd7d
}
Ivan Mahonin fdbd7d
Ivan Mahonin fdbd7d
Ivan Mahonin fdbd7d
Flags chunkCheckPoint(Chunk *c, Vec p) {
Ivan Mahonin fdbd7d
  Vec hs = vdiv(c->pz->cs, 2);
Ivan Mahonin fdbd7d
  double hbs = mind(hs.x, hs.y);
Ivan Mahonin fdbd7d
  Vec hs0 = vsub(hs, vecxy(hbs*0.25));
Ivan Mahonin fdbd7d
  Vec hs1 = vadd(hs, vecxy(hbs*0.50));
Ivan Mahonin fdbd7d
  Vec gp = vsub(phGroupUntrans(c->parent, p), chunkGroupPos(c));
Ivan Mahonin fdbd7d
  int l = c->flags & (gp.x < 0 ? PF_HANDLE_L : PF_HANDLE_R);
Ivan Mahonin fdbd7d
  int t = c->flags & (gp.y < 0 ? PF_HANDLE_T : PF_HANDLE_B);
Ivan Mahonin fdbd7d
  gp = vabs(gp);
Ivan Mahonin fdbd7d
Ivan Mahonin fdbd7d
  int inx = gp.x < hs0.x;
Ivan Mahonin fdbd7d
  int iny = gp.y < hs0.y;
Ivan Mahonin fdbd7d
  if (!(gp.x < hs1.x) || !(gp.y < hs1.y)) return 0;
Ivan Mahonin fdbd7d
  if (inx && iny) return PCP_BODY;
Ivan Mahonin fdbd7d
  
Ivan Mahonin fdbd7d
  Flags res = 0;
Ivan Mahonin fdbd7d
  if (gp.x < hs.x && gp.y < hs.y) res |= PCP_BODY;
Ivan Mahonin fdbd7d
  double r = hs1.x - hs.x;
Ivan Mahonin fdbd7d
  if ( (l && !inx && gp.y < hs.y)
Ivan Mahonin fdbd7d
    || (t && !iny && gp.x < hs.x)
Ivan Mahonin fdbd7d
    || (l && t && !inx && !iny && vdist2(gp, hs) < r*r) ) res |= PCP_EDGE;
Ivan Mahonin fdbd7d
  return res;
Ivan Mahonin fdbd7d
}
Ivan Mahonin fdbd7d
Ivan Mahonin fdbd7d