Refactor GifImage

This commit is contained in:
Nomango 2019-08-23 13:00:43 +08:00
parent 66558a3bc4
commit a5fe64fa2c
13 changed files with 615 additions and 615 deletions

View File

@ -30,7 +30,6 @@ namespace kiwano
, next_index_(0) , next_index_(0)
, total_loop_count_(1) , total_loop_count_(1)
, loop_count_(0) , loop_count_(0)
, disposal_type_(DisposalType::Unknown)
{ {
} }
@ -45,9 +44,9 @@ namespace kiwano
Load(res); Load(res);
} }
GifSprite::GifSprite(GifImage texture) GifSprite::GifSprite(GifImage gif)
{ {
Load(texture); Load(gif);
} }
bool GifSprite::Load(String const& file_path) bool GifSprite::Load(String const& file_path)
@ -62,24 +61,24 @@ namespace kiwano
return Load(texture); return Load(texture);
} }
bool GifSprite::Load(GifImage texture) bool GifSprite::Load(GifImage gif)
{ {
if (texture.IsValid()) if (gif.IsValid())
{ {
texture_ = texture; gif_ = gif;
next_index_ = 0; next_index_ = 0;
loop_count_ = 0; loop_count_ = 0;
disposal_type_ = DisposalType::None; frame_.disposal_type = GifImage::DisposalType::None;
SetSize(Size{ static_cast<Float32>(texture_.GetWidthInPixels()), static_cast<Float32>(texture_.GetHeightInPixels()) }); SetSize(Size{ static_cast<Float32>(gif_.GetWidthInPixels()), static_cast<Float32>(gif_.GetHeightInPixels()) });
if (!frame_rt_.IsValid()) if (!frame_rt_.IsValid())
{ {
Renderer::GetInstance()->CreateTextureRenderTarget(frame_rt_); Renderer::GetInstance()->CreateTextureRenderTarget(frame_rt_);
} }
if (texture_.GetFramesCount() > 0) if (gif_.GetFramesCount() > 0)
{ {
ComposeNextFrame(); ComposeNextFrame();
} }
@ -90,11 +89,11 @@ namespace kiwano
void GifSprite::OnRender(RenderTarget* rt) void GifSprite::OnRender(RenderTarget* rt)
{ {
if (frame_.IsValid() && rt->CheckVisibility(GetBounds(), GetTransformMatrix())) if (frame_.raw.IsValid() && rt->CheckVisibility(GetBounds(), GetTransformMatrix()))
{ {
PrepareRender(rt); PrepareRender(rt);
rt->DrawTexture(frame_); rt->DrawTexture(frame_.raw, &frame_.rect, nullptr);
} }
} }
@ -102,24 +101,30 @@ namespace kiwano
{ {
Actor::Update(dt); Actor::Update(dt);
if (texture_.IsValid() && animating_) if (gif_.IsValid() && animating_)
{ {
frame_elapsed_ += dt; frame_elapsed_ += dt;
if (frame_delay_ <= frame_elapsed_) if (frame_.delay <= frame_elapsed_)
{ {
frame_delay_ -= frame_elapsed_; frame_.delay -= frame_elapsed_;
frame_elapsed_ = 0; frame_elapsed_ = 0;
ComposeNextFrame(); ComposeNextFrame();
} }
} }
} }
void GifSprite::SetGifImage(GifImage const& gif)
{
gif_ = gif;
RestartAnimation();
}
void GifSprite::RestartAnimation() void GifSprite::RestartAnimation()
{ {
animating_ = true; animating_ = true;
next_index_ = 0; next_index_ = 0;
loop_count_ = 0; loop_count_ = 0;
disposal_type_ = DisposalType::None; frame_.disposal_type = GifImage::DisposalType::None;
} }
void GifSprite::ComposeNextFrame() void GifSprite::ComposeNextFrame()
@ -130,27 +135,27 @@ namespace kiwano
{ {
DisposeCurrentFrame(); DisposeCurrentFrame();
OverlayNextFrame(); OverlayNextFrame();
} while (frame_delay_.IsZero() && !IsLastFrame()); } while (frame_.delay.IsZero() && !IsLastFrame());
animating_ = (!EndOfAnimation() && texture_.GetFramesCount() > 1); animating_ = (!EndOfAnimation() && gif_.GetFramesCount() > 1);
} }
} }
void GifSprite::DisposeCurrentFrame() void GifSprite::DisposeCurrentFrame()
{ {
switch (disposal_type_) switch (frame_.disposal_type)
{ {
case DisposalType::Unknown: case GifImage::DisposalType::Unknown:
case DisposalType::None: case GifImage::DisposalType::None:
break; break;
case DisposalType::Background: case GifImage::DisposalType::Background:
{ {
ClearCurrentFrameArea(); ClearCurrentFrameArea();
break; break;
} }
case DisposalType::Previous: case GifImage::DisposalType::Previous:
{ {
RestoreSavedFrame(); RestoreSavedFrame();
break; break;
@ -163,43 +168,30 @@ namespace kiwano
void GifSprite::OverlayNextFrame() void GifSprite::OverlayNextFrame()
{ {
Texture raw_texture; Renderer::GetInstance()->CreateGifImageFrame(frame_, gif_, next_index_);
HRESULT hr = texture_.GetRawFrame(next_index_, raw_texture, frame_rect_, frame_delay_, disposal_type_);
if (SUCCEEDED(hr)) if (frame_.disposal_type == GifImage::DisposalType::Previous)
{ {
if (disposal_type_ == DisposalType::Previous) SaveComposedFrame();
{
SaveComposedFrame();
}
} }
if (SUCCEEDED(hr)) if (frame_rt_.IsValid())
{ {
frame_rt_.BeginDraw(); frame_rt_.BeginDraw();
if (next_index_ == 0) if (next_index_ == 0)
{ {
// ÖØÐ»æÖƱ³¾°
frame_rt_.Clear(texture_.GetBackgroundColor());
loop_count_++; loop_count_++;
} }
frame_rt_.DrawTexture(raw_texture, nullptr, &frame_rect_); frame_rt_.DrawTexture(frame_.raw, nullptr, &frame_.rect);
frame_rt_.EndDraw(); frame_rt_.EndDraw();
}
if (SUCCEEDED(hr))
{
Texture frame_to_render = frame_rt_.GetOutput(); Texture frame_to_render = frame_rt_.GetOutput();
if (frame_to_render.IsValid())
hr = frame_to_render.IsValid() ? S_OK : E_FAIL;
if (SUCCEEDED(hr))
{ {
frame_ = frame_to_render; frame_.raw = frame_to_render;
next_index_ = (++next_index_) % texture_.GetFramesCount(); next_index_ = (++next_index_) % gif_.GetFramesCount();
} }
} }
@ -212,8 +204,6 @@ namespace kiwano
{ {
done_cb_(); done_cb_();
} }
ThrowIfFailed(hr);
} }
void GifSprite::SaveComposedFrame() void GifSprite::SaveComposedFrame()
@ -270,8 +260,8 @@ namespace kiwano
{ {
frame_rt_.BeginDraw(); frame_rt_.BeginDraw();
frame_rt_.PushClipRect(frame_rect_); frame_rt_.PushClipRect(frame_.rect);
frame_rt_.Clear(texture_.GetBackgroundColor()); frame_rt_.Clear();
frame_rt_.PopClipRect(); frame_rt_.PopClipRect();
return frame_rt_.EndDraw(); return frame_rt_.EndDraw();

View File

@ -31,7 +31,6 @@ namespace kiwano
: public Actor : public Actor
{ {
public: public:
using DisposalType = GifImage::DisposalType;
using LoopDoneCallback = Function<void(Int32)>; using LoopDoneCallback = Function<void(Int32)>;
using DoneCallback = Function<void()>; using DoneCallback = Function<void()>;
@ -46,7 +45,7 @@ namespace kiwano
); );
GifSprite( GifSprite(
GifImage texture GifImage gif
); );
bool Load( bool Load(
@ -58,7 +57,7 @@ namespace kiwano
); );
bool Load( bool Load(
GifImage texture GifImage gif
); );
// 设置 GIF 动画循环次数 // 设置 GIF 动画循环次数
@ -70,12 +69,17 @@ namespace kiwano
// 设置 GIF 动画结束回调函数 // 设置 GIF 动画结束回调函数
inline void SetDoneCallback(DoneCallback const& cb) { done_cb_ = cb; } inline void SetDoneCallback(DoneCallback const& cb) { done_cb_ = cb; }
// ÉèÖà GIF ͼÏñ
void SetGifImage(GifImage const& gif);
// 重新播放动画 // 重新播放动画
void RestartAnimation(); void RestartAnimation();
inline LoopDoneCallback GetLoopDoneCallback() const { return loop_cb_; } inline LoopDoneCallback GetLoopDoneCallback() const { return loop_cb_; }
inline DoneCallback GetDoneCallback() const { return done_cb_; } inline DoneCallback GetDoneCallback() const { return done_cb_; }
inline GifImage const& GetGifImage() const { return gif_; }
void OnRender(RenderTarget* rt) override; void OnRender(RenderTarget* rt) override;
@ -103,14 +107,11 @@ namespace kiwano
Int32 total_loop_count_; Int32 total_loop_count_;
Int32 loop_count_; Int32 loop_count_;
UInt32 next_index_; UInt32 next_index_;
Duration frame_delay_;
Duration frame_elapsed_; Duration frame_elapsed_;
DisposalType disposal_type_;
LoopDoneCallback loop_cb_; LoopDoneCallback loop_cb_;
DoneCallback done_cb_; DoneCallback done_cb_;
GifImage texture_; GifImage gif_;
Texture frame_; GifImage::Frame frame_;
Rect frame_rect_;
Texture saved_frame_; Texture saved_frame_;
TextureRenderTarget frame_rt_; TextureRenderTarget frame_rt_;
}; };

View File

@ -20,6 +20,7 @@
#include "Window.h" #include "Window.h"
#include "Logger.h" #include "Logger.h"
#include "../platform/Application.h"
#define WINDOW_FIXED_STYLE WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX #define WINDOW_FIXED_STYLE WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX
#define WINDOW_RESIZABLE_STYLE WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_SIZEBOX | WS_MAXIMIZEBOX #define WINDOW_RESIZABLE_STYLE WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_SIZEBOX | WS_MAXIMIZEBOX
@ -39,6 +40,16 @@ namespace kiwano
void RestoreResolution(WCHAR* device_name); void RestoreResolution(WCHAR* device_name);
} }
WindowConfig::WindowConfig(String const& title, UInt32 width, UInt32 height, UInt32 icon, bool resizable, bool fullscreen)
: title(title)
, width(width)
, height(height)
, icon(icon)
, resizable(resizable)
, fullscreen(fullscreen)
{
}
Window::Window() Window::Window()
: handle_(nullptr) : handle_(nullptr)
, width_(0) , width_(0)
@ -68,7 +79,7 @@ namespace kiwano
} }
} }
void Window::Init(String const& title, Int32 width, Int32 height, UInt32 icon, bool resizable, bool fullscreen, WNDPROC proc) void Window::Init(WindowConfig const& config, WNDPROC proc)
{ {
HINSTANCE hinst = GetModuleHandleW(nullptr); HINSTANCE hinst = GetModuleHandleW(nullptr);
WNDCLASSEX wcex = { 0 }; WNDCLASSEX wcex = { 0 };
@ -84,9 +95,10 @@ namespace kiwano
wcex.lpszMenuName = nullptr; wcex.lpszMenuName = nullptr;
wcex.hCursor = ::LoadCursorW(hinst, IDC_ARROW); wcex.hCursor = ::LoadCursorW(hinst, IDC_ARROW);
if (icon) if (config.icon)
{ {
wcex.hIcon = (HICON)::LoadImageW(hinst, MAKEINTRESOURCE(icon), IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE); wcex.hIcon = (HICON)::LoadImageW(hinst, MAKEINTRESOURCE(config.icon), IMAGE_ICON, 0, 0,
LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
} }
::RegisterClassExW(&wcex); ::RegisterClassExW(&wcex);
@ -105,22 +117,24 @@ namespace kiwano
device_name_ = new WCHAR[len + 1]; device_name_ = new WCHAR[len + 1];
lstrcpyW(device_name_, monitor_info_ex.szDevice); lstrcpyW(device_name_, monitor_info_ex.szDevice);
UInt32 width = config.width;
UInt32 height = config.height;
Int32 left = -1; Int32 left = -1;
Int32 top = -1; Int32 top = -1;
resizable_ = resizable; resizable_ = config.resizable;
is_fullscreen_ = fullscreen; is_fullscreen_ = config.fullscreen;
if (is_fullscreen_) if (is_fullscreen_)
{ {
top = monitor_info_ex.rcMonitor.top; top = monitor_info_ex.rcMonitor.top;
left = monitor_info_ex.rcMonitor.left; left = monitor_info_ex.rcMonitor.left;
if (width > monitor_info_ex.rcWork.right - left) if (width > static_cast<UInt32>(monitor_info_ex.rcWork.right - left))
width = monitor_info_ex.rcWork.right - left; width = static_cast<UInt32>(monitor_info_ex.rcWork.right - left);
if (height > monitor_info_ex.rcWork.bottom - top) if (height > static_cast<UInt32>(monitor_info_ex.rcWork.bottom - top))
height = monitor_info_ex.rcWork.bottom - top; height = static_cast<UInt32>(monitor_info_ex.rcWork.bottom - top);
} }
else else
{ {
@ -145,7 +159,7 @@ namespace kiwano
handle_ = ::CreateWindowExW( handle_ = ::CreateWindowExW(
is_fullscreen_ ? WS_EX_TOPMOST : 0, is_fullscreen_ ? WS_EX_TOPMOST : 0,
KGE_WND_CLASS_NAME, KGE_WND_CLASS_NAME,
title.c_str(), config.title.c_str(),
GetWindowStyle(), GetWindowStyle(),
left, left,
top, top,
@ -417,4 +431,5 @@ namespace kiwano
::ChangeDisplaySettingsExW(device_name, NULL, NULL, 0, NULL); ::ChangeDisplaySettingsExW(device_name, NULL, NULL, 0, NULL);
} }
} }
} }

View File

@ -38,6 +38,26 @@ namespace kiwano
SizeWE, SizeWE,
}; };
// 窗口设置
struct WindowConfig
{
String title; // 标题
UInt32 width; // 宽度
UInt32 height; // 高度
UInt32 icon; // 图标资源 ID
bool resizable; // 窗口大小可拉伸
bool fullscreen; // 全屏模式
WindowConfig(
String const& title = L"Kiwano Game",
UInt32 width = 640,
UInt32 height = 480,
UInt32 icon = 0,
bool resizable = false,
bool fullscreen = false
);
};
// ´°żÚ // ´°żÚ
class KGE_API Window class KGE_API Window
@ -74,15 +94,7 @@ namespace kiwano
void SetCursor(CursorType cursor); void SetCursor(CursorType cursor);
public: public:
void Init( void Init(WindowConfig const& config, WNDPROC proc);
String const& title,
Int32 width,
Int32 height,
UInt32 icon,
bool resizable,
bool fullscreen,
WNDPROC proc
);
void Prepare(); void Prepare();

