PageRenderTime 52ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/DXGifRenderWP8/GifRenderer.cpp

https://github.com/hippiehunter/Baconography
C++ | 315 lines | 264 code | 51 blank | 0 comment | 47 complexity | 3c61355eaa179d8ddd0b4e44792a9cb2 MD5 | raw file
  1. #include "GifRenderer.h"
  2. #include "SpriteBatch.h"
  3. using namespace DXGifRenderWP8;
  4. using namespace Platform;
  5. using namespace DirectX;
  6. using std::uint8_t;
  7. using Microsoft::WRL::ComPtr;
  8. using Windows::Foundation::Rect;
  9. using namespace Microsoft::WRL;
  10. using namespace Windows::Phone::Graphics::Interop;
  11. struct gif_user_data
  12. {
  13. int position;
  14. int length;
  15. uint8_t* data;
  16. };
  17. int istreamReader(GifFileType * gft, GifByteType * buf, int length)
  18. {
  19. auto egi = reinterpret_cast<gif_user_data*>(gft->UserData);
  20. if (egi->position == egi->length) return 0;
  21. if (egi->position + length == egi->length) length = egi->length - egi->position;
  22. memcpy(buf, egi->data + egi->position, length);
  23. egi->position += length;
  24. return length;
  25. }
  26. struct bgraColor
  27. {
  28. uint8_t blue;
  29. uint8_t green;
  30. uint8_t red;
  31. uint8_t alpha;
  32. };
  33. void mapRasterBits(uint8_t* rasterBits, std::unique_ptr<uint32_t>& targetFrame, ColorMapObject * colorMap, int top, int left, int bottom, int right, int width, int32_t transparencyColor)
  34. {
  35. int i = 0;
  36. for (int y = top; y < bottom; y++)
  37. {
  38. for (int x = left; x < right; x++)
  39. {
  40. int offset = y * width + x;
  41. int index = rasterBits[i];
  42. if (transparencyColor == -1||
  43. transparencyColor != index)
  44. {
  45. auto& gifColor = colorMap->Colors[index];
  46. bgraColor color = { gifColor.Blue, gifColor.Green, gifColor.Red, (uint8_t)255};
  47. memcpy(targetFrame.get() + offset, &color, 4);
  48. }
  49. i++;
  50. }
  51. }
  52. }
  53. void loadTexture(ID3D11Device1* d3dDevice, ID3D11DeviceContext1* context, std::unique_ptr<uint32_t>& buffer, int width, int height,
  54. Microsoft::WRL::ComPtr<ID3D11Texture2D>& preRendered, Microsoft::WRL::ComPtr<ID3D11ShaderResourceView>& resource)
  55. {
  56. CD3D11_TEXTURE2D_DESC textureDesc(
  57. DXGI_FORMAT_B8G8R8A8_UNORM,
  58. width, //picture width
  59. height,
  60. 1, 1);
  61. D3D11_SUBRESOURCE_DATA data;
  62. data.pSysMem = buffer.get();
  63. data.SysMemPitch = 4 * width;
  64. data.SysMemSlicePitch = 0;
  65. DXGifRenderWP8::ThrowIfFailed(d3dDevice->CreateTexture2D(&textureDesc, &data, &preRendered));
  66. D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc;
  67. memset( &SRVDesc, 0, sizeof( SRVDesc ) );
  68. SRVDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
  69. SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
  70. SRVDesc.Texture2D.MipLevels = 1;
  71. DXGifRenderWP8::ThrowIfFailed(d3dDevice->CreateShaderResourceView(preRendered.Get(), &SRVDesc, &resource));
  72. }
  73. void loadGifFrames(GifFileType* gifFile, std::vector<GifFrame>& frames, ID3D11Device1* d3dDevice, ID3D11DeviceContext1* context)
  74. {
  75. UINT width = gifFile->SWidth;
  76. UINT height = gifFile->SHeight;
  77. int loopCount = 0;
  78. bool hasLoop = true;
  79. for(int i = 0; i < gifFile->ImageCount; i++)
  80. {
  81. uint32_t delay ;
  82. DISPOSAL_METHODS disposal;
  83. int32_t transparentColor = -1;
  84. auto extensionBlocks = gifFile->SavedImages[i].ExtensionBlocks;
  85. for(int ext = 0; ext < gifFile->SavedImages[i].ExtensionBlockCount; ext++)
  86. {
  87. if(extensionBlocks[ext].Function == 0xF9)
  88. {
  89. GraphicsControlBlock gcb;
  90. DGifExtensionToGCB(extensionBlocks[ext].ByteCount, extensionBlocks[ext].Bytes, &gcb);
  91. UIntMult(gcb.DelayTime, 10, &delay);
  92. if (delay < 20)
  93. {
  94. delay = 100;
  95. }
  96. disposal = (DISPOSAL_METHODS)gcb.DisposalMode;
  97. transparentColor = gcb.TransparentColor;
  98. }
  99. }
  100. auto& imageDesc = gifFile->SavedImages[i].ImageDesc;
  101. int right = imageDesc.Left + imageDesc.Width;
  102. int bottom = imageDesc.Top + imageDesc.Height;
  103. int top = imageDesc.Top;
  104. int left = imageDesc.Left;
  105. frames.push_back(GifFrame());
  106. auto& frame = frames.back();
  107. frame.transparentColor = transparentColor;
  108. frame.height = height;
  109. frame.width = width;
  110. frame.delay = delay;
  111. frame.top = top;
  112. frame.bottom = bottom;
  113. frame.right = right;
  114. frame.left = left;
  115. frame.imageData = gifFile->SavedImages + i;
  116. frame.disposal = disposal;
  117. }
  118. }
  119. void loadGifFrame(GifFileType* gifFile, GifFrame& frame, std::unique_ptr<uint32_t>& buffer, int currentFrame, int targetFrame)
  120. {
  121. UINT width = gifFile->SWidth;
  122. UINT height = gifFile->SHeight;
  123. int loopCount = 0;
  124. bool hasLoop = true;
  125. bgraColor bgColor;
  126. if(gifFile->SColorMap != nullptr)
  127. {
  128. auto color = gifFile->SColorMap->Colors[gifFile->SBackGroundColor];
  129. bgColor.red = color.Red;
  130. bgColor.green = color.Green;
  131. bgColor.blue = color.Blue;
  132. bgColor.alpha = 255;
  133. }
  134. std::unique_ptr<uint32_t> lastFrame = nullptr;
  135. if(buffer == nullptr || targetFrame == 0 || currentFrame > targetFrame)
  136. {
  137. if(buffer == nullptr)
  138. {
  139. buffer = std::unique_ptr<uint32_t>(new uint32_t[width * height]);
  140. currentFrame = 0;
  141. }
  142. if(currentFrame > targetFrame)
  143. currentFrame = 0;
  144. uint8_t* bufPtr = (uint8_t*)buffer.get();
  145. uint8_t* lastFramePtr = (uint8_t*)lastFrame.get();
  146. for (int y = 0; y < height; y++)
  147. {
  148. for (int x = 0; x < width; x++)
  149. {
  150. int offset = y * width + x;
  151. memcpy(buffer.get() + offset, &bgColor, 4);
  152. }
  153. }
  154. }
  155. for(int i = currentFrame; i < gifFile->ImageCount && i <= targetFrame; i++)
  156. {
  157. auto decodeFrame = frame.imageData;
  158. auto disposal = frame.disposal;
  159. auto colorMap = (decodeFrame->ImageDesc.ColorMap != nullptr ? decodeFrame->ImageDesc.ColorMap : (gifFile->SColorMap != nullptr ? gifFile->SColorMap : nullptr));
  160. if(disposal == DISPOSAL_METHODS::DM_PREVIOUS)
  161. {
  162. if(lastFrame == nullptr)
  163. lastFrame = std::unique_ptr<uint32_t>(new uint32_t[width * height]);
  164. memcpy(lastFrame.get(), buffer.get(), width * height * sizeof(uint32_t));
  165. }
  166. mapRasterBits(decodeFrame->RasterBits, buffer, colorMap, frame.top, frame.left, frame.bottom, frame.right, width, frame.transparentColor);
  167. switch(disposal)
  168. {
  169. case DISPOSAL_METHODS::DM_BACKGROUND:
  170. for (int y = 0; y < height; y++)
  171. {
  172. for (int x = 0; x < width; x++)
  173. {
  174. int offset = y * width + x;
  175. memcpy(buffer.get() + offset, &bgColor, 4);
  176. }
  177. }
  178. break;
  179. case DISPOSAL_METHODS::DM_PREVIOUS:
  180. memcpy(buffer.get(), lastFrame.get(), width * height * sizeof(uint32_t));
  181. break;
  182. }
  183. }
  184. }
  185. GifRenderer::GifRenderer(GifFileType* gifFile)
  186. {
  187. _gifFile = gifFile;
  188. _lastFrame = 0;
  189. _currentFrame = 0;
  190. _startedRendering = false;
  191. }
  192. bool GifRenderer::Update(float total, float delta)
  193. {
  194. double msDelta = ((double)total) * 1000;
  195. double accountedFor = 0;
  196. int i = 0;
  197. for(; accountedFor < msDelta ;i++)
  198. {
  199. if(i >= _frames.size())
  200. i = 0;
  201. accountedFor += _frames[i].delay;
  202. }
  203. auto newFrame = max(i - 1, 0);
  204. if(newFrame != _currentFrame || _currentFrame == 0)
  205. {
  206. _currentFrame = newFrame;
  207. _startedRendering = true;
  208. return true;
  209. }
  210. else
  211. {
  212. if(!_startedRendering)
  213. {
  214. _startedRendering = true;
  215. return true;
  216. }
  217. else
  218. return false;
  219. }
  220. }
  221. void GifRenderer::Render()
  222. {
  223. auto& frame = _frames[_currentFrame];
  224. loadGifFrame(_gifFile, frame, _buffer, _lastFrame, _currentFrame);
  225. _lastFrame = _currentFrame;
  226. loadTexture(m_d3dDevice.Get(), m_d3dContext.Get(), _buffer, frame.width, frame.height, preRendered, resource);
  227. if(_spriteBatch == nullptr)
  228. _spriteBatch = std::unique_ptr<SpriteBatch>(new DirectX::SpriteBatch(m_d3dContext.Get()));
  229. const float white[] = { 1.0f, 1.0f, 1.0f , 1.0f };
  230. m_d3dContext->ClearRenderTargetView(
  231. m_renderTargetView.Get(),
  232. white
  233. );
  234. m_d3dContext->ClearDepthStencilView(
  235. m_depthStencilView.Get(),
  236. D3D11_CLEAR_DEPTH,
  237. 1.0f,
  238. 0
  239. );
  240. m_d3dContext->OMSetRenderTargets(
  241. 1,
  242. m_renderTargetView.GetAddressOf(),
  243. m_depthStencilView.Get()
  244. );
  245. _spriteBatch->Begin();
  246. RECT rect = { 0, 0, frame.width, frame.height};
  247. _spriteBatch->Draw(resource.Get(), rect, Colors::White);
  248. _spriteBatch->End();
  249. }
  250. void GifRenderer::CreateDeviceResources()
  251. {
  252. Direct3DBase::CreateDeviceResources();
  253. try
  254. {
  255. if(_gifFile != nullptr)
  256. {
  257. loadGifFrames(_gifFile, _frames, m_d3dDevice.Get(), m_d3dContext.Get());
  258. }
  259. }
  260. catch(...)
  261. {
  262. throw ref new Platform::FailureException("error loading gif");
  263. }
  264. }