1 /* 2 * Copyright (c) 2002-2008 LWJGL Project 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * * Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * * Neither the name of 'LWJGL' nor the names of 17 * its contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 package org.lwjgl.util.glu; 33 34 import java.nio.ByteBuffer; 35 36 import org.lwjgl.BufferUtils; 37 38 import static org.lwjgl.opengl.GL11.*; 39 import static org.lwjgl.util.glu.GLU.*; 40 41 /** 42 * MipMap.java 43 * 44 * 45 * Created 11-jan-2004 46 * @author Erik Duijs 47 */ 48 public class MipMap extends Util { 49 50 /** 51 * Method gluBuild2DMipmaps 52 * 53 * @param target 54 * @param components 55 * @param width 56 * @param height 57 * @param format 58 * @param type 59 * @param data 60 * @return int 61 */ gluBuild2DMipmaps(final int target, final int components, final int width, final int height, final int format, final int type, final ByteBuffer data)62 public static int gluBuild2DMipmaps(final int target, 63 final int components, final int width, final int height, 64 final int format, final int type, final ByteBuffer data) { 65 if ( width < 1 || height < 1 ) return GLU_INVALID_VALUE; 66 67 final int bpp = bytesPerPixel(format, type); 68 if ( bpp == 0 ) 69 return GLU_INVALID_ENUM; 70 71 final int maxSize = glGetIntegerv(GL_MAX_TEXTURE_SIZE); 72 73 int w = nearestPower(width); 74 if ( w > maxSize ) 75 w = maxSize; 76 77 int h = nearestPower(height); 78 if ( h > maxSize ) 79 h = maxSize; 80 81 // Get current glPixelStore state 82 PixelStoreState pss = new PixelStoreState(); 83 84 // set pixel packing 85 glPixelStorei(GL_PACK_ROW_LENGTH, 0); 86 glPixelStorei(GL_PACK_ALIGNMENT, 1); 87 glPixelStorei(GL_PACK_SKIP_ROWS, 0); 88 glPixelStorei(GL_PACK_SKIP_PIXELS, 0); 89 90 ByteBuffer image; 91 int retVal = 0; 92 boolean done = false; 93 94 if ( w != width || h != height ) { 95 // must rescale image to get "top" mipmap texture image 96 image = BufferUtils.createByteBuffer((w + 4) * h * bpp); 97 int error = gluScaleImage(format, width, height, type, data, w, h, type, image); 98 if ( error != 0 ) { 99 retVal = error; 100 done = true; 101 } 102 103 /* set pixel unpacking */ 104 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 105 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 106 glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); 107 glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); 108 } else { 109 image = data; 110 } 111 112 ByteBuffer bufferA = null; 113 ByteBuffer bufferB = null; 114 115 int level = 0; 116 while ( !done ) { 117 if (image != data) { 118 /* set pixel unpacking */ 119 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 120 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 121 glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); 122 glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); 123 } 124 125 glTexImage2D(target, level, components, w, h, 0, format, type, image); 126 127 if ( w == 1 && h == 1 ) 128 break; 129 130 final int newW = (w < 2) ? 1 : w >> 1; 131 final int newH = (h < 2) ? 1 : h >> 1; 132 133 final ByteBuffer newImage; 134 135 if ( bufferA == null ) 136 newImage = (bufferA = BufferUtils.createByteBuffer((newW + 4) * newH * bpp)); 137 else if ( bufferB == null ) 138 newImage = (bufferB = BufferUtils.createByteBuffer((newW + 4) * newH * bpp)); 139 else 140 newImage = bufferB; 141 142 int error = gluScaleImage(format, w, h, type, image, newW, newH, type, newImage); 143 if ( error != 0 ) { 144 retVal = error; 145 done = true; 146 } 147 148 image = newImage; 149 if ( bufferB != null ) 150 bufferB = bufferA; 151 152 w = newW; 153 h = newH; 154 level++; 155 } 156 157 // Restore original glPixelStore state 158 pss.save(); 159 160 return retVal; 161 } 162 163 /** 164 * Method gluScaleImage. 165 * @param format 166 * @param widthIn 167 * @param heightIn 168 * @param typein 169 * @param dataIn 170 * @param widthOut 171 * @param heightOut 172 * @param typeOut 173 * @param dataOut 174 * @return int 175 */ gluScaleImage(int format, int widthIn, int heightIn, int typein, ByteBuffer dataIn, int widthOut, int heightOut, int typeOut, ByteBuffer dataOut)176 public static int gluScaleImage(int format, 177 int widthIn, int heightIn, int typein, ByteBuffer dataIn, 178 int widthOut, int heightOut, int typeOut, ByteBuffer dataOut) { 179 180 final int components = compPerPix(format); 181 if ( components == -1 ) 182 return GLU_INVALID_ENUM; 183 184 int i, j, k; 185 float[] tempIn, tempOut; 186 float sx, sy; 187 int sizein, sizeout; 188 int rowstride, rowlen; 189 190 // temp image data 191 tempIn = new float[widthIn * heightIn * components]; 192 tempOut = new float[widthOut * heightOut * components]; 193 194 // Determine bytes per input type 195 switch ( typein ) { 196 case GL_UNSIGNED_BYTE: 197 sizein = 1; 198 break; 199 case GL_FLOAT: 200 sizein = 4; 201 break; 202 default: 203 return GL_INVALID_ENUM; 204 } 205 206 // Determine bytes per output type 207 switch ( typeOut ) { 208 case GL_UNSIGNED_BYTE: 209 sizeout = 1; 210 break; 211 case GL_FLOAT: 212 sizeout = 4; 213 break; 214 default: 215 return GL_INVALID_ENUM; 216 } 217 218 // Get glPixelStore state 219 PixelStoreState pss = new PixelStoreState(); 220 221 //Unpack the pixel data and convert to floating point 222 if ( pss.unpackRowLength > 0 ) 223 rowlen = pss.unpackRowLength; 224 else 225 rowlen = widthIn; 226 227 if ( sizein >= pss.unpackAlignment ) 228 rowstride = components * rowlen; 229 else 230 rowstride = pss.unpackAlignment / sizein * ceil(components * rowlen * sizein, pss.unpackAlignment); 231 232 switch ( typein ) { 233 case GL_UNSIGNED_BYTE: 234 k = 0; 235 dataIn.rewind(); 236 for ( i = 0; i < heightIn; i++ ) { 237 int ubptr = i * rowstride + pss.unpackSkipRows * rowstride + pss.unpackSkipPixels * components; 238 for ( j = 0; j < widthIn * components; j++ ) { 239 tempIn[k++] = dataIn.get(ubptr++) & 0xff; 240 } 241 } 242 break; 243 case GL_FLOAT: 244 k = 0; 245 dataIn.rewind(); 246 for ( i = 0; i < heightIn; i++ ) 247 { 248 int fptr = 4 * (i * rowstride + pss.unpackSkipRows * rowstride + pss.unpackSkipPixels * components); 249 for ( j = 0; j < widthIn * components; j++ ) 250 { 251 tempIn[k++] = dataIn.getFloat(fptr); 252 fptr += 4; 253 } 254 } 255 break; 256 default: 257 return GLU_INVALID_ENUM; 258 } 259 260 // Do scaling 261 sx = (float)widthIn / (float)widthOut; 262 sy = (float)heightIn / (float)heightOut; 263 264 float[] c = new float[components]; 265 int src, dst; 266 267 for ( int iy = 0; iy < heightOut; iy++ ) { 268 for ( int ix = 0; ix < widthOut; ix++ ) { 269 int x0 = (int)(ix * sx); 270 int x1 = (int)((ix + 1) * sx); 271 int y0 = (int)(iy * sy); 272 int y1 = (int)((iy + 1) * sy); 273 274 int readPix = 0; 275 276 // reset weighted pixel 277 for ( int ic = 0; ic < components; ic++ ) { 278 c[ic] = 0; 279 } 280 281 // create weighted pixel 282 for ( int ix0 = x0; ix0 < x1; ix0++ ) { 283 for ( int iy0 = y0; iy0 < y1; iy0++ ) { 284 285 src = (iy0 * widthIn + ix0) * components; 286 287 for ( int ic = 0; ic < components; ic++ ) { 288 c[ic] += tempIn[src + ic]; 289 } 290 291 readPix++; 292 } 293 } 294 295 // store weighted pixel 296 dst = (iy * widthOut + ix) * components; 297 298 if ( readPix == 0 ) { 299 // Image is sized up, caused by non power of two texture as input 300 src = (y0 * widthIn + x0) * components; 301 for ( int ic = 0; ic < components; ic++ ) { 302 tempOut[dst++] = tempIn[src + ic]; 303 } 304 } else { 305 // sized down 306 for ( k = 0; k < components; k++ ) { 307 tempOut[dst++] = c[k] / readPix; 308 } 309 } 310 } 311 } 312 313 314 // Convert temp output 315 if ( pss.packRowLength > 0 ) 316 rowlen = pss.packRowLength; 317 else 318 rowlen = widthOut; 319 320 if ( sizeout >= pss.packAlignment ) 321 rowstride = components * rowlen; 322 else 323 rowstride = pss.packAlignment / sizeout * ceil(components * rowlen * sizeout, pss.packAlignment); 324 325 switch ( typeOut ) { 326 case GL_UNSIGNED_BYTE: 327 k = 0; 328 for ( i = 0; i < heightOut; i++ ) { 329 int ubptr = i * rowstride + pss.packSkipRows * rowstride + pss.packSkipPixels * components; 330 331 for ( j = 0; j < widthOut * components; j++ ) { 332 dataOut.put(ubptr++, (byte)tempOut[k++]); 333 } 334 } 335 break; 336 case GL_FLOAT: 337 k = 0; 338 for ( i = 0; i < heightOut; i++ ) { 339 int fptr = 4 * (i * rowstride + pss.unpackSkipRows * rowstride + pss.unpackSkipPixels * components); 340 341 for ( j = 0; j < widthOut * components; j++ ) { 342 dataOut.putFloat(fptr, tempOut[k++]); 343 fptr += 4; 344 } 345 } 346 break; 347 default: 348 return GLU_INVALID_ENUM; 349 } 350 351 return 0; 352 } 353 } 354