/*
===========================================================================
Doom 3 GPL Source Code
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
Doom 3 Source Code 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 3 of the License, or
(at your option) any later version.
Doom 3 Source Code 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 Doom 3 Source Code. If not, see .
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "../../../idlib/precompiled.h"
#pragma hdrstop
#include "codec.h"
// flibit wedged this in for Win32... eh. -flibit
#ifdef _WIN32
#undef HUGE_VAL
#define HUGE_VAL HUGE
#endif
float glimit( const float val ) {
if (val<0) return 0;
if (val>255) return 255;
return val;
}
codec::codec() {
int i;
common->Printf("init: initing.....\n");
codebooksize = 256;
codebook2 = (VQDATA **) Mem_ClearedAlloc(256*sizeof(VQDATA *));
for(i=0; i < 256; i++) {
codebook2[i] = (VQDATA *) Mem_ClearedAlloc(16*sizeof(VQDATA));
}
codebook4 = (VQDATA **) Mem_ClearedAlloc(256*sizeof(VQDATA *));
for(i=0; i < 256; i++) {
codebook4[i] = (VQDATA *) Mem_ClearedAlloc(64*sizeof(VQDATA));
}
previousImage[0] = 0;
previousImage[1] = 0;
image = 0;
whichFrame = 0;
qStatus = 0;
luti = 0;
overAmount = 0;
codebookmade = 0;
slop = 0;
}
codec::~codec()
{
common->Printf("codec: resetting\n");
if (qStatus) Mem_Free( qStatus);
if (luti) Mem_Free(luti);
if (previousImage[0]) delete previousImage[0];
if (previousImage[1]) delete previousImage[1];
qStatus = 0;
initRGBtab = 0;
previousImage[0] = 0;
whichFrame = 0;
luti = 0;
return;
}
/* Because Shellsort is a variation on Insertion Sort, it has the same
* inconsistency that I noted in the InsertionSort class. Notice where I
* subtract a move to compensate for calling a swap for visual purposes.
*/
void codec::Sort( float *list, int *intIndex, int numElements )
{
#define STRIDE_FACTOR 3 // good value for stride factor is not well-understood
// 3 is a fairly good choice (Sedgewick)
int c,d, stride;
bool found;
stride = 1;
while (stride <= numElements)
stride = stride*STRIDE_FACTOR +1;
while (stride>(STRIDE_FACTOR-1)) { // loop to sort for each value of stride
stride = stride / STRIDE_FACTOR;
for (c = stride; c < numElements; c++){
found = false;
d = c-stride;
while ((d >= 0) && !found) { // move to left until correct place
if (list[d]CurrentFilename());
sprintf( temptb, "%s.tb", theRoQ->CurrentFilename());
onf = 0;
len = (int)strlen(tempcb);
for(x=0;xPrintf("trying %s\n", cbFile);
fpcb = fileSystem->OpenFileRead( cbFile );
if ( !fpcb ) {
doopen = true;
common->Printf("failed....\n");
} else {
if ( dimension2 == 16 ) x = 3584; else x = 2560;
if ( fpcb->Read( lineout, x ) != x ) {
doopen = true;
common->Printf("failed....\n");
}
fileSystem->CloseFile( fpcb );
}
if ( doopen ) {
common->Printf("segment: making %s\n", cbFile);
numc = numElements;
if (numElements > numc) numc = numElements;
onf = 0;
for(x=0;x<256;x++) {
for(y=0;ysamplesPerPixel();
cbook = (byte *)Mem_ClearedAlloc( 3 * image->pixelsWide() * image->pixelsHigh());
float *snrBook = (float *)Mem_ClearedAlloc( image->pixelsWide() * image->pixelsHigh() );
dst = cbook;
int numEntries = 0;
for (i=0; i= MIN_SNR*4) {
for(y=qStatus[i].yat;ybitmapData() + (yy*(bpp*image->pixelsWide())) + (xx*bpp);
memcpy( dst, src, 3); dst += 3;
}
}
}
}
}
}
common->Printf("segment: %d 4x4 cels to vq\n", numEntries );
VQ( numEntries, dimension4, cbook, snrBook, codebook4, true );
dst = cbook;
numEntries = 0;
for( i=0; i<256; i++ ) {
for(y=0;y<4;y+=2) {
for(x=0;x<4;x+=2) {
snrBook[numEntries] = 1.0f;
numEntries++;
for(yy=y;yy<(y+2);yy++) {
for(xx=x;xx<(x+2);xx++) {
dst[0] = codebook4[i][yy*12+xx*3+0];
dst[1] = codebook4[i][yy*12+xx*3+1];
dst[2] = codebook4[i][yy*12+xx*3+2];
dst += 3;
}
}
}
}
}
common->Printf("segment: %d 2x2 cels to vq\n", numEntries);
VQ( numEntries, dimension2, cbook, snrBook, codebook2, false );
Mem_Free(cbook);
Mem_Free(snrBook);
index = 0;
for( onf = 0; onf < 256; onf++ ) {
numc = 0; fcr = fcb = 0;
for( x = 0; x < 4; x++ ) {
fy = RMULT*(float)(codebook2[onf][numc+0]) +
GMULT*(float)(codebook2[onf][numc+1]) +
BMULT*(float)(codebook2[onf][numc+2]) + 0.5f;
if (fy<0) fy = 0; if (fy>255) fy = 255;
fcr += RIEMULT*(float)(codebook2[onf][numc+0]);
fcr += GIEMULT*(float)(codebook2[onf][numc+1]);
fcr += BIEMULT*(float)(codebook2[onf][numc+2]);
fcb += RQEMULT*(float)(codebook2[onf][numc+0]);
fcb += GQEMULT*(float)(codebook2[onf][numc+1]);
fcb += BQEMULT*(float)(codebook2[onf][numc+2]);
lineout[index++] = (byte)fy;
numc += 3;
}
fcr = (fcr/4)+128.5f; if (fcr<0) fcr = 0; if (fcr>255) fcr = 255;
fcb = (fcb/4)+128.5f; if (fcb<0) fcb = 0; if (fcb>255) fcr = 255;
//common->Printf(" fcr == %f, fcb == %f\n", fcr, fcb );
lineout[index++] = (byte)fcr;
lineout[index++] = (byte)fcb;
}
for(onf=0;onf<256;onf++) {
for(y=0;y<4;y+=2) {
for(x=0;x<4;x+=2) {
numc = 0;
for(yy=y;yy<(y+2);yy++) {
temp = (yy*dimension2)+x*(dimension2/4);
find[numc++] = (byte)(codebook4[onf][temp+0] + 0.50f);
find[numc++] = (byte)(codebook4[onf][temp+1] + 0.50f);
find[numc++] = (byte)(codebook4[onf][temp+2] + 0.50f);
find[numc++] = (byte)(codebook4[onf][temp+3] + 0.50f);
find[numc++] = (byte)(codebook4[onf][temp+4] + 0.50f);
find[numc++] = (byte)(codebook4[onf][temp+5] + 0.50f);
}
lineout[index++] = BestCodeword( find, dimension2, codebook2 );
}
}
}
fpcb = fileSystem->OpenFileWrite( cbFile );
common->Printf("made up %d entries\n", index);
fpcb->Write( lineout, index );
fileSystem->CloseFile( fpcb );
common->Printf("finished write\n");
}
for(y=0;y<256;y++) {
x = y*6;
y0 = (float)lineout[x++];
y1 = (float)lineout[x++];
y2 = (float)lineout[x++];
y3 = (float)lineout[x++];
cb = (float)lineout[x++]; cb -= 128;
cr = (float)lineout[x ]; cr -= 128;
x = 0;
codebook2[y][x++] = glimit( y0 + 1.40200f*cr );
codebook2[y][x++] = glimit( y0 - 0.34414f*cb - 0.71414f*cr );
codebook2[y][x++] = glimit( y0 + 1.77200f*cb );
codebook2[y][x++] = glimit( y1 + 1.40200f*cr );
codebook2[y][x++] = glimit( y1 - 0.34414f*cb - 0.71414f*cr );
codebook2[y][x++] = glimit( y1 + 1.77200f*cb );
codebook2[y][x++] = glimit( y2 + 1.40200f*cr );
codebook2[y][x++] = glimit( y2 - 0.34414f*cb - 0.71414f*cr );
codebook2[y][x++] = glimit( y2 + 1.77200f*cb );
codebook2[y][x++] = glimit( y3 + 1.40200f*cr );
codebook2[y][x++] = glimit( y3 - 0.34414f*cb - 0.71414f*cr );
codebook2[y][x++] = glimit( y3 + 1.77200f*cb );
}
index = 6*256;
for(onf=0;onf<256;onf++) {
for(y=0;y<4;y+=2) {
for(x=0;x<4;x+=2) {
best = lineout[index++];
numc = 0;
for(yy=y;yy<(y+2);yy++) {
temp = (yy*dimension2)+x*(dimension2/4);
codebook4[onf][temp+0] = codebook2[best][numc++]; //r
codebook4[onf][temp+1] = codebook2[best][numc++]; //g
codebook4[onf][temp+2] = codebook2[best][numc++]; //b
codebook4[onf][temp+3] = codebook2[best][numc++]; //r a
codebook4[onf][temp+4] = codebook2[best][numc++]; //g r
codebook4[onf][temp+5] = codebook2[best][numc++]; //b g
}
}
}
}
theRoQ->WriteCodeBook(lineout);
//PrepareCodeBook();
Mem_Free(lineout);
}
int codec::BestCodeword( unsigned char *tempvector, int dimension, VQDATA **codebook )
{
VQDATA dist;
VQDATA bestDist = HUGE_VAL;
VQDATA tempvq[64];
int bestIndex = -1;
for( int i=0; i= bestDist) {
continue;
}
dist += (g0-g1)*(g0-g1);
if (dist >= bestDist) {
continue;
}
dist += (b0-b1)*(b0-b1);
if (dist >= bestDist) {
continue;
}
}
if ( dist < bestDist ) {
bestDist = dist;
bestIndex = i;
}
}
return bestIndex;
}
void codec::SetPreviousImage( const char*filename, NSBitmapImageRep *timage )
{
if (previousImage[0]) {
delete previousImage[0];
}
if (previousImage[1]) {
delete previousImage[1];
}
common->Printf("setPreviousImage:%s\n", filename);
previousImage[0] = new NSBitmapImageRep( );
previousImage[1] = new NSBitmapImageRep( );
whichFrame=1;
*previousImage[0] = *timage;
*previousImage[1] = *timage;
pixelsHigh = previousImage[0]->pixelsHigh();
pixelsWide = previousImage[0]->pixelsWide();
common->Printf("setPreviousImage: %dx%d\n", pixelsWide, pixelsHigh );
}
void codec::MakePreviousImage( quadcel *pquad )
{
int i, dy, dx, pluck, size, ind, xx, yy, pWide;
int x, y;
byte *rgbmap, *idataA, *fccdictionary;
bool diff;
for(i=0;i<256;i++) { used2[i] = used4[i] = false; }
pWide = pixelsWide & 0xfff0;
if (!previousImage[0]) {
previousImage[0] = new NSBitmapImageRep( pWide, (pixelsHigh & 0xfff0) );
previousImage[1] = new NSBitmapImageRep( pWide, (pixelsHigh & 0xfff0) );
}
rgbmap = previousImage[(whichFrame&1)]->bitmapData();
if ((whichFrame&1) == 1) {
fccdictionary = previousImage[0]->bitmapData();
} else {
fccdictionary = previousImage[1]->bitmapData();
}
idataA = (byte *)Mem_Alloc( 16*16*4 );
for(i=0;i>1)*dimension2)+(dx>>1)*(dimension2/4);
if (rgbmap[pluck+0] != codebook4[ind][xx+0]) diff = true;
if (rgbmap[pluck+1] != codebook4[ind][xx+1]) diff = true;
if (rgbmap[pluck+2] != codebook4[ind][xx+2]) diff = true;
if (dimension4 == 64 && rgbmap[pluck+3] != codebook4[ind][xx+3]) diff = true;
rgbmap[pluck+0] = (byte)codebook4[ind][xx+0];
rgbmap[pluck+1] = (byte)codebook4[ind][xx+1];
rgbmap[pluck+2] = (byte)codebook4[ind][xx+2];
if (dimension4 == 64)
rgbmap[pluck+3] = (byte)codebook4[ind][xx+3];
else
rgbmap[pluck+3] = 255;
pluck += 4;
}
}
if (diff == false && whichFrame) common->Printf("drawImage: SLD just changed the same thing\n");
break;
case PAT:
ind = pquad[i].patten[0];
used4[ind] = true;
for( dy=0; dyPrintf("drawImage: PAT just changed the same thing\n");
break;
case CCC:
dx = 1;
for(yy=0;yy<4;yy+=2) {
for(xx=0;xx<4;xx+=2) {
ind = pquad[i].patten[dx++];
used2[ind] = true;
dy = 0;
for(y=yy;y<(yy+2);y++) {
for(x=xx;x<(xx+2);x++) {
pluck = (((y+pquad[i].yat)*pWide)+(pquad[i].xat+x))*4;
if (rgbmap[pluck+0] != codebook2[ind][dy+0]) diff = true;
if (rgbmap[pluck+1] != codebook2[ind][dy+1]) diff = true;
if (rgbmap[pluck+2] != codebook2[ind][dy+2]) diff = true;
if (dimension4 == 64 && rgbmap[pluck+3] != codebook2[ind][dy+3]) diff = true;
rgbmap[pluck+0] = (byte)codebook2[ind][dy+0];
rgbmap[pluck+1] = (byte)codebook2[ind][dy+1];
rgbmap[pluck+2] = (byte)codebook2[ind][dy+2];
if (dimension4 == 64) {
rgbmap[pluck+3] = (byte)codebook2[ind][dy+3];
dy += 4;
} else {
rgbmap[pluck+3] = 255;
dy += 3;
}
}
}
}
}
if (diff == false && whichFrame) {
/*
common->Printf("drawImage: CCC just changed the same thing\n");
common->Printf("sparseEncode: something is wrong here\n");
common->Printf("xat: %d\n", pquad[i].xat);
common->Printf("yat: %d\n", pquad[i].yat);
common->Printf("size %d\n", pquad[i].size);
common->Printf("type: %d\n", pquad[i].status);
common->Printf("motsnr: %0f\n", pquad[i].snr[FCC]);
common->Printf("cccsnr: %0f\n", pquad[i].snr[CCC]);
common->Printf("rmse: %0f\n", pquad[i].rsnr);
common->Printf("pat0: %0d\n", pquad[i].patten[1]);
common->Printf("pat1: %0d\n", pquad[i].patten[2]);
common->Printf("pat2: %0d\n", pquad[i].patten[3]);
common->Printf("pat3: %0d\n", pquad[i].patten[4]);
//exit(1);
*/
}
break;
case FCC:
dx = pquad[i].xat - ((pquad[i].domain >> 8 ) - 128);
dy = pquad[i].yat - ((pquad[i].domain & 0xff) - 128);
if (image->pixelsWide()==(image->pixelsHigh()*4)) dx = pquad[i].xat - ((pquad[i].domain >> 8 ) - 128)*2;
if (theRoQ->Scaleable()) {
dx = pquad[i].xat - ((pquad[i].domain >> 8 ) - 128)*2;
dy = pquad[i].yat - ((pquad[i].domain & 0xff) - 128)*2;
}
// if (pquad[i].yat == 0) common->Printf("dx = %d, dy = %d, xat = %d\n", dx, dy, pquad[i].xat);
ind = (dy*pWide+dx)*4;
for( dy=0; dyPrintf("drawImage: FCC just changed the same thing\n");
break;
case MOT:
break;
default:
common->Error( "bad code!!\n");
break;
}
}
}
if (whichFrame == 0) {
memcpy( previousImage[1]->bitmapData(), previousImage[0]->bitmapData(), pWide*(pixelsHigh & 0xfff0)*4);
}
x = 0; y = 0;
for(i=0;i<256;i++) {
if (used4[i]) x++;
if (used2[i]) y++;
}
if (theRoQ->IsQuiet() == false) common->Printf("drawImage: used %d 4x4 and %d 2x2 VQ cels\n", x,y);
Mem_Free( idataA );
}
void codec::InitImages( void )
{
int x,y, index0, index1, temp;
float ftemp;
byte *lutimage;
numQuadCels = ((pixelsWide & 0xfff0)*(pixelsHigh & 0xfff0))/(MINSIZE*MINSIZE);
numQuadCels += numQuadCels/4 + numQuadCels/16;
if (qStatus) Mem_Free(qStatus);
qStatus = (quadcel *)Mem_ClearedAlloc(numQuadCels*sizeof (quadcel));
InitQStatus();
//
if (previousImage[0]) {
pixelsWide = previousImage[0]->pixelsWide();
pixelsHigh = previousImage[0]->pixelsHigh();
temp = ((whichFrame+1)&1);
if (!luti) luti = (byte *)Mem_Alloc(pixelsWide*pixelsHigh);
lutimage = previousImage[temp]->bitmapData();
if (theRoQ->IsQuiet() == false) {
common->Printf("initImage: remaking lut image using buffer %d\n", temp);
}
index0 = index1 = 0;
for(y=0;ysamplesPerPixel();
index1++;
}
}
}
}
void codec::QuadX( int startX, int startY, int quadSize)
{
int startSize;
int bigx, bigy, lowx, lowy;
lowx = lowy = 0;
bigx = pixelsWide & 0xfff0;
bigy = pixelsHigh & 0xfff0;
if ( (startX >= lowx) && (startX+quadSize) <= (bigx) && (startY+quadSize) <= (bigy) && (startY >= lowy) && quadSize <= MAXSIZE) {
qStatus[onQuad].size = quadSize;
qStatus[onQuad].xat = startX;
qStatus[onQuad].yat = startY;
qStatus[onQuad].rsnr = 999999;
onQuad++;
}
if (quadSize != MINSIZE) {
startSize = quadSize>>1;
QuadX( startX , startY , startSize );
QuadX( startX+startSize , startY , startSize );
QuadX( startX , startY+startSize , startSize );
QuadX( startX+startSize , startY+startSize , startSize );
}
}
void codec::InitQStatus( void )
{
int i,x,y;
for (i=0; ipatten[0] = best = BestCodeword( tempImage, dimension4, codebook4 );
for(y=0;y<8;y++) {
for(x=0;x<8;x++) {
temp = y*32+x*4;
i = ((y/2)*4*(dimension2/4))+(x/2)*(dimension2/4);
tempImage[temp+0] = (byte)codebook4[best][i+0];
tempImage[temp+1] = (byte)codebook4[best][i+1];
tempImage[temp+2] = (byte)codebook4[best][i+2];
if (dimension4 == 64)
tempImage[temp+3] = (byte)codebook4[best][i+3];
else
tempImage[temp+3] = 255;
}
}
pquad->snr[SLD] = Snr( cel, tempImage, 8 )+1.0;
}
void codec::VqData4( byte *cel, quadcel *pquad )
{
byte tempImage[64];
int i, best, bpp;
// if (theRoQ->makingVideo] && previousImage[0]) return self;
if (dimension4 == 64) bpp = 4; else bpp = 3;
for(i=0;i<16;i++) {
tempImage[i*bpp+0] = cel[i*4+0];
tempImage[i*bpp+1] = cel[i*4+1];
tempImage[i*bpp+2] = cel[i*4+2];
if (dimension4 == 64) tempImage[i*bpp+3] = cel[i*4+3];
}
pquad->patten[0] = best = BestCodeword( tempImage, dimension4, codebook4 );
for(i=0;i<16;i++) {
tempImage[i*4+0] = (byte)codebook4[best][i*bpp+0];
tempImage[i*4+1] = (byte)codebook4[best][i*bpp+1];
tempImage[i*4+2] = (byte)codebook4[best][i*bpp+2];
if (dimension4 == 64)
tempImage[i*4+3] = (byte)codebook4[best][i*bpp+3];
else
tempImage[i*4+3] = 255;
}
pquad->snr[PAT] = Snr( cel, tempImage, 4 );
}
void codec::VqData2( byte *cel, quadcel *pquad )
{
byte tempImage[16], tempOut[64];
int i, j, best,x,y,xx,yy,bpp;
if (dimension4 == 64) bpp = 4; else bpp = 3;
j = 1;
for(yy=0;yy<4;yy+=2) {
for(xx=0;xx<4;xx+=2) {
i = 0;
for(y=yy;y<(yy+2);y++) {
for(x=xx;x<(xx+2);x++) {
tempImage[i++] = cel[y*16+x*4+0];
tempImage[i++] = cel[y*16+x*4+1];
tempImage[i++] = cel[y*16+x*4+2];
if (dimension4 == 64) tempImage[i++] = cel[y*16+x*4+3];
}
}
pquad->patten[j++] = best = BestCodeword( tempImage, dimension2, codebook2 );
i = 0;
for(y=yy;y<(yy+2);y++) {
for(x=xx;x<(xx+2);x++) {
tempOut[y*16+x*4+0] = (byte)codebook2[best][i++];
tempOut[y*16+x*4+1] = (byte)codebook2[best][i++];
tempOut[y*16+x*4+2] = (byte)codebook2[best][i++];
if (dimension4 == 64)
tempOut[y*16+x*4+3] = (byte)codebook2[best][i++];
else
tempOut[y*16+x*4+3] = 255;
}
}
}
}
pquad->snr[CCC] = Snr( cel, tempOut, 4 );
}
void codec::IRGBtab(void)
{
initRGBtab++;
}
float codec::Snr( byte *old, byte *bnew, int size ) {
int i, j;
float fsnr;
register int ind;
ind = 0;
for(i=0; idomain = 0x8080;
pquad->snr[FCC] = 9999;
return;
}
ony = realy - (realy & 0xfff0);
onx = realx - (realx & 0xfff0);
xLen = previousImage[0]->pixelsWide();
yLen = previousImage[0]->pixelsHigh();
ripl = xLen-size;
breakHigh = 99999999;
fabort = 0;
lowX = lowY = -1;
depthx = depthy = 1;
searchY = 8; //16;
searchX = 8; //32;
//if (xLen == (yLen*4)) depthx = 2;
//if (theRoQ->Scaleable()) depthx = depthy = 2;
if (clamp) { searchX = searchY = 8; }
searchX = searchX*depthx;
searchY = searchY*depthy;
xxMean = dxMean*depthx;
yyMean = dyMean*depthy;
if (((realx-xxMean)+searchX)<0 ||(((realx-xxMean)-searchX)+depthx+size)>xLen || ((realy-yyMean)+searchY)<0 || (((realy-yyMean)-searchY)+depthy+size)>yLen) {
pquad->snr[FCC] = 9999;
return;
}
int sPsQ = -1;
for( sX=(((realx-xxMean)-searchX)+depthx); sX<=((realx-xxMean)+searchX) && !fabort; sX+=depthx ) {
for( sY=(((realy-yyMean)-searchY)+depthy); sY<=((realy-yyMean)+searchY) && breakHigh; sY+=depthy ) {
temp1 = xLen*sY+sX;
if ( sX >= 0 && (sX+size) <= xLen && sY >= 0 && (sY+size) <= yLen ) {
bpp = previousImage[0]->samplesPerPixel();
ripl = (xLen-size)*bpp;
mblur0 = 0;
bitma2 = bitmap;
scale1 = previousImage[((whichFrame+1)&1)]->bitmapData() + temp1*bpp;
// mblur0 = 0;
// bitma2 = luty;
// scale1 = luti + temp1;
for( y=0; y breakHigh) {
break;
}
scale1 += ripl;
}
if (breakHigh > mblur0) {
breakHigh = mblur0;
lowX = sX;
lowY = sY;
}
}
}
}
if (lowX != -1 && lowY != -1) {
bpp = previousImage[0]->samplesPerPixel();
ripl = (xLen-size)*bpp;
mblur0 = 0;
bitma2 = bitmap;
scale1 = previousImage[((whichFrame+1)&1)]->bitmapData() + (xLen*lowY+lowX)*bpp;
for( y=0; ydomain = (sX<<8)+sY;
pquad->snr[FCC] = lowestSNR;
}
}
void codec::GetData( unsigned char *iData, int qSize, int startX, int startY, NSBitmapImageRep *bitmap)
{
int x,y,yoff,bpp,yend,xend;
byte *iPlane[5];
int r,g,b,a;
yend = qSize+startY;
xend = qSize+startX;
if (startY > bitmap->pixelsHigh()) return;
if (yend > bitmap->pixelsHigh()) yend = bitmap->pixelsHigh();
if (xend > bitmap->pixelsWide()) xend = bitmap->pixelsWide();
bpp = bitmap->samplesPerPixel();
if (bitmap->hasAlpha()) {
iPlane[0] = bitmap->bitmapData();
for(y=startY;ypixelsWide()*bpp;
for(x=startX;xbitmapData();
for(y=startY;ypixelsWide()*bpp;
for(x=startX;x theRoQ->NormalFrameSize()) {
quickadd[CCC] = 0.5f;
quickadd[PAT] = 1.0f;
}
*/
wtemp = 99999;
for(i=(DEAD-1);i>0;i--) {
if ( qtemp->snr[i]*quickadd[i] < wtemp ) {
*status = i;
*snr = qtemp->snr[i];
wtemp = qtemp->snr[i]*quickadd[i];
}
}
if ( qtemp->mark ) *status = MOT;
}
int codec::GetCurrentQuadOutputSize( quadcel *pquad )
{
int totalbits, i, totalbytes;
int quickadd[DEAD+1];
totalbits = 0;
quickadd[DEP] = 2;
quickadd[SLD] = 10;
quickadd[PAT] = 10;
quickadd[CCC] = 34;
quickadd[MOT] = 2;
quickadd[FCC] = 10;
quickadd[DEAD] = 0;
for( i=0; i> 3)+2;
return (totalbytes);
}
float codec::GetCurrentRMSE( quadcel *pquad )
{
int i, j;
double totalbits;
totalbits = 0;
j = 0;
for( i=0; iIsLastFrame() && !detail) {
pquad[i].mark = true;
}
}
LowestQuad( &pquad[i] ,&pquad[i].status, &pquad[i].rsnr, true );
newsnr += pquad[i].rsnr;
}
Mem_Free(idataA); Mem_Free(idataB);
newsnr /= 4;
LowestQuad( &pquad[lownum], &pquad[lownum].status, &pquad[lownum].rsnr, false );
if ( pquad[lownum+nx*0+1].status == MOT && pquad[lownum+nx*1+1].status == MOT
&& pquad[lownum+nx*2+1].status == MOT && pquad[lownum+nx*3+1].status == MOT
&& nsize == 4) { newsnr = 9999; pquad[lownum].status = MOT; }
if ( pquad[lownum].rsnr > newsnr ) {
pquad[lownum].status = DEP;
pquad[lownum].rsnr = 0;
for( i=lownum+1; iMarkQuadx( pquad[i].xat, pquad[i].yat, nsize, pquad[i].rsnr, qStatus[i].status );
}
} else {
theRoQ->MarkQuadx( pquad[lownum].xat, pquad[lownum].yat, nsize*2, pquad[lownum].rsnr, qStatus[lownum].status );
pquad[lownum+nx*0+1].status = 0;
pquad[lownum+nx*1+1].status = 0;
pquad[lownum+nx*2+1].status = 0;
pquad[lownum+nx*3+1].status = 0;
pquad[lownum+nx*0+1].size = 0;
pquad[lownum+nx*1+1].size = 0;
pquad[lownum+nx*2+1].size = 0;
pquad[lownum+nx*3+1].size = 0;
}
} else {
lownum = -1;
}
return lownum;
}
int codec::MotMeanX( void )
{
return dxMean;
}
int codec::MotMeanY( void )
{
return dyMean;
}
void codec::SparseEncode( void )
{
int i, j, osize, fsize, num[DEAD+1], *ilist, onf, ong, wtype, temp;
float *flist, sRMSE, numredo;
byte *idataA, *idataB;
osize = 8;
image = theRoQ->CurrentImage();
newImage = 0;
pixelsHigh = image->pixelsHigh();
pixelsWide = image->pixelsWide();
dimension2 = 12; dimension4 = 48;
if (image->hasAlpha()&&(theRoQ->ParamNoAlpha() == false)) { dimension2 = 16; dimension4 = 64; }
idataA = (byte *)Mem_Alloc( 16*16*4 );
idataB = (byte *)Mem_Alloc( 16*16*4 );
if (!previousImage[0]) common->Printf("sparseEncode: sparsely encoding a %d,%d image\n", pixelsWide, pixelsHigh);
InitImages();
flist = (float *)Mem_ClearedAlloc( (numQuadCels+1) *sizeof(float) );
ilist = (int *)Mem_ClearedAlloc( (numQuadCels+1) *sizeof(int ) );
fsize = 56*1024;
if (theRoQ->NumberOfFrames()>2) {
if (previousImage[0]) fsize = theRoQ->NormalFrameSize(); else fsize = theRoQ->FirstFrameSize();
if (theRoQ->HasSound() && fsize > 6000 && previousImage[0]) fsize = 6000;
}
fsize += (slop/50);
if (fsize > 64000) {
fsize = 64000;
}
if (previousImage[0] && fsize > theRoQ->NormalFrameSize()*2) {
fsize = theRoQ->NormalFrameSize()*2;
}
dxMean = dyMean = 0;
if (previousImage[0]) wtype = 1; else wtype = 0;
for( i=0; iIsLastFrame()) {
qStatus[i].mark = true;
}
if (!qStatus[i].mark) {
FvqData( idataA, qStatus[i].size, qStatus[i].xat, qStatus[i].yat, &qStatus[i], false );
}
}
LowestQuad( &qStatus[i], &qStatus[i].status, &qStatus[i].rsnr, wtype );
if (qStatus[i].rsnr < 9999)
theRoQ->MarkQuadx( qStatus[i].xat, qStatus[i].yat, qStatus[i].size, qStatus[i].rsnr, qStatus[i].status );
} else {
if ( qStatus[i].size < osize ) {
qStatus[i].status = 0;
qStatus[i].size = 0;
} else {
qStatus[i].status = DEP;
qStatus[i].rsnr = 0;
}
}
}
//
// the quad is complete, so status can now be used for quad decomposition
// the first thing to do is to set it up for all the 4x4 cels to get output
// and then recurse from there to see what's what
//
sRMSE = GetCurrentRMSE( qStatus );
if (theRoQ->IsQuiet() == false) {
common->Printf("sparseEncode: rmse of quad0 is %f, size is %d (meant to be %d)\n", sRMSE, GetCurrentQuadOutputSize(qStatus), fsize );
}
onf = 0;
for(i=0;i> 8 ) - 128;
dyMean += (qStatus[i].domain & 0xff) - 128;
temp++;
}
}
if (temp) { dxMean /= temp; dyMean /= temp; }
*/
common->Printf("sparseEncode: dx/dy mean is %d,%d\n", dxMean, dyMean);
numredo = 0;
detail = false;
if (codebookmade && whichFrame>4) fsize -= 256;
temp = 0;
for( i=0; i 0 ) {
GetData( idataA, qStatus[i].size, qStatus[i].xat, qStatus[i].yat, image );
if (osize == 8) VqData8( idataA, &qStatus[i] );
if (previousImage[0]) {
int dx,dy;
dx = (qStatus[i].domain >> 8 ) - 128 - dxMean + 8;
dy = (qStatus[i].domain & 0xff) - 128 - dyMean + 8;
if (dx<0||dx>15||dy<0||dy>15) {
qStatus[i].snr[FCC] = 9999;
temp++;
FvqData( idataA, qStatus[i].size, qStatus[i].xat, qStatus[i].yat, &qStatus[i], true );
dx = (qStatus[i].domain >> 8 ) - 128 - dxMean + 8;
dy = (qStatus[i].domain & 0xff) - 128 - dyMean + 8;
if ((dx<0||dx>15||dy<0||dy>15)&&qStatus[i].snr[FCC]!=9999&&qStatus[i].status==FCC) {
common->Printf("sparseEncode: something is wrong here, dx/dy is %d,%d after being clamped\n", dx, dy);
common->Printf("xat: %d\n", qStatus[i].xat);
common->Printf("yat: %d\n", qStatus[i].yat);
common->Printf("size %d\n", qStatus[i].size);
common->Printf("type: %d\n", qStatus[i].status);
common->Printf("mot: %04x\n", qStatus[i].domain);
common->Printf("motsnr: %0f\n", qStatus[i].snr[FCC]);
common->Printf("rmse: %0f\n", qStatus[i].rsnr);
common->Error("need to go away now\n");
}
}
}
LowestQuad( &qStatus[i], &qStatus[i].status, &qStatus[i].rsnr, wtype );
theRoQ->MarkQuadx( qStatus[i].xat, qStatus[i].yat, qStatus[i].size, qStatus[i].rsnr, qStatus[i].status );
/*
if (qStatus[i].status==FCC && qStatus[i].snr[FCC]>qStatus[i].snr[SLD]) {
common->Printf("sparseEncode: something is wrong here\n");
common->Printf("xat: %d\n", qStatus[i].xat);
common->Printf("yat: %d\n", qStatus[i].yat);
common->Printf("size %d\n", qStatus[i].size);
common->Printf("type: %d\n", qStatus[i].status);
common->Printf("mot: %04x\n", qStatus[i].domain);
common->Printf("motsnr: %0f\n", qStatus[i].snr[FCC]);
common->Printf("sldsnr: %0f\n", qStatus[i].snr[SLD]);
common->Printf("rmse: %0f\n", qStatus[i].rsnr);
//common->Error("need to go away now\n");
}
*/
}
}
if (theRoQ->IsQuiet() == false) {
common->Printf("sparseEncode: rmse of quad0 is %f, size is %d (meant to be %d)\n", GetCurrentRMSE( qStatus ), GetCurrentQuadOutputSize( qStatus ), fsize );
common->Printf("sparseEncode: %d outside fcc limits\n", temp);
}
onf = 0;
for(i=0;i 0 && qStatus[ilist[ong]].mark == false) {
// badsnr = [self getCurrentRMSE: qStatus];
osize = AddQuad( qStatus, ilist[ong++] );
// if ([self getCurrentRMSE: qStatus] >= badsnr) {
// break;
// }
}
if ( GetCurrentQuadOutputSize( qStatus ) < fsize) {
ong = 0;
while ( GetCurrentQuadOutputSize(qStatus) < fsize && ong < onf) {
// badsnr = [self getCurrentRMSE: qStatus];
i = ilist[ong++];
if (qStatus[i].mark) {
detail = false;
qStatus[i].mark = false;
GetData( idataA, qStatus[i].size, qStatus[i].xat, qStatus[i].yat, image );
if (qStatus[i].size == 8) VqData8( idataA, &qStatus[i] );
if (qStatus[i].size == 4) VqData4( idataA, &qStatus[i] );
if (qStatus[i].size == 4) VqData2( idataA, &qStatus[i] );
if (previousImage[0]) {
FvqData( idataA, qStatus[i].size, qStatus[i].xat, qStatus[i].yat, &qStatus[i], true );
}
LowestQuad( &qStatus[i], &qStatus[i].status, &qStatus[i].rsnr, wtype );
if (qStatus[i].rsnr <= MIN_SNR) {
break;
}
theRoQ->MarkQuadx( qStatus[i].xat, qStatus[i].yat, qStatus[i].size, qStatus[i].rsnr, qStatus[i].status );
}
// if ([self getCurrentRMSE: qStatus] >= badsnr) {
// break;
// }
}
ong = 0;
while ( GetCurrentQuadOutputSize( qStatus ) < fsize && ong < onf && flist[ong] > 0) {
// badsnr = [self getCurrentRMSE: qStatus];
i = ilist[ong++];
// if (qStatus[i].rsnr <= MIN_SNR) {
// break;
// }
detail = true;
osize = AddQuad( qStatus, i );
// if ([self getCurrentRMSE: qStatus] >= badsnr) {
// break;
// }
}
}
common->Printf("sparseEncode: rmse of frame %d is %f, size is %d\n", whichFrame, GetCurrentRMSE(qStatus), GetCurrentQuadOutputSize(qStatus) );
if (previousImage[0])
fsize = theRoQ->NormalFrameSize();
else
fsize = theRoQ->FirstFrameSize();
slop += (fsize - GetCurrentQuadOutputSize(qStatus));
if (theRoQ->IsQuiet() == false) {
for(i=0;iPrintf("sparseEncode: for 08x08 CCC = %d, FCC = %d, MOT = %d, SLD = %d, PAT = %d\n", num[CCC], num[FCC], num[MOT], num[SLD], num[PAT]);
for(i=0;iPrintf("sparseEncode: for 04x04 CCC = %d, FCC = %d, MOT = %d, SLD = %d, PAT = %d\n", num[CCC], num[FCC], num[MOT], num[SLD], num[PAT]);
common->Printf("sparseEncode: average RMSE = %f, numActiveQuadCels = %d, estSize = %d, slop = %d \n", GetCurrentRMSE(qStatus), j, GetCurrentQuadOutputSize(qStatus), slop);
}
theRoQ->WriteFrame( qStatus );
MakePreviousImage( qStatus );
Mem_Free(idataA);
Mem_Free(idataB);
Mem_Free(flist);
Mem_Free(ilist);
if (newImage) delete newImage;
whichFrame++;
}
void codec::EncodeNothing( void )
{
int i, j, osize, fsize, num[DEAD+1], *ilist, wtype;
float *flist, sRMSE;
byte *idataA, *idataB;
osize = 8;
image = theRoQ->CurrentImage();
newImage = 0;
pixelsHigh = image->pixelsHigh();
pixelsWide = image->pixelsWide();
dimension2 = 12; dimension4 = 48;
if (image->hasAlpha()&&(theRoQ->ParamNoAlpha() == false)) { dimension2 = 16; dimension4 = 64; }
idataA = (byte *)Mem_Alloc( 16*16*4 );
idataB = (byte *)Mem_Alloc( 16*16*4 );
if (!previousImage[0]) common->Printf("sparseEncode: sparsely encoding a %d,%d image\n", pixelsWide, pixelsHigh);
InitImages();
flist = (float *)Mem_ClearedAlloc( (numQuadCels+1) * sizeof(float) );
ilist = (int *)Mem_ClearedAlloc( (numQuadCels+1) * sizeof(int ) );
fsize = 56*1024;
if (theRoQ->NumberOfFrames()>2) {
if (previousImage[0]) fsize = theRoQ->NormalFrameSize(); else fsize = theRoQ->FirstFrameSize();
if (theRoQ->HasSound() && fsize > 6000 && previousImage[0]) fsize = 6000;
}
dxMean = dyMean = 0;
if (previousImage[0]) wtype = 1; else wtype = 0;
for( i=0; iMarkQuadx( qStatus[i].xat, qStatus[i].yat, qStatus[i].size, qStatus[i].rsnr, qStatus[i].status );
} else {
if ( qStatus[i].size < osize ) {
qStatus[i].status = 0;
qStatus[i].size = 0;
} else {
qStatus[i].status = DEP;
qStatus[i].rsnr = 0;
}
}
}
//
// the quad is complete, so status can now be used for quad decomposition
// the first thing to do is to set it up for all the 4x4 cels to get output
// and then recurse from there to see what's what
//
sRMSE = GetCurrentRMSE( qStatus );
common->Printf("sparseEncode: rmse of frame %d is %f, size is %d\n", whichFrame, sRMSE, GetCurrentQuadOutputSize( qStatus ) );
if (theRoQ->IsQuiet() == false) {
for(i=0;iPrintf("sparseEncode: for 08x08 CCC = %d, FCC = %d, MOT = %d, SLD = %d, PAT = %d\n", num[CCC], num[FCC], num[MOT], num[SLD], num[PAT]);
for(i=0;iPrintf("sparseEncode: for 04x04 CCC = %d, FCC = %d, MOT = %d, SLD = %d, PAT = %d\n", num[CCC], num[FCC], num[MOT], num[SLD], num[PAT]);
common->Printf("sparseEncode: average RMSE = %f, numActiveQuadCels = %d, estSize = %d \n", GetCurrentRMSE(qStatus), j, GetCurrentQuadOutputSize(qStatus));
}
theRoQ->WriteFrame( qStatus );
MakePreviousImage( qStatus );
Mem_Free(idataA);
Mem_Free(idataB);
Mem_Free(flist);
Mem_Free(ilist);
if (newImage) delete newImage;
whichFrame++;
}
void codec::VQ( const int numEntries, const int dimension, const unsigned char *vectors, float *import, VQDATA **codebook, const bool optimize ) {
int startMsec = Sys_Milliseconds();
if (numEntries <= 256) {
//
// copy the entries into the codebooks
//
for( int i=0; iPrintf("VQ: has %d entries to process\n", numFinalEntries );
//
// are we done?
//
int end;
if (numFinalEntries > 256) {
//
// find the closest two and eliminate one
//
double bestDist = HUGE_VAL;
double dist, simport;
int bestIndex = -1;
int bestOtherIndex = 0;
int aentries = 0;
for( i=0; i8192) {
end = i+32;
} else if (numFinalEntries>4096) {
end = i+64;
} else if (numFinalEntries>2048) {
end = i+128;
} else if (numFinalEntries>1024) {
end = i+256;
} else if (numFinalEntries>512) {
end = i+512;
}
if (end>numEntries) {
end = numEntries;
}
}
ibase = i*dimension;
for( j=i+1; j8192) {
end = i+32;
} else if (numFinalEntries>4096) {
end = i+64;
} else if (numFinalEntries>2048) {
end = i+128;
} else if (numFinalEntries>1024) {
end = i+256;
} else if (numFinalEntries>512) {
end = i+512;
}
}
if (end>numEntries) {
end = numEntries;
}
ibase = i*dimension;
for( j=i+1; j scaledBestDist ) {
break;
}
#endif
}
dist *= simport;
if ( dist < bestDist ) {
bestDist = dist;
bestIndex = i;
bestOtherIndex = j;
}
}
snrs[aentries] = bestDist;
indexes[aentries] = bestIndex;
indexet[aentries] = bestOtherIndex;
aentries++;
}
}
//
// and lose one
//
inuse[bestIndex] = false;
numFinalEntries--;
import[bestOtherIndex] += import[bestIndex];
if ((numFinalEntries&511)==0) {
common->Printf("VQ: has %d entries to process\n", numFinalEntries );
session->UpdateScreen();
}
} while (numFinalEntries > 256);
}
//
// copy the entries into the codebooks
//
int onEntry = 0;
for( i=0; iPrintf("First vq = %d\n ", i);
}
if (onEntry == 255) {
common->Printf("last vq = %d\n", i);
}
onEntry++;
}
}
int endMsec = Sys_Milliseconds();
common->Printf( "VQ took %i msec\n", endMsec - startMsec );
}