/// \see http://tfc.duke.free.fr/old/models/md2.htm
void MD2::ModelData::Load(Stream::IStream& stream)
{
   Stream::EndianAwareFilter filter(stream);

   Header header = { 0 };
   header.Read(filter);

   if ((header.ident != c_uiMagicNumber) && (header.version != c_uiVersion))
      throw Exception(_T("invalid MD2 signature"), __FILE__, __LINE__);

   // initialize member variables
   m_iNumFrames = header.num_frames;
   m_iNumXyz = header.num_xyz;
   m_iNumGlcmds = header.num_glcmds;

   // allocate memory
   m_vecVertices.resize(header.num_xyz * header.num_frames);
   m_vecGlcmds.resize(header.num_glcmds);
   m_vecLightNormals.resize(header.num_xyz * header.num_frames);
   m_vecMinBounds.resize(header.num_frames);
   m_vecMaxBounds.resize(header.num_frames);

   /////////////////////////////////////////////
   //          reading file data

   std::vector<char> buffer(header.num_frames * header.framesize);

   DWORD dwBytesRead = 0;

   // TODO read frame endian-independent
   // read frame data...
   stream.Seek(header.ofs_frames, Stream::IStream::seekBegin);
   stream.Read(&buffer[0], buffer.size(), dwBytesRead);

   if (buffer.size() != dwBytesRead)
      throw Exception(_T("invalid MD2 content"), __FILE__, __LINE__);

   // read opengl commands...
   stream.Seek(header.ofs_glcmds, Stream::IStream::seekBegin);
   for (size_t i = 0; i < m_vecGlcmds.size(); i++)
      m_vecGlcmds[i] = static_cast<int>(filter.Read32LE());

   /////////////////////////////////////////////
   // vertex array initialization

   for (unsigned int numframe = 0; numframe < header.num_frames; numframe++)
   {
      // get frame struct for this
      Frame* frame = reinterpret_cast<Frame*>(&buffer[header.framesize * numframe]);

      //ATLTRACE(_T("loading frame %u, [%-16hs]\n"), numframe, frame->name);

      Vector3d* ptrverts = &m_vecVertices[header.num_xyz * numframe];
      unsigned int* ptrnormals = &m_vecLightNormals[header.num_xyz * numframe];

      Vector3d vMinBound, vMaxBound;

      for (unsigned int i = 0; i < header.num_xyz; i++)
      {
         Vector3d& v = ptrverts[i];
         v = Vector3d(
            (frame->verts[i].v[0] * frame->scale[0]) + frame->translate[0],
            (frame->verts[i].v[1] * frame->scale[1]) + frame->translate[1],
            (frame->verts[i].v[2] * frame->scale[2]) + frame->translate[2]);

         ptrnormals[i] = frame->verts[i].lightnormalindex;

         // get min and max bounds
         vMinBound.X(std::min(v.X(), vMinBound.X()));
         vMinBound.Y(std::min(v.Y(), vMinBound.Y()));
         vMinBound.Z(std::min(v.Z(), vMinBound.Z()));

         vMaxBound.X(std::max(v.X(), vMaxBound.X()));
         vMaxBound.Y(std::max(v.Y(), vMaxBound.Y()));
         vMaxBound.Z(std::max(v.Z(), vMaxBound.Z()));
      }

      m_vecMinBounds[numframe] = vMinBound;
      m_vecMaxBounds[numframe] = vMaxBound;
   }
}
void PcxImageReader::Load(Stream::IStream& stream)
{
   // read header
   PCXHeader header = {0};
   DWORD dwRead = 0;
   stream.Read(&header, sizeof(header), dwRead);

   // check header
   if (header.manufacturer != 0x0a)
      throw Exception(_T("wrong manufacturer number!"), __FILE__, __LINE__);

   // allocate pixels
   m_uiWidth = header.xmax - header.xmin + 1;
   m_uiHeight = header.ymax - header.ymin + 1;

   m_vecPixels.resize(m_uiWidth * m_uiHeight);

   // read in palette
   ULONGLONG ullPos = stream.Position();

   BYTE palette[256][3];
   stream.Seek(-768LL, Stream::IStream::seekEnd);
   stream.Read(&palette, sizeof(palette), dwRead);
   ATLASSERT(dwRead == sizeof(palette));

   stream.Seek(static_cast<LONGLONG>(ullPos), Stream::IStream::seekBegin);

   // read in image
   // \note only supports 8-bit at the moment
   unsigned int uiBitcount = header.bitsPerPixel * header.numColorPlanes;
   if (uiBitcount != 8)
      throw Exception(_T("wrong bit count!"), __FILE__, __LINE__);

   // read pixel data
   for (unsigned int y = 0; y < m_uiHeight; ++y)
   {
      Color* pColor = &m_vecPixels[y * m_uiWidth];
      unsigned int uiBytesLeft = header.bytesPerScanLine;

      // decode line
      unsigned int uiCount = 0;
      BYTE ubValue = 0;
      while (uiBytesLeft--)
      {
         if (uiCount == 0)
         {
            BYTE b = stream.ReadByte();
            if (b < 0xc0)
            {
               uiCount = 1;
               ubValue = b;
            }
            else
            {
               uiCount = b - 0xc0;
               ubValue = stream.ReadByte();
            }
         }

         uiCount--;

         *pColor = Color(
            palette[ubValue][0],
            palette[ubValue][1],
            palette[ubValue][2],
            255); // opaque
         pColor++;
      }
   }
}