View File

@ -1,5 +1,5 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Compile-time options for Kiwano // Compile-time configurations for Kiwano
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#pragma once #pragma once

View File

@ -20,12 +20,10 @@
#include "Application.h" #include "Application.h"
#include "modules.h" #include "modules.h"
#include "../base/Window.h"
#include "../base/Logger.h" #include "../base/Logger.h"
#include "../base/input.h" #include "../base/input.h"
#include "../base/Director.h" #include "../base/Director.h"
#include "../renderer/TextureCache.h" #include "../renderer/TextureCache.h"
#include "../renderer/Renderer.h"
#include "../utils/ResourceCache.h" #include "../utils/ResourceCache.h"
#include <windowsx.h> // GET_X_LPARAM, GET_Y_LPARAM #include <windowsx.h> // GET_X_LPARAM, GET_Y_LPARAM
#include <imm.h> // ImmAssociateContext #include <imm.h> // ImmAssociateContext
@ -43,17 +41,19 @@ namespace kiwano
Queue<FunctionToPerform> functions_to_perform_; Queue<FunctionToPerform> functions_to_perform_;
} }
Options::Options(String const& title, Int32 width, Int32 height, UInt32 icon, Color clear_color, bool vsync, bool resizable, bool fullscreen, bool debug) Config::Config(String const& title, UInt32 width, UInt32 height, UInt32 icon)
: title(title) {
, width(width) window.title = title;
, height(height) window.width = width;
, icon(icon) window.height = height;
, clear_color(clear_color) window.icon = icon;
, vsync(vsync) }
, resizable(resizable)
, fullscreen(fullscreen) Config::Config(WindowConfig const& wnd_config, RenderConfig const& render_config)
, debug(debug) {
{} window = wnd_config;
render = render_config;
}
} }
namespace kiwano namespace kiwano
@ -79,20 +79,10 @@ namespace kiwano
::CoUninitialize(); ::CoUninitialize();
} }
void Application::Init(const Options& options) void Application::Init(const Config& config)
{ {
Window::GetInstance()->Init( Window::GetInstance()->Init(config.window, Application::WndProc);
options.title, Renderer::GetInstance()->Init(config.render);
options.width,
options.height,
options.icon,
options.resizable,
options.fullscreen,
Application::WndProc
);
Renderer::GetInstance()->SetClearColor(options.clear_color);
Renderer::GetInstance()->SetVSyncEnabled(options.vsync);
// Setup all components // Setup all components
for (Component* c : components_) for (Component* c : components_)
@ -100,7 +90,7 @@ namespace kiwano
c->SetupComponent(); c->SetupComponent();
} }
if (options.debug) if (config.debug)
{ {
Director::GetInstance()->ShowDebugInfo(true); Director::GetInstance()->ShowDebugInfo(true);
Renderer::GetInstance()->SetCollectingStatus(true); Renderer::GetInstance()->SetCollectingStatus(true);
@ -299,10 +289,11 @@ namespace kiwano
LRESULT CALLBACK Application::WndProc(HWND hwnd, UInt32 msg, WPARAM wparam, LPARAM lparam) LRESULT CALLBACK Application::WndProc(HWND hwnd, UInt32 msg, WPARAM wparam, LPARAM lparam)
{ {
Application * app = reinterpret_cast<Application*>(static_cast<LONG_PTR>(::GetWindowLongPtrW(hwnd, GWLP_USERDATA))); Application* app = reinterpret_cast<Application*>(static_cast<LONG_PTR>(::GetWindowLongPtrW(hwnd, GWLP_USERDATA)));
if (app == nullptr)
if (!app) {
return ::DefWindowProcW(hwnd, msg, wparam, lparam); return ::DefWindowProcW(hwnd, msg, wparam, lparam);
}
// Handle Message // Handle Message
for (Component* c : app->components_) for (Component* c : app->components_)

View File

@ -23,32 +23,27 @@
#include "../base/time.h" #include "../base/time.h"
#include "../base/Component.h" #include "../base/Component.h"
#include "../base/Event.hpp" #include "../base/Event.hpp"
#include "../renderer/Color.h" #include "../base/Window.h"
#include "../renderer/Renderer.h"
namespace kiwano namespace kiwano
{ {
struct Options struct Config
{ {
String title; // 标题 WindowConfig window; // ´°¿ÚÉèÖÃ
Int32 width; // 宽度 RenderConfig render; // äÖȾÉèÖÃ
Int32 height; // 高度 bool debug; // µ÷ÊÔģʽ
UInt32 icon; // 图标资源 ID
Color clear_color; // 清屏颜色
bool vsync; // 垂直同步
bool resizable; // 窗口大小可拉伸
bool fullscreen; // 全屏模式
bool debug; // 调试模式
Options( Config(
String const& title = L"Kiwano Game", String const& title = L"Kiwano Game",
Int32 width = 640, UInt32 width = 640,
Int32 height = 480, UInt32 height = 480,
UInt32 icon = 0, UInt32 icon = 0
Color clear_color = Color::Black, );
bool vsync = true,
bool resizable = false, Config(
bool fullscreen = false, WindowConfig const& wnd_config,
bool debug = false RenderConfig const& render_config = RenderConfig()
); );
}; };
@ -64,7 +59,7 @@ namespace kiwano
// 初始化 // 初始化
void Init( void Init(
Options const& options = Options{} Config const& config = Config()
); );
// 初始化成功时 // 初始化成功时

View File

@ -28,7 +28,6 @@ namespace kiwano
: frames_count_(0) : frames_count_(0)
, width_in_pixels_(0) , width_in_pixels_(0)
, height_in_pixels_(0) , height_in_pixels_(0)
, bg_color_{}
{ {
} }
@ -82,15 +81,6 @@ namespace kiwano
HRESULT GifImage::GetGlobalMetadata() HRESULT GifImage::GetGlobalMetadata()
{ {
UInt32 width = 0;
UInt32 height = 0;
PROPVARIANT prop_val;
::PropVariantInit(&prop_val);
ComPtr<IWICMetadataQueryReader> metadata_reader;
// 获取帧数量
HRESULT hr = decoder_ ? S_OK : E_FAIL; HRESULT hr = decoder_ ? S_OK : E_FAIL;
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
@ -100,317 +90,91 @@ namespace kiwano
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
ComPtr<IWICMetadataQueryReader> metadata_reader;
hr = decoder_->GetMetadataQueryReader(&metadata_reader); hr = decoder_->GetMetadataQueryReader(&metadata_reader);
}
if (SUCCEEDED(hr))
{
// 获取背景色
if (FAILED(GetBackgroundColor(metadata_reader.get())))
{
// 如果未能获得颜色,则默认为透明
bg_color_ = Color(0, 0.f);
}
}
// 获取全局 frame 大小
if (SUCCEEDED(hr))
{
// 获取宽度
hr = metadata_reader->GetMetadataByName(L"/logscrdesc/Width", &prop_val);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL); UInt32 width = 0;
UInt32 height = 0;
PROPVARIANT prop_val;
::PropVariantInit(&prop_val);
// 获取全局 frame 大小
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
width = prop_val.uiVal; // 获取宽度
} hr = metadata_reader->GetMetadataByName(L"/logscrdesc/Width", &prop_val);
::PropVariantClear(&prop_val);
}
}
if (SUCCEEDED(hr))
{
// 获取高度
hr = metadata_reader->GetMetadataByName(L"/logscrdesc/Height", &prop_val);
if (SUCCEEDED(hr))
{
hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL);
if (SUCCEEDED(hr))
{
height = prop_val.uiVal;
}
::PropVariantClear(&prop_val);
}
}
if (SUCCEEDED(hr))
{
// 获得像素纵横比
hr = metadata_reader->GetMetadataByName(L"/logscrdesc/PixelAspectRatio", &prop_val);
if (SUCCEEDED(hr))
{
hr = (prop_val.vt == VT_UI1 ? S_OK : E_FAIL);
if (SUCCEEDED(hr))
{
if (prop_val.bVal != 0)
{
// 需要计算比率
// 最高像素 14最宽像素 41增量为 1/64
Float32 pixel_asp_ratio = (prop_val.bVal + 15.f) / 64.f;
// 根据像素长宽比计算像素中的图像宽度和高度,只缩小图像
if (pixel_asp_ratio > 1.f)
{
width_in_pixels_ = width;
height_in_pixels_ = static_cast<UInt32>(height / pixel_asp_ratio);
}
else
{
width_in_pixels_ = static_cast<UInt32>(width * pixel_asp_ratio);
height_in_pixels_ = height;
}
}
else
{
// 值为 0, 所以像素比为 1
width_in_pixels_ = width;
height_in_pixels_ = height;
}
}
::PropVariantClear(&prop_val);
}
}
::PropVariantClear(&prop_val);
return hr;
}
HRESULT GifImage::GetBackgroundColor(ComPtr<IWICMetadataQueryReader> metadata_reader)
{
UChar bg_index = 0;
WICColor bgcolors[256];
UInt32 colors_copied = 0;
ComPtr<IWICPalette> wic_palette;
PROPVARIANT prop_val;
PropVariantInit(&prop_val);
HRESULT hr = metadata_reader->GetMetadataByName(L"/logscrdesc/GlobalColorTableFlag", &prop_val);
if (SUCCEEDED(hr))
{
hr = (prop_val.vt != VT_BOOL || !prop_val.boolVal) ? E_FAIL : S_OK;
::PropVariantClear(&prop_val);
}
if (SUCCEEDED(hr))
{
hr = metadata_reader->GetMetadataByName(L"/logscrdesc/BackgroundColorIndex", &prop_val);
if (SUCCEEDED(hr))
{
hr = (prop_val.vt != VT_UI1) ? E_FAIL : S_OK;
if (SUCCEEDED(hr))
{
bg_index = prop_val.bVal;
}
::PropVariantClear(&prop_val);
}
}
if (SUCCEEDED(hr))
{
auto factory = Renderer::GetInstance()->GetD2DDeviceResources()->GetWICImagingFactory();
hr = factory->CreatePalette(&wic_palette);
}
if (SUCCEEDED(hr))
{
hr = decoder_->CopyPalette(wic_palette.get());
}
if (SUCCEEDED(hr))
{
hr = wic_palette->GetColors(
ARRAYSIZE(bgcolors),
bgcolors,
&colors_copied);
}
if (SUCCEEDED(hr))
{
hr = (bg_index >= colors_copied) ? E_FAIL : S_OK;
}
if (SUCCEEDED(hr))
{
// 转换为 ARGB 格式
Float32 alpha = (bgcolors[bg_index] >> 24) / 255.f;
bg_color_ = Color(bgcolors[bg_index], alpha);
}
return hr;
}
HRESULT GifImage::GetRawFrame(UInt32 frame_index, Texture& raw_frame, Rect& frame_rect, Duration& delay, DisposalType& disposal_type)
{
ComPtr<IWICFormatConverter> converter;
ComPtr<IWICBitmapFrameDecode> wic_frame;
ComPtr<IWICMetadataQueryReader> metadata_reader;
PROPVARIANT prop_val;
PropVariantInit(&prop_val);
// Retrieve the current frame
HRESULT hr = decoder_->GetFrame(frame_index, &wic_frame);
if (SUCCEEDED(hr))
{
// Format convert to 32bppPBGRA which D2D expects
auto factory = Renderer::GetInstance()->GetD2DDeviceResources()->GetWICImagingFactory();
hr = factory->CreateFormatConverter(&converter);
}
if (SUCCEEDED(hr))
{
hr = converter->Initialize(
wic_frame.get(),
GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone,
nullptr,
0.f,
WICBitmapPaletteTypeCustom);
}
if (SUCCEEDED(hr))
{
auto ctx = Renderer::GetInstance()->GetD2DDeviceResources()->GetDeviceContext();
// Create a D2DBitmap from IWICBitmapSource
ComPtr<ID2D1Bitmap> raw_bitmap;
hr = ctx->CreateBitmapFromWicBitmap(
converter.get(),
nullptr,
&raw_bitmap
);
if (SUCCEEDED(hr))
{
raw_frame.SetBitmap(raw_bitmap);
}
}
if (SUCCEEDED(hr))
{
// Get Metadata Query Reader from the frame
hr = wic_frame->GetMetadataQueryReader(&metadata_reader);
}
// Get the Metadata for the current frame
if (SUCCEEDED(hr))
{
hr = metadata_reader->GetMetadataByName(L"/imgdesc/Left", &prop_val);
if (SUCCEEDED(hr))
{
hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL);
if (SUCCEEDED(hr))
{
frame_rect.left_top.x = static_cast<Float32>(prop_val.uiVal);
}
PropVariantClear(&prop_val);
}
}
if (SUCCEEDED(hr))
{
hr = metadata_reader->GetMetadataByName(L"/imgdesc/Top", &prop_val);
if (SUCCEEDED(hr))
{
hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL);
if (SUCCEEDED(hr))
{
frame_rect.left_top.y = static_cast<Float32>(prop_val.uiVal);
}
PropVariantClear(&prop_val);
}
}
if (SUCCEEDED(hr))
{
hr = metadata_reader->GetMetadataByName(L"/imgdesc/Width", &prop_val);
if (SUCCEEDED(hr))
{
hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL);
if (SUCCEEDED(hr))
{
frame_rect.right_bottom.x = frame_rect.left_top.x + static_cast<Float32>(prop_val.uiVal);
}
PropVariantClear(&prop_val);
}
}
if (SUCCEEDED(hr))
{
hr = metadata_reader->GetMetadataByName(L"/imgdesc/Height", &prop_val);
if (SUCCEEDED(hr))
{
hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL);
if (SUCCEEDED(hr))
{
frame_rect.right_bottom.y = frame_rect.left_top.y + static_cast<Float32>(prop_val.uiVal);
}
PropVariantClear(&prop_val);
}
}
if (SUCCEEDED(hr))
{
hr = metadata_reader->GetMetadataByName(L"/grctlext/Delay", &prop_val);
if (SUCCEEDED(hr))
{
hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL);
if (SUCCEEDED(hr))
{
UInt32 udelay = 0;
hr = UIntMult(prop_val.uiVal, 10, &udelay);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
delay.SetMilliseconds(static_cast<long>(udelay)); hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL);
if (SUCCEEDED(hr))
{
width = prop_val.uiVal;
}
::PropVariantClear(&prop_val);
} }
} }
PropVariantClear(&prop_val);
}
else
{
delay = 0;
}
}
if (SUCCEEDED(hr))
{
hr = metadata_reader->GetMetadataByName(L"/grctlext/Disposal", &prop_val);
if (SUCCEEDED(hr))
{
hr = (prop_val.vt == VT_UI1) ? S_OK : E_FAIL;
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
disposal_type = DisposalType(prop_val.bVal); // 获取高度
hr = metadata_reader->GetMetadataByName(L"/logscrdesc/Height", &prop_val);
if (SUCCEEDED(hr))
{
hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL);
if (SUCCEEDED(hr))
{
height = prop_val.uiVal;
}
::PropVariantClear(&prop_val);
}
}
if (SUCCEEDED(hr))
{
// 获得像素纵横比
hr = metadata_reader->GetMetadataByName(L"/logscrdesc/PixelAspectRatio", &prop_val);
if (SUCCEEDED(hr))
{
hr = (prop_val.vt == VT_UI1 ? S_OK : E_FAIL);
if (SUCCEEDED(hr))
{
if (prop_val.bVal != 0)
{
// 需要计算比率
// 最高像素 14最宽像素 41增量为 1/64
Float32 pixel_asp_ratio = (prop_val.bVal + 15.f) / 64.f;
// 根据像素长宽比计算像素中的图像宽度和高度,只缩小图像
if (pixel_asp_ratio > 1.f)
{
width_in_pixels_ = width;
height_in_pixels_ = static_cast<UInt32>(height / pixel_asp_ratio);
}
else
{
width_in_pixels_ = static_cast<UInt32>(width * pixel_asp_ratio);
height_in_pixels_ = height;
}
}
else
{
// 值为 0, 所以像素比为 1
width_in_pixels_ = width;
height_in_pixels_ = height;
}
}
::PropVariantClear(&prop_val);
}
} }
::PropVariantClear(&prop_val); ::PropVariantClear(&prop_val);
} }
else
{
// 获取 DisposalType 失败,可能图片是只有一帧的图片
disposal_type = DisposalType::Unknown;
}
} }
::PropVariantClear(&prop_val);
return hr; return hr;
} }

