gtkradiant/tools/quake2/qdata_heretic2/animcomp.c

365 lines
9.2 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 );
}