627d74bff7505b9032d987d282cee5940644a667
[platform/core/uifw/dali-demo.git] / examples / rendering-basic-pbr / ktx-loader.cpp
1 /*
2  * Copyright (c) 2019 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 #include <dali/integration-api/debug.h>
26 #include <dali/devel-api/adaptor-framework/file-loader.h>
27
28 namespace PbrDemo
29 {
30
31 struct KtxFileHeader
32 {
33   char   identifier[12];
34   uint32_t  endianness;
35   uint32_t  glType;    //(UNSIGNED_BYTE, UNSIGNED_SHORT_5_6_5, etc.)
36   uint32_t  glTypeSize;
37   uint32_t  glFormat;  //(RGB, RGBA, BGRA, etc.)
38   uint32_t  glInternalFormat; //For uncompressed textures, specifies the internalformat parameter passed to glTexStorage*D or glTexImage*D
39   uint32_t  glBaseInternalFormat;
40   uint32_t  pixelWidth;
41   uint32_t  pixelHeight;
42   uint32_t  pixelDepth;
43   uint32_t  numberOfArrayElements;
44   uint32_t  numberOfFaces; //Cube map faces are stored in the order: +X, -X, +Y, -Y, +Z, -Z.
45   uint32_t  numberOfMipmapLevels;
46   uint32_t  bytesOfKeyValueData;
47 };
48
49 /**
50  * Convert KTX format to Dali::Pixel::Format
51  */
52 bool ConvertPixelFormat(const uint32_t ktxPixelFormat, Dali::Pixel::Format& format)
53 {
54   switch( ktxPixelFormat )
55   {
56     case 0x93B0: // GL_COMPRESSED_RGBA_ASTC_4x4_KHR
57     {
58       format = Dali::Pixel::COMPRESSED_RGBA_ASTC_4x4_KHR;
59       break;
60     }
61     case 0x881B:// GL_RGB16F
62     {
63       format = Dali::Pixel::RGB16F;
64       break;
65     }
66     case 0x8815: // GL_RGB32F
67     {
68       format = Dali::Pixel::RGB32F;
69       break;
70     }
71     case 0x8C3A: // GL_R11F_G11F_B10F
72     {
73       format = Dali::Pixel::RGB32F;
74       break;
75     }
76     case 0x8D7C: // GL_RGBA8UI
77     {
78       format = Dali::Pixel::RGBA8888;
79       break;
80     }
81     case 0x8D7D: // GL_RGB8UI
82     {
83       format = Dali::Pixel::RGB888;
84       break;
85     }
86     default:
87     {
88       return false;
89     }
90   }
91
92   return true;
93 }
94
95 bool LoadCubeMapFromKtxFile( const std::string& path, CubeData& cubedata )
96 {
97   std::streampos bufferSize = 0;
98   Dali::Vector<char> fileBuffer;
99   if( !Dali::FileLoader::ReadFile( path, bufferSize, fileBuffer, FileLoader::FileType::BINARY ) )
100   {
101     return false;
102   }
103
104   FILE* fp = fmemopen( &fileBuffer[0], bufferSize, "rb" );
105   if( NULL == fp )
106   {
107     return false;
108   }
109
110   KtxFileHeader header;
111
112   int result = fread(&header,1,sizeof(KtxFileHeader),fp);
113   if( 0 == result )
114   {
115     fclose( fp );
116     return false;
117   }
118
119   long lSize = 0;
120
121   // Skip the key-values:
122   const long int imageSizeOffset = sizeof(KtxFileHeader) + header.bytesOfKeyValueData;
123
124   if( fseek(fp, imageSizeOffset, SEEK_END) )
125   {
126     fclose( fp );
127     return false;
128   }
129
130   lSize = ftell(fp);
131   if( lSize == -1L )
132   {
133     fclose( fp );
134     return false;
135   }
136
137   rewind(fp);
138
139   if( fseek(fp, imageSizeOffset, SEEK_SET) )
140   {
141     fclose( fp );
142     return false;
143   }
144
145   cubedata.img.resize(header.numberOfFaces);
146
147   for(unsigned int face=0; face < header.numberOfFaces; ++face) //array_element must be 0 or 1
148   {
149     cubedata.img[face].resize(header.numberOfMipmapLevels);
150   }
151
152   unsigned char* buffer= reinterpret_cast<unsigned char*>( malloc( lSize ) );
153
154   unsigned char* img[6];
155   unsigned int imgSize[6];
156   unsigned char* imgPointer = buffer;
157   result = fread(buffer,1,lSize,fp);
158
159   fclose(fp);
160
161   if( 0 == result )
162   {
163     free( buffer );
164     return false;
165   }
166
167   if( 0 == header.numberOfMipmapLevels )
168   {
169     header.numberOfMipmapLevels = 1u;
170   }
171
172   if( 0 == header.numberOfArrayElements )
173   {
174     header.numberOfArrayElements = 1u;
175   }
176
177   if( 0 == header.pixelDepth )
178   {
179     header.pixelDepth = 1u;
180   }
181
182   if( 0 == header.pixelHeight )
183   {
184     header.pixelHeight = 1u;
185   }
186
187   Dali::Pixel::Format daliformat = Pixel::RGB888;
188
189   ConvertPixelFormat(header.glInternalFormat, daliformat);
190
191   for( unsigned int mipmapLevel = 0; mipmapLevel < header.numberOfMipmapLevels; ++mipmapLevel )
192   {
193     long int byteSize = 0;
194     int imageSize;
195     memcpy(&imageSize,imgPointer,sizeof(unsigned int));
196     imgPointer += 4u;
197     for(unsigned int arrayElement=0; arrayElement < header.numberOfArrayElements; ++arrayElement) //arrayElement must be 0 or 1
198     {
199       for(unsigned int face=0; face < header.numberOfFaces; ++face)
200       {
201         byteSize = imageSize;
202         if(byteSize % 4u)
203         {
204           byteSize += 4u - byteSize % 4u;
205         }
206         img[face] = reinterpret_cast<unsigned char*>( malloc( byteSize ) ); // resources will be freed when the PixelData is destroyed.
207         memcpy(img[face],imgPointer,byteSize);
208         imgSize[face] = byteSize;
209         imgPointer += byteSize;
210         cubedata.img[face][mipmapLevel] = PixelData::New( img[face], imgSize[face], header.pixelWidth , header.pixelHeight , daliformat, PixelData::FREE );
211       }
212     }
213     header.pixelHeight/=2u;
214     header.pixelWidth/=2u;
215   }
216
217   free(buffer);
218   return true;
219 }
220
221 } // namespace PbrDemo