]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake2/qdata_heretic2/animcomp.c
7e0c96d17fcec8fb7a61fabad65d4696b9fde8f4
[xonotic/netradiant.git] / tools / quake2 / qdata_heretic2 / animcomp.c
1 /*\r
2 Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
3 For a list of contributors, see the accompanying CONTRIBUTORS file.\r
4 \r
5 This file is part of GtkRadiant.\r
6 \r
7 GtkRadiant is free software; you can redistribute it and/or modify\r
8 it under the terms of the GNU General Public License as published by\r
9 the Free Software Foundation; either version 2 of the License, or\r
10 (at your option) any later version.\r
11 \r
12 GtkRadiant is distributed in the hope that it will be useful,\r
13 but WITHOUT ANY WARRANTY; without even the implied warranty of\r
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
15 GNU General Public License for more details.\r
16 \r
17 You should have received a copy of the GNU General Public License\r
18 along with GtkRadiant; if not, write to the Free Software\r
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
20 */\r
21 \r
22 \r
23 #include <stdlib.h>\r
24 #include <stdio.h>\r
25 #include <math.h>\r
26 #include <memory.h>\r
27 #include "animcomp.h"\r
28 \r
29 \r
30 void    *SafeMalloc(size_t n, char *desc);\r
31 \r
32 \r
33 \r
34 float *matrix;\r
35 float *delta;\r
36 float *best;\r
37 float *comp;\r
38 float *tcomp;\r
39 float *bestcomp;\r
40 float *frames;\r
41 float *base;\r
42 \r
43 int MatWidth;\r
44 int MatHeight;\r
45 int CFrameSize;\r
46 int nFrames;\r
47 \r
48 \r
49 void AnimCompressInit(int nframes,int nVerts,int CompressedFrameSize)\r
50 {\r
51         nFrames=nframes;\r
52         MatWidth=nVerts*3;\r
53         MatHeight=CompressedFrameSize;\r
54         CFrameSize=CompressedFrameSize;\r
55         matrix=(float *)SafeMalloc(MatWidth*MatHeight*sizeof(float), "AnimCompressInit");\r
56         best=(float *)SafeMalloc(MatWidth*MatHeight*sizeof(float), "AnimCompressInit");\r
57         delta=(float *)SafeMalloc(MatWidth*MatHeight*sizeof(float), "AnimCompressInit");\r
58         comp=(float *)SafeMalloc(CFrameSize*nFrames*sizeof(float), "AnimCompressInit");\r
59         tcomp=(float *)SafeMalloc(CFrameSize*nFrames*sizeof(float), "AnimCompressInit");\r
60         bestcomp=(float *)SafeMalloc(CFrameSize*nFrames*sizeof(float), "AnimCompressInit");\r
61         base=(float *)SafeMalloc(MatWidth*sizeof(float), "AnimCompressInit");\r
62         frames=(float *)SafeMalloc(MatWidth*nFrames*sizeof(float), "AnimCompressInit");\r
63 }\r
64 \r
65 void AnimSetFrame(int frame,int index,float x,float y,float z)\r
66 {\r
67         frames[frame*MatWidth+index*3]=x;\r
68         frames[frame*MatWidth+index*3+1]=y;\r
69         frames[frame*MatWidth+index*3+2]=z;\r
70 }\r
71 \r
72 typedef struct \r
73 {\r
74         int index;\r
75         float val;\r
76 } SORTP;\r
77 \r
78 \r
79 #define F_RANDOM (((float)rand())/(float)RAND_MAX)\r
80 \r
81 extern void DOsvd(float *a,float *res,float *comp,float *values,int nframes,int framesize,int compressedsize);\r
82 \r
83 void AnimCompressDoit()\r
84 {\r
85         float compression;\r
86         float *rescale;\r
87         float *ans;\r
88         float maxdev;\r
89         float avedev;\r
90         float tmp;\r
91         int j,k,l,numave;\r
92 \r
93         for (k=0;k<MatWidth;k++)\r
94                 base[k]=0.0f;\r
95         for (j=0;j<nFrames;j++)\r
96                 for (k=0;k<MatWidth;k++)\r
97                         base[k]+=frames[j*MatWidth+k];\r
98         tmp=1.0f/(float)nFrames;\r
99         for (k=0;k<MatWidth;k++)\r
100                 base[k]*=tmp;\r
101         for (j=0;j<nFrames;j++)\r
102                 for (k=0;k<MatWidth;k++)\r
103                         frames[j*MatWidth+k]-=base[k];\r
104 \r
105         ans=(float *)SafeMalloc(sizeof(float)*MatWidth, "AnimCompressDoit");\r
106         rescale=(float *)SafeMalloc(sizeof(float)*CFrameSize, "AnimCompressDoit");\r
107         DOsvd(frames,best,bestcomp,rescale,nFrames,MatWidth,MatHeight);\r
108         avedev=0.0;\r
109         for (l=0;l<CFrameSize;l++)\r
110                 avedev+=rescale[l];\r
111         for (l=0;l<CFrameSize;l++)\r
112                 printf("%3.1f ",100.0f*rescale[l]/avedev);\r
113         printf("\n");\r
114         for (j=0;j<nFrames;j++)\r
115         {\r
116                 for (l=0;l<CFrameSize;l++)\r
117                 {\r
118                         bestcomp[j*CFrameSize+l]=0.0;\r
119                         for (k=0;k<MatWidth;k++)\r
120                                 bestcomp[j*CFrameSize+l]+=best[l*MatWidth+k]*frames[j*MatWidth+k];\r
121                 }\r
122         }\r
123         numave=0;\r
124         avedev=0.0;\r
125         maxdev=0.0;\r
126         for (j=0;j<nFrames;j++)\r
127         {\r
128                 for (k=0;k<MatWidth;k++)\r
129                 {\r
130                         ans[k]=0.0;\r
131                         for (l=0;l<CFrameSize;l++)\r
132                                 ans[k]+=best[l*MatWidth+k]*bestcomp[j*CFrameSize+l];\r
133                         ans[k]-=frames[j*MatWidth+k];\r
134                         tmp=(float)fabs(ans[k]);\r
135                         if (tmp>maxdev)\r
136                                 maxdev=tmp;\r
137                         avedev+=tmp;\r
138                         numave++;\r
139                 }\r
140         }\r
141         avedev/=(float)numave;\r
142 printf("%f Max Deviation (inches)  %f Ave Dev. (inches)\n",maxdev,avedev);\r
143 printf("%d bytes original size\n",MatWidth*nFrames);\r
144 printf("%d bytes of overhead\n",MatWidth*MatHeight);\r
145 printf("%d bytes/frame * %d frames = %d bytes\n",CFrameSize,nFrames,CFrameSize*nFrames);\r
146         compression=(float)(MatWidth*MatHeight+CFrameSize*nFrames+MatWidth);\r
147         compression/=(float)(MatWidth*nFrames);\r
148 printf("Overall compression = %f %%\n",100.0f-100.0f*compression);\r
149         compression=(float)(CFrameSize);\r
150         compression/=(float)(MatWidth);\r
151 printf("frame size compression = %f %%\n",100.0f-100.0f*compression);\r
152         free(rescale);\r
153         free(ans);\r
154 }\r
155 \r
156 void AnimCompressToBytes(float *trans,float *scale,char *mat,char *ccomp,unsigned char *cbase,float *cscale,float *coffset,float *bmin,float *bmax)\r
157 {\r
158         int k,l,nv,j;\r
159         float maxdev;\r
160         float avedev;\r
161         float tmp;\r
162         int numave;\r
163         float t,mx;\r
164         float *ans;\r
165 \r
166 \r
167         nv=MatWidth/3;\r
168 \r
169         trans[0]=1E30f;\r
170         scale[0]=-1E30f;\r
171         trans[1]=1E30f;\r
172         scale[1]=-1E30f;\r
173         trans[2]=1E30f;\r
174         scale[2]=-1E30f;\r
175         for (k=0;k<MatWidth;k+=3)\r
176         {\r
177                 if (base[k]>scale[0])\r
178                         scale[0]=base[k];\r
179                 if (base[k]<trans[0])\r
180                         trans[0]=base[k];\r
181 \r
182                 if (base[k+1]>scale[1])\r
183                         scale[1]=base[k+1];\r
184                 if (base[k+1]<trans[1])\r
185                         trans[1]=base[k+1];\r
186 \r
187                 if (base[k+2]>scale[2])\r
188                         scale[2]=base[k+2];\r
189                 if (base[k+2]<trans[2])\r
190                         trans[2]=base[k+2];\r
191         }\r
192 \r
193         scale[0]-=trans[0];\r
194         scale[1]-=trans[1];\r
195         scale[2]-=trans[2];\r
196         scale[0]/=255.0f;\r
197         scale[1]/=255.0f;\r
198         scale[2]/=255.0f;\r
199         for (k=0;k<MatWidth;k+=3)\r
200         {\r
201                 t=(base[k]-trans[0])/scale[0];\r
202                 if (t<0.0f)\r
203                         t=0.0f;\r
204                 if (t>255.0f)\r
205                         t=255.0f;\r
206                 cbase[k]=(unsigned char)t;\r
207 \r
208                 t=(base[k+1]-trans[1])/scale[1];\r
209                 if (t<0.0f)\r
210                         t=0.0f;\r
211                 if (t>255.0f)\r
212                         t=255.0f;\r
213                 cbase[k+1]=(unsigned char)t;\r
214 \r
215                 t=(base[k+2]-trans[2])/scale[2];\r
216                 if (t<0.0f)\r
217                         t=0.0f;\r
218                 if (t>255.0f)\r
219                         t=255.0f;\r
220                 cbase[k+2]=(unsigned char)t;\r
221         }\r
222         for (l=0;l<MatHeight;l++)\r
223         {\r
224                 mx=0.0;\r
225                 for (k=0;k<MatWidth;k++)\r
226                 {\r
227                         if (fabs(best[l*MatWidth+k])>mx)\r
228                                 mx=(float)fabs(best[l*MatWidth+k]);\r
229                 }\r
230                 if (mx>1E-8)\r
231                 {\r
232                         mx/=127.0f;\r
233                         coffset[l]=1E30f;\r
234                         cscale[l]=-1E30f;\r
235                         for (j=0;j<nFrames;j++)\r
236                         {\r
237                                 bestcomp[j*MatHeight+l]*=mx;\r
238                                 if (bestcomp[j*MatHeight+l]>cscale[l])\r
239                                         cscale[l]=bestcomp[j*MatHeight+l];\r
240                                 if (bestcomp[j*MatHeight+l]<coffset[l])\r
241                                         coffset[l]=bestcomp[j*MatHeight+l];\r
242                         }\r
243                         cscale[l]-=coffset[l];\r
244                         if (cscale[l]>1E-10)\r
245                         {\r
246                                 for (j=0;j<nFrames;j++)\r
247                                 {\r
248                                         tmp=254.0f*(bestcomp[j*MatHeight+l]-coffset[l])/cscale[l]-127.0f;\r
249                                         if (tmp>127.0f)\r
250                                                 tmp=127.0f;\r
251                                         if (tmp<-127.0f)\r
252                                                 tmp=-127.0f;\r
253                                         ccomp[j*MatHeight+l]=(char)floor(tmp+0.5);\r
254                                 }\r
255                                 coffset[l]+=cscale[l]*127.0f/254.0f;\r
256                                 cscale[l]/=254.0f;\r
257                         }\r
258                         else\r
259                         {\r
260                                 cscale[l]=1.0f;\r
261                                 coffset[l]=0.0f;\r
262                                 for (j=0;j<nFrames;j++)\r
263                                         ccomp[j*MatHeight+l]=0;\r
264                         }\r
265                         mx=1.0f/mx;\r
266                         for (k=0;k<MatWidth;k++)\r
267                         {\r
268                                 tmp=best[l*MatWidth+k]*mx;\r
269                                 if (tmp>127.0f)\r
270                                         tmp=127.0f;\r
271                                 if (tmp<-127.0f)\r
272                                         tmp=-127.0f;\r
273                                 mat[k*MatHeight+l]=(char)floor(tmp+0.5);\r
274                         }\r
275                 }\r
276                 else\r
277                 {\r
278                         cscale[l]=1.0f;\r
279                         coffset[l]=0.0f;\r
280                         for (j=0;j<nFrames;j++)\r
281                                 ccomp[j*MatHeight+l]=0;\r
282                         for (k=0;k<MatWidth;k++)\r
283                                 mat[k*MatHeight+l]=0;\r
284                 }\r
285         }\r
286         bmin[0]=1E30f;\r
287         bmin[1]=1E30f;\r
288         bmin[2]=1E30f;\r
289         bmax[0]=-1E30f;\r
290         bmax[1]=-1E30f;\r
291         bmax[2]=-1E30f;\r
292         numave=0;\r
293         avedev=0.0;\r
294         maxdev=0.0;\r
295         ans=(float *)SafeMalloc(sizeof(float)*MatWidth, "AnimCompressToBytes");\r
296         for (j=0;j<nFrames;j++)\r
297         {\r
298                 for (k=0;k<MatWidth;k++)\r
299                 {\r
300                         ans[k]=0.0;\r
301                         for (l=0;l<CFrameSize;l++)\r
302                                 ans[k]+=(float)(mat[l+k*MatHeight])*((float)(ccomp[j*CFrameSize+l])*cscale[l]+coffset[l]);\r
303                         ans[k]+=(float)(cbase[k])*scale[k%3]+trans[k%3];\r
304                         tmp=(float)fabs(ans[k]-frames[j*MatWidth+k]-base[k]);\r
305                         if (tmp>maxdev)\r
306                                 maxdev=tmp;\r
307                         avedev+=tmp;\r
308                         numave++;\r
309 \r
310                         if (bmin[k%3]>ans[k])\r
311                                 bmin[k%3]=ans[k];\r
312                         if (bmax[k%3]<ans[k])\r
313                                 bmax[k%3]=ans[k];\r
314                 }\r
315         }\r
316         avedev/=(float)numave;\r
317 printf("%f Max Deviation (inches)  %f Ave Dev. (inches)\n",maxdev,avedev);\r
318         free(ans);\r
319 }\r
320 \r
321 void AnimCompressGetMatrix(float *mat)\r
322 {\r
323         int k,l;\r
324         for (k=0;k<MatWidth;k++)\r
325                 for (l=0;l<MatHeight;l++)\r
326                         mat[k*MatHeight+l]=best[l*MatWidth+k];\r
327 }\r
328 \r
329 void AnimCompressGetFrames(float *mat)\r
330 {\r
331         memcpy(mat,bestcomp,CFrameSize*nFrames*sizeof(float));\r
332 }\r
333 \r
334 void AnimCompressGetBase(int i,float *x,float *y,float *z)\r
335 {\r
336         *x=base[i*3];\r
337         *y=base[i*3+1];\r
338         *z=base[i*3+2];\r
339 }\r
340 \r
341 void AnimCompressEnd()\r
342 {\r
343         free(matrix);\r
344         free(best);\r
345         free(delta);\r
346         free(comp);\r
347         free(tcomp);\r
348         free(bestcomp);\r
349         free(base);\r
350         free(frames);\r
351 }\r