2015-03-01 12 views
2

Мне нужно нарисовать много фигур с помощью Direct2D. Я использую фабрику для создания цели рендеринга, которую я использую для рисования. Над этими формами мне нужно добавить другие фигуры, не изменяя предыдущий (рисованный рисунок), но если я использую одну и ту же цель рендеринга, мне нужно обновить весь холст (т. Е. Перерисовать все фигуры), и это невозможно, потому что это слишком медленно.Несколько целей рендеринга, заданных на той же фабрике Direct2D

Мне нужно решение I, которое позволяет мне нарисовать фигуры статические формы без сплошного прозрачного рисования всего холста. Я думал создать новую цель рендеринга, используя ту же фабрику, но это решение не работает для меня (т. Е. Новые формы не отображаются на экране).

Есть ли решение, которое может решить эту проблему? Например, чтобы нарисовать статические формы на растровом изображении?

+1

Решение состоит в том, чтобы нарисовать статические фигуры на экране вне растра и перерисовать его только тогда, когда формы меняются. И в вашей функции рендеринга вы сначала рисуете заставку растрового изображения, а затем свободную руку, рисующую сверху. Какую визуализацию вы используете? hwnd render target? –

+0

@AntonAngelov Да, я использую ID2D1HwndRenderTarget, можете ли вы предоставить решение с этим типом рендеринга? – Nick

ответ

3

Ладно .. это. У меня сейчас нет MS VS, поэтому я пишу простой пример в Delphi. Все имена функций одинаковы, так что я надеюсь, что вы поймаете идею ..

Вот переменные, которые я использую:

FFactory: ID2D1Factory;    //ID2D1Factory* FFactory; 
FHWNDRT: ID2D1HwndRenderTarget;  //ID2D1HwndRenderTarget* FHWNDRT; 
FBitmapRT: ID2D1BitmapRenderTarget; //Etc.. 
FBrush: ID2D1SolidColorBrush; 

Вот пример:

function TForm1.InitializeD2D: HRESULT; 
var 
    TargetRect: TRect; 
    BrushProps: D2D1_BRUSH_PROPERTIES; 
begin 
    { Create factory } 
    Result := D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, ID2D1Factory, nil, FFactory); 
    If Failed(Result) then Exit; 

    { Get form's client rect } 
    Winapi.Windows.GetClientRect(Self.Handle, targetRect); 

    { Create hwnd render target } 
    Result := FFactory.CreateHwndRenderTarget(
     D2D1RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_HARDWARE, D2D1PixelFormat(DXGI_FORMAT_R8G8B8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED), 96, 96, D2D1_RENDER_TARGET_USAGE_NONE, D2D1_FEATURE_LEVEL_10), 
     D2D1HwndRenderTargetProperties(Self.Handle, D2D1SizeU(TargetRect.Width, TargetRect.Height)), 
     FHWNDRT 
); 
    If Failed(Result) then Exit; 

    { Create bitmap render target } 
    Result := FHWNDRT.CreateCompatibleRenderTarget(
     nil, 
     nil, 
     nil, 
     D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_NONE, 
     FBitmapRT 
); 
    If Failed(Result) then Exit; 

    With BrushProps do Begin 
    opacity := 1; 
    transform := D2D1_MATRIX_3X2_F.Identity; 
    End; 

    { Create brush so we can draw } 
    Result := FBitmapRT.CreateSolidColorBrush(D2D1ColorF(0, 0.25, 0.75, 1), @BrushProps, FBrush); 
end; 

function TForm1.UpdateStaticShapes: HRESULT; 
begin 
    //Draw the static shapes on the offscreen bitmap 
    FBitmapRT.BeginDraw; 

    //Clear the offscreen bitmap 
    FBitmapRT.Clear(D2D1ColorF(0, 0, 0, 1)); 

    //Draw a line 
    FBrush.SetColor(D2D1ColorF(1, 0, 0, 1)); 
    FBitmapRT.DrawLine(D2D1PointF(Random(10)+10, Random(10)+10), D2D1PointF(50, 50), FBrush); 

    //Draw a filled rect 
    FBrush.SetColor(D2D1ColorF(0, 0.25, 0.75, 1)); 
    FBitmapRT.FillRectangle(D2D1RectF(Random(50), Random(50), Random(250)+50, Random(300) + 50), FBrush); 

    //Etc.. (draw all your shapes) 

    Result := FBitmapRT.EndDraw(); 
end; 

function TForm1.Render: HRESULT; 
var 
    pBitmap: ID2D1Bitmap; 
begin 
    FHWNDRT.BeginDraw; 

    FHWNDRT.Clear(D2D1ColorF(0, 0, 0, 1)); 

    { Draw the offscreen bitmap } 
    FBitmapRT.GetBitmap(pBitmap); 

    If pBitmap <> nil then Begin 
    FHWNDRT.DrawBitmap(pBitmap); 
    pBitmap := nil; //Equivalent to _Release() 
    End; 

    { Draw the additional free hand drawing here } 
    FBrush.SetColor(D2D1ColorF(1, 1, 1, 1)); 
    FHWNDRT.DrawRectangle(D2D1RectF(100, 100, 200, 200), FBrush); 

    Result := FHWNDRT.EndDraw(); 
