1 //
2 // Copyright (c) 2008-2017 the Urho3D project.
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21 //
22
23 #include "../../Precompiled.h"
24
25 #include "../../Core/Context.h"
26 #include "../../Core/Profiler.h"
27 #include "../../Graphics/Graphics.h"
28 #include "../../Graphics/GraphicsEvents.h"
29 #include "../../Graphics/GraphicsImpl.h"
30 #include "../../Graphics/Renderer.h"
31 #include "../../Graphics/Texture2DArray.h"
32 #include "../../IO/FileSystem.h"
33 #include "../../IO/Log.h"
34 #include "../../Resource/ResourceCache.h"
35 #include "../../Resource/XMLFile.h"
36
37 #include "../../DebugNew.h"
38
39 #ifdef _MSC_VER
40 #pragma warning(disable:4355)
41 #endif
42
43 namespace Urho3D
44 {
45
OnDeviceLost()46 void Texture2DArray::OnDeviceLost()
47 {
48 if (usage_ > TEXTURE_STATIC)
49 Release();
50 }
51
OnDeviceReset()52 void Texture2DArray::OnDeviceReset()
53 {
54 if (usage_ > TEXTURE_STATIC || !object_.ptr_ || dataPending_)
55 {
56 // If has a resource file, reload through the resource cache. Otherwise just recreate.
57 ResourceCache* cache = GetSubsystem<ResourceCache>();
58 if (cache->Exists(GetName()))
59 dataLost_ = !cache->ReloadResource(this);
60
61 if (!object_.ptr_)
62 {
63 Create();
64 dataLost_ = true;
65 }
66 }
67
68 dataPending_ = false;
69 }
70
Release()71 void Texture2DArray::Release()
72 {
73 if (graphics_)
74 {
75 for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
76 {
77 if (graphics_->GetTexture(i) == this)
78 graphics_->SetTexture(i, 0);
79 }
80 }
81
82 if (renderSurface_)
83 renderSurface_->Release();
84
85 URHO3D_SAFE_RELEASE(object_.ptr_);
86 }
87
SetData(unsigned layer,unsigned level,int x,int y,int width,int height,const void * data)88 bool Texture2DArray::SetData(unsigned layer, unsigned level, int x, int y, int width, int height, const void* data)
89 {
90 URHO3D_LOGERROR("Texture2DArray not supported on Direct3D9, can not set data");
91 return false;
92 }
93
SetData(unsigned layer,Deserializer & source)94 bool Texture2DArray::SetData(unsigned layer, Deserializer& source)
95 {
96 SharedPtr<Image> image(new Image(context_));
97 if (!image->Load(source))
98 return false;
99
100 return SetData(layer, image);
101 }
102
SetData(unsigned layer,Image * image,bool useAlpha)103 bool Texture2DArray::SetData(unsigned layer, Image* image, bool useAlpha)
104 {
105 if (!image)
106 {
107 URHO3D_LOGERROR("Null image, can not set data");
108 return false;
109 }
110 if (!layers_)
111 {
112 URHO3D_LOGERROR("Number of layers in the array must be set first");
113 return false;
114 }
115 if (layer >= layers_)
116 {
117 URHO3D_LOGERROR("Illegal layer for setting data");
118 return false;
119 }
120
121 // Use a shared ptr for managing the temporary mip images created during this function
122 SharedPtr<Image> mipImage;
123 unsigned memoryUse = 0;
124 int quality = QUALITY_HIGH;
125 Renderer* renderer = GetSubsystem<Renderer>();
126 if (renderer)
127 quality = renderer->GetTextureQuality();
128
129 if (!image->IsCompressed())
130 {
131 unsigned char* levelData = image->GetData();
132 int levelWidth = image->GetWidth();
133 int levelHeight = image->GetHeight();
134 unsigned components = image->GetComponents();
135 unsigned format = 0;
136
137 // Discard unnecessary mip levels
138 for (unsigned i = 0; i < mipsToSkip_[quality]; ++i)
139 {
140 mipImage = image->GetNextLevel(); image = mipImage;
141 levelData = image->GetData();
142 levelWidth = image->GetWidth();
143 levelHeight = image->GetHeight();
144 }
145
146 switch (components)
147 {
148 case 1:
149 format = Graphics::GetAlphaFormat();
150 break;
151
152 case 4:
153 format = Graphics::GetRGBAFormat();
154 break;
155
156 default: break;
157 }
158
159 // Create the texture array when layer 0 is being loaded, check that rest of the layers are same size & format
160 if (!layer)
161 {
162 // If image was previously compressed, reset number of requested levels to avoid error if level count is too high for new size
163 if (IsCompressed() && requestedLevels_ > 1)
164 requestedLevels_ = 0;
165 // Create the texture array (the number of layers must have been already set)
166 SetSize(0, levelWidth, levelHeight, format);
167 }
168 else
169 {
170 if (!object_.ptr_)
171 {
172 // Do not spam this error on D3D9
173 //URHO3D_LOGERROR("Texture array layer 0 must be loaded first");
174 return false;
175 }
176 if (levelWidth != width_ || levelHeight != height_ || format != format_)
177 {
178 URHO3D_LOGERROR("Texture array layer does not match size or format of layer 0");
179 return false;
180 }
181 }
182
183 for (unsigned i = 0; i < levels_; ++i)
184 {
185 SetData(layer, i, 0, 0, levelWidth, levelHeight, levelData);
186 memoryUse += levelWidth * levelHeight * components;
187
188 if (i < levels_ - 1)
189 {
190 mipImage = image->GetNextLevel(); image = mipImage;
191 levelData = image->GetData();
192 levelWidth = image->GetWidth();
193 levelHeight = image->GetHeight();
194 }
195 }
196 }
197 else
198 {
199 int width = image->GetWidth();
200 int height = image->GetHeight();
201 unsigned levels = image->GetNumCompressedLevels();
202 unsigned format = graphics_->GetFormat(image->GetCompressedFormat());
203 bool needDecompress = false;
204
205 if (!format)
206 {
207 format = Graphics::GetRGBAFormat();
208 needDecompress = true;
209 }
210
211 unsigned mipsToSkip = mipsToSkip_[quality];
212 if (mipsToSkip >= levels)
213 mipsToSkip = levels - 1;
214 while (mipsToSkip && (width / (1 << mipsToSkip) < 4 || height / (1 << mipsToSkip) < 4))
215 --mipsToSkip;
216 width /= (1 << mipsToSkip);
217 height /= (1 << mipsToSkip);
218
219 // Create the texture array when layer 0 is being loaded, assume rest of the layers are same size & format
220 if (!layer)
221 {
222 SetNumLevels(Max((levels - mipsToSkip), 1U));
223 SetSize(0, width, height, format);
224 }
225 else
226 {
227 if (!object_.ptr_)
228 {
229 //URHO3D_LOGERROR("Texture array layer 0 must be loaded first");
230 return false;
231 }
232 if (width != width_ || height != height_ || format != format_)
233 {
234 URHO3D_LOGERROR("Texture array layer does not match size or format of layer 0");
235 return false;
236 }
237 }
238
239 for (unsigned i = 0; i < levels_ && i < levels - mipsToSkip; ++i)
240 {
241 CompressedLevel level = image->GetCompressedLevel(i + mipsToSkip);
242 if (!needDecompress)
243 {
244 SetData(layer, i, 0, 0, level.width_, level.height_, level.data_);
245 memoryUse += level.rows_ * level.rowSize_;
246 }
247 else
248 {
249 unsigned char* rgbaData = new unsigned char[level.width_ * level.height_ * 4];
250 level.Decompress(rgbaData);
251 SetData(layer, i, 0, 0, level.width_, level.height_, rgbaData);
252 memoryUse += level.width_ * level.height_ * 4;
253 delete[] rgbaData;
254 }
255 }
256 }
257
258 layerMemoryUse_[layer] = memoryUse;
259 unsigned totalMemoryUse = sizeof(Texture2DArray) + layerMemoryUse_.Capacity() * sizeof(unsigned);
260 for (unsigned i = 0; i < layers_; ++i)
261 totalMemoryUse += layerMemoryUse_[i];
262 SetMemoryUse(totalMemoryUse);
263
264 return true;
265 }
266
GetData(unsigned layer,unsigned level,void * dest) const267 bool Texture2DArray::GetData(unsigned layer, unsigned level, void* dest) const
268 {
269 URHO3D_LOGERROR("Texture2DArray not supported on Direct3D9, can not get data");
270 return false;
271 }
272
Create()273 bool Texture2DArray::Create()
274 {
275 Release();
276
277 if (!graphics_ || !width_ || !height_ || !layers_)
278 return false;
279
280 URHO3D_LOGERROR("Texture2DArray not supported on Direct3D9, can not create");
281 return false;
282 }
283
284 }
285