ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

codec.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "common/list.h"
00024 #include "common/scummsys.h"
00025 
00026 #include "image/codecs/codec.h"
00027 
00028 #include "image/jpeg.h"
00029 #include "image/codecs/bmp_raw.h"
00030 #include "image/codecs/cdtoons.h"
00031 #include "image/codecs/cinepak.h"
00032 #include "image/codecs/indeo3.h"
00033 #include "image/codecs/indeo4.h"
00034 #include "image/codecs/indeo5.h"
00035 #include "image/codecs/mjpeg.h"
00036 #include "image/codecs/mpeg.h"
00037 #include "image/codecs/msvideo1.h"
00038 #include "image/codecs/msrle.h"
00039 #include "image/codecs/msrle4.h"
00040 #include "image/codecs/qtrle.h"
00041 #include "image/codecs/rpza.h"
00042 #include "image/codecs/smc.h"
00043 #include "image/codecs/svq1.h"
00044 #include "image/codecs/truemotion1.h"
00045 
00046 #include "common/endian.h"
00047 #include "common/textconsole.h"
00048 
00049 namespace Image {
00050 
00051 namespace {
00052 
00056 inline void addColorToQueue(uint16 color, uint16 index, byte *checkBuffer, Common::List<uint16> &checkQueue) {
00057     if ((READ_UINT16(checkBuffer + color * 2) & 0xFF) == 0) {
00058         // Previously unfound color
00059         WRITE_UINT16(checkBuffer + color * 2, index);
00060         checkQueue.push_back(color);
00061     }
00062 }
00063 
00064 inline byte adjustColorRange(byte currentColor, byte correctColor, byte palColor) {
00065     return CLIP<int>(currentColor - palColor + correctColor, 0, 255);
00066 }
00067 
00068 inline uint16 makeQuickTimeDitherColor(byte r, byte g, byte b) {
00069     // RGB554
00070     return ((r & 0xF8) << 6) | ((g & 0xF8) << 1) | (b >> 4);
00071 }
00072 
00073 } // End of anonymous namespace
00074 
00075 byte *Codec::createQuickTimeDitherTable(const byte *palette, uint colorCount) {
00076     byte *buf = new byte[0x10000];
00077     memset(buf, 0, 0x10000);
00078 
00079     Common::List<uint16> checkQueue;
00080 
00081     bool foundBlack = false;
00082     bool foundWhite = false;
00083 
00084     const byte *palPtr = palette;
00085 
00086     // See what colors we have, and add them to the queue to check
00087     for (uint i = 0; i < colorCount; i++) {
00088         byte r = *palPtr++;
00089         byte g = *palPtr++;
00090         byte b = *palPtr++;
00091         uint16 n = (i << 8) | 1;
00092         uint16 col = makeQuickTimeDitherColor(r, g, b);
00093 
00094         if (col == 0) {
00095             // Special case for close-to-black
00096             // The original did more here, but it effectively discarded the value
00097             // due to a poor if-check (whole 16-bit value instead of lower 8-bits).
00098             WRITE_UINT16(buf, n);
00099             foundBlack = true;
00100         } else if (col == 0x3FFF) {
00101             // Special case for close-to-white
00102             // The original did more here, but it effectively discarded the value
00103             // due to a poor if-check (whole 16-bit value instead of lower 8-bits).
00104             WRITE_UINT16(buf + 0x7FFE, n);
00105             foundWhite = true;
00106         } else {
00107             // Previously unfound color
00108             addColorToQueue(col, n, buf, checkQueue);
00109         }
00110     }
00111 
00112     // More special handling for white
00113     if (foundWhite)
00114         checkQueue.push_front(0x3FFF);
00115 
00116     // More special handling for black
00117     if (foundBlack)
00118         checkQueue.push_front(0);
00119 
00120     // Go through the list of colors we have and match up similar colors
00121     // to fill in the table as best as we can.
00122     while (!checkQueue.empty()) {
00123         uint16 col = checkQueue.front();
00124         checkQueue.pop_front();
00125         uint16 index = READ_UINT16(buf + col * 2);
00126 
00127         uint32 x = col << 4;
00128         if ((x & 0xFF) < 0xF0)
00129             addColorToQueue((x + 0x10) >> 4, index, buf, checkQueue);
00130         if ((x & 0xFF) >= 0x10)
00131             addColorToQueue((x - 0x10) >> 4, index, buf, checkQueue);
00132 
00133         uint32 y = col << 7;
00134         if ((y & 0xFF00) < 0xF800)
00135             addColorToQueue((y + 0x800) >> 7, index, buf, checkQueue);
00136         if ((y & 0xFF00) >= 0x800)
00137             addColorToQueue((y - 0x800) >> 7, index, buf, checkQueue);
00138 
00139         uint32 z = col << 2;
00140         if ((z & 0xFF00) < 0xF800)
00141             addColorToQueue((z + 0x800) >> 2, index, buf, checkQueue);
00142         if ((z & 0xFF00) >= 0x800)
00143             addColorToQueue((z - 0x800) >> 2, index, buf, checkQueue);
00144     }
00145 
00146     // Contract the table back to just palette entries
00147     for (int i = 0; i < 0x4000; i++)
00148         buf[i] = READ_UINT16(buf + i * 2) >> 8;
00149 
00150     // Now go through and distribute the error to three more pixels
00151     byte *bufPtr = buf;
00152     for (uint realR = 0; realR < 0x100; realR += 8) {
00153         for (uint realG = 0; realG < 0x100; realG += 8) {
00154             for (uint realB = 0; realB < 0x100; realB += 16) {
00155                 byte palIndex = *bufPtr;
00156                 byte r = realR;
00157                 byte g = realG;
00158                 byte b = realB;
00159 
00160                 byte palR = palette[palIndex * 3] & 0xF8;
00161                 byte palG = palette[palIndex * 3 + 1] & 0xF8;
00162                 byte palB = palette[palIndex * 3 + 2] & 0xF0;
00163 
00164                 r = adjustColorRange(r, realR, palR);
00165                 g = adjustColorRange(g, realG, palG);
00166                 b = adjustColorRange(b, realB, palB);
00167                 palIndex = buf[makeQuickTimeDitherColor(r, g, b)];
00168                 bufPtr[0x4000] = palIndex;
00169 
00170                 palR = palette[palIndex * 3] & 0xF8;
00171                 palG = palette[palIndex * 3 + 1] & 0xF8;
00172                 palB = palette[palIndex * 3 + 2] & 0xF0;
00173 
00174                 r = adjustColorRange(r, realR, palR);
00175                 g = adjustColorRange(g, realG, palG);
00176                 b = adjustColorRange(b, realB, palB);
00177                 palIndex = buf[makeQuickTimeDitherColor(r, g, b)];
00178                 bufPtr[0x8000] = palIndex;
00179 
00180                 palR = palette[palIndex * 3] & 0xF8;
00181                 palG = palette[palIndex * 3 + 1] & 0xF8;
00182                 palB = palette[palIndex * 3 + 2] & 0xF0;
00183 
00184                 r = adjustColorRange(r, realR, palR);
00185                 g = adjustColorRange(g, realG, palG);
00186                 b = adjustColorRange(b, realB, palB);
00187                 palIndex = buf[makeQuickTimeDitherColor(r, g, b)];
00188                 bufPtr[0xC000] = palIndex;
00189 
00190                 bufPtr++;
00191             }
00192         }
00193     }
00194 
00195     return buf;
00196 }
00197 
00198 Codec *createBitmapCodec(uint32 tag, int width, int height, int bitsPerPixel) {
00199     switch (tag) {
00200     case SWAP_CONSTANT_32(0):
00201         return new BitmapRawDecoder(width, height, bitsPerPixel);
00202     case SWAP_CONSTANT_32(1):
00203         return new MSRLEDecoder(width, height, bitsPerPixel);
00204     case SWAP_CONSTANT_32(2):
00205         return new MSRLE4Decoder(width, height, bitsPerPixel);
00206     case MKTAG('C','R','A','M'):
00207     case MKTAG('m','s','v','c'):
00208     case MKTAG('W','H','A','M'):
00209         return new MSVideo1Decoder(width, height, bitsPerPixel);
00210     case MKTAG('c','v','i','d'):
00211         return new CinepakDecoder(bitsPerPixel);
00212     case MKTAG('I','V','3','2'):
00213         return new Indeo3Decoder(width, height, bitsPerPixel);
00214     case MKTAG('I', 'V', '4', '1'):
00215     case MKTAG('I', 'V', '4', '2'):
00216         return new Indeo4Decoder(width, height, bitsPerPixel);
00217     case MKTAG('I', 'V', '5', '0'):
00218         return new Indeo5Decoder(width, height, bitsPerPixel);
00219 #ifdef IMAGE_CODECS_TRUEMOTION1_H
00220     case MKTAG('D','U','C','K'):
00221     case MKTAG('d','u','c','k'):
00222         return new TrueMotion1Decoder();
00223 #endif
00224 #ifdef USE_MPEG2
00225     case MKTAG('m','p','g','2'):
00226         return new MPEGDecoder();
00227 #endif
00228     case MKTAG('M','J','P','G'):
00229     case MKTAG('m','j','p','g'):
00230         return new MJPEGDecoder();
00231     default:
00232         if (tag & 0x00FFFFFF)
00233             warning("Unknown BMP/AVI compression format \'%s\'", tag2str(tag));
00234         else
00235             warning("Unknown BMP/AVI compression format %d", SWAP_BYTES_32(tag));
00236     }
00237 
00238     return 0;
00239 }
00240 
00241 Codec *createQuickTimeCodec(uint32 tag, int width, int height, int bitsPerPixel) {
00242     switch (tag) {
00243     case MKTAG('c','v','i','d'):
00244         // Cinepak: As used by most Myst and all Riven videos as well as some Myst ME videos. "The Chief" videos also use this.
00245         return new CinepakDecoder(bitsPerPixel);
00246     case MKTAG('r','p','z','a'):
00247         // Apple Video ("Road Pizza"): Used by some Myst videos.
00248         return new RPZADecoder(width, height);
00249     case MKTAG('r','l','e',' '):
00250         // QuickTime RLE: Used by some Myst ME videos.
00251         return new QTRLEDecoder(width, height, bitsPerPixel);
00252     case MKTAG('s','m','c',' '):
00253         // Apple SMC: Used by some Myst videos.
00254         return new SMCDecoder(width, height);
00255     case MKTAG('S','V','Q','1'):
00256         // Sorenson Video 1: Used by some Myst ME videos.
00257         return new SVQ1Decoder(width, height);
00258     case MKTAG('S','V','Q','3'):
00259         // Sorenson Video 3: Used by some Myst ME videos.
00260         warning("Sorenson Video 3 not yet supported");
00261         break;
00262     case MKTAG('j','p','e','g'):
00263         // JPEG: Used by some Myst ME 10th Anniversary videos.
00264         return new JPEGDecoder();
00265     case MKTAG('Q','k','B','k'):
00266         // CDToons: Used by most of the Broderbund games.
00267         return new CDToonsDecoder(width, height);
00268     default:
00269         warning("Unsupported QuickTime codec \'%s\'", tag2str(tag));
00270     }
00271 
00272     return 0;
00273 }
00274 
00275 } // End of namespace Image


Generated on Sat May 25 2019 05:00:40 for ResidualVM by doxygen 1.7.1
curved edge   curved edge