end; 

offscreen bitmap перерисовывается в UpdateStaticShapes() метод. И окончательный кадр отображается в Render() метод.

Редактировать: Я попытался сделать масштабирование и понял вашу проблему. Я думаю, что решение состоит в том, чтобы воссоздать цель рендеринга растрового изображения каждый раз, когда вы изменяете коэффициент масштабирования (также каждый раз, когда вы изменяете размер окна). Размер внеэкранного растрового изображения должен быть:

OffscreenBitmap.Width/Height = HwndRT.Width/Height * ScaleFactor; 

Когда вы рисуете форму вы должны использовать координаты относительно внеэкранного размера растрового изображения. Например: вместо рисования линии (50,50, 100,100) вы должны нарисовать ее (50 * K, 50 * K, 100 * K, 100 * K) где K = ScaleFactor;

Вот как я создаю растровый RT:

//In C++ this should look like: 
//HRESULT TForm::CreateBitmapRT(float ScaleFactor) {} 
function TForm1.CreateBitmapRT(ScaleFactor: Single): HRESULT; 
var 
    DesiredSize: D2D1_POINT_2F; 
begin 
    FBitmapRT := nil; //FBitmapRT->_Release(); FBitmapRT = NULL; 

    { Decide offscreen bitmap's size } 
    DesiredSize := D2D1PointF(FWindowRect.Width * ScaleFactor, FWindowRect.Height * ScaleFactor); 

    { Create bitmap render target } 
    Result := FHWNDRT.CreateCompatibleRenderTarget(
     @DesiredSize, 
     nil, 
     nil, 
     D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_NONE, 
     FBitmapRT 
); 
end; 

Здесь дополненная Рендер() метод:

function TForm1.Render: HRESULT; 
var 
    pBitmap: ID2D1Bitmap; 
    SrcRect, DestRect: D2D1_RECT_F; 
begin 
    FHWNDRT.BeginDraw; 

    FHWNDRT.Clear(D2D1ColorF(0, 0, 0, 1)); 

    If FBitmapRT <> nil then Begin 
    { Draw the offscreen bitmap } 
    FBitmapRT.GetBitmap(pBitmap); 

    If pBitmap <> nil then Begin 
     SrcRect := D2D1RectF(FZoomOffset.x, FZoomOffset.y, FZoomOffset.x + FWindowRect.Width, FZoomOffset.y + FWindowRect.Height); 
     DestRect := D2D1RectF(0, 0, FWindowRect.Width, FWindowRect.Height); 

     FHWNDRT.DrawBitmap(pBitmap, @DestRect, 1, D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, @SrcRect); 
     pBitmap := nil; //pBitmap->_Release(); pBitmap = NULL; 
    End; 
    End; 

    { Draw the additional free hand drawing here } 
    FBrush.SetColor(D2D1ColorF(1, 1, 1, 1)); 
    FHWNDRT.DrawRectangle(D2D1RectF(100, 100, 200, 200), FBrush); 

    Result := FHWNDRT.EndDraw(); 
end; 

Вот что произойдет, если изменить коэффициент масштабирования (увеличения или уменьшение масштаба):

function TForm1.ApplyZoom(fScaleFactor: Single): HRESULT; 
begin 
    If fScaleFactor = FZoomFactor then Exit(S_OK);  
    If fScaleFactor = 0 then fScaleFactor := 0.1; 

    { Recreate the offscreen bitmap } 
    Result := CreateBitmapRT(fScaleFactor); 
    If Failed(Result) then Exit; 

    { Here you have to redraw the shapes once again } 
    Result := UpdateStaticShapes; 
    If Failed(Result) then Exit; 

    { I save the new Zoom Factor in a class field } 
    FZoomFactor := fScaleFactor; 
end; 
+0

Здесь проблема заключается в том, что отображаемое растровое изображение отличается от сглаженной версии фигур, нарисованных без использования целевой рендеринга Bitmap (когда я использую масштабное преобразование, то есть масштабирование).Есть ли способ создать растровое изображение, которое отображается как скриншот Windows? То есть, растровое изображение, похожее на сглаженную версию. – Nick

+0

Этот эффект вызван тем, что ваши формы растеризуются в растровом изображении. Решение, чтобы сделать растровое изображение вне экрана больше (на 2, 4 или более раз больше), чтобы он мог удерживать более подробный растровый файл. –

+0

Ваше решение является допустимым решением, но у меня есть следующая проблема: http://stackoverflow.com/questions/28806029/direct2d-bitmap-brush-longated. Пожалуйста, не стесняйтесь отвечать. Благодарю. – Nick