View File

@ -43,9 +43,7 @@ namespace kiwano
inline UInt32 GetHeightInPixels() const { return height_in_pixels_; } inline UInt32 GetHeightInPixels() const { return height_in_pixels_; }
inline UInt32 GetFramesCount() const { return frames_count_; } inline UInt32 GetFramesCount() const { return frames_count_; }
inline Color GetBackgroundColor() const { return bg_color_; }
public: public:
enum class DisposalType enum class DisposalType
@ -56,13 +54,15 @@ namespace kiwano
Previous Previous
}; };
HRESULT GetRawFrame( struct Frame
UInt32 frame_index, {
Texture& raw_frame, Duration delay;
Rect& frame_rect, Texture raw;
Duration& delay, Rect rect;
DisposalType& disposal_type DisposalType disposal_type;
);
Frame() : disposal_type(DisposalType::Unknown) {}
};
inline ComPtr<IWICBitmapDecoder> GetDecoder() const { return decoder_; } inline ComPtr<IWICBitmapDecoder> GetDecoder() const { return decoder_; }
@ -71,16 +71,11 @@ namespace kiwano
protected: protected:
HRESULT GetGlobalMetadata(); HRESULT GetGlobalMetadata();
HRESULT GetBackgroundColor(
ComPtr<IWICMetadataQueryReader> metadata_reader
);
protected: protected:
UInt32 frames_count_; UInt32 frames_count_;
UInt32 width_in_pixels_; UInt32 width_in_pixels_;
UInt32 height_in_pixels_; UInt32 height_in_pixels_;
Color bg_color_;
ComPtr<IWICBitmapDecoder> decoder_; ComPtr<IWICBitmapDecoder> decoder_;
}; };
} }

