PBR demo
[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 <dali/devel-api/images/pixel-devel.h>
23 #include <dali/devel-api/images/pixel-data-devel.h>
24 #include <memory.h>
25 #include <stdio.h>
26 #include <stdint.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::DevelPixel::Format& format)
53 {
54   switch( ktxPixelFormat )
55   {
56     case 0x93B0: // GL_COMPRESSED_RGBA_ASTC_4x4_KHR
57     {
58       format = Dali::DevelPixel::COMPRESSED_RGBA_ASTC_4x4_KHR;
59       break;
60     }
61     case 0x881B:// GL_RGB16F
62     {
63       format = Dali::DevelPixel::RGB16F;
64       break;
65     }
66     case 0x8815: // GL_RGB32F
67     {
68       format = Dali::DevelPixel::RGB32F;
69       break;
70     }
71     case 0x8C3A: // GL_R11F_G11F_B10F
72     {
73       format = Dali::DevelPixel::RGB32F;
74       break;
75     }
76     case 0x8D7C: // GL_RGBA8UI
77     {
78       format = Dali::DevelPixel::RGBA8888;
79       break;
80     }
81     case 0x8D7D: // GL_RGB8UI
82     {
83       format = Dali::DevelPixel::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   FILE* fp = fopen(path.c_str(),"rb");
98
99   if( NULL == fp )
100   {
101     return false;
102   }
103
104   KtxFileHeader header;
105
106   int result = fread(&header,1,sizeof(KtxFileHeader),fp);
107   if( 0 == result )
108   {
109     return false;
110   }
111
112   long lSize = 0;
113
114   // Skip the key-values:
115   const long int imageSizeOffset = sizeof(KtxFileHeader) + header.bytesOfKeyValueData;
116
117   fseek(fp, imageSizeOffset, SEEK_END);
118   lSize = ftell(fp);
119   rewind(fp);
120
121   if(fseek(fp, imageSizeOffset, SEEK_SET))
122   {
123     return false;
124   }
125   cubedata.img.resize(header.numberOfFaces);
126
127   for(unsigned int face=0; face < header.numberOfFaces; ++face) //array_element must be 0 or 1
128   {
129     cubedata.img[face].resize(header.numberOfMipmapLevels);
130   }
131
132   unsigned char* buffer= reinterpret_cast<unsigned char*>( malloc( lSize ) );
133
134   unsigned char* img[6];
135   unsigned int imgSize[6];
136   unsigned char* imgPointer = buffer;
137   result = fread(buffer,1,lSize,fp);
138   if( 0 == result )
139   {
140     return false;
141   }
142
143   fclose(fp);
144
145   if( 0 == header.numberOfMipmapLevels )
146   {
147     header.numberOfMipmapLevels = 1u;
148   }
149
150   if( 0 == header.numberOfArrayElements )
151   {
152     header.numberOfArrayElements = 1u;
153   }
154
155   if( 0 == header.pixelDepth )
156   {
157     header.pixelDepth = 1u;
158   }
159
160   if( 0 == header.pixelHeight )
161   {
162     header.pixelHeight = 1u;
163   }
164
165   Dali::DevelPixel::Format daliformat = DevelPixel::RGB888;
166
167   ConvertPixelFormat(header.glInternalFormat, daliformat);
168
169   for( unsigned int mipmapLevel = 0; mipmapLevel < header.numberOfMipmapLevels; ++mipmapLevel )
170   {
171     long int byteSize = 0;
172     int imageSize;
173     memcpy(&imageSize,imgPointer,sizeof(unsigned int));
174     imgPointer += 4u;
175     for(unsigned int arrayElement=0; arrayElement < header.numberOfArrayElements; ++arrayElement) //arrayElement must be 0 or 1
176     {
177       for(unsigned int face=0; face < header.numberOfFaces; ++face)
178       {
179         byteSize = imageSize;
180         if(byteSize % 4u)
181         {
182           byteSize += 4u - byteSize % 4u;
183         }
184         img[face] = reinterpret_cast<unsigned char*>( malloc( byteSize ) ); // resources will be freed when the PixelData is destroyed.
185         memcpy(img[face],imgPointer,byteSize);
186         imgSize[face] = byteSize;
187         imgPointer += byteSize;
188         cubedata.img[face][mipmapLevel] = DevelPixelData::New( img[face], imgSize[face], header.pixelWidth , header.pixelHeight , daliformat, PixelData::FREE );
189       }
190     }
191     header.pixelHeight/=2u;
192     header.pixelWidth/=2u;
193   }
194
195   free(buffer);
196   return true;
197 }
198
199 } // namespace PbrDemo