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