Updated demos to use DALi clang-format
[platform/core/uifw/dali-demo.git] / examples / rendering-basic-pbr / ktx-loader.cpp
1 /*
2  * Copyright (c) 2020 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/adaptor-framework/file-stream.h>
23 #include <dali/integration-api/debug.h>
24 #include <memory.h>
25 #include <stdint.h>
26 #include <stdio.h>
27
28 namespace PbrDemo
29 {
30 struct KtxFileHeader
31 {
32   char     identifier[12];
33   uint32_t endianness;
34   uint32_t glType; //(UNSIGNED_BYTE, UNSIGNED_SHORT_5_6_5, etc.)
35   uint32_t glTypeSize;
36   uint32_t glFormat;         //(RGB, RGBA, BGRA, etc.)
37   uint32_t glInternalFormat; //For uncompressed textures, specifies the internalformat parameter passed to glTexStorage*D or glTexImage*D
38   uint32_t glBaseInternalFormat;
39   uint32_t pixelWidth;
40   uint32_t pixelHeight;
41   uint32_t pixelDepth;
42   uint32_t numberOfArrayElements;
43   uint32_t numberOfFaces; //Cube map faces are stored in the order: +X, -X, +Y, -Y, +Z, -Z.
44   uint32_t numberOfMipmapLevels;
45   uint32_t bytesOfKeyValueData;
46 };
47
48 /**
49  * Convert KTX format to Dali::Pixel::Format
50  */
51 bool ConvertPixelFormat(const uint32_t ktxPixelFormat, Dali::Pixel::Format& format)
52 {
53   switch(ktxPixelFormat)
54   {
55     case 0x93B0: // GL_COMPRESSED_RGBA_ASTC_4x4_KHR
56     {
57       format = Dali::Pixel::COMPRESSED_RGBA_ASTC_4x4_KHR;
58       break;
59     }
60     case 0x881B: // GL_RGB16F
61     {
62       format = Dali::Pixel::RGB16F;
63       break;
64     }
65     case 0x8815: // GL_RGB32F
66     {
67       format = Dali::Pixel::RGB32F;
68       break;
69     }
70     case 0x8C3A: // GL_R11F_G11F_B10F
71     {
72       format = Dali::Pixel::RGB32F;
73       break;
74     }
75     case 0x8D7C: // GL_RGBA8UI
76     {
77       format = Dali::Pixel::RGBA8888;
78       break;
79     }
80     case 0x8D7D: // GL_RGB8UI
81     {
82       format = Dali::Pixel::RGB888;
83       break;
84     }
85     default:
86     {
87       return false;
88     }
89   }
90
91   return true;
92 }
93
94 bool LoadCubeMapFromKtxFile(const std::string& path, CubeData& cubedata)
95 {
96   std::unique_ptr<FILE, void (*)(FILE*)> fp(fopen(path.c_str(), "rb"), [](FILE* fp) {
97     if(fp)
98     {
99       fclose(fp);
100     }
101   });
102   if(!fp)
103   {
104     return false;
105   }
106
107   KtxFileHeader header;
108   int           result = fread(&header, sizeof(KtxFileHeader), 1u, fp.get());
109   if(0 == result)
110   {
111     return false;
112   }
113
114   // Skip the key-values:
115   if(fseek(fp.get(), header.bytesOfKeyValueData, SEEK_CUR))
116   {
117     return false;
118   }
119
120   cubedata.img.resize(header.numberOfFaces);
121
122   for(unsigned int face = 0; face < header.numberOfFaces; ++face) //array_element must be 0 or 1
123   {
124     cubedata.img[face].resize(header.numberOfMipmapLevels);
125   }
126
127   if(0 == header.numberOfMipmapLevels)
128   {
129     header.numberOfMipmapLevels = 1u;
130   }
131
132   if(0 == header.numberOfArrayElements)
133   {
134     header.numberOfArrayElements = 1u;
135   }
136
137   if(0 == header.pixelDepth)
138   {
139     header.pixelDepth = 1u;
140   }
141
142   if(0 == header.pixelHeight)
143   {
144     header.pixelHeight = 1u;
145   }
146
147   Dali::Pixel::Format daliformat = Pixel::RGB888;
148
149   ConvertPixelFormat(header.glInternalFormat, daliformat);
150
151   for(unsigned int mipmapLevel = 0; mipmapLevel < header.numberOfMipmapLevels; ++mipmapLevel)
152   {
153     uint32_t byteSize = 0;
154     if(fread(&byteSize, sizeof(byteSize), 1u, fp.get()) != 1)
155     {
156       return false;
157     }
158
159     if(0 != byteSize % 4u)
160     {
161       byteSize += 4u - byteSize % 4u;
162     }
163
164     for(unsigned int arrayElement = 0; arrayElement < header.numberOfArrayElements; ++arrayElement) // arrayElement must be 0 or 1
165     {
166       for(unsigned int face = 0; face < header.numberOfFaces; ++face)
167       {
168         std::unique_ptr<uint8_t, void (*)(void*)> img(static_cast<unsigned char*>(malloc(byteSize)), free); // resources will be freed when the PixelData is destroyed.
169         if(fread(img.get(), byteSize, 1u, fp.get()) != 1)
170         {
171           return false;
172         }
173         cubedata.img[face][mipmapLevel] = PixelData::New(img.release(), byteSize, header.pixelWidth, header.pixelHeight, daliformat, PixelData::FREE);
174       }
175     }
176
177     header.pixelHeight /= 2u;
178     header.pixelWidth /= 2u;
179   }
180
181   return true;
182 }
183
184 } // namespace PbrDemo