]> icculus.org git repositories - divverent/netradiant.git/blob - radiant/texmanip.cpp
update changelog
[divverent/netradiant.git] / radiant / texmanip.cpp
1 /*
2 Copyright (c) 2002 Forest "LordHavoc" Hale
3
4 All rights reserved.
5
6 Redistribution and use in source and binary forms, with or without modification,
7 are permitted provided that the following conditions are met:
8
9 Redistributions of source code must retain the above copyright notice, this list
10 of conditions and the following disclaimer.
11
12 Redistributions in binary form must reproduce the above copyright notice, this
13 list of conditions and the following disclaimer in the documentation and/or
14 other materials provided with the distribution.
15
16 Neither the name of Forest Hale nor the names of other contributors may be used
17 to endorse or promote products derived from this software without specific prior
18 written permission. 
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
21 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY 
24 DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
25 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
27 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
30 */
31
32 #include "texmanip.h"
33
34 #include <stdlib.h>
35 #include "stream/textstream.h"
36
37 static byte *row1 = NULL, *row2 = NULL;
38 static int rowsize = 0;
39
40 void R_ResampleTextureLerpLine (const byte *in, byte *out, int inwidth, int outwidth, int bytesperpixel)
41 {
42   int   j, xi, oldx = 0, f, fstep, endx, lerp;
43 #define LERPBYTE(i) out[i] = (byte) ((((row2[i] - row1[i]) * lerp) >> 16) + row1[i])
44
45   fstep = (int) (inwidth * 65536.0f / outwidth);
46   endx = (inwidth - 1);
47   if (bytesperpixel == 4)
48   {
49     for (j = 0,f = 0;j < outwidth;j++, f += fstep)
50     {
51       xi = f >> 16;
52       if (xi != oldx)
53       {
54         in += (xi - oldx) * 4;
55         oldx = xi;
56       }
57
58       if (xi < endx)
59       {
60         lerp = f & 0xFFFF;
61         *out++ = (byte) ((((in[4] - in[0]) * lerp) >> 16) + in[0]);
62         *out++ = (byte) ((((in[5] - in[1]) * lerp) >> 16) + in[1]);
63         *out++ = (byte) ((((in[6] - in[2]) * lerp) >> 16) + in[2]);
64         *out++ = (byte) ((((in[7] - in[3]) * lerp) >> 16) + in[3]);
65       }
66       else // last pixel of the line has no pixel to lerp to
67       {
68         *out++ = in[0];
69         *out++ = in[1];
70         *out++ = in[2];
71         *out++ = in[3];
72       }
73     }
74   }
75   else if (bytesperpixel == 3)
76   {
77     for (j = 0, f = 0; j < outwidth; j++, f += fstep)
78     {
79       xi = f >> 16;
80       if (xi != oldx)
81       {
82         in += (xi - oldx) * 3;
83         oldx = xi;
84       }
85
86       if (xi < endx)
87       {
88         lerp = f & 0xFFFF;
89         *out++ = (byte) ((((in[3] - in[0]) * lerp) >> 16) + in[0]);
90         *out++ = (byte) ((((in[4] - in[1]) * lerp) >> 16) + in[1]);
91         *out++ = (byte) ((((in[5] - in[2]) * lerp) >> 16) + in[2]);
92       }
93       else // last pixel of the line has no pixel to lerp to
94       {
95         *out++ = in[0];
96         *out++ = in[1];
97         *out++ = in[2];
98       }
99     }
100   }
101   else
102   {
103     globalOutputStream() << "R_ResampleTextureLerpLine: unsupported bytesperpixel " << bytesperpixel << "\n";
104   }
105 }
106
107 /*
108 ================
109 R_ResampleTexture
110 ================
111 */
112 void R_ResampleTexture (const void *indata, int inwidth, int inheight, void *outdata,  int outwidth, int outheight, int bytesperpixel)
113 {
114   if (rowsize < outwidth * bytesperpixel)
115   {
116     if (row1)
117       free(row1);
118     if (row2)
119       free(row2);
120
121     rowsize = outwidth * bytesperpixel;
122     row1 = (byte *)malloc(rowsize);
123     row2 = (byte *)malloc(rowsize);
124   }
125
126   if (bytesperpixel == 4)
127   {
128     int i, j, yi, oldy, f, fstep, lerp, endy = (inheight-1), inwidth4 = inwidth*4, outwidth4 = outwidth*4;
129     byte *inrow, *out;
130     out = (byte *)outdata;
131     fstep = (int) (inheight * 65536.0f / outheight);
132 #define LERPBYTE(i) out[i] = (byte) ((((row2[i] - row1[i]) * lerp) >> 16) + row1[i])
133
134     inrow = (byte *)indata;
135     oldy = 0;
136     R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel);
137     R_ResampleTextureLerpLine (inrow + inwidth4, row2, inwidth, outwidth, bytesperpixel);
138
139     for (i = 0, f = 0;i < outheight;i++,f += fstep)
140     {
141       yi = f >> 16;
142       if (yi < endy)
143       {
144         lerp = f & 0xFFFF;
145         if (yi != oldy)
146         {
147           inrow = (byte *)indata + inwidth4 * yi;
148           if (yi == oldy+1)
149             memcpy(row1, row2, outwidth4);
150           else
151             R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel);
152
153           R_ResampleTextureLerpLine (inrow + inwidth4, row2, inwidth, outwidth, bytesperpixel);
154           oldy = yi;
155         }
156         j = outwidth - 4;
157         while(j >= 0)
158         {
159           LERPBYTE( 0);
160           LERPBYTE( 1);
161           LERPBYTE( 2);
162           LERPBYTE( 3);
163           LERPBYTE( 4);
164           LERPBYTE( 5);
165           LERPBYTE( 6);
166           LERPBYTE( 7);
167           LERPBYTE( 8);
168           LERPBYTE( 9);
169           LERPBYTE(10);
170           LERPBYTE(11);
171           LERPBYTE(12);
172           LERPBYTE(13);
173           LERPBYTE(14);
174           LERPBYTE(15);
175           out += 16;
176           row1 += 16;
177           row2 += 16;
178           j -= 4;
179         }
180         if (j & 2)
181         {
182           LERPBYTE( 0);
183           LERPBYTE( 1);
184           LERPBYTE( 2);
185           LERPBYTE( 3);
186           LERPBYTE( 4);
187           LERPBYTE( 5);
188           LERPBYTE( 6);
189           LERPBYTE( 7);
190           out += 8;
191           row1 += 8;
192           row2 += 8;
193         }
194         if (j & 1)
195         {
196           LERPBYTE( 0);
197           LERPBYTE( 1);
198           LERPBYTE( 2);
199           LERPBYTE( 3);
200           out += 4;
201           row1 += 4;
202           row2 += 4;
203         }
204         row1 -= outwidth4;
205         row2 -= outwidth4;
206       }
207       else
208       {
209         if (yi != oldy)
210         {
211           inrow = (byte *)indata + inwidth4*yi;
212           if (yi == oldy+1)
213             memcpy(row1, row2, outwidth4);
214           else
215             R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel);
216
217           oldy = yi;
218         }
219         memcpy(out, row1, outwidth4);
220       }
221     }
222   }
223   else if (bytesperpixel == 3)
224   {
225     int i, j, yi, oldy, f, fstep, lerp, endy = (inheight-1), inwidth3 = inwidth * 3, outwidth3 = outwidth * 3;
226     byte *inrow, *out;
227     out = (byte *)outdata;
228     fstep = (int) (inheight*65536.0f/outheight);
229 #define LERPBYTE(i) out[i] = (byte) ((((row2[i] - row1[i]) * lerp) >> 16) + row1[i])
230
231     inrow = (byte *)indata;
232     oldy = 0;
233     R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel);
234     R_ResampleTextureLerpLine (inrow + inwidth3, row2, inwidth, outwidth, bytesperpixel);
235     for (i = 0, f = 0;i < outheight;i++,f += fstep)
236     {
237       yi = f >> 16;
238       if (yi < endy)
239       {
240         lerp = f & 0xFFFF;
241         if (yi != oldy)
242         {
243           inrow = (byte *)indata + inwidth3*yi;
244           if (yi == oldy+1)
245             memcpy(row1, row2, outwidth3);
246           else
247             R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel);
248
249           R_ResampleTextureLerpLine (inrow + inwidth3, row2, inwidth, outwidth, bytesperpixel);
250           oldy = yi;
251         }
252         j = outwidth - 4;
253         while(j >= 0)
254         {
255           LERPBYTE( 0);
256           LERPBYTE( 1);
257           LERPBYTE( 2);
258           LERPBYTE( 3);
259           LERPBYTE( 4);
260           LERPBYTE( 5);
261           LERPBYTE( 6);
262           LERPBYTE( 7);
263           LERPBYTE( 8);
264           LERPBYTE( 9);
265           LERPBYTE(10);
266           LERPBYTE(11);
267           out += 12;
268           row1 += 12;
269           row2 += 12;
270           j -= 4;
271         }
272         if (j & 2)
273         {
274           LERPBYTE( 0);
275           LERPBYTE( 1);
276           LERPBYTE( 2);
277           LERPBYTE( 3);
278           LERPBYTE( 4);
279           LERPBYTE( 5);
280           out += 6;
281           row1 += 6;
282           row2 += 6;
283         }
284         if (j & 1)
285         {
286           LERPBYTE( 0);
287           LERPBYTE( 1);
288           LERPBYTE( 2);
289           out += 3;
290           row1 += 3;
291           row2 += 3;
292         }
293         row1 -= outwidth3;
294         row2 -= outwidth3;
295       }
296       else
297       {
298         if (yi != oldy)
299         {
300           inrow = (byte *)indata + inwidth3*yi;
301           if (yi == oldy+1)
302             memcpy(row1, row2, outwidth3);
303           else
304             R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel);
305
306           oldy = yi;
307         }
308         memcpy(out, row1, outwidth3);
309       }
310     }
311   }
312   else
313   {
314     globalOutputStream() << "R_ResampleTexture: unsupported bytesperpixel " << bytesperpixel << "\n";
315   }
316 }
317
318 // in can be the same as out
319 void GL_MipReduce(byte *in, byte *out, int width, int height, int destwidth, int destheight)
320 {
321   int x, y, width2, height2, nextrow;
322   if (width > destwidth)
323   {
324     if (height > destheight)
325     {
326       // reduce both
327       width2 = width >> 1;
328       height2 = height >> 1;
329       nextrow = width << 2;
330       for (y = 0;y < height2;y++)
331       {
332         for (x = 0;x < width2;x++)
333         {
334           out[0] = (byte) ((in[0] + in[4] + in[nextrow  ] + in[nextrow+4]) >> 2);
335           out[1] = (byte) ((in[1] + in[5] + in[nextrow+1] + in[nextrow+5]) >> 2);
336           out[2] = (byte) ((in[2] + in[6] + in[nextrow+2] + in[nextrow+6]) >> 2);
337           out[3] = (byte) ((in[3] + in[7] + in[nextrow+3] + in[nextrow+7]) >> 2);
338           out += 4;
339           in += 8;
340         }
341         in += nextrow; // skip a line
342       }
343     }
344     else
345     {
346       // reduce width
347       width2 = width >> 1;
348       for (y = 0;y < height;y++)
349       {
350         for (x = 0;x < width2;x++)
351         {
352           out[0] = (byte) ((in[0] + in[4]) >> 1);
353           out[1] = (byte) ((in[1] + in[5]) >> 1);
354           out[2] = (byte) ((in[2] + in[6]) >> 1);
355           out[3] = (byte) ((in[3] + in[7]) >> 1);
356           out += 4;
357           in += 8;
358         }
359       }
360     }
361   }
362   else
363   {
364     if (height > destheight)
365     {
366       // reduce height
367       height2 = height >> 1;
368       nextrow = width << 2;
369       for (y = 0;y < height2;y++)
370       {
371         for (x = 0;x < width;x++)
372         {
373           out[0] = (byte) ((in[0] + in[nextrow  ]) >> 1);
374           out[1] = (byte) ((in[1] + in[nextrow+1]) >> 1);
375           out[2] = (byte) ((in[2] + in[nextrow+2]) >> 1);
376           out[3] = (byte) ((in[3] + in[nextrow+3]) >> 1);
377           out += 4;
378           in += 4;
379         }
380         in += nextrow; // skip a line
381       }
382     }
383     else
384     {
385       globalOutputStream() << "GL_MipReduce: desired size already achieved\n";
386     }
387   }
388 }