apply misc fixes from Markus Fischer and Rambetter
[xonotic/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 "stdafx.h"
33 #include "str.h"
34
35 static byte *row1 = NULL, *row2 = NULL;
36 static int rowsize = 0;
37
38 void R_ResampleTextureLerpLine (byte *in, byte *out, int inwidth, int outwidth, int bytesperpixel)
39 {
40   int   j, xi, oldx = 0, f, fstep, endx, lerp;
41 #define LERPBYTE(i) out[i] = (byte) ((((row2[i] - row1[i]) * lerp) >> 16) + row1[i])
42
43   fstep = (int) (inwidth * 65536.0f / outwidth);
44   endx = (inwidth - 1);
45   if (bytesperpixel == 4)
46   {
47     for (j = 0,f = 0;j < outwidth;j++, f += fstep)
48     {
49       xi = f >> 16;
50       if (xi != oldx)
51       {
52         in += (xi - oldx) * 4;
53         oldx = xi;
54       }
55
56       if (xi < endx)
57       {
58         lerp = f & 0xFFFF;
59         *out++ = (byte) ((((in[4] - in[0]) * lerp) >> 16) + in[0]);
60         *out++ = (byte) ((((in[5] - in[1]) * lerp) >> 16) + in[1]);
61         *out++ = (byte) ((((in[6] - in[2]) * lerp) >> 16) + in[2]);
62         *out++ = (byte) ((((in[7] - in[3]) * lerp) >> 16) + in[3]);
63       }
64       else // last pixel of the line has no pixel to lerp to
65       {
66         *out++ = in[0];
67         *out++ = in[1];
68         *out++ = in[2];
69         *out++ = in[3];
70       }
71     }
72   }
73   else if (bytesperpixel == 3)
74   {
75     for (j = 0, f = 0; j < outwidth; j++, f += fstep)
76     {
77       xi = f >> 16;
78       if (xi != oldx)
79       {
80         in += (xi - oldx) * 3;
81         oldx = xi;
82       }
83
84       if (xi < endx)
85       {
86         lerp = f & 0xFFFF;
87         *out++ = (byte) ((((in[3] - in[0]) * lerp) >> 16) + in[0]);
88         *out++ = (byte) ((((in[4] - in[1]) * lerp) >> 16) + in[1]);
89         *out++ = (byte) ((((in[5] - in[2]) * lerp) >> 16) + in[2]);
90       }
91       else // last pixel of the line has no pixel to lerp to
92       {
93         *out++ = in[0];
94         *out++ = in[1];
95         *out++ = in[2];
96       }
97     }
98   }
99   else
100     Sys_Printf("R_ResampleTextureLerpLine: unsupported bytesperpixel %i\n", bytesperpixel);
101 }
102
103 /*
104 ================
105 R_ResampleTexture
106 ================
107 */
108 void R_ResampleTexture (void *indata, int inwidth, int inheight, void *outdata,  int outwidth, int outheight, int bytesperpixel)
109 {
110   if (rowsize < outwidth * bytesperpixel)
111   {
112     if (row1)
113       free(row1);
114     if (row2)
115       free(row2);
116
117     rowsize = outwidth * bytesperpixel;
118     row1 = (byte *)malloc(rowsize);
119     row2 = (byte *)malloc(rowsize);
120   }
121
122   if (bytesperpixel == 4)
123   {
124     int         i, j, yi, oldy, f, fstep, lerp, endy = (inheight-1), inwidth4 = inwidth*4, outwidth4 = outwidth*4;
125     byte        *inrow, *out;
126     out = (byte *)outdata;
127     fstep = (int) (inheight * 65536.0f / outheight);
128 #define LERPBYTE(i) out[i] = (byte) ((((row2[i] - row1[i]) * lerp) >> 16) + row1[i])
129
130     inrow = (byte *)indata;
131     oldy = 0;
132     R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel);
133     R_ResampleTextureLerpLine (inrow + inwidth4, row2, inwidth, outwidth, bytesperpixel);
134
135     for (i = 0, f = 0;i < outheight;i++,f += fstep)
136     {
137       yi = f >> 16;
138       if (yi < endy)
139       {
140         lerp = f & 0xFFFF;
141         if (yi != oldy)
142         {
143           inrow = (byte *)indata + inwidth4 * yi;
144           if (yi == oldy+1)
145             memcpy(row1, row2, outwidth4);
146           else
147             R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel);
148
149           R_ResampleTextureLerpLine (inrow + inwidth4, row2, inwidth, outwidth, bytesperpixel);
150           oldy = yi;
151         }
152         j = outwidth - 4;
153         while(j >= 0)
154         {
155           LERPBYTE( 0);
156           LERPBYTE( 1);
157           LERPBYTE( 2);
158           LERPBYTE( 3);
159           LERPBYTE( 4);
160           LERPBYTE( 5);
161           LERPBYTE( 6);
162           LERPBYTE( 7);
163           LERPBYTE( 8);
164           LERPBYTE( 9);
165           LERPBYTE(10);
166           LERPBYTE(11);
167           LERPBYTE(12);
168           LERPBYTE(13);
169           LERPBYTE(14);
170           LERPBYTE(15);
171           out += 16;
172           row1 += 16;
173           row2 += 16;
174           j -= 4;
175         }
176         if (j & 2)
177         {
178           LERPBYTE( 0);
179           LERPBYTE( 1);
180           LERPBYTE( 2);
181           LERPBYTE( 3);
182           LERPBYTE( 4);
183           LERPBYTE( 5);
184           LERPBYTE( 6);
185           LERPBYTE( 7);
186           out += 8;
187           row1 += 8;
188           row2 += 8;
189         }
190         if (j & 1)
191         {
192           LERPBYTE( 0);
193           LERPBYTE( 1);
194           LERPBYTE( 2);
195           LERPBYTE( 3);
196           out += 4;
197           row1 += 4;
198           row2 += 4;
199         }
200         row1 -= outwidth4;
201         row2 -= outwidth4;
202       }
203       else
204       {
205         if (yi != oldy)
206         {
207           inrow = (byte *)indata + inwidth4*yi;
208           if (yi == oldy+1)
209             memcpy(row1, row2, outwidth4);
210           else
211             R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel);
212
213           oldy = yi;
214         }
215         memcpy(out, row1, outwidth4);
216       }
217     }
218   }
219   else if (bytesperpixel == 3)
220   {
221     int         i, j, yi, oldy, f, fstep, lerp, endy = (inheight-1), inwidth3 = inwidth * 3, outwidth3 = outwidth * 3;
222     byte        *inrow, *out;
223     out = (byte *)outdata;
224     fstep = (int) (inheight*65536.0f/outheight);
225 #define LERPBYTE(i) out[i] = (byte) ((((row2[i] - row1[i]) * lerp) >> 16) + row1[i])
226
227     inrow = (byte *)indata;
228     oldy = 0;
229     R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel);
230     R_ResampleTextureLerpLine (inrow + inwidth3, row2, inwidth, outwidth, bytesperpixel);
231     for (i = 0, f = 0;i < outheight;i++,f += fstep)
232     {
233       yi = f >> 16;
234       if (yi < endy)
235       {
236         lerp = f & 0xFFFF;
237         if (yi != oldy)
238         {
239           inrow = (byte *)indata + inwidth3*yi;
240           if (yi == oldy+1)
241             memcpy(row1, row2, outwidth3);
242           else
243             R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel);
244
245           R_ResampleTextureLerpLine (inrow + inwidth3, row2, inwidth, outwidth, bytesperpixel);
246           oldy = yi;
247         }
248         j = outwidth - 4;
249         while(j >= 0)
250         {
251           LERPBYTE( 0);
252           LERPBYTE( 1);
253           LERPBYTE( 2);
254           LERPBYTE( 3);
255           LERPBYTE( 4);
256           LERPBYTE( 5);
257           LERPBYTE( 6);
258           LERPBYTE( 7);
259           LERPBYTE( 8);
260           LERPBYTE( 9);
261           LERPBYTE(10);
262           LERPBYTE(11);
263           out += 12;
264           row1 += 12;
265           row2 += 12;
266           j -= 4;
267         }
268         if (j & 2)
269         {
270           LERPBYTE( 0);
271           LERPBYTE( 1);
272           LERPBYTE( 2);
273           LERPBYTE( 3);
274           LERPBYTE( 4);
275           LERPBYTE( 5);
276           out += 6;
277           row1 += 6;
278           row2 += 6;
279         }
280         if (j & 1)
281         {
282           LERPBYTE( 0);
283           LERPBYTE( 1);
284           LERPBYTE( 2);
285           out += 3;
286           row1 += 3;
287           row2 += 3;
288         }
289         row1 -= outwidth3;
290         row2 -= outwidth3;
291       }
292       else
293       {
294         if (yi != oldy)
295         {
296           inrow = (byte *)indata + inwidth3*yi;
297           if (yi == oldy+1)
298             memcpy(row1, row2, outwidth3);
299           else
300             R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel);
301
302           oldy = yi;
303         }
304         memcpy(out, row1, outwidth3);
305       }
306     }
307   }
308   else
309     Sys_Printf("R_ResampleTexture: unsupported bytesperpixel %i\n", bytesperpixel);
310 }
311
312 // in can be the same as out
313 void GL_MipReduce(byte *in, byte *out, int width, int height, int destwidth, int destheight)
314 {
315   int x, y, width2, height2, nextrow;
316   if (width > destwidth)
317   {
318     if (height > destheight)
319     {
320       // reduce both
321       width2 = width >> 1;
322       height2 = height >> 1;
323       nextrow = width << 2;
324       for (y = 0;y < height2;y++)
325       {
326         for (x = 0;x < width2;x++)
327         {
328           out[0] = (byte) ((in[0] + in[4] + in[nextrow  ] + in[nextrow+4]) >> 2);
329           out[1] = (byte) ((in[1] + in[5] + in[nextrow+1] + in[nextrow+5]) >> 2);
330           out[2] = (byte) ((in[2] + in[6] + in[nextrow+2] + in[nextrow+6]) >> 2);
331           out[3] = (byte) ((in[3] + in[7] + in[nextrow+3] + in[nextrow+7]) >> 2);
332           out += 4;
333           in += 8;
334         }
335         in += nextrow; // skip a line
336       }
337     }
338     else
339     {
340       // reduce width
341       width2 = width >> 1;
342       for (y = 0;y < height;y++)
343       {
344         for (x = 0;x < width2;x++)
345         {
346           out[0] = (byte) ((in[0] + in[4]) >> 1);
347           out[1] = (byte) ((in[1] + in[5]) >> 1);
348           out[2] = (byte) ((in[2] + in[6]) >> 1);
349           out[3] = (byte) ((in[3] + in[7]) >> 1);
350           out += 4;
351           in += 8;
352         }
353       }
354     }
355   }
356   else
357   {
358     if (height > destheight)
359     {
360       // reduce height
361       height2 = height >> 1;
362       nextrow = width << 2;
363       for (y = 0;y < height2;y++)
364       {
365         for (x = 0;x < width;x++)
366         {
367           out[0] = (byte) ((in[0] + in[nextrow  ]) >> 1);
368           out[1] = (byte) ((in[1] + in[nextrow+1]) >> 1);
369           out[2] = (byte) ((in[2] + in[nextrow+2]) >> 1);
370           out[3] = (byte) ((in[3] + in[nextrow+3]) >> 1);
371           out += 4;
372           in += 4;
373         }
374         in += nextrow; // skip a line
375       }
376     }
377     else
378       Sys_Printf("GL_MipReduce: desired size already achieved\n");
379   }
380 }