gtkradiant/tools/quake2/qdata_heretic2/animcomp.c

352 lines
8.3 KiB
C
Raw Normal View History

/*
Copyright (C) 1999-2007 id Software, Inc. and contributors.
For a list of contributors, see the accompanying CONTRIBUTORS file.
This file is part of GtkRadiant.
GtkRadiant 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.
GtkRadiant 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 GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <memory.h>
#include "animcomp.h"
void *SafeMalloc(size_t n, char *desc);
float *matrix;
float *delta;
float *best;
float *comp;
float *tcomp;
float *bestcomp;
float *frames;
float *base;
int MatWidth;
int MatHeight;
int CFrameSize;
int nFrames;
void AnimCompressInit(int nframes,int nVerts,int CompressedFrameSize)
{
nFrames=nframes;
MatWidth=nVerts*3;
MatHeight=CompressedFrameSize;
CFrameSize=CompressedFrameSize;
matrix=(float *)SafeMalloc(MatWidth*MatHeight*sizeof(float), "AnimCompressInit");
best=(float *)SafeMalloc(MatWidth*MatHeight*sizeof(float), "AnimCompressInit");
delta=(float *)SafeMalloc(MatWidth*MatHeight*sizeof(float), "AnimCompressInit");
comp=(float *)SafeMalloc(CFrameSize*nFrames*sizeof(float), "AnimCompressInit");
tcomp=(float *)SafeMalloc(CFrameSize*nFrames*sizeof(float), "AnimCompressInit");
bestcomp=(float *)SafeMalloc(CFrameSize*nFrames*sizeof(float), "AnimCompressInit");
base=(float *)SafeMalloc(MatWidth*sizeof(float), "AnimCompressInit");
frames=(float *)SafeMalloc(MatWidth*nFrames*sizeof(float), "AnimCompressInit");
}
void AnimSetFrame(int frame,int index,float x,float y,float z)
{
frames[frame*MatWidth+index*3]=x;
frames[frame*MatWidth+index*3+1]=y;
frames[frame*MatWidth+index*3+2]=z;
}
typedef struct
{
int index;
float val;
} SORTP;
#define F_RANDOM (((float)rand())/(float)RAND_MAX)
extern void DOsvd(float *a,float *res,float *comp,float *values,int nframes,int framesize,int compressedsize);
void AnimCompressDoit()
{
float compression;
float *rescale;
float *ans;
float maxdev;
float avedev;
float tmp;
int j,k,l,numave;
for (k=0;k<MatWidth;k++)
base[k]=0.0f;
for (j=0;j<nFrames;j++)
for (k=0;k<MatWidth;k++)
base[k]+=frames[j*MatWidth+k];
tmp=1.0f/(float)nFrames;
for (k=0;k<MatWidth;k++)
base[k]*=tmp;
for (j=0;j<nFrames;j++)
for (k=0;k<MatWidth;k++)
frames[j*MatWidth+k]-=base[k];
ans=(float *)SafeMalloc(sizeof(float)*MatWidth, "AnimCompressDoit");
rescale=(float *)SafeMalloc(sizeof(float)*CFrameSize, "AnimCompressDoit");
DOsvd(frames,best,bestcomp,rescale,nFrames,MatWidth,MatHeight);
avedev=0.0;
for (l=0;l<CFrameSize;l++)
avedev+=rescale[l];
for (l=0;l<CFrameSize;l++)
printf("%3.1f ",100.0f*rescale[l]/avedev);
printf("\n");
for (j=0;j<nFrames;j++)
{
for (l=0;l<CFrameSize;l++)
{
bestcomp[j*CFrameSize+l]=0.0;
for (k=0;k<MatWidth;k++)
bestcomp[j*CFrameSize+l]+=best[l*MatWidth+k]*frames[j*MatWidth+k];
}
}
numave=0;
avedev=0.0;
maxdev=0.0;
for (j=0;j<nFrames;j++)
{
for (k=0;k<MatWidth;k++)
{
ans[k]=0.0;
for (l=0;l<CFrameSize;l++)
ans[k]+=best[l*MatWidth+k]*bestcomp[j*CFrameSize+l];
ans[k]-=frames[j*MatWidth+k];
tmp=(float)fabs(ans[k]);
if (tmp>maxdev)
maxdev=tmp;
avedev+=tmp;
numave++;
}
}
avedev/=(float)numave;
printf("%f Max Deviation (inches) %f Ave Dev. (inches)\n",maxdev,avedev);
printf("%d bytes original size\n",MatWidth*nFrames);
printf("%d bytes of overhead\n",MatWidth*MatHeight);
printf("%d bytes/frame * %d frames = %d bytes\n",CFrameSize,nFrames,CFrameSize*nFrames);
compression=(float)(MatWidth*MatHeight+CFrameSize*nFrames+MatWidth);
compression/=(float)(MatWidth*nFrames);
printf("Overall compression = %f %%\n",100.0f-100.0f*compression);
compression=(float)(CFrameSize);
compression/=(float)(MatWidth);
printf("frame size compression = %f %%\n",100.0f-100.0f*compression);
free(rescale);
free(ans);
}
void AnimCompressToBytes(float *trans,float *scale,char *mat,char *ccomp,unsigned char *cbase,float *cscale,float *coffset,float *bmin,float *bmax)
{
int k,l,nv,j;
float maxdev;
float avedev;
float tmp;
int numave;
float t,mx;
float *ans;
nv=MatWidth/3;
trans[0]=1E30f;
scale[0]=-1E30f;
trans[1]=1E30f;
scale[1]=-1E30f;
trans[2]=1E30f;
scale[2]=-1E30f;
for (k=0;k<MatWidth;k+=3)
{
if (base[k]>scale[0])
scale[0]=base[k];
if (base[k]<trans[0])
trans[0]=base[k];
if (base[k+1]>scale[1])
scale[1]=base[k+1];
if (base[k+1]<trans[1])
trans[1]=base[k+1];
if (base[k+2]>scale[2])
scale[2]=base[k+2];
if (base[k+2]<trans[2])
trans[2]=base[k+2];
}
scale[0]-=trans[0];
scale[1]-=trans[1];
scale[2]-=trans[2];
scale[0]/=255.0f;
scale[1]/=255.0f;
scale[2]/=255.0f;
for (k=0;k<MatWidth;k+=3)
{
t=(base[k]-trans[0])/scale[0];
if (t<0.0f)
t=0.0f;
if (t>255.0f)
t=255.0f;
cbase[k]=(unsigned char)t;
t=(base[k+1]-trans[1])/scale[1];
if (t<0.0f)
t=0.0f;
if (t>255.0f)
t=255.0f;
cbase[k+1]=(unsigned char)t;
t=(base[k+2]-trans[2])/scale[2];
if (t<0.0f)
t=0.0f;
if (t>255.0f)
t=255.0f;
cbase[k+2]=(unsigned char)t;
}
for (l=0;l<MatHeight;l++)
{
mx=0.0;
for (k=0;k<MatWidth;k++)
{
if (fabs(best[l*MatWidth+k])>mx)
mx=(float)fabs(best[l*MatWidth+k]);
}
if (mx>1E-8)
{
mx/=127.0f;
coffset[l]=1E30f;
cscale[l]=-1E30f;
for (j=0;j<nFrames;j++)
{
bestcomp[j*MatHeight+l]*=mx;
if (bestcomp[j*MatHeight+l]>cscale[l])
cscale[l]=bestcomp[j*MatHeight+l];
if (bestcomp[j*MatHeight+l]<coffset[l])
coffset[l]=bestcomp[j*MatHeight+l];
}
cscale[l]-=coffset[l];
if (cscale[l]>1E-10)
{
for (j=0;j<nFrames;j++)
{
tmp=254.0f*(bestcomp[j*MatHeight+l]-coffset[l])/cscale[l]-127.0f;
if (tmp>127.0f)
tmp=127.0f;
if (tmp<-127.0f)
tmp=-127.0f;
ccomp[j*MatHeight+l]=(char)floor(tmp+0.5);
}
coffset[l]+=cscale[l]*127.0f/254.0f;
cscale[l]/=254.0f;
}
else
{
cscale[l]=1.0f;
coffset[l]=0.0f;
for (j=0;j<nFrames;j++)
ccomp[j*MatHeight+l]=0;
}
mx=1.0f/mx;
for (k=0;k<MatWidth;k++)
{
tmp=best[l*MatWidth+k]*mx;
if (tmp>127.0f)
tmp=127.0f;
if (tmp<-127.0f)
tmp=-127.0f;
mat[k*MatHeight+l]=(char)floor(tmp+0.5);
}
}
else
{
cscale[l]=1.0f;
coffset[l]=0.0f;
for (j=0;j<nFrames;j++)
ccomp[j*MatHeight+l]=0;
for (k=0;k<MatWidth;k++)
mat[k*MatHeight+l]=0;
}
}
bmin[0]=1E30f;
bmin[1]=1E30f;
bmin[2]=1E30f;
bmax[0]=-1E30f;
bmax[1]=-1E30f;
bmax[2]=-1E30f;
numave=0;
avedev=0.0;
maxdev=0.0;
ans=(float *)SafeMalloc(sizeof(float)*MatWidth, "AnimCompressToBytes");
for (j=0;j<nFrames;j++)
{
for (k=0;k<MatWidth;k++)
{
ans[k]=0.0;
for (l=0;l<CFrameSize;l++)
ans[k]+=(float)(mat[l+k*MatHeight])*((float)(ccomp[j*CFrameSize+l])*cscale[l]+coffset[l]);
ans[k]+=(float)(cbase[k])*scale[k%3]+trans[k%3];
tmp=(float)fabs(ans[k]-frames[j*MatWidth+k]-base[k]);
if (tmp>maxdev)
maxdev=tmp;
avedev+=tmp;
numave++;
if (bmin[k%3]>ans[k])
bmin[k%3]=ans[k];
if (bmax[k%3]<ans[k])
bmax[k%3]=ans[k];
}
}
avedev/=(float)numave;
printf("%f Max Deviation (inches) %f Ave Dev. (inches)\n",maxdev,avedev);
free(ans);
}
void AnimCompressGetMatrix(float *mat)
{
int k,l;
for (k=0;k<MatWidth;k++)
for (l=0;l<MatHeight;l++)
mat[k*MatHeight+l]=best[l*MatWidth+k];
}
void AnimCompressGetFrames(float *mat)
{
memcpy(mat,bestcomp,CFrameSize*nFrames*sizeof(float));
}
void AnimCompressGetBase(int i,float *x,float *y,float *z)
{
*x=base[i*3];
*y=base[i*3+1];
*z=base[i*3+2];
}
void AnimCompressEnd()
{
free(matrix);
free(best);
free(delta);
free(comp);
free(tcomp);
free(bestcomp);
free(base);
free(frames);
}