]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CSoftwareTexture2.cpp
Merging r6196 through r6248 from trunk to ogl-es branch
[irrlicht.git] / source / Irrlicht / CSoftwareTexture2.cpp
1 // Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten\r
2 // This file is part of the "Irrlicht Engine".\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h\r
4 \r
5 #include "IrrCompileConfig.h"\r
6 #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_\r
7 \r
8 #include "SoftwareDriver2_compile_config.h"\r
9 #include "SoftwareDriver2_helper.h"\r
10 #include "CSoftwareTexture2.h"\r
11 #include "CSoftwareDriver2.h"\r
12 #include "CBlit.h"\r
13 #include "os.h"\r
14 \r
15 namespace irr\r
16 {\r
17 namespace video\r
18 {\r
19 \r
20 //! stretches srcRect src to dstRect dst, applying a sliding window box filter in linear color space (sRGB->linear->sRGB)\r
21 void Resample_subSampling(eBlitter op, video::IImage* dst, const core::rect<s32>* dstRect, const video::IImage* src, const core::rect<s32>* srcRect, size_t flags);\r
22 \r
23 //nearest pow of 2 ( 257 will be 256 not 512 )\r
24 static inline core::dimension2d<u32> getOptimalSize(const core::dimension2d<u32>& original, const u32 allowNonPowerOfTwo, const u32 maxSize)\r
25 {\r
26         u32 w, h;\r
27         if (allowNonPowerOfTwo)\r
28         {\r
29                 w = original.Width;\r
30                 h = original.Height;\r
31         }\r
32         else\r
33         {\r
34                 w = 1;\r
35                 while (w * 2 < original.Width) w *= 2;\r
36                 if (w * 2 - original.Width < original.Width - w) w *= 2;\r
37 \r
38                 h = 1;\r
39                 while (h * 2 < original.Height) h *= 2;\r
40                 if (h * 2 - original.Height < original.Height - h) h *= 2;\r
41         }\r
42         if (maxSize && w > maxSize) w = maxSize;\r
43         if (maxSize && h > maxSize) h = maxSize;\r
44         return core::dimension2d<u32>(w, h);\r
45 }\r
46 \r
47 //! constructor\r
48 CSoftwareTexture2::CSoftwareTexture2(IImage* image, const io::path& name, u32 flags, CBurningVideoDriver* driver)\r
49         : ITexture(name\r
50 #if !defined(PATCH_SUPERTUX_8_0_1_with_1_9_0)\r
51                 , ETT_2D\r
52 #endif\r
53         )\r
54         , MipMapLOD(0), Flags(flags), Driver(driver)\r
55 {\r
56 #ifdef _DEBUG\r
57         setDebugName("CSoftwareTexture2");\r
58 #endif\r
59 \r
60 #if SOFTWARE_DRIVER_2_MIPMAPPING_MAX <= 1\r
61         Flags &= ~(GEN_MIPMAP | GEN_MIPMAP_AUTO);\r
62 #endif\r
63         //set baseclass properties\r
64         DriverType = EDT_BURNINGSVIDEO;\r
65         ColorFormat = (Flags & IS_RENDERTARGET) ? SOFTWARE_DRIVER_2_RENDERTARGET_COLOR_FORMAT : SOFTWARE_DRIVER_2_TEXTURE_COLOR_FORMAT;\r
66         IsRenderTarget = (Flags & IS_RENDERTARGET) != 0;\r
67         HasMipMaps = (Flags & GEN_MIPMAP) != 0;\r
68         MipMap0_Area[0] = 1;\r
69         MipMap0_Area[1] = 1;\r
70         LodBIAS = 1.f;\r
71         for (size_t i = 0; i < array_size(MipMap); ++i) MipMap[i] = 0;\r
72         if (!image) return;\r
73 \r
74         OriginalSize = image->getDimension();\r
75         OriginalColorFormat = image->getColorFormat();\r
76 \r
77 \r
78 #if defined(IRRLICHT_sRGB)\r
79         if (Flags & IMAGE_IS_LINEAR) image->set_sRGB(0);\r
80 #else\r
81         //guessing linear image\r
82         if (name.find("light") >= 0 ||\r
83                 name.find("bump") >= 0 ||\r
84                 name.find("height") >= 0\r
85                 )\r
86         {\r
87                 Flags |= TEXTURE_IS_LINEAR | IMAGE_IS_LINEAR;\r
88         }\r
89 #endif\r
90 \r
91         bool isCompressed = IImage::isCompressedFormat(OriginalColorFormat);\r
92         if (isCompressed)\r
93         {\r
94                 os::Printer::log("Texture compression not available.", ELL_ERROR);\r
95         }\r
96 \r
97         //visual studio code warning\r
98         u32 maxTexSize = SOFTWARE_DRIVER_2_TEXTURE_MAXSIZE;\r
99 \r
100 #if defined(PATCH_SUPERTUX_8_0_1_with_1_9_0)\r
101         if (IsRenderTarget && name.find("RaceGUI::markers") >= 0)\r
102         {\r
103                 maxTexSize = 0;\r
104         }\r
105 #endif\r
106         /*\r
107                 core::dimension2d<u32> optSize(OriginalSize.getOptimalSize(\r
108                         (Flags & ALLOW_NPOT) ? 0 : 1, // requirePowerOfTwo\r
109                         false, // requireSquare\r
110                         (Flags & ALLOW_NPOT) ? 1 : maxTexSize == SOFTWARE_DRIVER_2_TEXTURE_MAXSIZE, // larger\r
111                         (Flags & ALLOW_NPOT) ? 0 : maxTexSize // maxValue\r
112                 )\r
113                 );\r
114         */\r
115         core::dimension2d<u32> optSize(getOptimalSize(OriginalSize, Flags & ALLOW_NPOT, maxTexSize));\r
116         if (OriginalSize == optSize)\r
117         {\r
118                 MipMap[0] = new CImage(ColorFormat, image->getDimension());\r
119 #if defined(IRRLICHT_sRGB)\r
120                 MipMap[0]->set_sRGB((Flags & TEXTURE_IS_LINEAR) ? 0 : image->get_sRGB());\r
121 #endif\r
122                 if (!isCompressed && image->getData())\r
123                         image->copyTo(MipMap[0]);\r
124         }\r
125         else\r
126         {\r
127                 MipMap[0] = new CImage(ColorFormat, optSize);\r
128 #if defined(IRRLICHT_sRGB)\r
129                 MipMap[0]->set_sRGB((Flags & TEXTURE_IS_LINEAR) ? 0 : image->get_sRGB());\r
130 #endif\r
131                 if (!isCompressed)\r
132                 {\r
133                         //image->copyToScalingBoxFilter ( MipMap[0],0, false );\r
134                         Resample_subSampling(BLITTER_TEXTURE, MipMap[0], 0, image, 0, Flags);\r
135                 }\r
136                 // if Original Size is used for calculation ( 2D position, font) it will be wrong\r
137                 //OriginalSize = optSize;\r
138         }\r
139 \r
140         // Show Information about resizing\r
141         if (OriginalSize != optSize ||\r
142                 (       OriginalColorFormat != ColorFormat &&\r
143                         !((OriginalColorFormat == ECF_R8G8B8 || OriginalColorFormat == ECF_A1R5G5B5) && ColorFormat == ECF_A8R8G8B8)\r
144                 )\r
145         )\r
146         {\r
147                 char buf[256];\r
148                 core::stringw showName(name);\r
149                 snprintf_irr(buf, sizeof(buf), "Burningvideo: Texture '%ls' reformat %ux%u,%s -> %ux%u,%s",\r
150                         showName.c_str(),\r
151                         OriginalSize.Width, OriginalSize.Height, ColorFormatNames[OriginalColorFormat],\r
152                         optSize.Width, optSize.Height, ColorFormatNames[ColorFormat]\r
153                 );\r
154                 os::Printer::log(buf, ELL_DEBUG);\r
155         }\r
156 \r
157 \r
158         //select highest mipmap 0\r
159         regenerateMipMapLevels(image->getMipMapsData());\r
160 }\r
161 \r
162 \r
163 //! destructor\r
164 CSoftwareTexture2::~CSoftwareTexture2()\r
165 {\r
166         for (size_t i = 0; i < array_size(MipMap); ++i)\r
167         {\r
168                 if (MipMap[i])\r
169                 {\r
170                         MipMap[i]->drop();\r
171                         MipMap[i] = 0;\r
172                 }\r
173         }\r
174 }\r
175 \r
176 \r
177 //! Regenerates the mip map levels of the texture. Useful after locking and\r
178 //! modifying the texture\r
179 #if !defined(PATCH_SUPERTUX_8_0_1_with_1_9_0)\r
180 void CSoftwareTexture2::regenerateMipMapLevels(void* data, u32 layer)\r
181 #else\r
182 void CSoftwareTexture2::regenerateMipMapLevels(void* data)\r
183 #endif\r
184 {\r
185         size_t i;\r
186 \r
187         // release\r
188         for (i = 1; i < array_size(MipMap); ++i)\r
189         {\r
190                 if (MipMap[i])\r
191                 {\r
192                         MipMap[i]->drop();\r
193                         MipMap[i] = 0;\r
194                 }\r
195         }\r
196 \r
197         core::dimension2d<u32> newSize;\r
198 \r
199         if (HasMipMaps && ((Flags & GEN_MIPMAP_AUTO) || 0 == data))\r
200         {\r
201                 //need memory also if autogen mipmap disabled\r
202                 for (i = 1; i < array_size(MipMap); ++i)\r
203                 {\r
204                         const core::dimension2du& upperDim = MipMap[i - 1]->getDimension();\r
205                         //isotropic\r
206                         newSize.Width = core::s32_max(SOFTWARE_DRIVER_2_MIPMAPPING_MIN_SIZE, upperDim.Width >> 1);\r
207                         newSize.Height = core::s32_max(SOFTWARE_DRIVER_2_MIPMAPPING_MIN_SIZE, upperDim.Height >> 1);\r
208                         if (upperDim == newSize)\r
209                                 break;\r
210 \r
211                         MipMap[i] = new CImage(ColorFormat, newSize);\r
212 #if defined(IRRLICHT_sRGB)\r
213                         MipMap[i]->set_sRGB(MipMap[i - 1]->get_sRGB());\r
214 #endif\r
215                         //MipMap[i]->fill ( 0xFFFF4040 );\r
216                         //MipMap[i-1]->copyToScalingBoxFilter( MipMap[i], 0, false );\r
217                         Resample_subSampling(BLITTER_TEXTURE, MipMap[i], 0, MipMap[0], 0, Flags);\r
218                 }\r
219         }\r
220         else if (HasMipMaps && data)\r
221         {\r
222                 //deactivated outside mipdata until TA knows how to handle this.\r
223 \r
224                 //query mipmap dimension\r
225                 u8* mip_current = (u8*)data;\r
226                 const u8* mip_end = (u8*)data;\r
227 \r
228                 core::dimension2d<u32> origSize = OriginalSize;\r
229                 i = 1;\r
230                 do\r
231                 {\r
232                         if (origSize.Width > 1) origSize.Width >>= 1;\r
233                         if (origSize.Height > 1) origSize.Height >>= 1;\r
234                         mip_end += IImage::getDataSizeFromFormat(OriginalColorFormat, origSize.Width, origSize.Height);\r
235                         i += 1;\r
236                 } while ((origSize.Width != 1 || origSize.Height != 1) && i < array_size(MipMap));\r
237 \r
238                 //TODO: this is not true\r
239                 LodBIAS = i * 2.f;\r
240 \r
241                 origSize = OriginalSize;\r
242                 for (i = 1; i < array_size(MipMap) && mip_current < mip_end; ++i)\r
243                 {\r
244                         const core::dimension2du& upperDim = MipMap[i - 1]->getDimension();\r
245                         //isotropic\r
246                         newSize.Width = core::s32_max(SOFTWARE_DRIVER_2_MIPMAPPING_MIN_SIZE, upperDim.Width >> 1);\r
247                         newSize.Height = core::s32_max(SOFTWARE_DRIVER_2_MIPMAPPING_MIN_SIZE, upperDim.Height >> 1);\r
248                         if (upperDim == newSize)\r
249                                 break;\r
250 \r
251                         if (origSize.Width > 1) origSize.Width >>= 1;\r
252                         if (origSize.Height > 1) origSize.Height >>= 1;\r
253 \r
254                         if (OriginalColorFormat != ColorFormat)\r
255                         {\r
256                                 IImage* tmpImage = new CImage(OriginalColorFormat, origSize, mip_current, true, false);\r
257                                 MipMap[i] = new CImage(ColorFormat, newSize);\r
258                                 if (origSize == newSize)\r
259                                         tmpImage->copyTo(MipMap[i]);\r
260                                 else\r
261                                         tmpImage->copyToScalingBoxFilter(MipMap[i]);\r
262                                 tmpImage->drop();\r
263                         }\r
264                         else\r
265                         {\r
266                                 if (origSize == newSize)\r
267                                         MipMap[i] = new CImage(ColorFormat, newSize, mip_current, false);\r
268                                 else\r
269                                 {\r
270                                         MipMap[i] = new CImage(ColorFormat, newSize);\r
271                                         IImage* tmpImage = new CImage(ColorFormat, origSize, mip_current, true, false);\r
272                                         tmpImage->copyToScalingBoxFilter(MipMap[i]);\r
273                                         tmpImage->drop();\r
274                                 }\r
275                         }\r
276                         mip_current += IImage::getDataSizeFromFormat(OriginalColorFormat, origSize.Width, origSize.Height);\r
277                 }\r
278         }\r
279 \r
280 #if 0\r
281         //visualize mipmap\r
282         for (i = 1; i < 0 && i < array_size(MipMap); ++i)\r
283         {\r
284                 static u32 color[] = {\r
285                         0xFFFF0000,\r
286                         0xFFFF0000,0xFF00FF00,0xFF0000FF,\r
287                         0xFFFFFF00,0xFF00FFFF,0xFFFF00FF,\r
288                         0xFFff6600,0xFF00ff66,0xFF6600FF,\r
289                         0xFF66ff00,0xFF0066ff,0xFFff0066,\r
290                         0xFF33ff00,0xFF0033ff,0xFF3300ff,\r
291                         0xFF0000FF,0xFF0000FF,0xFF0000FF\r
292                 };\r
293 \r
294                 if (MipMap[i])\r
295                 {\r
296                         int border = 0;\r
297                         const core::dimension2du& d = MipMap[i]->getDimension();\r
298                         core::rect<s32> p(0, 0, d.Width, d.Height);\r
299                         SColor c((color[i & 15] & 0x00FFFFFF) | 0xFF000000);\r
300 \r
301                         core::rect<s32> dclip(border, border, d.Width - border, d.Height - border);\r
302                         \r
303                         Blit(BLITTER_TEXTURE_ALPHA_COLOR_BLEND, MipMap[i], &dclip, 0, MipMap[i], &p, c.color);\r
304                 }\r
305         }\r
306 \r
307         //save mipmap chain\r
308         if (0)\r
309         {\r
310                 char buf[256];\r
311                 const char* name = getName().getPath().c_str();\r
312                 int filename = 0;\r
313                 //int ext = -1;\r
314                 i = 0;\r
315                 while (name[i])\r
316                 {\r
317                         if (name[i] == '/' || name[i] == '\\') filename = (s32)i + 1;\r
318                         //if (name[i] == '.') ext = i;\r
319                         i += 1;\r
320                 }\r
321                 for (i = 0; i < array_size(MipMap); ++i)\r
322                 {\r
323                         if (MipMap[i])\r
324                         {\r
325                                 snprintf_irr(buf, sizeof(buf), "mip/%s_%02d.png", name + filename, (s32)i);\r
326                                 Driver->writeImageToFile(MipMap[i], buf);\r
327                         }\r
328                 }\r
329         }\r
330 #endif\r
331         calcDerivative();\r
332 }\r
333 \r
334 void CSoftwareTexture2::calcDerivative()\r
335 {\r
336         //reset current MipMap\r
337         MipMapLOD = 0;\r
338         if (MipMap[0])\r
339         {\r
340                 const core::dimension2du& dim = MipMap[0]->getDimension();\r
341                 MipMap0_Area[0] = dim.Width;\r
342                 MipMap0_Area[1] = dim.Height; // screensize of a triangle\r
343 \r
344                 //TA: try to mimic openGL mipmap. ( don't do this!)\r
345                 //if (MipMap0_Area[0] < 32) MipMap0_Area[0] = 32;\r
346                 //if (MipMap0_Area[1] < 32) MipMap0_Area[1] = 32;\r
347 \r
348                 Size = dim; // MipMap[MipMapLOD]->getDimension();\r
349                 Pitch = MipMap[MipMapLOD]->getPitch();\r
350         }\r
351 \r
352         //preCalc mipmap texel center boundaries\r
353         for (size_t i = 0; i < array_size(MipMap); ++i)\r
354         {\r
355                 CSoftwareTexture2_Bound& b = TexBound[i];\r
356                 if (MipMap[i])\r
357                 {\r
358                         const core::dimension2du& dim = MipMap[i]->getDimension();\r
359                         //f32 u = 1.f / dim.Width;\r
360                         //f32 v = 1.f / dim.Height;\r
361 \r
362                         b.w = dim.Width - 1.f;\r
363                         b.h = dim.Height - 1.f;\r
364                         b.cx = 0.f; //u*0.005f;\r
365                         b.cy = 0.f; //v*0.005f;\r
366                 }\r
367                 else\r
368                 {\r
369                         b.w = 0.f;\r
370                         b.h = 0.f;\r
371                         b.cx = 0.f;\r
372                         b.cy = 0.f;\r
373                 }\r
374         }\r
375 \r
376 }\r
377 \r
378 \r
379 /* Software Render Target 2 */\r
380 \r
381 CSoftwareRenderTarget2::CSoftwareRenderTarget2(CBurningVideoDriver* driver) : Driver(driver)\r
382 #if defined(PATCH_SUPERTUX_8_0_1_with_1_9_0)\r
383         , IRenderTarget(0)\r
384 #endif\r
385 {\r
386         DriverType = EDT_BURNINGSVIDEO;\r
387 \r
388         Textures.set_used(1);\r
389         Textures[0] = 0;\r
390 }\r
391 \r
392 CSoftwareRenderTarget2::~CSoftwareRenderTarget2()\r
393 {\r
394         if (Textures[0])\r
395                 Textures[0]->drop();\r
396 }\r
397 \r
398 void CSoftwareRenderTarget2::setTextures(ITexture* const * textures, u32 numTextures, ITexture* depthStencil, const E_CUBE_SURFACE* cubeSurfaces, u32 numCubeSurfaces)\r
399 {\r
400         if (!Textures.equals(textures, numTextures))\r
401         {\r
402                 ITexture* prevTexture = Textures[0];\r
403 \r
404                 bool textureDetected = false;\r
405 \r
406                 for (u32 i = 0; i < numTextures; ++i)\r
407                 {\r
408                         if (textures[i] && textures[i]->getDriverType() == EDT_BURNINGSVIDEO)\r
409                         {\r
410                                 Textures[0] = textures[i];\r
411                                 Textures[0]->grab();\r
412                                 textureDetected = true;\r
413 \r
414                                 break;\r
415                         }\r
416                 }\r
417 \r
418                 if (prevTexture)\r
419                         prevTexture->drop();\r
420 \r
421                 if (!textureDetected)\r
422                         Textures[0] = 0;\r
423         }\r
424 }\r
425 \r
426 \r
427 static const float srgb_8bit_to_linear_float[1 << 8] = {\r
428         0.0f, 3.03527e-4f, 6.07054e-4f, 9.10581e-4f,\r
429         0.001214108f, 0.001517635f, 0.001821162f, 0.0021246888f,\r
430         0.002428216f, 0.002731743f, 0.00303527f, 0.0033465358f,\r
431         0.0036765074f, 0.004024717f, 0.004391442f, 0.0047769537f,\r
432         0.005181517f, 0.005605392f, 0.0060488335f, 0.006512091f,\r
433         0.0069954107f, 0.007499032f, 0.008023193f, 0.008568126f,\r
434         0.009134059f, 0.009721218f, 0.010329823f, 0.010960095f,\r
435         0.011612245f, 0.012286489f, 0.0129830325f, 0.013702083f,\r
436         0.014443845f, 0.015208516f, 0.015996294f, 0.016807377f,\r
437         0.017641956f, 0.018500222f, 0.019382363f, 0.020288564f,\r
438         0.021219011f, 0.022173885f, 0.023153368f, 0.024157634f,\r
439         0.025186861f, 0.026241222f, 0.027320893f, 0.02842604f,\r
440         0.029556835f, 0.030713445f, 0.031896032f, 0.033104766f,\r
441         0.034339808f, 0.035601314f, 0.036889452f, 0.038204372f,\r
442         0.039546236f, 0.0409152f, 0.04231141f, 0.04373503f,\r
443         0.045186203f, 0.046665087f, 0.048171826f, 0.049706567f,\r
444         0.051269464f, 0.05286065f, 0.05448028f, 0.056128494f,\r
445         0.057805438f, 0.059511244f, 0.06124606f, 0.06301002f,\r
446         0.06480327f, 0.066625945f, 0.068478175f, 0.0703601f,\r
447         0.07227185f, 0.07421357f, 0.07618539f, 0.07818743f,\r
448         0.08021983f, 0.082282715f, 0.084376216f, 0.086500466f,\r
449         0.08865559f, 0.09084172f, 0.093058966f, 0.09530747f,\r
450         0.097587354f, 0.09989873f, 0.10224174f, 0.10461649f,\r
451         0.107023105f, 0.10946172f, 0.111932434f, 0.11443538f,\r
452         0.11697067f, 0.119538434f, 0.122138776f, 0.12477182f,\r
453         0.12743768f, 0.13013647f, 0.13286832f, 0.13563333f,\r
454         0.13843162f, 0.14126329f, 0.14412847f, 0.14702727f,\r
455         0.14995979f, 0.15292616f, 0.15592647f, 0.15896083f,\r
456         0.16202939f, 0.1651322f, 0.1682694f, 0.17144111f,\r
457         0.1746474f, 0.17788842f, 0.18116425f, 0.18447499f,\r
458         0.18782078f, 0.19120169f, 0.19461784f, 0.19806932f,\r
459         0.20155625f, 0.20507874f, 0.20863687f, 0.21223076f,\r
460         0.21586053f, 0.21952623f, 0.22322798f, 0.2269659f,\r
461         0.23074007f, 0.23455061f, 0.2383976f, 0.24228115f,\r
462         0.24620135f, 0.2501583f, 0.25415212f, 0.25818288f,\r
463         0.2622507f, 0.26635563f, 0.27049783f, 0.27467734f,\r
464         0.2788943f, 0.28314877f, 0.28744087f, 0.29177067f,\r
465         0.2961383f, 0.3005438f, 0.30498734f, 0.30946895f,\r
466         0.31398875f, 0.3185468f, 0.32314324f, 0.32777813f,\r
467         0.33245155f, 0.33716366f, 0.34191445f, 0.3467041f,\r
468         0.35153264f, 0.35640016f, 0.36130682f, 0.36625263f,\r
469         0.3712377f, 0.37626216f, 0.38132605f, 0.38642946f,\r
470         0.3915725f, 0.39675525f, 0.4019778f, 0.40724024f,\r
471         0.41254264f, 0.4178851f, 0.4232677f, 0.42869052f,\r
472         0.43415368f, 0.4396572f, 0.44520122f, 0.45078582f,\r
473         0.45641103f, 0.46207702f, 0.4677838f, 0.4735315f,\r
474         0.4793202f, 0.48514995f, 0.4910209f, 0.496933f,\r
475         0.5028865f, 0.50888133f, 0.5149177f, 0.5209956f,\r
476         0.52711517f, 0.53327644f, 0.5394795f, 0.5457245f,\r
477         0.55201143f, 0.55834043f, 0.5647115f, 0.57112485f,\r
478         0.57758045f, 0.58407843f, 0.59061885f, 0.5972018f,\r
479         0.60382736f, 0.61049557f, 0.6172066f, 0.62396044f,\r
480         0.63075715f, 0.6375969f, 0.6444797f, 0.65140563f,\r
481         0.65837485f, 0.66538733f, 0.67244315f, 0.6795425f,\r
482         0.6866853f, 0.6938718f, 0.7011019f, 0.7083758f,\r
483         0.71569353f, 0.7230551f, 0.73046076f, 0.73791045f,\r
484         0.74540424f, 0.7529422f, 0.7605245f, 0.76815116f,\r
485         0.7758222f, 0.7835378f, 0.791298f, 0.7991027f,\r
486         0.8069523f, 0.8148466f, 0.82278574f, 0.8307699f,\r
487         0.838799f, 0.8468732f, 0.8549926f, 0.8631572f,\r
488         0.8713671f, 0.8796224f, 0.8879231f, 0.8962694f,\r
489         0.9046612f, 0.91309863f, 0.92158186f, 0.9301109f,\r
490         0.9386857f, 0.9473065f, 0.9559733f, 0.9646863f,\r
491         0.9734453f, 0.9822506f, 0.9911021f, 1.0f,\r
492 };\r
493 /*\r
494 int linear_to_srgb_8bit(const float x) {\r
495         if (x <= 0.f) return 0;\r
496         if (x >= 1.f) return 255;\r
497         const float *table = SRGB_8BIT_TO_LINEAR_FLOAT;\r
498         int y = 0;\r
499         for (int i = 128; i != 0; i >>= 1) {\r
500                 if (table[y + i] <= x)\r
501                         y += i;\r
502         }\r
503         if (x - table[y] <= table[y + 1] - x)\r
504                 return y;\r
505         else\r
506                 return y + 1;\r
507 }\r
508 */\r
509 \r
510 \r
511 u32 linear_to_srgb_8bit(const float v)\r
512 {\r
513         ieee754 c;\r
514         c.f = v;\r
515         const size_t x = c.u;\r
516         const u32* table = (u32*)srgb_8bit_to_linear_float;\r
517         u32 y = 0;\r
518         y += table[y + 128] <= x ? 128 : 0;\r
519         y += table[y + 64] <= x ? 64 : 0;\r
520         y += table[y + 32] <= x ? 32 : 0;\r
521         y += table[y + 16] <= x ? 16 : 0;\r
522         y += table[y + 8] <= x ? 8 : 0;\r
523         y += table[y + 4] <= x ? 4 : 0;\r
524         y += table[y + 2] <= x ? 2 : 0;\r
525         y += table[y + 1] <= x ? 1 : 0;\r
526 \r
527         return y;\r
528 }\r
529 \r
530 // 2D Region half open [x0;x1[\r
531 struct absrect2\r
532 {\r
533         s32 x0;\r
534         s32 y0;\r
535         s32 x1;\r
536         s32 y1;\r
537 };\r
538 \r
539 static inline int clipTest(absrect2& o, const core::rect<s32>* a, const absrect2& b)\r
540 {\r
541         if (a == 0)\r
542         {\r
543                 o.x0 = b.x0;\r
544                 o.y0 = b.y0;\r
545                 o.x1 = b.x1;\r
546                 o.y1 = b.y1;\r
547         }\r
548         else\r
549         {\r
550                 o.x0 = core::s32_max(a->UpperLeftCorner.X, b.x0);\r
551                 o.x1 = core::s32_min(a->LowerRightCorner.X, b.x1);\r
552                 o.y0 = core::s32_max(a->UpperLeftCorner.Y, b.y0);\r
553                 o.y1 = core::s32_min(a->LowerRightCorner.Y, b.y1);\r
554         }\r
555         int clipTest = 0;\r
556         clipTest |= o.x0 >= o.x1 ? 1 : 0;\r
557         clipTest |= o.y0 >= o.y1 ? 2 : 0;\r
558         return clipTest;\r
559 }\r
560 \r
561 //! stretches srcRect src to dstRect dst, applying a sliding window box filter in linear color space (sRGB->linear->sRGB)\r
562 // todo: texture jumps (mip selection problem)\r
563 void Resample_subSampling(eBlitter op, video::IImage* dst, const core::rect<s32>* dstRect,\r
564         const video::IImage* src, const core::rect<s32>* srcRect, size_t flags)\r
565 {\r
566         u8* dstData = (u8*)dst->getData();\r
567         const absrect2 dst_clip = { 0,0,(s32)dst->getDimension().Width,(s32)dst->getDimension().Height };\r
568         absrect2 dc;\r
569         if (clipTest(dc, dstRect, dst_clip) || !dstData) return;\r
570         const video::ECOLOR_FORMAT dstFormat = dst->getColorFormat();\r
571 \r
572         const u8* srcData = (u8*)src->getData();\r
573         const absrect2 src_clip = { 0,0,(s32)src->getDimension().Width,(s32)src->getDimension().Height };\r
574         absrect2 sc;\r
575         if (clipTest(sc, srcRect, src_clip) || !srcData) return;\r
576         const video::ECOLOR_FORMAT srcFormat = src->getColorFormat();\r
577 \r
578 #if defined(IRRLICHT_sRGB)\r
579         const int dst_sRGB = dst->get_sRGB();\r
580         const int src_sRGB = src->get_sRGB();\r
581 #else\r
582         const int dst_sRGB = (flags & CSoftwareTexture2::TEXTURE_IS_LINEAR) ? 0 : 1;\r
583         const int src_sRGB = (flags & CSoftwareTexture2::IMAGE_IS_LINEAR) ? 0 : 1;\r
584 #endif\r
585 \r
586 \r
587 \r
588         float scale[2];\r
589         scale[0] = (float)(sc.x1 - sc.x0) / (float)(dc.x1 - dc.x0);\r
590         scale[1] = (float)(sc.y1 - sc.y0) / (float)(dc.y1 - dc.y0);\r
591         const float rs = 1.f / (scale[0] * scale[1]);\r
592 \r
593         float sum[4];\r
594         u32 sbgra = 0;\r
595 \r
596         float f[4];\r
597         int fi[4];\r
598         f[3] = (float)sc.y0;\r
599         for (int dy = dc.y0; dy < dc.y1; ++dy)\r
600         {\r
601                 f[1] = f[3];\r
602                 f[3] = sc.y0 + (dy + 1 - dc.y0) * scale[1];\r
603                 if (f[3] >= sc.y1) f[3] = sc.y1 - 0.001f; //todo:1.f/dim should be enough\r
604 \r
605                 f[2] = (float)sc.x0;\r
606                 for (int dx = dc.x0; dx < dc.x1; ++dx)\r
607                 {\r
608                         f[0] = f[2];\r
609                         f[2] = sc.x0 + (dx + 1 - dc.x0) * scale[0];\r
610                         if (f[2] >= sc.x1) f[2] = sc.x1 - 0.001f;\r
611 \r
612                         //accumulate linear color\r
613                         sum[0] = 0.f;\r
614                         sum[1] = 0.f;\r
615                         sum[2] = 0.f;\r
616                         sum[3] = 0.f;\r
617 \r
618                         //sample border\r
619                         fi[0] = (int)(f[0]);\r
620                         fi[1] = (int)(f[1]);\r
621                         fi[2] = (int)(f[2]);\r
622                         fi[3] = (int)(f[3]);\r
623 \r
624                         float w[2];\r
625                         for (int fy = fi[1]; fy <= fi[3]; ++fy)\r
626                         {\r
627                                 w[1] = 1.f;\r
628                                 if (fy == fi[1]) w[1] -= f[1] - fy;\r
629                                 if (fy == fi[3]) w[1] -= fy + 1 - f[3];\r
630 \r
631                                 for (int fx = fi[0]; fx <= fi[2]; ++fx)\r
632                                 {\r
633                                         w[0] = 1.f;\r
634                                         if (fx == fi[0]) w[0] -= f[0] - fx;\r
635                                         if (fx == fi[2]) w[0] -= fx + 1 - f[2];\r
636 \r
637                                         const float ws = w[1] * w[0] * rs;\r
638 \r
639                                         switch (srcFormat)\r
640                                         {\r
641                                         case video::ECF_A1R5G5B5: sbgra = video::A1R5G5B5toA8R8G8B8(*(u16*)(srcData + (fy * src_clip.x1) * 2 + (fx * 2))); break;\r
642                                         case video::ECF_R5G6B5: sbgra = video::R5G6B5toA8R8G8B8(*(u16*)(srcData + (fy * src_clip.x1) * 2 + (fx * 2))); break;\r
643                                         case video::ECF_A8R8G8B8: sbgra = *(u32*)(srcData + (fy * src_clip.x1) * 4 + (fx * 4)); break;\r
644                                         case video::ECF_R8G8B8:\r
645                                         {\r
646                                                 const u8* p = srcData + (fy * src_clip.x1) * 3 + (fx * 3);\r
647                                                 sbgra = 0xFF000000 | p[0] << 16 | p[1] << 8 | p[2];\r
648                                         } break;\r
649                                         default: break;\r
650                                         }\r
651                                         if (src_sRGB)\r
652                                         {\r
653                                                 sum[0] += srgb_8bit_to_linear_float[(sbgra) & 0xFF] * ws;\r
654                                                 sum[1] += srgb_8bit_to_linear_float[(sbgra >> 8) & 0xFF] * ws;\r
655                                                 sum[2] += srgb_8bit_to_linear_float[(sbgra >> 16) & 0xFF] * ws;\r
656                                                 sum[3] += ((sbgra >> 24) & 0xFF) * ws;\r
657                                         }\r
658                                         else\r
659                                         {\r
660                                                 sum[0] += ((sbgra) & 0xFF) * ws;\r
661                                                 sum[1] += ((sbgra >> 8) & 0xFF) * ws;\r
662                                                 sum[2] += ((sbgra >> 16) & 0xFF) * ws;\r
663                                                 sum[3] += ((sbgra >> 24) & 0xFF) * ws;\r
664                                         }\r
665 \r
666                                 }\r
667                         }\r
668                         switch (op)\r
669                         {\r
670                         case BLITTER_TEXTURE_ALPHA_BLEND:\r
671                         case BLITTER_TEXTURE_ALPHA_COLOR_BLEND:\r
672                                 break;\r
673                         default:\r
674                                 break;\r
675                         }\r
676                         if (dst_sRGB)\r
677                         {\r
678                                 sbgra = linear_to_srgb_8bit(sum[0]) |\r
679                                         linear_to_srgb_8bit(sum[1]) << 8 |\r
680                                         linear_to_srgb_8bit(sum[2]) << 16 |\r
681                                         (u32)(sum[3]) << 24;\r
682                         }\r
683                         else\r
684                         {\r
685                                 sbgra = (u32)(sum[0]) |\r
686                                         (u32)(sum[1]) << 8 |\r
687                                         (u32)(sum[2]) << 16 |\r
688                                         (u32)(sum[3]) << 24;\r
689                         }\r
690                         switch (dstFormat)\r
691                         {\r
692                         case video::ECF_A8R8G8B8: *(u32*)(dstData + (dy * dst_clip.x1) * 4 + (dx * 4)) = sbgra; break;\r
693                         case video::ECF_R8G8B8:\r
694                         {\r
695                                 u8* p = dstData + (dy * dst_clip.x1) * 3 + (dx * 3);\r
696                                 p[2] = (sbgra) & 0xFF;\r
697                                 p[1] = (sbgra >> 8) & 0xFF;\r
698                                 p[0] = (sbgra >> 16) & 0xFF;\r
699                         } break;\r
700                         case video::ECF_A1R5G5B5: *(u16*)(dstData + (dy * dst_clip.x1) * 2 + (dx * 2)) = video::A8R8G8B8toA1R5G5B5(sbgra); break;\r
701                         case video::ECF_R5G6B5:   *(u16*)(dstData + (dy * dst_clip.x1) * 2 + (dx * 2)) = video::A8R8G8B8toR5G6B5(sbgra); break;\r
702                         default:\r
703                                 break;\r
704                         }\r
705                 }\r
706         }\r
707 \r
708 }\r
709 \r
710 } // end namespace video\r
711 } // end namespace irr\r
712 \r
713 #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_\r