Fixed SVACE issues in ktx-loader.cpp + general maintenance.
[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-stream.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::unique_ptr<FILE, void(*)(FILE*)> fp(fopen(path.c_str(), "rb"), [](FILE* fp) {
98     if (fp)
99     {
100       fclose(fp);
101     }
102   });
103   if (!fp)
104   {
105     return false;
106   }
107
108   KtxFileHeader header;
109   int result = fread(&header, sizeof(KtxFileHeader), 1u, fp.get());
110   if (0 == result)
111   {
112     return false;
113   }
114
115   // Skip the key-values:
116   if (fseek(fp.get(), header.bytesOfKeyValueData, SEEK_CUR))
117   {
118     return false;
119   }
120
121   cubedata.img.resize(header.numberOfFaces);
122
123   for (unsigned int face = 0; face < header.numberOfFaces; ++face) //array_element must be 0 or 1
124   {
125     cubedata.img[face].resize(header.numberOfMipmapLevels);
126   }
127
128   if (0 == header.numberOfMipmapLevels)
129   {
130     header.numberOfMipmapLevels = 1u;
131   }
132
133   if (0 == header.numberOfArrayElements)
134   {
135     header.numberOfArrayElements = 1u;
136   }
137
138   if (0 == header.pixelDepth)
139   {
140     header.pixelDepth = 1u;
141   }
142
143   if (0 == header.pixelHeight)
144   {
145     header.pixelHeight = 1u;
146   }
147
148   Dali::Pixel::Format daliformat = Pixel::RGB888;
149
150   ConvertPixelFormat(header.glInternalFormat, daliformat);
151
152   for (unsigned int mipmapLevel = 0; mipmapLevel < header.numberOfMipmapLevels; ++mipmapLevel)
153   {
154     uint32_t byteSize = 0;
155     if (fread(&byteSize, sizeof(byteSize), 1u, fp.get()) != 1)
156     {
157       return false;
158     }
159
160     if (0 != byteSize % 4u)
161     {
162       byteSize += 4u - byteSize % 4u;
163     }
164
165     for (unsigned int arrayElement = 0; arrayElement < header.numberOfArrayElements; ++arrayElement) // arrayElement must be 0 or 1
166     {
167       for (unsigned int face = 0; face < header.numberOfFaces; ++face)
168       {
169         std::unique_ptr<uint8_t, void(*)(void*)> img(static_cast<unsigned char*>(malloc(byteSize)), free); // resources will be freed when the PixelData is destroyed.
170         if (fread(img.get(), byteSize, 1u, fp.get()) != 1)
171         {
172           return false;
173         }
174         cubedata.img[face][mipmapLevel] = PixelData::New(img.release(), byteSize, header.pixelWidth, header.pixelHeight, daliformat, PixelData::FREE);
175       }
176     }
177
178     header.pixelHeight /= 2u;
179     header.pixelWidth /= 2u;
180   }
181
182   return true;
183 }
184
185 } // namespace PbrDemo