コード例 #1
0
ファイル: t1.c プロジェクト: piotrm0/progs
GLvoid draw_tile(tile* t, u_int d, u_int draw, GLfloat alpha) {
  u_int i;
  //printf("draw_tile(%d)\n", (u_int) t);

  if (t == NULL)
    return;

  if (t->flags & TILE_DRAWN)
    return;

  t->flags |= TILE_DRAWN;

  glPushMatrix();

  glTranslatef((GLfloat) t->coord[0],
	       0,
	       (GLfloat) t->coord[1]);

  if (draw & DRAW_WALL)
    draw_tile_wall(t);

  if ((t->flags & TILE_HAS_PRISM) &&
      (draw & DRAW_PRISM))
    draw_tile_prism(t->prism_dir, t->prism_color);
    
  if (draw & DRAW_INFO) {
    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, fvone);
    glMaterialfv(GL_FRONT, GL_EMISSION, fvone);
    gl_print(0.0f, 0.0f, 0.0f, tile_label(t));
  }

  if ((t->flags & TILE_HAS_MARK) &&
      (draw & DRAW_MARK))
    draw_tile_mark(t->mark_type, t->mark_color, alpha);

  if (draw & DRAW_TILE) {

    tile_diffuse[3] = alpha;
    tile_emit[3] = alpha;

    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, tile_diffuse);
    glMaterialfv(GL_FRONT, GL_EMISSION, tile_emit);

    glPushMatrix();
    //glTranslatef(0.0f, 0.025f, 0.0f);
    //  glScalef(1.0f, 0.05f, 1.0f);
    //glutSolidCube(1.0f);
    glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_TILE]);

    //    glActiveTextureARB( GL_TEXTURE1_ARB );
    //    glClientActiveTextureARB( GL_TEXTURE1_ARB );
    //    glEnable( GL_TEXTURE_2D );

    //Set up the blending of the 2 textures
    /*glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE_EXT);
    glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB_EXT,GL_INTERPOLATE_EXT);
    glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE0_RGB_EXT,GL_PREVIOUS_EXT);
    glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND0_RGB_EXT,GL_SRC_COLOR);
    glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE1_RGB_EXT,GL_TEXTURE);
    glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND1_RGB_EXT,GL_SRC_COLOR);
    glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE2_RGB_EXT,GL_TEXTURE);
    glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND2_RGB_EXT,GL_SRC_ALPHA);*/

    //Texture 0 on TU 1
    //glBindTexture( GL_TEXTURE_2D, textures[TEXTURE_MARK_MOON_RED]);

    //Switch off the TU 1
    //    glDisable( GL_TEXTURE_2D );
    //    glActiveTextureARB( GL_TEXTURE0_ARB );
    //    glClientActiveTextureARB( GL_TEXTURE0_ARB );

    glBegin(GL_QUADS);
    glTexCoord2d(0.0, 0.0); glVertex3f(-0.5, 0.0, -0.5);
    glTexCoord2d(0.0, 1.0); glVertex3f(-0.5, 0.0,  0.5);
    glTexCoord2d(1.0, 1.0); glVertex3f( 0.5, 0.0,  0.5);
    glTexCoord2d(1.0, 0.0); glVertex3f( 0.5, 0.0, -0.5);
    glEnd();
    glPopMatrix();

    /*
    glLineWidth(2.0f);
    glPushMatrix();
      glTranslatef(0, 0.06, 0);
      glScalef(0.5f, 1, 0.5f);
      glBegin(GL_LINE_LOOP);
        glVertex3f(-1, 0, -1);
	glVertex3f(1, 0, -1);
	glVertex3f(1, 0, 1);
	glVertex3f(-1, 0, 1);
      glEnd();
    glPopMatrix();
    */

  }

  glPopMatrix();

  for (i = 0; i < DIRS; i++)
    draw_tile(t->tile_p[i], i, draw, alpha);
}
コード例 #2
0
ファイル: t1.c プロジェクト: piotrm0/progs
GLvoid init_scene(GLvoid) {
  u_int* temp;

  temp = (u_int*) calloc(DIMS, sizeof(u_int));
  //  printf("allocated initial [%x]\n", temp);
  temp[0] = 0;
  temp[1] = 0;

  view_main = view_new(0,
		       VIEW_NONE,
		       GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT,
		       0, 0,
		       1, 1);
  view_main->draw_func = draw_scene;

  /*
    view_main->subviews[0] = view_new(0,
				    VIEW_FG | VIEW_BG | VIEW_ASPECT,
				    GL_DEPTH_BUFFER_BIT,
				    0.0, 0.0,
				    0.3, 0.3);
  view_main->subviews[0]->alpha = 0.5f;
  view_main->subviews[0]->draw_func = draw_static_board;
  */
  

  board* b11;
  board* b12;
  board* b13;
  board* b21;
  board* b22;
  board* b23;
  board* b31;
  board* b32;
  board* b33;

  b11 = read_2d("boards/red-star-p.board");
  b21 = read_2d("boards/red-saturn-p.board");
  //b31 = read_2d("boards/red-gear-p.board");
  b12 = read_2d("boards/red-gear-p.board");

  b22 = read_2d("boards/red-moon-p.board");

  //b32 = read_2d("boards/red-saturn-np.board");
  //b13 = read_2d("boards/red-star-p.board");
  //b23 = read_2d("boards/red-gear-np.board");
  //b33 = read_2d("boards/red-moon-p.board");

  //  board_rotate_2d(b2, 1);
  //  board_rotate_2d(b3, 3);
  //  board_rotate_2d(b4, 2);

  boards_stich_2d(b11, DIR_RIGHT, b12);
  // boards_stich_2d(b12, DIR_RIGHT, b13);
  boards_stich_2d(b21, DIR_RIGHT, b22);
  //boards_stich_2d(b22, DIR_RIGHT, b23);
  //boards_stich_2d(b31, DIR_RIGHT, b32);
  //boards_stich_2d(b32, DIR_RIGHT, b33);

  boards_stich_2d(b11, DIR_DOWN, b21);
  //boards_stich_2d(b21, DIR_DOWN, b31);
  boards_stich_2d(b12, DIR_DOWN, b22);
  //boards_stich_2d(b22, DIR_DOWN, b32);
  //boards_stich_2d(b13, DIR_DOWN, b23);
  //boards_stich_2d(b23, DIR_DOWN, b33);

  board_clean_stich(b11);
  board_clean_stich(b12);
  //board_clean_stich(b13);
  board_clean_stich(b21);
  board_clean_stich(b22);
  //board_clean_stich(b23);
  //board_clean_stich(b31);
  //board_clean_stich(b32);
  //board_clean_stich(b33);

  tile_clear_flag(b11->origin, TILE_CHECKED);
  tile_fill_coord(b11->origin, temp);

  //  exit(0);

  robots   = robots_new();
  robots_v = robots_new();

  origin = b11->origin;
  cursor = origin;

  place_robot(COLOR_RED, origin);
  place_robot(COLOR_GREEN, origin->tile_p[DIR_RIGHT]);
  place_robot(COLOR_BLUE, origin->tile_p[DIR_DOWN]);
  place_robot(COLOR_YELLOW, origin->tile_p[DIR_RIGHT]->tile_p[DIR_RIGHT]);
  place_robot(COLOR_BLACK, origin->tile_p[DIR_DOWN]->tile_p[DIR_DOWN]);

  textures = (GLuint*) calloc(TEXTURES, sizeof(GLuint));
  if (textures == NULL)
    pexit(errno, "init_scene: can't allocate texture array");

  textures[TEXTURE_TILE] = gl_load_texture_png("gfx/tile.png", 0);
  textures[TEXTURE_MARK_MOON_RED]    = gl_load_texture_png("gfx/mark_moon_red.png", 1);
  textures[TEXTURE_MARK_MOON_GREEN]  = gl_load_texture_png("gfx/mark_moon_green.png", 1);
  textures[TEXTURE_MARK_MOON_BLUE]   = gl_load_texture_png("gfx/mark_moon_blue.png", 1);
  textures[TEXTURE_MARK_MOON_YELLOW] = gl_load_texture_png("gfx/mark_moon_yellow.png", 1);
  textures[TEXTURE_MARK_STAR_RED]    = gl_load_texture_png("gfx/mark_star_red.png", 1);
  textures[TEXTURE_MARK_STAR_GREEN]  = gl_load_texture_png("gfx/mark_star_green.png", 1);
  textures[TEXTURE_MARK_STAR_BLUE]   = gl_load_texture_png("gfx/mark_star_blue.png", 1);
  textures[TEXTURE_MARK_STAR_YELLOW] = gl_load_texture_png("gfx/mark_star_yellow.png", 1);
  textures[TEXTURE_MARK_SATURN_RED]    = gl_load_texture_png("gfx/mark_saturn_red.png", 1);
  textures[TEXTURE_MARK_SATURN_GREEN]  = gl_load_texture_png("gfx/mark_saturn_green.png", 1);
  textures[TEXTURE_MARK_SATURN_BLUE]   = gl_load_texture_png("gfx/mark_saturn_blue.png", 1);
  textures[TEXTURE_MARK_SATURN_YELLOW] = gl_load_texture_png("gfx/mark_saturn_yellow.png", 1);
  textures[TEXTURE_MARK_GEAR_RED]    = gl_load_texture_png("gfx/mark_gear_red.png", 1);
  textures[TEXTURE_MARK_GEAR_GREEN]  = gl_load_texture_png("gfx/mark_gear_green.png", 1);
  textures[TEXTURE_MARK_GEAR_BLUE]   = gl_load_texture_png("gfx/mark_gear_blue.png", 1);
  textures[TEXTURE_MARK_GEAR_YELLOW] = gl_load_texture_png("gfx/mark_gear_yellow.png", 1);
  textures[TEXTURE_MARK_WARP]        = gl_load_texture_png("gfx/mark_warp.png", 1);

  glNewList(DRAW_LIST_TABLE, GL_COMPILE);
  draw_table();
  glEndList();

  tile_clear_flag(origin, TILE_DRAWN);
  glNewList(DRAW_LIST_TILE, GL_COMPILE);
  draw_tile(origin, DIR_LEFT, DRAW_TILE, 1.0f);
  glEndList();

  tile_clear_flag(origin, TILE_DRAWN);
  glNewList(DRAW_LIST_TILE_TRANS, GL_COMPILE);
  draw_tile(origin, DIR_LEFT, DRAW_TILE, 0.75f);
  glEndList();

  tile_clear_flag(origin, TILE_DRAWN);
  glNewList(DRAW_LIST_MARK, GL_COMPILE);
  glDisable(GL_DEPTH_TEST);
  draw_tile(origin, DIR_LEFT, DRAW_MARK, 1.0f);
  glEnable(GL_DEPTH_TEST);
  glEndList();

  tile_clear_flag(origin, TILE_DRAWN);
  glNewList(DRAW_LIST_MARK_TRANS, GL_COMPILE);
  glDisable(GL_DEPTH_TEST);
  draw_tile(origin, DIR_LEFT, DRAW_MARK, 0.75f);
  glEnable(GL_DEPTH_TEST);
  glEndList();

  tile_clear_flag(origin, TILE_DRAWN);
  glNewList(DRAW_LIST_WALL, GL_COMPILE);
  draw_tile(origin, DIR_LEFT, DRAW_WALL, 1.0f);
  glEndList();

  tile_clear_flag(origin, TILE_DRAWN);
  glNewList(DRAW_LIST_PRISM, GL_COMPILE);
  draw_tile(origin, DIR_LEFT, DRAW_PRISM, 1.0f);
  glEndList();

  compile_robots();
}
コード例 #3
0
ファイル: twiddle.c プロジェクト: chrisboyle/sgtpuzzles
static void game_redraw(drawing *dr, game_drawstate *ds,
                        const game_state *oldstate, const game_state *state,
                        int dir, const game_ui *ui,
                        float animtime, float flashtime)
{
    int i, bgcolour;
    struct rotation srot, *rot;
    int lastx = -1, lasty = -1, lastr = -1;
    int cx, cy, n = state->n;
    bool cmoved = false;

    cx = ui->cur_visible ? ui->cur_x : -state->n;
    cy = ui->cur_visible ? ui->cur_y : -state->n;
    if (cx != ds->cur_x || cy != ds->cur_y)
        cmoved = true;

    if (flashtime > 0) {
        int frame = (int)(flashtime / FLASH_FRAME);
        bgcolour = (frame % 2 ? COL_LOWLIGHT : COL_HIGHLIGHT);
    } else
        bgcolour = COL_BACKGROUND;

    if (!ds->started) {
        int coords[10];

	draw_rect(dr, 0, 0,
		  TILE_SIZE * state->w + 2 * BORDER,
		  TILE_SIZE * state->h + 2 * BORDER, COL_BACKGROUND);
	draw_update(dr, 0, 0,
		    TILE_SIZE * state->w + 2 * BORDER,
		    TILE_SIZE * state->h + 2 * BORDER);

        /*
         * Recessed area containing the whole puzzle.
         */
        coords[0] = COORD(state->w) + HIGHLIGHT_WIDTH - 1;
        coords[1] = COORD(state->h) + HIGHLIGHT_WIDTH - 1;
        coords[2] = COORD(state->w) + HIGHLIGHT_WIDTH - 1;
        coords[3] = COORD(0) - HIGHLIGHT_WIDTH;
        coords[4] = coords[2] - TILE_SIZE;
        coords[5] = coords[3] + TILE_SIZE;
        coords[8] = COORD(0) - HIGHLIGHT_WIDTH;
        coords[9] = COORD(state->h) + HIGHLIGHT_WIDTH - 1;
        coords[6] = coords[8] + TILE_SIZE;
        coords[7] = coords[9] - TILE_SIZE;
        draw_polygon(dr, coords, 5, COL_HIGHLIGHT, COL_HIGHLIGHT);

        coords[1] = COORD(0) - HIGHLIGHT_WIDTH;
        coords[0] = COORD(0) - HIGHLIGHT_WIDTH;
        draw_polygon(dr, coords, 5, COL_LOWLIGHT, COL_LOWLIGHT);

        ds->started = true;
    }

    /*
     * If we're drawing any rotated tiles, sort out the rotation
     * parameters, and also zap the rotation region to the
     * background colour before doing anything else.
     */
    if (oldstate) {
	float angle;
	float anim_max = game_anim_length_real(oldstate, state, dir, ui);

	if (dir > 0) {
	    lastx = state->lastx;
	    lasty = state->lasty;
	    lastr = state->lastr;
	} else {
	    lastx = oldstate->lastx;
	    lasty = oldstate->lasty;
	    lastr = -oldstate->lastr;
	}

	rot = &srot;
	rot->cx = COORD(lastx);
	rot->cy = COORD(lasty);
	rot->cw = rot->ch = TILE_SIZE * state->n;
	rot->ox = rot->cx + rot->cw/2;
	rot->oy = rot->cy + rot->ch/2;
	angle = (float)((-PI/2 * lastr) * (1.0 - animtime / anim_max));
	rot->c = (float)cos(angle);
	rot->s = (float)sin(angle);

	/*
	 * Sort out the colours of the various sides of the tile.
	 */
	rot->lc = highlight_colour((float)PI + angle);
	rot->rc = highlight_colour(angle);
	rot->tc = highlight_colour((float)(PI/2.0) + angle);
	rot->bc = highlight_colour((float)(-PI/2.0) + angle);

	draw_rect(dr, rot->cx, rot->cy, rot->cw, rot->ch, bgcolour);
    } else
	rot = NULL;

    /*
     * Now draw each tile.
     */
    for (i = 0; i < state->w * state->h; i++) {
	int t;
        bool cc = false;
	int tx = i % state->w, ty = i / state->w;

	/*
	 * Figure out what should be displayed at this location.
	 * Usually it will be state->grid[i], unless we're in the
	 * middle of animating an actual rotation and this cell is
	 * within the rotation region, in which case we set -1
	 * (always display).
	 */
	if (oldstate && lastx >= 0 && lasty >= 0 &&
	    tx >= lastx && tx < lastx + state->n &&
	    ty >= lasty && ty < lasty + state->n)
	    t = -1;
	else
	    t = state->grid[i];

        if (cmoved) {
            /* cursor has moved (or changed visibility)... */
            if (tx == cx || tx == cx+n-1 || ty == cy || ty == cy+n-1)
                cc = true; /* ...we're on new cursor, redraw */
            if (tx == ds->cur_x || tx == ds->cur_x+n-1 ||
                ty == ds->cur_y || ty == ds->cur_y+n-1)
                cc = true; /* ...we were on old cursor, redraw */
        }

	if (ds->bgcolour != bgcolour ||   /* always redraw when flashing */
	    ds->grid[i] != t || ds->grid[i] == -1 || t == -1 || cc) {
	    int x = COORD(tx), y = COORD(ty);
            unsigned cedges = 0;

            if (tx == cx     && ty >= cy && ty <= cy+n-1) cedges |= CUR_LEFT;
            if (ty == cy     && tx >= cx && tx <= cx+n-1) cedges |= CUR_TOP;
            if (tx == cx+n-1 && ty >= cy && ty <= cy+n-1) cedges |= CUR_RIGHT;
            if (ty == cy+n-1 && tx >= cx && tx <= cx+n-1) cedges |= CUR_BOTTOM;

	    draw_tile(dr, ds, state, x, y, state->grid[i], bgcolour, rot, cedges);
            ds->grid[i] = t;
        }
    }
    ds->bgcolour = bgcolour;
    ds->cur_x = cx; ds->cur_y = cy;

    /*
     * Update the status bar.
     */
    {
	char statusbuf[256];

        /*
         * Don't show the new status until we're also showing the
         * new _state_ - after the game animation is complete.
         */
        if (oldstate)
            state = oldstate;

	if (state->used_solve)
	    sprintf(statusbuf, _("Moves since auto-solve: %d"),
		    state->movecount - state->completed);
	else {
	    if (state->completed) {
		strcpy(statusbuf, _("COMPLETED!"));
		strcpy(statusbuf+strlen(statusbuf)," ");
	    } else statusbuf[0]='\0';
	    sprintf(statusbuf+strlen(statusbuf), _("Moves: %d"),
		    (state->completed ? state->completed : state->movecount));
            if (state->movetarget) {
                strcpy(statusbuf+strlen(statusbuf)," ");
                sprintf(statusbuf+strlen(statusbuf), _("(target %d)"),
                        state->movetarget);
	    }
        }

	status_bar(dr, statusbuf);
    }
}
コード例 #4
0
ファイル: fifteen.c プロジェクト: marspeople/sgtpuzzles
static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate,
                 game_state *state, int dir, game_ui *ui,
                 float animtime, float flashtime)
{
    int i, pass, bgcolour;

    if (flashtime > 0) {
        int frame = (int)(flashtime / FLASH_FRAME);
        bgcolour = (frame % 2 ? COL_LOWLIGHT : COL_HIGHLIGHT);
    } else
        bgcolour = COL_BACKGROUND;

    if (!ds->started) {
        int coords[10];

	draw_rect(dr, 0, 0,
		  TILE_SIZE * state->w + 2 * BORDER,
		  TILE_SIZE * state->h + 2 * BORDER, COL_BACKGROUND);
	draw_update(dr, 0, 0,
		    TILE_SIZE * state->w + 2 * BORDER,
		    TILE_SIZE * state->h + 2 * BORDER);

        /*
         * Recessed area containing the whole puzzle.
         */
        coords[0] = COORD(state->w) + HIGHLIGHT_WIDTH - 1;
        coords[1] = COORD(state->h) + HIGHLIGHT_WIDTH - 1;
        coords[2] = COORD(state->w) + HIGHLIGHT_WIDTH - 1;
        coords[3] = COORD(0) - HIGHLIGHT_WIDTH;
        coords[4] = coords[2] - TILE_SIZE;
        coords[5] = coords[3] + TILE_SIZE;
        coords[8] = COORD(0) - HIGHLIGHT_WIDTH;
        coords[9] = COORD(state->h) + HIGHLIGHT_WIDTH - 1;
        coords[6] = coords[8] + TILE_SIZE;
        coords[7] = coords[9] - TILE_SIZE;
        draw_polygon(dr, coords, 5, COL_HIGHLIGHT, COL_HIGHLIGHT);

        coords[1] = COORD(0) - HIGHLIGHT_WIDTH;
        coords[0] = COORD(0) - HIGHLIGHT_WIDTH;
        draw_polygon(dr, coords, 5, COL_LOWLIGHT, COL_LOWLIGHT);

        ds->started = TRUE;
    }

    /*
     * Now draw each tile. We do this in two passes to make
     * animation easy.
     */
    for (pass = 0; pass < 2; pass++) {
        for (i = 0; i < state->n; i++) {
            int t, t0;
            /*
             * Figure out what should be displayed at this
             * location. It's either a simple tile, or it's a
             * transition between two tiles (in which case we say
             * -1 because it must always be drawn).
             */

            if (oldstate && oldstate->tiles[i] != state->tiles[i])
                t = -1;
            else
                t = state->tiles[i];

            t0 = t;

            if (ds->bgcolour != bgcolour ||   /* always redraw when flashing */
                ds->tiles[i] != t || ds->tiles[i] == -1 || t == -1) {
                int x, y;

                /*
                 * Figure out what to _actually_ draw, and where to
                 * draw it.
                 */
                if (t == -1) {
                    int x0, y0, x1, y1;
                    int j;

                    /*
                     * On the first pass, just blank the tile.
                     */
                    if (pass == 0) {
                        x = COORD(X(state, i));
                        y = COORD(Y(state, i));
                        t = 0;
                    } else {
                        float c;

                        t = state->tiles[i];

                        /*
                         * Don't bother moving the gap; just don't
                         * draw it.
                         */
                        if (t == 0)
                            continue;

                        /*
                         * Find the coordinates of this tile in the old and
                         * new states.
                         */
                        x1 = COORD(X(state, i));
                        y1 = COORD(Y(state, i));
                        for (j = 0; j < oldstate->n; j++)
                            if (oldstate->tiles[j] == state->tiles[i])
                                break;
                        assert(j < oldstate->n);
                        x0 = COORD(X(state, j));
                        y0 = COORD(Y(state, j));

                        c = (animtime / ANIM_TIME);
                        if (c < 0.0F) c = 0.0F;
                        if (c > 1.0F) c = 1.0F;

                        x = x0 + (int)(c * (x1 - x0));
                        y = y0 + (int)(c * (y1 - y0));
                    }

                } else {
                    if (pass == 0)
                        continue;
                    x = COORD(X(state, i));
                    y = COORD(Y(state, i));
                }

                draw_tile(dr, ds, state, x, y, t, bgcolour);
            }
            ds->tiles[i] = t0;
        }
    }
    ds->bgcolour = bgcolour;

    /*
     * Update the status bar.
     */
    {
	char statusbuf[256];

        /*
         * Don't show the new status until we're also showing the
         * new _state_ - after the game animation is complete.
         */
        if (oldstate)
            state = oldstate;

	if (state->used_solve)
	    sprintf(statusbuf, _("Moves since auto-solve: %d"),
		    state->movecount - state->completed);
	else {
	    if (state->completed) {
		strcpy(statusbuf,_("COMPLETED!"));
		strcpy(statusbuf+strlen(statusbuf)," ");
	    } else statusbuf[0]='\0';
	    sprintf(statusbuf+strlen(statusbuf), _("Moves: %d"),
		    (state->completed ? state->completed : state->movecount));
	}

	status_bar(dr, statusbuf);
    }
}
コード例 #5
0
ファイル: penrose.c プロジェクト: Bluerise/bitrig-xenocara
/*-
 * Add a tile described by vtype to the side of vertex.  This must be
 * allowed by the rules -- we do not check it here.  New vertices are
 * allocated as necessary.  The fringe and the forced vertex pool are updated.
 * The new tile is drawn on the display.
 *
 * One thing we do check here is whether the new tile causes an untiled
 * area to become enclosed by the tiling.  If this would happen, the tile
 * is not added.  The return value is true iff a tile was added.
 */
