[dali_1.3.4] Merge branch 'devel/master'
[platform/core/uifw/dali-demo.git] / examples / rendering-basic-pbr / ktx-loader.cpp
1 /*
2  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // FILE HEADER
19 #include "ktx-loader.h"
20
21 // EXTERNAL INCLUDES
22 #include <memory.h>
23 #include <stdio.h>
24 #include <stdint.h>
25
26 namespace PbrDemo
27 {
28
29 struct KtxFileHeader
30 {
31   char   identifier[12];
32   uint32_t  endianness;
33   uint32_t  glType;    //(UNSIGNED_BYTE, UNSIGNED_SHORT_5_6_5, etc.)
34   uint32_t  glTypeSize;
35   uint32_t  glFormat;  //(RGB, RGBA, BGRA, etc.)
36   uint32_t  glInternalFormat; //For uncompressed textures, specifies the internalformat parameter passed to glTexStorage*D or glTexImage*D
37   uint32_t  glBaseInternalFormat;
38   uint32_t  pixelWidth;
39   uint32_t  pixelHeight;
40   uint32_t  pixelDepth;
41   uint32_t  numberOfArrayElements;
42   uint32_t  numberOfFaces; //Cube map faces are stored in the order: +X, -X, +Y, -Y, +Z, -Z.
43   uint32_t  numberOfMipmapLevels;
44   uint32_t  bytesOfKeyValueData;
45 };
46
47 /**
48  * Convert KTX format to Dali::Pixel::Format
49  */
50 bool ConvertPixelFormat(const uint32_t ktxPixelFormat, Dali::Pixel::Format& format)
51 {
52   switch( ktxPixelFormat )
53   {
54     case 0x93B0: // GL_COMPRESSED_RGBA_ASTC_4x4_KHR
55     {
56       format = Dali::Pixel::COMPRESSED_RGBA_ASTC_4x4_KHR;
57       break;
58     }
59     case 0x881B:// GL_RGB16F
60     {
61       format = Dali::Pixel::RGB16F;
62       break;
63     }
64     case 0x8815: // GL_RGB32F
65     {
66       format = Dali::Pixel::RGB32F;
67       break;
68     }
69     case 0x8C3A: // GL_R11F_G11F_B10F
70     {
71       format = Dali::Pixel::RGB32F;
72       break;
73     }
74     case 0x8D7C: // GL_RGBA8UI
75     {
76       format = Dali::Pixel::RGBA8888;
77       break;
78     }
79     case 0x8D7D: // GL_RGB8UI
80     {
81       format = Dali::Pixel::RGB888;
82       break;
83     }
84     default:
85     {
86       return false;
87     }
88   }
89
90   return true;
91 }
92
93 bool LoadCubeMapFromKtxFile( const std::string& path, CubeData& cubedata )
94 {
95   FILE* fp = fopen(path.c_str(),"rb");
96
97   if( NULL == fp )
98   {
99     return false;
100   }
101
102   KtxFileHeader header;
103
104   int result = fread(&header,1,sizeof(KtxFileHeader),fp);
105   if( 0 == result )
106   {
107     fclose( fp );
108     return false;
109   }
110
111   long lSize = 0;
112
113   // Skip the key-values:
114   const long int imageSizeOffset = sizeof(KtxFileHeader) + header.bytesOfKeyValueData;
115
116   if( fseek(fp, imageSizeOffset, SEEK_END) )
117   {
118     fclose( fp );
119     return false;
120   }
121
122   lSize = ftell(fp);
123   if( lSize == -1L )
124   {
125     fclose( fp );
126     return false;
127   }
128
129   rewind(fp);
130
131   if( fseek(fp, imageSizeOffset, SEEK_SET) )
132   {
133     fclose( fp );
134     return false;
135   }
136
137   cubedata.img.resize(header.numberOfFaces);
138
139   for(unsigned int face=0; face < header.numberOfFaces; ++face) //array_element must be 0 or 1
140   {
141     cubedata.img[face].resize(header.numberOfMipmapLevels);
142   }
143
144   unsigned char* buffer= reinterpret_cast<unsigned char*>( malloc( lSize ) );
145
146   unsigned char* img[6];
147   unsigned int imgSize[6];
148   unsigned char* imgPointer = buffer;
149   result = fread(buffer,1,lSize,fp);
150
151   fclose(fp);
152
153   if( 0 == result )
154   {
155     free( buffer );
156     return false;
157   }
158
159   if( 0 == header.numberOfMipmapLevels )
160   {
161     header.numberOfMipmapLevels = 1u;
162   }
163
164   if( 0 == header.numberOfArrayElements )
165   {
166     header.numberOfArrayElements = 1u;
167   }
168
169   if( 0 == header.pixelDepth )
170   {
171     header.pixelDepth = 1u;
172   }
173
174   if( 0 == header.pixelHeight )
175   {
176     header.pixelHeight = 1u;
177   }
178
179   Dali::Pixel::Format daliformat = Pixel::RGB888;
180
181   ConvertPixelFormat(header.glInternalFormat, daliformat);
182
183   for( unsigned int mipmapLevel = 0; mipmapLevel < header.numberOfMipmapLevels; ++mipmapLevel )
184   {
185     long int byteSize = 0;
186     int imageSize;
187     memcpy(&imageSize,imgPointer,sizeof(unsigned int));
188     imgPointer += 4u;
189     for(unsigned int arrayElement=0; arrayElement < header.numberOfArrayElements; ++arrayElement) //arrayElement must be 0 or 1
190     {
191       for(unsigned int face=0; face < header.numberOfFaces; ++face)
192       {
193         byteSize = imageSize;
194         if(byteSize % 4u)
195         {
196           byteSize += 4u - byteSize % 4u;
197         }
198         img[face] = reinterpret_cast<unsigned char*>( malloc( byteSize ) ); // resources will be freed when the PixelData is destroyed.
199         memcpy(img[face],imgPointer,byteSize);
200         imgSize[face] = byteSize;
201         imgPointer += byteSize;
202         cubedata.img[face][mipmapLevel] = PixelData::New( img[face], imgSize[face], header.pixelWidth , header.pixelHeight , daliformat, PixelData::FREE );
203       }
204     }
205     header.pixelHeight/=2u;
206     header.pixelWidth/=2u;
207   }
208
209   free(buffer);
210   return true;
211 }
212
213 } // namespace PbrDemo