View File

@ -25,6 +25,12 @@
namespace kiwano namespace kiwano
{ {
RenderConfig::RenderConfig(Color clear_color, bool vsync)
: clear_color(clear_color)
, vsync(vsync)
{
}
Renderer::Renderer() Renderer::Renderer()
: hwnd_(nullptr) : hwnd_(nullptr)
, vsync_(true) , vsync_(true)
@ -37,6 +43,12 @@ namespace kiwano
{ {
} }
void Renderer::Init(RenderConfig const& config)
{
SetClearColor(config.clear_color);
SetVSyncEnabled(config.vsync);
}
void Renderer::SetupComponent() void Renderer::SetupComponent()
{ {
KGE_LOG(L"Creating device resources"); KGE_LOG(L"Creating device resources");
@ -253,14 +265,50 @@ namespace kiwano
hr = E_UNEXPECTED; hr = E_UNEXPECTED;
} }
if (!FileUtil::ExistsFile(file_path))
{
KGE_WARNING_LOG(L"Texture file '%s' not found!", file_path.c_str());
hr = E_FAIL;
}
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
ComPtr<ID2D1Bitmap> bitmap; ComPtr<IWICBitmapDecoder> decoder;
hr = d2d_res_->CreateBitmapFromFile(bitmap, file_path); hr = d2d_res_->CreateBitmapDecoderFromFile(decoder, file_path);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
texture.SetBitmap(bitmap); ComPtr<IWICBitmapFrameDecode> source;
hr = decoder->GetFrame(0, &source);
if (SUCCEEDED(hr))
{
ComPtr<IWICFormatConverter> converter;
hr = d2d_res_->CreateBitmapConverter(
converter,
source,
GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone,
nullptr,
0.f,
WICBitmapPaletteTypeMedianCut
);
if (SUCCEEDED(hr))
{
ComPtr<ID2D1Bitmap> bitmap;
hr = d2d_res_->CreateBitmapFromConverter(
bitmap,
nullptr,
converter
);
if (SUCCEEDED(hr))
{
texture.SetBitmap(bitmap);
}
}
}
} }
} }
@ -270,7 +318,7 @@ namespace kiwano
} }
} }
void Renderer::CreateTexture(Texture& texture, Resource const& res) void Renderer::CreateTexture(Texture& texture, Resource const& resource)
{ {
HRESULT hr = S_OK; HRESULT hr = S_OK;
if (!d2d_res_) if (!d2d_res_)
@ -280,12 +328,42 @@ namespace kiwano
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
ComPtr<ID2D1Bitmap> bitmap; ComPtr<IWICBitmapDecoder> decoder;
hr = d2d_res_->CreateBitmapFromResource(bitmap, res); hr = d2d_res_->CreateBitmapDecoderFromResource(decoder, resource);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
texture.SetBitmap(bitmap); ComPtr<IWICBitmapFrameDecode> source;
hr = decoder->GetFrame(0, &source);
if (SUCCEEDED(hr))
{
ComPtr<IWICFormatConverter> converter;
hr = d2d_res_->CreateBitmapConverter(
converter,
source,
GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone,
nullptr,
0.f,
WICBitmapPaletteTypeMedianCut
);
if (SUCCEEDED(hr))
{
ComPtr<ID2D1Bitmap> bitmap;
hr = d2d_res_->CreateBitmapFromConverter(
bitmap,
nullptr,
converter
);
if (SUCCEEDED(hr))
{
texture.SetBitmap(bitmap);
}
}
}
} }
} }
@ -295,7 +373,7 @@ namespace kiwano
} }
} }
void Renderer::CreateGifImage(GifImage& texture, String const& file_path) void Renderer::CreateGifImage(GifImage& gif, String const& file_path)
{ {
HRESULT hr = S_OK; HRESULT hr = S_OK;
if (!d2d_res_) if (!d2d_res_)
@ -312,17 +390,11 @@ namespace kiwano
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
ComPtr<IWICBitmapDecoder> decoder; ComPtr<IWICBitmapDecoder> decoder;
hr = d2d_res_->GetWICImagingFactory()->CreateDecoderFromFilename( hr = d2d_res_->CreateBitmapDecoderFromFile(decoder, file_path);
file_path.c_str(),
nullptr,
GENERIC_READ,
WICDecodeMetadataCacheOnLoad,
&decoder
);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
texture.SetDecoder(decoder); gif.SetDecoder(decoder);
} }
} }
@ -332,7 +404,7 @@ namespace kiwano
} }
} }
void Renderer::CreateGifImage(GifImage& texture, Resource const& res) void Renderer::CreateGifImage(GifImage& gif, Resource const& resource)
{ {
HRESULT hr = S_OK; HRESULT hr = S_OK;
if (!d2d_res_) if (!d2d_res_)
@ -340,37 +412,14 @@ namespace kiwano
hr = E_UNEXPECTED; hr = E_UNEXPECTED;
} }
Resource::Data res_data = res.GetData();
hr = res_data ? S_OK : E_FAIL;
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
ComPtr<IWICStream> stream; ComPtr<IWICBitmapDecoder> decoder;
hr = d2d_res_->GetWICImagingFactory()->CreateStream(&stream); hr = d2d_res_->CreateBitmapDecoderFromResource(decoder, resource);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
hr = stream->InitializeFromMemory( gif.SetDecoder(decoder);
static_cast<WICInProcPointer>(res_data.buffer),
res_data.size
);
}
if (SUCCEEDED(hr))
{
ComPtr<IWICBitmapDecoder> decoder;
hr = d2d_res_->GetWICImagingFactory()->CreateDecoderFromStream(
stream.get(),
nullptr,
WICDecodeMetadataCacheOnLoad,
&decoder
);
if (SUCCEEDED(hr))
{
texture.SetDecoder(decoder);
}
} }
} }
@ -380,6 +429,173 @@ namespace kiwano
} }
} }
void Renderer::CreateGifImageFrame(GifImage::Frame& frame, GifImage const& gif, UInt32 frame_index)
{
HRESULT hr = S_OK;
if (!d2d_res_)
{
hr = E_UNEXPECTED;
}
if (gif.GetDecoder() == nullptr)
{
hr = E_INVALIDARG;
}
if (SUCCEEDED(hr))
{
ComPtr<IWICBitmapFrameDecode> wic_frame;
HRESULT hr = gif.GetDecoder()->GetFrame(frame_index, &wic_frame);
if (SUCCEEDED(hr))
{
ComPtr<IWICFormatConverter> converter;
d2d_res_->CreateBitmapConverter(
converter,
wic_frame,
GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone,
nullptr,
0.f,
WICBitmapPaletteTypeCustom
);
if (SUCCEEDED(hr))
{
ComPtr<ID2D1Bitmap> raw_bitmap;
hr = d2d_res_->CreateBitmapFromConverter(
raw_bitmap,
nullptr,
converter
);
if (SUCCEEDED(hr))
{
frame.raw.SetBitmap(raw_bitmap);
}
}
}
if (SUCCEEDED(hr))
{
PROPVARIANT prop_val;
PropVariantInit(&prop_val);
// Get Metadata Query Reader from the frame
ComPtr<IWICMetadataQueryReader> metadata_reader;
hr = wic_frame->GetMetadataQueryReader(&metadata_reader);
// Get the Metadata for the current frame
if (SUCCEEDED(hr))
{
hr = metadata_reader->GetMetadataByName(L"/imgdesc/Left", &prop_val);
if (SUCCEEDED(hr))
{
hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL);
if (SUCCEEDED(hr))
{
frame.rect.left_top.x = static_cast<Float32>(prop_val.uiVal);
}
PropVariantClear(&prop_val);
}
}
if (SUCCEEDED(hr))
{
hr = metadata_reader->GetMetadataByName(L"/imgdesc/Top", &prop_val);
if (SUCCEEDED(hr))
{
hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL);
if (SUCCEEDED(hr))
{
frame.rect.left_top.y = static_cast<Float32>(prop_val.uiVal);
}
PropVariantClear(&prop_val);
}
}
if (SUCCEEDED(hr))
{
hr = metadata_reader->GetMetadataByName(L"/imgdesc/Width", &prop_val);
if (SUCCEEDED(hr))
{
hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL);
if (SUCCEEDED(hr))
{
frame.rect.right_bottom.x = frame.rect.left_top.x + static_cast<Float32>(prop_val.uiVal);
}
PropVariantClear(&prop_val);
}
}
if (SUCCEEDED(hr))
{
hr = metadata_reader->GetMetadataByName(L"/imgdesc/Height", &prop_val);
if (SUCCEEDED(hr))
{
hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL);
if (SUCCEEDED(hr))
{
frame.rect.right_bottom.y = frame.rect.left_top.y + static_cast<Float32>(prop_val.uiVal);
}
PropVariantClear(&prop_val);
}
}
if (SUCCEEDED(hr))
{
hr = metadata_reader->GetMetadataByName(L"/grctlext/Delay", &prop_val);
if (SUCCEEDED(hr))
{
hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL);
if (SUCCEEDED(hr))
{
UInt32 udelay = 0;
hr = UIntMult(prop_val.uiVal, 10, &udelay);
if (SUCCEEDED(hr))
{
frame.delay.SetMilliseconds(static_cast<long>(udelay));
}
}
PropVariantClear(&prop_val);
}
else
{
frame.delay = 0;
}
}
if (SUCCEEDED(hr))
{
hr = metadata_reader->GetMetadataByName(L"/grctlext/Disposal", &prop_val);
if (SUCCEEDED(hr))
{
hr = (prop_val.vt == VT_UI1) ? S_OK : E_FAIL;
if (SUCCEEDED(hr))
{
frame.disposal_type = GifImage::DisposalType(prop_val.bVal);
}
::PropVariantClear(&prop_val);
}
else
{
frame.disposal_type = GifImage::DisposalType::Unknown;
}
}
::PropVariantClear(&prop_val);
}
}
if (FAILED(hr))
{
KGE_WARNING_LOG(L"Load GIF frame failed with HRESULT of %08X!", hr);
}
}
void Renderer::CreateFontCollection(FontCollection& collection, Vector<String> const& file_paths) void Renderer::CreateFontCollection(FontCollection& collection, Vector<String> const& file_paths)
{ {
HRESULT hr = S_OK; HRESULT hr = S_OK;

View File

@ -39,6 +39,18 @@ namespace kiwano
typedef ID3D11DeviceResources ID3DDeviceResources; typedef ID3D11DeviceResources ID3DDeviceResources;
#endif #endif
// 斡횡<E696A1>
struct RenderConfig
{
Color clear_color; // 헌팁奈<ED8C81>
bool vsync; // 뉩殮谿꼍
RenderConfig(
Color clear_color = Color::Black,
bool vsync = true
);
};
// 分辨率模式 // 分辨率模式
// 分辨率模式决定了将画面渲染到视区上的方式 // 分辨率模式决定了将画面渲染到视区上的方式
// Fixed (固定): 分辨率不随视区改变, 且画面始终与视区边界对齐(默认) // Fixed (固定): 分辨率不随视区改变, 且画面始终与视区边界对齐(默认)
@ -89,17 +101,23 @@ namespace kiwano
void CreateTexture( void CreateTexture(
Texture& texture, Texture& texture,
Resource const& res Resource const& resource
); );
void CreateGifImage( void CreateGifImage(
GifImage& texture, GifImage& gif,
String const& file_path String const& file_path
); );
void CreateGifImage( void CreateGifImage(
GifImage& texture, GifImage& gif,
Resource const& res Resource const& resource
);
void CreateGifImageFrame(
GifImage::Frame& frame,
GifImage const& gif,
UInt32 frame_index
); );
void CreateFontCollection( void CreateFontCollection(
@ -156,6 +174,8 @@ namespace kiwano
); );
public: public:
void Init(RenderConfig const& config);
void SetupComponent() override; void SetupComponent() override;
void DestroyComponent() override; void DestroyComponent() override;

View File

@ -20,7 +20,6 @@
#include "D2DDeviceResources.h" #include "D2DDeviceResources.h"
#include "../../base/Logger.h" #include "../../base/Logger.h"
#include "../../utils/FileUtil.h"
#pragma comment(lib, "d2d1.lib") #pragma comment(lib, "d2d1.lib")
#pragma comment(lib, "dwrite.lib") #pragma comment(lib, "dwrite.lib")
@ -38,14 +37,30 @@ namespace kiwano
HRESULT CreateDeviceIndependentResources(); HRESULT CreateDeviceIndependentResources();
public: public:
HRESULT CreateBitmapFromFile( HRESULT CreateBitmapConverter(
_Out_ ComPtr<ID2D1Bitmap>& bitmap, _Out_ ComPtr<IWICFormatConverter>& converter,
_In_ String const& file_path _In_opt_ ComPtr<IWICBitmapSource> source,
_In_ REFWICPixelFormatGUID format,
WICBitmapDitherType dither,
_In_opt_ ComPtr<IWICPalette> palette,
double alpha_threshold_percent,
WICBitmapPaletteType palette_translate
) override; ) override;
HRESULT CreateBitmapFromResource( HRESULT CreateBitmapFromConverter(
_Out_ ComPtr<ID2D1Bitmap>& bitmap, _Out_ ComPtr<ID2D1Bitmap>& bitmap,
_In_ Resource const& res _In_opt_ const D2D1_BITMAP_PROPERTIES* properties,
_In_ ComPtr<IWICFormatConverter> converter
) override;
HRESULT CreateBitmapDecoderFromFile(
_Out_ ComPtr<IWICBitmapDecoder>& decoder,
const String& file_path
) override;
HRESULT CreateBitmapDecoderFromResource(
_Out_ ComPtr<IWICBitmapDecoder>& decoder,
const Resource& resource
) override; ) override;
HRESULT CreateTextFormat( HRESULT CreateTextFormat(
@ -189,16 +204,16 @@ namespace kiwano
ComPtr<IWICImagingFactory> imaging_factory; ComPtr<IWICImagingFactory> imaging_factory;
ComPtr<IDWriteFactory> dwrite_factory; ComPtr<IDWriteFactory> dwrite_factory;
D2D1_FACTORY_OPTIONS options; D2D1_FACTORY_OPTIONS config;
ZeroMemory(&options, sizeof(D2D1_FACTORY_OPTIONS)); ZeroMemory(&config, sizeof(D2D1_FACTORY_OPTIONS));
#if defined(KGE_DEBUG) && defined(KGE_ENABLE_DX_DEBUG) #if defined(KGE_DEBUG) && defined(KGE_ENABLE_DX_DEBUG)
options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION; config.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION;
#endif #endif
hr = D2D1CreateFactory( hr = D2D1CreateFactory(
D2D1_FACTORY_TYPE_SINGLE_THREADED, D2D1_FACTORY_TYPE_SINGLE_THREADED,
__uuidof(ID2D1Factory1), __uuidof(ID2D1Factory1),
&options, &config,
reinterpret_cast<void**>(&d2d_factory) reinterpret_cast<void**>(&d2d_factory)
); );
@ -310,143 +325,113 @@ namespace kiwano
device_context_->SetTarget(target_bitmap_.get()); device_context_->SetTarget(target_bitmap_.get());
} }
HRESULT D2DDeviceResources::CreateBitmapFromFile(_Out_ ComPtr<ID2D1Bitmap> & bitmap, _In_ String const & file_path) HRESULT D2DDeviceResources::CreateBitmapConverter(_Out_ ComPtr<IWICFormatConverter>& converter, _In_opt_ ComPtr<IWICBitmapSource> source,
_In_ REFWICPixelFormatGUID format, WICBitmapDitherType dither, _In_opt_ ComPtr<IWICPalette> palette, double alpha_threshold_percent,
WICBitmapPaletteType palette_translate
)
{ {
if (!imaging_factory_ || !device_context_) if (!imaging_factory_)
return E_UNEXPECTED; return E_UNEXPECTED;
if (!FileUtil::ExistsFile(file_path)) ComPtr<IWICFormatConverter> output;
HRESULT hr = imaging_factory_->CreateFormatConverter(&output);
if (SUCCEEDED(hr))
{ {
KGE_WARNING_LOG(L"Texture file '%s' not found!", file_path.c_str()); hr = output->Initialize(
return E_FAIL; source.get(),
format,
dither,
palette.get(),
alpha_threshold_percent,
palette_translate
);
} }
ComPtr<IWICBitmapDecoder> decoder; if (SUCCEEDED(hr))
ComPtr<IWICBitmapFrameDecode> source; {
ComPtr<IWICStream> stream; converter = output;
ComPtr<IWICFormatConverter> converter; }
ComPtr<ID2D1Bitmap> bitmap_tmp; return hr;
}
HRESULT D2DDeviceResources::CreateBitmapFromConverter(_Out_ ComPtr<ID2D1Bitmap>& bitmap, _In_opt_ const D2D1_BITMAP_PROPERTIES* properties,
_In_ ComPtr<IWICFormatConverter> converter)
{
if (!device_context_)
return E_UNEXPECTED;
ComPtr<ID2D1Bitmap> output;
HRESULT hr = device_context_->CreateBitmapFromWicBitmap(
converter.get(),
properties,
&output
);
if (SUCCEEDED(hr))
{
bitmap = output;
}
return hr;
}
HRESULT D2DDeviceResources::CreateBitmapDecoderFromFile(_Out_ ComPtr<IWICBitmapDecoder>& decoder, const String& file_path)
{
if (!imaging_factory_)
return E_UNEXPECTED;
ComPtr<IWICBitmapDecoder> decoder_output;
HRESULT hr = imaging_factory_->CreateDecoderFromFilename( HRESULT hr = imaging_factory_->CreateDecoderFromFilename(
file_path.c_str(), file_path.c_str(),
nullptr, nullptr,
GENERIC_READ, GENERIC_READ,
WICDecodeMetadataCacheOnLoad, WICDecodeMetadataCacheOnLoad,
&decoder &decoder_output
); );
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
hr = decoder->GetFrame(0, &source); decoder = decoder_output;
}
if (SUCCEEDED(hr))
{
hr = imaging_factory_->CreateFormatConverter(&converter);
}
if (SUCCEEDED(hr))
{
// 图片格式转换成 32bppPBGRA
hr = converter->Initialize(
source.get(),
GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone,
nullptr,
0.f,
WICBitmapPaletteTypeMedianCut
);
}
if (SUCCEEDED(hr))
{
hr = device_context_->CreateBitmapFromWicBitmap(
converter.get(),
nullptr,
&bitmap_tmp
);
}
if (SUCCEEDED(hr))
{
bitmap = bitmap_tmp;
} }
return hr; return hr;
} }
HRESULT D2DDeviceResources::CreateBitmapFromResource(_Out_ ComPtr<ID2D1Bitmap> & bitmap, _In_ Resource const & res) HRESULT D2DDeviceResources::CreateBitmapDecoderFromResource(_Out_ ComPtr<IWICBitmapDecoder>& decoder, const Resource& resource)
{ {
if (!imaging_factory_ || !device_context_) if (!imaging_factory_)
return E_UNEXPECTED; return E_UNEXPECTED;
ComPtr<IWICBitmapDecoder> decoder; Resource::Data res_data = resource.GetData();
ComPtr<IWICBitmapFrameDecode> source;
ComPtr<IWICStream> stream;
ComPtr<IWICFormatConverter> converter;
ComPtr<ID2D1Bitmap> bitmap_tmp;
// 加载资源
Resource::Data res_data = res.GetData();
HRESULT hr = res_data ? S_OK : E_FAIL; HRESULT hr = res_data ? S_OK : E_FAIL;
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
ComPtr<IWICStream> stream;
hr = imaging_factory_->CreateStream(&stream); hr = imaging_factory_->CreateStream(&stream);
}
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
hr = stream->InitializeFromMemory( hr = stream->InitializeFromMemory(
static_cast<WICInProcPointer>(res_data.buffer), static_cast<WICInProcPointer>(res_data.buffer),
res_data.size res_data.size
); );
} }
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
hr = imaging_factory_->CreateDecoderFromStream( ComPtr<IWICBitmapDecoder> decoder_output;
stream.get(), hr = imaging_factory_->CreateDecoderFromStream(
nullptr, stream.get(),
WICDecodeMetadataCacheOnLoad, nullptr,
&decoder WICDecodeMetadataCacheOnLoad,
); &decoder_output
} );
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
hr = decoder->GetFrame(0, &source); decoder = decoder_output;
} }
}
if (SUCCEEDED(hr))
{
hr = imaging_factory_->CreateFormatConverter(&converter);
}
if (SUCCEEDED(hr))
{
// 图片格式转换成 32bppPBGRA
hr = converter->Initialize(
source.get(),
GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone,
nullptr,
0.f,
WICBitmapPaletteTypeMedianCut
);
}
if (SUCCEEDED(hr))
{
hr = device_context_->CreateBitmapFromWicBitmap(
converter.get(),
nullptr,
&bitmap_tmp
);
}
if (SUCCEEDED(hr))
{
bitmap = bitmap_tmp;
} }
return hr; return hr;
} }

