void GifDecoder::setPixels(uint32_t* act)
{
	int32_t pixelNum = width * height;
	uint32_t* dest = new uint32_t[pixelNum];
	// fill in starting image contents based on last image's dispose code
	if (lastDispose > 0) {
		if (lastDispose == 3) {
			// use image before last
			int32_t n = frameCount - 2;
			if (n > 0) {
				lastBitmap = getFrame(n - 1);
			} else {
				lastBitmap = NULL;
			}
		}
		if (lastBitmap != NULL) {
			memcpy(dest, lastBitmap, pixelNum * 4);
			// copy pixels
			if (lastDispose == 2) {
				// fill last image rect area with background color
				int32_t c = 0;
				if (!transparency) {
					c = lastBgColor;
				}
				for (int32_t i = 0; i < lrh; i++) {
					int32_t n1 = (lry + i) * width + lrx;
					int32_t n2 = n1 + lrw;
					for (int32_t k = n1; k < n2; k++) {
						dest[k] = c;
					}
				}
			}
		}
	}
	// copy each source line to the appropriate place in the destination
	int32_t pass = 1;
	int32_t inc = 8;
	int32_t iline = 0;
	for (int32_t i = 0; i < ih; i++) {
		int32_t line = i;
		if (interlace) {
			if (iline >= ih) {
				pass++;
				switch (pass) {
				case 2:
					iline = 4;
					break;
				case 3:
					iline = 2;
					inc = 4;
					break;
				case 4:
					iline = 1;
					inc = 2;
					break;
				default:
					break;
				}
			}
			line = iline;
			iline += inc;
		}
		line += iy;
		if (line < height) {
			int32_t k = line * width;
			int32_t dx = k + ix; // start of line in dest
			int32_t dlim = dx + iw; // end of dest line
			if ((k + width) < dlim) {
				dlim = k + width; // past dest edge
			}
			int32_t sx = i * iw; // start of line in source
			while (dx < dlim) {
				// map color and insert in destination
				int32_t index = ((int32_t) pixels[sx++]) & 0xff;
				int32_t c = act[index];
				if (c != 0) {
					dest[dx] = c;
				}
				dx++;
			}
		}
	}
	frames.push_back(GifFrame(dest, delay));
	image = dest;
}
void AnimatedImage::extractGifData(const GifFileType *gifFile) {
  PixelAccessor *pa    = NULL;
  GifFrame      *frame = NULL;
  try {
    m_size.cx = gifFile->SWidth;
    m_size.cy = gifFile->SHeight;
    m_workPr  = new PixRect(m_device, PIXRECT_TEXTURE, m_size); TRACE_NEW(m_workPr);

    const int           imageCount   = gifFile->ImageCount;
    ColorMapObject     *gfColorMap   = gifFile->SColorMap;
    const GifColorType &colorType    = gfColorMap->Colors[gifFile->SBackGroundColor];
    const int           bitsPerPixel = gfColorMap->BitsPerPixel;

    m_backgroundColor      = D3DCOLOR_RGBA(colorType.Red, colorType.Green, colorType.Blue,255);

    for(int k = 0; k < gifFile->ExtensionBlockCount; k++) {
      const ExtensionBlock &block = gifFile->ExtensionBlocks[k];
      switch(block.Function) {
      case COMMENT_EXT_FUNC_CODE:
        m_comment += format(_T("%*.*s"), block.ByteCount, block.ByteCount, block.Bytes);
        break;
      case APPLICATION_EXT_FUNC_CODE:
        parseApplicationBlock(block.Bytes, block.ByteCount);
        break;
      }
    }
    m_frameTable.setCapacity(imageCount);
    for(int i = 0; i < imageCount; i++) {
      SavedImage &image = gifFile->SavedImages[i];
      m_frameTable.add(GifFrame());
      frame = &m_frameTable.last();

      String imageComment;
      for(int k = 0; k < image.ExtensionBlockCount; k++) {
        const ExtensionBlock &block = image.ExtensionBlocks[k];
        switch(block.Function) {
        case COMMENT_EXT_FUNC_CODE:
          imageComment += format(_T("%*.*s"), block.ByteCount, block.ByteCount, block.Bytes);
          break;

        case APPLICATION_EXT_FUNC_CODE:
          parseApplicationBlock(block.Bytes, block.ByteCount);
          break;
        }
      }
      if(imageComment.length() > 0) {
        m_comment += _T("\n") + imageComment;
      }

      frame->m_owner        = this;
      frame->m_rect.left    = image.ImageDesc.Left;
      frame->m_rect.top     = image.ImageDesc.Top;
      frame->m_rect.right   = image.ImageDesc.Left + image.ImageDesc.Width;
      frame->m_rect.bottom  = image.ImageDesc.Top  + image.ImageDesc.Height;
      frame->m_srcRect      = CRect(0,0, image.ImageDesc.Width, image.ImageDesc.Height);

      int transparentColor = NO_TRANSPARENT_COLOR;

      GraphicsControlBlock gcb;
      if(DGifSavedExtensionToGCB((GifFileType*)gifFile, i, &gcb) == GIF_OK) {
        frame->m_disposalMode = gcb.DisposalMode;
        frame->m_delayTime    = max(60,10*gcb.DelayTime);
        if((transparentColor = gcb.TransparentColor) != NO_TRANSPARENT_COLOR) {
          frame->m_useTransparency = true;
        }
      }

      const CSize sz = frame->m_rect.Size();
      frame->m_pr = new PixRect(m_device, PIXRECT_TEXTURE, sz, D3DPOOL_SYSTEMMEM, D3DFMT_A8R8G8B8); TRACE_NEW(frame->m_pr);

      const ColorMapObject *colorMap = image.ImageDesc.ColorMap ? image.ImageDesc.ColorMap : gfColorMap;
      const GifColorType   *colors   = colorMap->Colors;
      const GifPixelType   *pixelp   = image.RasterBits;

      pa = frame->m_pr->getPixelAccessor(0 /*D3DLOCK_NOSYSLOCK | D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_NOOVERWRITE*/);
      for(CPoint p(0,0); p.y < sz.cy; p.y++) {
        for(p.x = 0; p.x < sz.cx; p.x++) {
          const int entry = *(pixelp++);
          if((entry == transparentColor) && frame->m_useTransparency) {
            pa->setPixel(p, D3DCOLOR_RGBA(0,0,0,0));
          } else {
            const GifColorType &mapEntry = colors[entry];
            pa->setPixel(p, D3DCOLOR_RGBA(mapEntry.Red, mapEntry.Green, mapEntry.Blue, 255));
          }
        }
      }
      frame->m_pr->releasePixelAccessor();
      pa = NULL;
//      frame.m_pr->moveToPool(D3DPOOL_DEFAULT);
    }
  } catch(...) {
    if(pa) {
      frame->m_pr->releasePixelAccessor();
    }
    unload();
    throw;
  }
}