Logo Search packages:      
Sourcecode: scummvm version File versions

picture.cpp

/* ScummVM - Scumm Interpreter
 * Copyright (C) 2006 The ScummVM project
 *
 * Copyright (C) 1999-2001 Sarien Team
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 * $URL: https://svn.sourceforge.net/svnroot/scummvm/scummvm/tags/release-0-9-1/engines/agi/picture.cpp $
 * $Id: picture.cpp 22614 2006-05-24 19:51:37Z eriktorbjorn $
 *
 */

#include "common/stdafx.h"

#include "agi/agi.h"
#include "agi/graphics.h"
#include "agi/savegame.h"

namespace Agi {

#define next_byte data[foffs++]

static uint8 *data;
static uint32 flen;
static uint32 foffs;

static uint8 pat_code;
static uint8 pat_num;
static uint8 pri_on;
static uint8 scr_on;
static uint8 scr_colour;
static uint8 pri_colour;

static uint8 circles[][15] = {      /* agi circle bitmaps */
      {0x80},
      {0xfc},
      {0x5f, 0xf4},
      {0x66, 0xff, 0xf6, 0x60},
      {0x23, 0xbf, 0xff, 0xff, 0xee, 0x20},
      {0x31, 0xe7, 0x9e, 0xff, 0xff, 0xde, 0x79, 0xe3, 0x00},
      {0x38, 0xf9, 0xf3, 0xef, 0xff, 0xff, 0xff, 0xfe, 0xf9, 0xf3, 0xe3, 0x80},
      {0x18, 0x3c, 0x7e, 0x7e, 0x7e, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7e, 0x7e, 0x7e, 0x3c, 0x18}
};

static uint8 splatter_map[32] = {   /* splatter brush bitmaps */
      0x20, 0x94, 0x02, 0x24, 0x90, 0x82, 0xa4, 0xa2,
      0x82, 0x09, 0x0a, 0x22, 0x12, 0x10, 0x42, 0x14,
      0x91, 0x4a, 0x91, 0x11, 0x08, 0x12, 0x25, 0x10,
      0x22, 0xa8, 0x14, 0x24, 0x00, 0x50, 0x24, 0x04
};

static uint8 splatter_start[128] = {      /* starting bit position */
      0x00, 0x18, 0x30, 0xc4, 0xdc, 0x65, 0xeb, 0x48,
      0x60, 0xbd, 0x89, 0x05, 0x0a, 0xf4, 0x7d, 0x7d,
      0x85, 0xb0, 0x8e, 0x95, 0x1f, 0x22, 0x0d, 0xdf,
      0x2a, 0x78, 0xd5, 0x73, 0x1c, 0xb4, 0x40, 0xa1,
      0xb9, 0x3c, 0xca, 0x58, 0x92, 0x34, 0xcc, 0xce,
      0xd7, 0x42, 0x90, 0x0f, 0x8b, 0x7f, 0x32, 0xed,
      0x5c, 0x9d, 0xc8, 0x99, 0xad, 0x4e, 0x56, 0xa6,
      0xf7, 0x68, 0xb7, 0x25, 0x82, 0x37, 0x3a, 0x51,
      0x69, 0x26, 0x38, 0x52, 0x9e, 0x9a, 0x4f, 0xa7,
      0x43, 0x10, 0x80, 0xee, 0x3d, 0x59, 0x35, 0xcf,
      0x79, 0x74, 0xb5, 0xa2, 0xb1, 0x96, 0x23, 0xe0,
      0xbe, 0x05, 0xf5, 0x6e, 0x19, 0xc5, 0x66, 0x49,
      0xf0, 0xd1, 0x54, 0xa9, 0x70, 0x4b, 0xa4, 0xe2,
      0xe6, 0xe5, 0xab, 0xe4, 0xd2, 0xaa, 0x4c, 0xe3,
      0x06, 0x6f, 0xc6, 0x4a, 0xa4, 0x75, 0x97, 0xe1
};

static void fix_pixel_bothsides(int x, int y);

static void put_virt_pixel(int x, int y, int res) {
      uint8 *p;
      int width = _WIDTH * res;

      if (x < 0 || y < 0 || x >= width || y >= _HEIGHT)
            return;

      p = res > 1 ? &game.hires[y * width + x] : &game.sbuf[y * width + x];

      if (pri_on)
            *p = (pri_colour << 4) | (*p & 0x0f);
      if (scr_on)
            *p = scr_colour | (*p & 0xf0);
}

/* For the flood fill routines */

/* MH2 needs stack size > 300 */
#define STACK_SIZE 512
static unsigned int stack_ptr;
static uint16 stack[STACK_SIZE];

static INLINE void _PUSH(uint16 c) {
      assert(stack_ptr < STACK_SIZE);

      stack[stack_ptr] = c;
      stack_ptr++;
}

static INLINE uint16 _POP() {
      if (stack_ptr == 0)
            return 0xffff;

      stack_ptr--;
      return stack[stack_ptr];
}

/**
 * Draw an AGI line.
 * A line drawing routine sent by Joshua Neal, modified by Stuart George
 * (fixed >>2 to >>1 and some other bugs like x1 instead of y1, etc.)
 * @param x1  x coordinate of start point
 * @param y1  y coordinate of start point
 * @param x2  x coordinate of end point
 * @param y2  y coordinate of end point
 * @param res horizontal resolution multiplier
 */
static void draw_line(int x1, int y1, int x2, int y2, int res) {
      int i, x, y, deltaX, deltaY, stepX, stepY, errorX, errorY, detdelta;
      int width = _WIDTH * res;

      /* CM: Do clipping */
#define clip(x, y) if((x)>=(y)) (x)=(y)
      clip(x1, width - 1);
      clip(x2, width - 1);
      clip(y1, _HEIGHT - 1);
      clip(y2, _HEIGHT - 1);

      /* Vertical line */

      if (x1 == x2) {
            if (y1 > y2) {
                  y = y1;
                  y1 = y2;
                  y2 = y;
            }

            for (; y1 <= y2; y1++) {
                  put_virt_pixel(x1, y1, res);
                  if (res > 1)
                        fix_pixel_bothsides(x1, y1);
            }

            return;
      }

      /* Horizontal line */

      if (y1 == y2) {
            if (x1 > x2) {
                  x = x1;
                  x1 = x2;
                  x2 = x;
            }
            if (res > 1)
                  fix_pixel_bothsides(x1, y1);

            for (; x1 <= x2; x1++)
                  put_virt_pixel(x1, y1, res);

            if (res > 1) {
                  put_virt_pixel(x1, y1, res);
                  fix_pixel_bothsides(x1, y1);
            }

            return;
      }

      y = y1;
      x = x1;

      stepY = 1;
      deltaY = y2 - y1;
      if (deltaY < 0) {
            stepY = -1;
            deltaY = -deltaY;
      }

      stepX = 1;
      deltaX = x2 - x1;
      if (deltaX < 0) {
            stepX = -1;
            deltaX = -deltaX;
      }

      if (deltaY > deltaX) {
            i = deltaY;
            detdelta = deltaY;
            errorX = deltaY / 2;
            errorY = 0;
      } else {
            i = deltaX;
            detdelta = deltaX;
            errorX = 0;
            errorY = deltaX / 2;
      }

      put_virt_pixel(x, y, res);
      if (res > 1)
            fix_pixel_bothsides(x, y);

      do {
            errorY += deltaY;
            if (errorY >= detdelta) {
                  errorY -= detdelta;
                  y += stepY;
            }

            errorX += deltaX;
            if (errorX >= detdelta) {
                  errorX -= detdelta;
                  x += stepX;
            }

            put_virt_pixel(x, y, res);
            if (res > 1)
                  fix_pixel_bothsides(x, y);
            i--;
      } while (i > 0);

      if (res > 1) {
            put_virt_pixel(x, y, res);
            fix_pixel_bothsides(x, y);
      }
}

/**
 * Draw a relative AGI line.
 * Draws short lines relative to last position. (drawing action 0xF7)
 * @param res  horizontal resolution multiplier
 */
static void dynamic_draw_line(int res) {
      int x1, y1, disp, dx, dy;

      x1 = next_byte * res;
      y1 = next_byte;

      put_virt_pixel(x1, y1, res);

      while (42) {
            if ((disp = next_byte) >= 0xf0)
                  break;

            dx = ((disp & 0xf0) >> 4) & 0x0f;
            dy = (disp & 0x0f);

            if (dx & 0x08)
                  dx = -(dx & 0x07);
            if (dy & 0x08)
                  dy = -(dy & 0x07);

            dx *= res;

            draw_line(x1, y1, x1 + dx, y1 + dy, res);
            x1 += dx;
            y1 += dy;
      }
      foffs--;
}

/**************************************************************************
** absoluteLine
**
** Draws long lines to actual locations (cf. relative) (drawing action 0xF6)
**************************************************************************/
static void absolute_draw_line(int res) {
      int x1, y1, x2, y2;

      x1 = next_byte * res;
      y1 = next_byte;
      put_virt_pixel(x1, y1, res);

      while (42) {
            if ((x2 = next_byte) >= 0xf0)
                  break;

            if ((y2 = next_byte) >= 0xf0)
                  break;

            x2 *= res;

            draw_line(x1, y1, x2, y2, res);
            x1 = x2;
            y1 = y2;
      }
      foffs--;
}

/**************************************************************************
** okToFill
**************************************************************************/
static INLINE int is_ok_fill_here(int x, int y) {
      uint8 p;

      if (x < 0 || x >= _WIDTH || y < 0 || y >= _HEIGHT)
            return false;

      if (!scr_on && !pri_on)
            return false;

      p = game.sbuf[y * _WIDTH + x];

      if (!pri_on && scr_on && scr_colour != 15)
            return (p & 0x0f) == 15;

      if (pri_on && !scr_on && pri_colour != 4)
            return (p >> 4) == 4;

      return (scr_on && (p & 0x0f) == 15 && scr_colour != 15);
}

/**************************************************************************
** agi_fill
**************************************************************************/
static void fill_scanline(int x, int y) {
      unsigned int c;
      int newspan_up, newspan_down;

      if (!is_ok_fill_here(x, y))
            return;

      /* Scan for left border */
      for (c = x - 1; is_ok_fill_here(c, y); c--);

      newspan_up = newspan_down = 1;
      for (c++; is_ok_fill_here(c, y); c++) {
            put_virt_pixel(c, y, 1);
            if (is_ok_fill_here(c, y - 1)) {
                  if (newspan_up) {
                        _PUSH(c + 320 * (y - 1));
                        newspan_up = 0;
                  }
            } else {
                  newspan_up = 1;
            }

            if (is_ok_fill_here(c, y + 1)) {
                  if (newspan_down) {
                        _PUSH(c + 320 * (y + 1));
                        newspan_down = 0;
                  }
            } else {
                  newspan_down = 1;
            }
      }
}

static void agi_fill(unsigned int x, unsigned int y) {
      _PUSH(x + 320 * y);

      while (42) {
            uint16 c = _POP();

            /* Exit if stack is empty */
            if (c == 0xffff)
                  break;

            x = c % 320;
            y = c / 320;

            fill_scanline(x, y);
      }

      stack_ptr = 0;
}

/**************************************************************************
** xCorner
**
** Draws an xCorner  (drawing action 0xF5)
**************************************************************************/
static void x_corner(int res) {
      int x1, x2, y1, y2;

      x1 = next_byte * res;
      y1 = next_byte;
      put_virt_pixel(x1, y1, res);

      while (42) {
            x2 = next_byte;

            if (x2 >= 0xf0)
                  break;

            x2 *= res;

            draw_line(x1, y1, x2, y1, res);
            x1 = x2;
            y2 = next_byte;

            if (y2 >= 0xf0)
                  break;

            draw_line(x1, y1, x1, y2, res);
            y1 = y2;
      }
      foffs--;
}

/**************************************************************************
** yCorner
**
** Draws an yCorner  (drawing action 0xF4)
**************************************************************************/
static void y_corner(int res) {
      int x1, x2, y1, y2;

      x1 = next_byte * res;
      y1 = next_byte;
      put_virt_pixel(x1, y1, res);

      while (42) {
            y2 = next_byte;

            if (y2 >= 0xF0)
                  break;

            draw_line(x1, y1, x1, y2, res);
            y1 = y2;
            x2 = next_byte;

            if (x2 >= 0xf0)
                  break;

            x2 *= res;

            draw_line(x1, y1, x2, y1, res);
            x1 = x2;
      }

      foffs--;
}

/**************************************************************************
** fill
**
** AGI flood fill.  (drawing action 0xF8)
**************************************************************************/
static void fill() {
      int x1, y1;

      while ((x1 = next_byte) < 0xF0 && (y1 = next_byte) < 0xf0)
            agi_fill(x1, y1);

      foffs--;
}

/**************************************************************************
** plotPattern
**
** Draws pixels, circles, squares, or splatter brush patterns depending
** on the pattern code.
**************************************************************************/

static int plot_pattern_point(int x, int y, int bitpos, int res) {
      if (pat_code & 0x20) {
            if ((splatter_map[bitpos >> 3] >> (7 - (bitpos & 7))) & 1) {
                  if (res > 1) {
                        /* extra randomness in hi-res brush fill
                         */
                        if (rnd->getRandomNumber(3))
                              put_virt_pixel(x * 2, y, 2);
                        if (!rnd->getRandomNumber(3))
                              put_virt_pixel(x * 2 + 1, y, 2);
                  } else {
                        put_virt_pixel(x, y, 1);
                  }
            }
            bitpos++;
            if (bitpos == 0xff)
                  bitpos = 0;
      } else {
            if (res > 1) {
                  /* double width pixels make MUMG and others
                   * look nicer
                   */
                  put_virt_pixel(x * 2, y, 2);
                  put_virt_pixel(x * 2 + 1, y, 2);
            } else {
                  put_virt_pixel(x, y, 1);
            }
      }

      return bitpos;
}

static void plot_pattern(int x, int y, int res) {
      int32 circlePos = 0;
      uint32 x1, y1, pensize, bitpos = splatter_start[pat_num];

      pensize = (pat_code & 7);

      if (x < (int)pensize)
            x = pensize - 1;
      if (y < (int)pensize)
            y = pensize;

      for (y1 = y - pensize; y1 <= y + pensize; y1++) {
            for (x1 = x - (pensize + 1) / 2; x1 <= x + pensize / 2; x1++) {
                  if (pat_code & 0x10) {  /* Square */
                        bitpos = plot_pattern_point (x1, y1, bitpos, res);
                  } else {    /* Circle */
                        if ((circles[pat_code & 7][circlePos >> 3] >> (7 - (circlePos & 7))) & 1) {
                              bitpos = plot_pattern_point(x1, y1, bitpos, res);
                        }
                        circlePos++;
                  }
            }
      }
}

/**************************************************************************
** plotBrush
**
** Plots points and various brush patterns.
**************************************************************************/
static void plot_brush(int res) {
      int x1, y1;

      while (42) {
            if (pat_code & 0x20) {
                  if ((pat_num = next_byte) >= 0xF0)
                        break;
                  pat_num = (pat_num >> 1) & 0x7f;
            }

            if ((x1 = next_byte) >= 0xf0)
                  break;

            if ((y1 = next_byte) >= 0xf0)
                  break;

            plot_pattern(x1, y1, res);
      }

      foffs--;
}

static void fix_pixel_bothsides(int x, int y) {
      uint8 *p, *s;

      if (x >= (_WIDTH * 2) - 2)
            return;

      /* Sometimes a solid color area in the lo-res pic is made
       * with lines, and we want to keep this  effect in the
       * hi-res pic.
       */
      p = &game.hires[y * (_WIDTH * 2) + x];
      if ((*(p - 2) & 0x0f) == scr_colour)
            put_virt_pixel(x - 1, y, 2);
      if ((*(p + 2) & 0x0f) == scr_colour)
            put_virt_pixel(x + 1, y, 2);

      /* If two lines are contiguous in the lo-res pic, make them
       * contiguous in the hi-res pic. This condition is needed
       * in some scenes like in front of Lefty's in LSL1, to draw
       * the pole. Note: it adds artifacts in some cases.
       */
      s = &game.sbuf[y * _WIDTH + x / 2];
      if ((*(p - 1) & 0x0f) != (*(s - 1) & 0x0f))
            put_virt_pixel(x - 1, y, 2);
}

/**************************************************************************
** okToFill
**************************************************************************/
static INLINE int hires_fill_here(int x, int y) {
      uint8 *p, *s;

      if (x < 0 || x >= _WIDTH || y < 0 || y >= _HEIGHT)
            return false;

      if (!scr_on && !pri_on)
            return false;

      p = &game.hires[(int32) y * (_WIDTH * 2) + x * 2];
      s = &game.sbuf[y * _WIDTH + x];

      if (scr_on) {
            if (scr_colour == 0x0f)
                  return false;
            if ((*p & 0x0f) != 0x0f || (*(p + 1) & 0x0f) != 0x0f)
                  return false;
            if ((*s & 0x0f) != scr_colour)
                  return false;
      }

      if (pri_on) {
            if (pri_colour == 0x04)
                  return false;
            if ((*p >> 4) != 0x04 || (*(p + 1) >> 4) != 0x04)
                  return false;
            if ((*s >> 4) != pri_colour)
                  return false;
      }

      return true;
}

static void fix_pixel_left(int x, int y) {
      uint8 *p;

      if (!scr_on)
            return;

      p = &game.hires[y * (_WIDTH * 2) + x * 2 + 1];
      if ((*p & 0x0f) == 0x0f)
            put_virt_pixel(2 * x + 1, y, 2);
      else if ((*p & 0x0f) == (*(p - 1) & 0x0f))
            put_virt_pixel(2 * x + 1, y, 2);
}

static void fix_pixel_right(int x, int y) {
      int idx = y * (_WIDTH * 2) + x * 2;

      if (idx >= 160 * 168)
            return;

      if (scr_on && (game.hires[idx] & 0x0f) == 0x0f)
            put_virt_pixel(2 * x, y, 2);
}

static void fix_pixel_here(int x, int y) {
      uint8 p;

      p = game.hires[y * (_WIDTH * 2) + x * 2 + 1];
      if (scr_on && (p & 0x0f) == 0x0f)
            put_virt_pixel(2 * x + 1, y, 2);
}

/**************************************************************************
** agiFill
**************************************************************************/
static void hires_fill_scanline(int x, int y) {
      unsigned int c;
      int newspan_up, newspan_down;

      if (!hires_fill_here(x, y))
            return;

      /* Scan for left border */
      for (c = x - 1; c > 0 && hires_fill_here(c, y); c--);
      fix_pixel_left(c, y);

      newspan_up = newspan_down = 1;
      for (c++; hires_fill_here(c, y); c++) {
            put_virt_pixel(c * 2, y, 2);
            fix_pixel_here(c, y);

            if (hires_fill_here(c, y - 1)) {
                  if (newspan_up) {
                        _PUSH(c + 320 * (y - 1));
                        newspan_up = 0;
                  }
            } else {
                  newspan_up = 1;
            }

            if (hires_fill_here(c, y + 1)) {
                  if (newspan_down) {
                        _PUSH(c + 320 * (y + 1));
                        newspan_down = 0;
                  }
            } else {
                  newspan_down = 1;
            }
      }

      fix_pixel_right(c, y);
}

static void _hires_fill(unsigned int x, unsigned int y) {
      _PUSH(x + 320 * y);

      while (42) {
            uint16 c = _POP();

            /* Exit if stack is empty */
            if (c == 0xffff)
                  break;

            x = c % 320;
            y = c / 320;

            hires_fill_scanline(x, y);
      }

      stack_ptr = 0;
}

/**************************************************************************
** fill
**
** AGI flood fill.  (drawing action 0xF8)
**************************************************************************/
static void hires_fill() {
      int x1, y1;

      while ((x1 = next_byte) < 0xf0 && (y1 = next_byte) < 0xf0) {
            _hires_fill(x1, y1);
      }

      foffs--;
}

/**
 * Show AGI picture.
 * This function copies a ``hidden'' AGI picture to the output device.
 */
void show_hires_pic() {
      int y, offset;
      int32 i;

      i = 0;
      offset = game.line_min_print * CHAR_LINES;
      for (y = 0; y < _HEIGHT; y++) {
            put_pixels_hires(0, y + offset, _WIDTH * 2, &game.hires[i]);
            i += _WIDTH * 2;
      }

      flush_screen();
}

void fix_hires_picture() {
      uint8 *p, *b;
      int i;

      p = game.hires;
      b = game.sbuf;

      for (i = 0; p < &game.hires[_WIDTH * _HEIGHT * 2] - 1; p++, i++) {
            if ((*p & 0x0f) == 0x0f && (*b & 0x0f) != 0x0f) {
                  if ((*(p + 1) & 0x0f) != 0x0f)
                        *p = *(p + 1);
                  else
                        *p = *b;
            }
            if ((*p >> 4) == 4 && (*b >> 4) != 4 && (*(b + 1) >> 4) != 4) {
                  *p = (*p & 0x0f) | (*b & 0xf0);
            }
            b += (i & 1);
      }
}

static void draw_picture() {
      uint8 act;
      int drawing;
      int save_foffs;

      pat_code = 0;
      pat_num = 0;
      pri_on = scr_on = false;
      scr_colour = 0xf;
      pri_colour = 0x4;

      drawing = 1;

      debugC(8, kDebugLevelMain, "Drawing picture");
      for (drawing = 1; drawing && foffs < flen;) {
            save_foffs = foffs;
            act = next_byte;
            switch (act) {
            case 0xf0:  /* set colour on screen */
                  scr_colour = next_byte;
                  scr_colour &= 0xF;      /* for v3 drawing diff */
                  scr_on = true;
                  break;
            case 0xf1:  /* disable screen drawing */
                  scr_on = false;
                  break;
            case 0xf2:  /* set colour on priority */
                  pri_colour = next_byte;
                  pri_colour &= 0xf;      /* for v3 drawing diff */
                  pri_on = true;
                  break;
            case 0xf3:  /* disable priority screen */
                  pri_on = false;
                  break;
            case 0xf4:  /* y-corner */
                  y_corner(1);
                  break;
            case 0xf5:  /* x-corner */
                  x_corner(1);
                  break;
            case 0xf6:  /* absolute draw lines */
                  absolute_draw_line(1);
                  break;
            case 0xf7:  /* dynamic draw lines */
                  dynamic_draw_line(1);
                  break;
            case 0xf8:  /* fill */
                  fill();
                  break;
            case 0xf9:  /* set pattern */
                  pat_code = next_byte;
                  break;
            case 0xfA:  /* plot brush */
                  plot_brush(1);
                  break;
            case 0xFF:  /* end of pic data */
            default:
                  drawing = 0;
                  break;
            }

            foffs = save_foffs;

            act = next_byte;
            switch (act) {
            case 0xf0:  /* set colour on screen */
                  scr_colour = next_byte;
                  scr_colour &= 0xF;      /* for v3 drawing diff */
                  scr_on = true;
                  break;
            case 0xf1:  /* disable screen drawing */
                  scr_on = false;
                  break;
            case 0xf2:  /* set colour on priority */
                  pri_colour = next_byte;
                  pri_colour &= 0xf;      /* for v3 drawing diff */
                  pri_on = true;
                  break;
            case 0xf3:  /* disable priority screen */
                  pri_on = false;
                  break;
            case 0xf4:  /* y-corner */
                  y_corner(2);
                  break;
            case 0xf5:  /* x-corner */
                  x_corner(2);
                  break;
            case 0xf6:  /* absolute draw lines */
                  absolute_draw_line(2);
                  break;
            case 0xf7:  /* dynamic draw lines */
                  dynamic_draw_line(2);
                  break;
            case 0xf8:  /* fill */
                  hires_fill();
                  break;
            case 0xf9:  /* set pattern */
                  pat_code = next_byte;
                  break;
            case 0xfA:  /* plot brush */
                  plot_brush(2);
                  break;
            case 0xFF:  /* end of pic data */
            default:
                  drawing = 0;
                  break;
            }
      }
}

/*
 * Public functions
 */

/**
 *
 */
uint8 *convert_v3_pic(uint8 *src, uint32 len) {
      uint8 d, old = 0, x, *in, *xdata, *out, mode = 0;
      uint32 i, ulen;

      xdata = (uint8 *) malloc(len + len / 2);

      out = xdata;
      in = src;

      for (i = ulen = 0; i < len; i++, ulen++) {
            d = *in++;

            *out++ = x = mode ? ((d & 0xF0) >> 4) + ((old & 0x0F) << 4) : d;

            if (x == 0xFF) {
                  ulen++;
                  break;
            }

            if (x == 0xf0 || x == 0xf2) {
                  if (mode) {
                        *out++ = d & 0x0F;
                        ulen++;
                  } else {
                        d = *in++;
                        *out++ = (d & 0xF0) >> 4;
                        i++, ulen++;
                  }

                  mode = !mode;
            }

            old = d;
      }

      free(src);
      xdata = (uint8 *)realloc(xdata, ulen);

      return xdata;
}

/**
 * Decode an AGI picture resource.
 * This function decodes an AGI picture resource into the correct slot
 * and draws it on the AGI screen, optionally cleaning the screen before
 * drawing.
 * @param n      AGI picture resource number
 * @param clear  clear AGI screen before drawing
 */
int decode_picture(int n, int clear) {
      debugC(8, kDebugLevelResources, "(%d)", n);

      pat_code = 0;
      pat_num = 0;
      pri_on = scr_on = false;
      scr_colour = 0xF;
      pri_colour = 0x4;

      data = game.pictures[n].rdata;
      flen = game.dir_pic[n].len;
      foffs = 0;

      if (clear) {
            memset(game.sbuf, 0x4f, _WIDTH * _HEIGHT);
            memset(game.hires, 0x4f, _WIDTH * 2 * _HEIGHT);
      }

      draw_picture();

      fix_hires_picture();

      if (clear)
            clear_image_stack();
      record_image_stack_call(ADD_PIC, n, clear, 0, 0, 0, 0, 0);

      return err_OK;
}

/**
 * Unload an AGI picture resource.
 * This function unloads an AGI picture resource and deallocates
 * resource data.
 * @param n AGI picture resource number
 */
int unload_picture(int n) {
      /* remove visual buffer & priority buffer if they exist */
      if (game.dir_pic[n].flags & RES_LOADED) {
            free(game.pictures[n].rdata);
            game.dir_pic[n].flags &= ~RES_LOADED;
      }

      return err_OK;
}

/**
 * Show AGI picture.
 * This function copies a ``hidden'' AGI picture to the output device.
 */
void show_pic() {
      int i, y;
      int offset;

      debugC(8, kDebugLevelMain, "Show picture!");
      if (opt.hires) {
            show_hires_pic();
            return;
      }

      i = 0;
      offset = game.line_min_print * CHAR_LINES;
      for (y = 0; y < _HEIGHT; y++) {
            put_pixels_a(0, y + offset, _WIDTH, &game.sbuf[i]);
            i += _WIDTH;
      }

      flush_screen();
}

}                             // End of namespace Agi

Generated by  Doxygen 1.6.0   Back to index