View File

@ -189,14 +189,30 @@ namespace kiwano
public: public:
static HRESULT Create(ID2DDeviceResources** device_resources); static HRESULT Create(ID2DDeviceResources** device_resources);
virtual HRESULT CreateBitmapFromFile( virtual HRESULT CreateBitmapConverter(
_Out_ ComPtr<ID2D1Bitmap>& bitmap, _Out_ ComPtr<IWICFormatConverter>& converter,
_In_ String const& file_path _In_opt_ ComPtr<IWICBitmapSource> source,
_In_ REFWICPixelFormatGUID format,
WICBitmapDitherType dither,
_In_opt_ ComPtr<IWICPalette> palette,
double alpha_threshold_percent,
WICBitmapPaletteType palette_translate
) = 0; ) = 0;
virtual HRESULT CreateBitmapFromResource( virtual HRESULT CreateBitmapFromConverter(
_Out_ ComPtr<ID2D1Bitmap>& bitmap, _Out_ ComPtr<ID2D1Bitmap>& bitmap,
_In_ Resource const& res _In_opt_ const D2D1_BITMAP_PROPERTIES* properties,
_In_ ComPtr<IWICFormatConverter> converter
) = 0;
virtual HRESULT CreateBitmapDecoderFromFile(
_Out_ ComPtr<IWICBitmapDecoder>& decoder,
const String& file_path
) = 0;
virtual HRESULT CreateBitmapDecoderFromResource(
_Out_ ComPtr<IWICBitmapDecoder>& decoder,
const Resource& resource
) = 0; ) = 0;
virtual HRESULT CreateTextFormat( virtual HRESULT CreateTextFormat(