1/*
2 * Copyright (c) 2009-2010 jMonkeyEngine
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 'jMonkeyEngine' nor the names of its contributors
17 *   may be used to endorse or promote products derived from this software
18 *   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
33package com.jme3.renderer.lwjgl;
34
35import com.jme3.renderer.RendererException;
36import com.jme3.texture.Image;
37import com.jme3.texture.Image.Format;
38import java.nio.ByteBuffer;
39import static org.lwjgl.opengl.ATITextureCompression3DC.GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI;
40import static org.lwjgl.opengl.EXTTextureCompressionLATC.GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT;
41import static org.lwjgl.opengl.EXTTextureCompressionLATC.GL_COMPRESSED_LUMINANCE_LATC1_EXT;
42import static org.lwjgl.opengl.EXTTextureCompressionS3TC.*;
43import static org.lwjgl.opengl.GL11.*;
44import static org.lwjgl.opengl.GL12.*;
45import static org.lwjgl.opengl.GL13.glCompressedTexImage2D;
46import static org.lwjgl.opengl.GL13.glCompressedTexImage3D;
47import static org.lwjgl.opengl.GL14.*;
48import org.lwjgl.opengl.*;
49
50public class TextureUtil {
51
52    private static boolean isFormatSupported(Format fmt, ContextCapabilities caps){
53        switch (fmt){
54            case ARGB4444:
55                return false;
56            case BGR8:
57                return caps.OpenGL12 || caps.GL_EXT_bgra;
58            case DXT1:
59            case DXT1A:
60            case DXT3:
61            case DXT5:
62                return caps.GL_EXT_texture_compression_s3tc;
63            case Depth:
64            case Depth16:
65            case Depth24:
66            case Depth32:
67                return caps.OpenGL14 || caps.GL_ARB_depth_texture;
68            case Depth32F:
69            case Luminance16F:
70            case Luminance16FAlpha16F:
71            case Luminance32F:
72            case RGBA16F:
73            case RGBA32F:
74                return caps.OpenGL30 || caps.GL_ARB_texture_float;
75            case LATC:
76            case LTC:
77                return caps.GL_EXT_texture_compression_latc;
78            case RGB9E5:
79            case RGB16F_to_RGB9E5:
80                return caps.OpenGL30 || caps.GL_EXT_texture_shared_exponent;
81            case RGB111110F:
82            case RGB16F_to_RGB111110F:
83                return caps.OpenGL30 || caps.GL_EXT_packed_float;
84            default:
85                return true;
86        }
87    }
88
89    public static void checkFormatSupported(Format fmt) {
90        if (!isFormatSupported(fmt, GLContext.getCapabilities())) {
91            throw new RendererException("Image format '" + fmt + "' is unsupported by the video hardware.");
92        }
93    }
94
95    public static int convertTextureFormat(Format fmt){
96        switch (fmt){
97            case Alpha16:
98                return GL_ALPHA16;
99            case Alpha8:
100                return GL_ALPHA8;
101            case DXT1:
102                return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
103            case DXT1A:
104                return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
105            case DXT3:
106                return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
107            case DXT5:
108                return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
109            case LATC:
110                return GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT;
111            case Depth:
112                return GL_DEPTH_COMPONENT;
113            case Depth16:
114                return GL_DEPTH_COMPONENT16;
115            case Depth24:
116                return GL_DEPTH_COMPONENT24;
117            case Depth32:
118                return GL_DEPTH_COMPONENT32;
119            case Depth32F:
120                return ARBDepthBufferFloat.GL_DEPTH_COMPONENT32F;
121            case Luminance8Alpha8:
122                return GL_LUMINANCE8_ALPHA8;
123            case Luminance16Alpha16:
124                return GL_LUMINANCE16_ALPHA16;
125            case Luminance16FAlpha16F:
126                return ARBTextureFloat.GL_LUMINANCE_ALPHA16F_ARB;
127            case Intensity8:
128                return GL_INTENSITY8;
129            case Intensity16:
130                return GL_INTENSITY16;
131            case Luminance8:
132                return GL_LUMINANCE8;
133            case Luminance16:
134                return GL_LUMINANCE16;
135            case Luminance16F:
136                return ARBTextureFloat.GL_LUMINANCE16F_ARB;
137             case Luminance32F:
138                return ARBTextureFloat.GL_LUMINANCE32F_ARB;
139            case RGB10:
140                return GL_RGB10;
141            case RGB16:
142                return GL_RGB16;
143            case RGB111110F:
144                return EXTPackedFloat.GL_R11F_G11F_B10F_EXT;
145            case RGB9E5:
146                return EXTTextureSharedExponent.GL_RGB9_E5_EXT;
147            case RGB16F:
148                return ARBTextureFloat.GL_RGB16F_ARB;
149            case RGBA16F:
150                return ARBTextureFloat.GL_RGBA16F_ARB;
151            case RGB32F:
152                return ARBTextureFloat.GL_RGB32F_ARB;
153            case RGB5A1:
154                return GL_RGB5_A1;
155            case BGR8:
156                return GL_RGB8;
157            case RGB8:
158                return GL_RGB8;
159            case RGBA16:
160                return GL_RGBA16;
161            case RGBA8:
162                return GL_RGBA8;
163            default:
164                throw new UnsupportedOperationException("Unrecognized format: "+fmt);
165        }
166    }
167
168    public static void uploadTexture(Image img,
169                                     int target,
170                                     int index,
171                                     int border,
172                                     boolean tdc){
173        Image.Format fmt = img.getFormat();
174
175        checkFormatSupported(fmt);
176
177        ByteBuffer data;
178        if (index >= 0 && img.getData() != null && img.getData().size() > 0){
179            data = img.getData(index);
180        }else{
181            data = null;
182        }
183
184        int width = img.getWidth();
185        int height = img.getHeight();
186        int depth = img.getDepth();
187
188        boolean compress = false;
189        int internalFormat = -1;
190        int format = -1;
191        int dataType = -1;
192
193        switch (fmt){
194            case Alpha16:
195                internalFormat = GL_ALPHA16;
196                format = GL_ALPHA;
197                dataType = GL_UNSIGNED_BYTE;
198                break;
199            case Alpha8:
200                internalFormat = GL_ALPHA8;
201                format = GL_ALPHA;
202                dataType = GL_UNSIGNED_BYTE;
203                break;
204            case DXT1:
205                compress = true;
206                internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
207                format = GL_RGB;
208                dataType = GL_UNSIGNED_BYTE;
209                break;
210            case DXT1A:
211                compress = true;
212                internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
213                format = GL_RGBA;
214                dataType = GL_UNSIGNED_BYTE;
215                break;
216            case DXT3:
217                compress = true;
218                internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
219                format = GL_RGBA;
220                dataType = GL_UNSIGNED_BYTE;
221                break;
222            case DXT5:
223                compress = true;
224                internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
225                format = GL_RGBA;
226                dataType = GL_UNSIGNED_BYTE;
227                break;
228            case LATC:
229                compress = true;
230                if (tdc){
231                    internalFormat = GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI;
232                }else{
233                    internalFormat = GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT;
234                }
235                format = GL_LUMINANCE_ALPHA;
236                dataType = GL_UNSIGNED_BYTE;
237                break;
238            case LTC:
239                compress = true;
240                internalFormat = GL_COMPRESSED_LUMINANCE_LATC1_EXT;
241                format = GL_LUMINANCE_ALPHA;
242                dataType = GL_UNSIGNED_BYTE;
243                break;
244            case Depth:
245                internalFormat = GL_DEPTH_COMPONENT;
246                format = GL_DEPTH_COMPONENT;
247                dataType = GL_UNSIGNED_BYTE;
248                break;
249            case Depth16:
250                internalFormat = GL_DEPTH_COMPONENT16;
251                format = GL_DEPTH_COMPONENT;
252                dataType = GL_UNSIGNED_BYTE;
253                break;
254            case Depth24:
255                internalFormat = GL_DEPTH_COMPONENT24;
256                format = GL_DEPTH_COMPONENT;
257                dataType = GL_UNSIGNED_BYTE;
258                break;
259            case Depth32:
260                internalFormat = GL_DEPTH_COMPONENT32;
261                format = GL_DEPTH_COMPONENT;
262                dataType = GL_UNSIGNED_BYTE;
263                break;
264            case Depth32F:
265                internalFormat = NVDepthBufferFloat.GL_DEPTH_COMPONENT32F_NV;
266                format = GL_DEPTH_COMPONENT;
267                dataType = GL_FLOAT;
268                break;
269            case Luminance16FAlpha16F:
270                internalFormat = ARBTextureFloat.GL_LUMINANCE_ALPHA16F_ARB;
271                format = GL_LUMINANCE_ALPHA;
272                dataType = GL_UNSIGNED_BYTE;
273                break;
274            case Intensity8:
275                internalFormat = GL_INTENSITY8;
276                format = GL_INTENSITY;
277                dataType = GL_UNSIGNED_BYTE;
278                break;
279            case Intensity16:
280                internalFormat = GL_INTENSITY16;
281                format = GL_INTENSITY;
282                dataType = GL_UNSIGNED_BYTE;
283                break;
284            case Luminance8:
285                internalFormat = GL_LUMINANCE8;
286                format = GL_LUMINANCE;
287                dataType = GL_UNSIGNED_BYTE;
288                break;
289            case Luminance8Alpha8:
290                internalFormat = GL_LUMINANCE8_ALPHA8;
291                format = GL_LUMINANCE_ALPHA;
292                dataType = GL_UNSIGNED_BYTE;
293                break;
294            case Luminance16Alpha16:
295                internalFormat = GL_LUMINANCE16_ALPHA16;
296                format = GL_LUMINANCE_ALPHA;
297                dataType = GL_UNSIGNED_BYTE;
298                break;
299            case Luminance16:
300                internalFormat = GL_LUMINANCE16;
301                format = GL_LUMINANCE;
302                dataType = GL_UNSIGNED_BYTE;
303                break;
304            case Luminance16F:
305                internalFormat = ARBTextureFloat.GL_LUMINANCE16F_ARB;
306                format = GL_LUMINANCE;
307                dataType = ARBHalfFloatPixel.GL_HALF_FLOAT_ARB;
308                break;
309            case Luminance32F:
310                internalFormat = ARBTextureFloat.GL_LUMINANCE32F_ARB;
311                format = GL_LUMINANCE;
312                dataType = GL_FLOAT;
313                break;
314            case RGB10:
315                internalFormat = GL_RGB10;
316                format = GL_RGB;
317                dataType = GL_UNSIGNED_BYTE;
318                break;
319            case RGB16:
320                internalFormat = GL_RGB16;
321                format = GL_RGB;
322                dataType = GL_UNSIGNED_BYTE;
323                break;
324            case RGB111110F:
325                internalFormat = EXTPackedFloat.GL_R11F_G11F_B10F_EXT;
326                format = GL_RGB;
327                dataType = EXTPackedFloat.GL_UNSIGNED_INT_10F_11F_11F_REV_EXT;
328                break;
329            case RGB16F_to_RGB111110F:
330                internalFormat = EXTPackedFloat.GL_R11F_G11F_B10F_EXT;
331                format = GL_RGB;
332                dataType = ARBHalfFloatPixel.GL_HALF_FLOAT_ARB;
333                break;
334            case RGB16F_to_RGB9E5:
335                internalFormat = EXTTextureSharedExponent.GL_RGB9_E5_EXT;
336                format = GL_RGB;
337                dataType = ARBHalfFloatPixel.GL_HALF_FLOAT_ARB;
338                break;
339            case RGB9E5:
340                internalFormat = EXTTextureSharedExponent.GL_RGB9_E5_EXT;
341                format = GL_RGB;
342                dataType = EXTTextureSharedExponent.GL_UNSIGNED_INT_5_9_9_9_REV_EXT;
343                break;
344            case RGB16F:
345                internalFormat = ARBTextureFloat.GL_RGB16F_ARB;
346                format = GL_RGB;
347                dataType = ARBHalfFloatPixel.GL_HALF_FLOAT_ARB;
348                break;
349            case RGBA16F:
350                internalFormat = ARBTextureFloat.GL_RGBA16F_ARB;
351                format = GL_RGBA;
352                dataType = ARBHalfFloatPixel.GL_HALF_FLOAT_ARB;
353                break;
354            case RGB32F:
355                internalFormat = ARBTextureFloat.GL_RGB32F_ARB;
356                format = GL_RGB;
357                dataType = GL_FLOAT;
358                break;
359            case RGBA32F:
360                internalFormat = ARBTextureFloat.GL_RGBA32F_ARB;
361                format = GL_RGBA;
362                dataType = GL_FLOAT;
363                break;
364            case RGB5A1:
365                internalFormat = GL_RGB5_A1;
366                format = GL_RGBA;
367                dataType = GL_UNSIGNED_BYTE;
368                break;
369            case RGB8:
370                internalFormat = GL_RGB8;
371                format = GL_RGB;
372                dataType = GL_UNSIGNED_BYTE;
373                break;
374            case BGR8:
375                internalFormat = GL_RGB8;
376                format = GL_BGR;
377                dataType = GL_UNSIGNED_BYTE;
378                break;
379            case RGBA16:
380                internalFormat = GL_RGBA16;
381                format = GL_RGBA;
382                dataType = GL_UNSIGNED_BYTE;
383                break;
384            case RGBA8:
385                internalFormat = GL_RGBA8;
386                format = GL_RGBA;
387                dataType = GL_UNSIGNED_BYTE;
388                break;
389            case ABGR8:
390                internalFormat = GL_RGBA8;
391                format = EXTAbgr.GL_ABGR_EXT;
392                dataType = GL_UNSIGNED_BYTE;
393                break;
394            default:
395                throw new UnsupportedOperationException("Unrecognized format: "+fmt);
396        }
397
398        if (data != null)
399            glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
400
401        int[] mipSizes = img.getMipMapSizes();
402        int pos = 0;
403        // TODO: Remove unneccessary allocation
404        if (mipSizes == null){
405            if (data != null)
406                mipSizes = new int[]{ data.capacity() };
407            else
408                mipSizes = new int[]{ width * height * fmt.getBitsPerPixel() / 8 };
409        }
410
411        boolean subtex = false;
412        int samples = img.getMultiSamples();
413
414        for (int i = 0; i < mipSizes.length; i++){
415            int mipWidth =  Math.max(1, width  >> i);
416            int mipHeight = Math.max(1, height >> i);
417            int mipDepth =  Math.max(1, depth  >> i);
418
419            if (data != null){
420                data.position(pos);
421                data.limit(pos + mipSizes[i]);
422            }
423
424            if (compress && data != null){
425                if (target == GL_TEXTURE_3D){
426                    glCompressedTexImage3D(target,
427                                           i,
428                                           internalFormat,
429                                           mipWidth,
430                                           mipHeight,
431                                           mipDepth,
432                                           border,
433                                           data);
434                }else{
435                    //all other targets use 2D: array, cubemap, 2d
436                    glCompressedTexImage2D(target,
437                                           i,
438                                           internalFormat,
439                                           mipWidth,
440                                           mipHeight,
441                                           border,
442                                           data);
443                }
444            }else{
445                if (target == GL_TEXTURE_3D){
446                    glTexImage3D(target,
447                                 i,
448                                 internalFormat,
449                                 mipWidth,
450                                 mipHeight,
451                                 mipDepth,
452                                 border,
453                                 format,
454                                 dataType,
455                                 data);
456                }else if (target == EXTTextureArray.GL_TEXTURE_2D_ARRAY_EXT){
457                    // prepare data for 2D array
458                    // or upload slice
459                    if (index == -1){
460                        glTexImage3D(target,
461                                     0,
462                                     internalFormat,
463                                     mipWidth,
464                                     mipHeight,
465                                     img.getData().size(), //# of slices
466                                     border,
467                                     format,
468                                     dataType,
469                                     data);
470                    }else{
471                        glTexSubImage3D(target,
472                                        i, // level
473                                        0, // xoffset
474                                        0, // yoffset
475                                        index, // zoffset
476                                        width, // width
477                                        height, // height
478                                        1, // depth
479                                        format,
480                                        dataType,
481                                        data);
482                    }
483                }else{
484                    if (subtex){
485                        if (samples > 1)
486                            throw new IllegalStateException("Cannot update multisample textures");
487
488                        glTexSubImage2D(target,
489                                        i,
490                                        0, 0,
491                                        mipWidth, mipHeight,
492                                        format,
493                                        dataType,
494                                        data);
495                    }else{
496                        if (samples > 1){
497                            ARBTextureMultisample.glTexImage2DMultisample(target,
498                                                                          samples,
499                                                                          internalFormat,
500                                                                          mipWidth,
501                                                                          mipHeight,
502                                                                          true);
503                        }else{
504                            glTexImage2D(target,
505                                         i,
506                                         internalFormat,
507                                         mipWidth,
508                                         mipHeight,
509                                         border,
510                                         format,
511                                         dataType,
512                                         data);
513                        }
514                    }
515                }
516            }
517
518            pos += mipSizes[i];
519        }
520    }
521
522}
523