static int
add_tile(ModeInfo * mi,
	 fringe_node_c * vertex, unsigned side, vertex_type_c vtype)
{
	tiling_c   *tp = &tilings[MI_SCREEN(mi)];

	fringe_node_c
		*left = (fringe_node_c *) NULL,
		*right = (fringe_node_c *) NULL,
		*far = (fringe_node_c *) NULL,
		*node;
	unsigned    fc = fringe_changes(mi, vertex, side, vtype, &right, &far, &left);

	vertex_type_c
		ltype = VT_LEFT(vtype),
		rtype = VT_RIGHT(vtype),
		ftype = VT_FAR(vtype);

	/* By our conventions vertex->next lies to the left of vertex and
	   vertex->prev to the right. */

	/* This should never occur. */
	if (fc & FC_BAG) {
		tp->done = True;
		if (MI_IS_VERBOSE(mi)) {
			(void) fprintf(stderr, "Weirdness in add_tile()\n");
			(void) fprintf(stderr, "fc = %d, FC_BAG = %d\n", fc, FC_BAG);
		}
	}
	if (side == S_LEFT) {
		if (right == NULL)
			if ((right = alloc_vertex(mi, vertex_dir(mi, vertex, S_LEFT) -
					vtype_angle(vtype), vertex, tp)) == NULL)
				return False;
		if (far == NULL)
			if ((far = alloc_vertex(mi, vertex_dir(mi, left, S_RIGHT) +
					vtype_angle(ltype), left, tp)) == NULL)
				return False;
	} else {
		if (left == NULL)
			if ((left = alloc_vertex(mi, vertex_dir(mi, vertex, S_RIGHT) +
					vtype_angle(vtype), vertex, tp)) == NULL)
				return False;
		if (far == NULL)
			if ((far = alloc_vertex(mi, vertex_dir(mi, right, S_LEFT) -
					vtype_angle(rtype), right, tp)) == NULL)
				return False;
	}

	/* Having allocated the new vertices, but before joining them with
	   the rest of the fringe, check if vertices with same coordinates
	   already exist.  If any such are found, give up. */
	node = tp->fringe.nodes;
	do {
		if (((fc & FC_NEW_LEFT) && fived_equal(node->fived, left->fived))
		    || ((fc & FC_NEW_RIGHT) && fived_equal(node->fived, right->fived))
		    || ((fc & FC_NEW_FAR) && fived_equal(node->fived, far->fived))) {
			/* Better luck next time. */
			if (fc & FC_NEW_LEFT)
				delete_vertex(mi, left, tp);
			if (fc & FC_NEW_RIGHT)
				delete_vertex(mi, right, tp);
			if (fc & FC_NEW_FAR)
				delete_vertex(mi, far, tp);
			return False;
		}
		node = node->next;
	} while (node != tp->fringe.nodes);

	/* Rechain. */
	if (!(fc & FC_CUT_THIS)) {
		if (side == S_LEFT) {
			vertex->next = right;
			right->prev = vertex;
		} else {
			vertex->prev = left;
			left->next = vertex;
		}
	}
	if (!(fc & FC_CUT_FAR)) {
		if (!(fc & FC_CUT_LEFT)) {
			far->next = left;
			left->prev = far;
		}
		if (!(fc & FC_CUT_RIGHT)) {
			far->prev = right;
			right->next = far;
		}
	}
	draw_tile(vertex, right, far, left, vtype, mi);

	/* Delete vertices that are no longer on the fringe.  Check the others. */
	if (fc & FC_CUT_THIS) {
		tp->fringe.nodes = far;
		delete_vertex(mi, vertex, tp);
	} else {
		add_vtype(vertex, side, vtype);
		check_vertex(mi, vertex, tp);
		tp->fringe.nodes = vertex;
	}
	if (fc & FC_CUT_FAR)
		delete_vertex(mi, far, tp);
	else {
		add_vtype(far, fc & FC_CUT_RIGHT ? S_LEFT : S_RIGHT, ftype);
		check_vertex(mi, far, tp);
	}
	if (fc & FC_CUT_LEFT)
		delete_vertex(mi, left, tp);
	else {
		add_vtype(left, fc & FC_CUT_FAR ? S_LEFT : S_RIGHT, ltype);
		check_vertex(mi, left, tp);
	}
	if (fc & FC_CUT_RIGHT)
		delete_vertex(mi, right, tp);
	else {
		add_vtype(right, fc & FC_CUT_FAR ? S_RIGHT : S_LEFT, rtype);
		check_vertex(mi, right, tp);
	}
	return True;
}