mirror of
https://github.com/UberGames/GtkRadiant.git
synced 2024-11-26 22:01:38 +00:00
9998050654
git-svn-id: svn://svn.icculus.org/gtkradiant/GtkRadiant/branches/ZeroRadiant@183 8a3a26a2-13c4-0310-b231-cf6edde360e5
351 lines
8 KiB
C
351 lines
8 KiB
C
/*
|
|
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);
|
|
}
|