CYFROWY BARON • PROGRAMOWANIE • Zobacz wątek - Przyspieszenie wyświetlania na ekranie

Przyspieszenie wyświetlania na ekranie

problemy z tworzeniem aplikacji graficznych oraz audio i wideo

Przyspieszenie wyświetlania na ekranie

Nowy postprzez GrassHoppeR » niedziela, 9 stycznia 2011, 19:04

witam.

jestem programistą "z doskoku". programowałem w wielu językach zaczynając od BASICa i assemblera na C64 a na ActionScript kończąc. zwykle uczyłem się języka do wykonania konkretnego zadania nie zagłębiając się zanadto w jego zawiłościach. obecnie przyswajam programowanie obiektowe w C++ i nie ukrywam, że dzięki Waszemu serwisowi udało mi się niemal osiągnąć zamierzony cel. jednak o ile samo napisanie działającej aplikacji nie jest szczególnie trudne, to jednak jej szybkość działania czy "piękno kodu" wymaga jednak czegoś więcej niż analiza kodu a'la Bill Gates ze stopki Barona. postanowiłem więc zapytać o kilka spraw licząc na dopracowanie programu. jednocześnie przepraszam za niefachowe określenia, które na pewno się zdarzą, gdyż nie jestem jeszcze zaznajomiony ze słownictwem. ;)

poniżej zamieszczam kod okrojonej wersji programu, a w załącznikach exe'ka i źródło (BCB 6).
KOD cpp:     UKRYJ  
//---------------------------------------------------------------------------
#include <vcl.h>
#include <vector>
#pragma hdrstop
using namespace std;
#include <math.h>
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
vector<Clip> klip;
Clip tmp(100,4);
int akcja = -1;
int X0, S0;
int dX, dY, selected = 0;
//---------------------------------------------------------------------------
void upd_status ()
{
       Form1->Edit1->Text = tmp.s;
       Form1->Edit2->Text = tmp.t;
}
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
        DoubleBuffered = true;
        Edit1->Parent = StatusBar1;
        Edit2->Parent = StatusBar1;
        BitBtn1->Parent = StatusBar1;
        klip.push_back(tmp);
        if (klip.size()) klip.pop_back();
        upd_status();
}
//---------------------------------------------------------------------------
void rysuj ()
{
        int Y=Form1->Image2->Picture->Bitmap->Height+dY;
        Form1->Image2->Picture->Bitmap->PixelFormat = pf32bit;
        Form1->Image2->Canvas->Brush->Color = clWhite;
        Form1->Image2->Canvas->FillRect(Form1->Image2->BoundsRect);
        Form1->Image2->Canvas->Brush->Style = bsSolid;
        Form1->Image2->Canvas->Brush->Color = clYellow;
        for (unsigned int i=0; i<klip.size(); i++)
        {
                Form1->Image2->Canvas->Rectangle(klip[i].s-dX, Y-klip[i].t*32, klip[i].s-dX+100, Y-(klip[i].t*32+31));
        }
        Form1->Image2->Canvas->Brush->Color = clAqua;
        if (akcja>=0)
        {
                Form1->Image2->Canvas->Rectangle(tmp.s-dX, Y-tmp.t*32, tmp.s-dX+100, Y-(tmp.t*32+31));
        }
}
//---------------------------------------------------------------------------
int ktory(int X, int Y)
{
        int i=klip.size()-1;
        while (!(klip[i].t==floor(Y/32) && klip[i].s<=X && klip[i].s+100>=X)&&(i>=0)) i--;
        return i;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Image2MouseDown(TObject *Sender,
                                        TMouseButton Button, TShiftState Shift, int X, int Y)
{
        Form1->BitBtn1->SetFocus();
        if (akcja>=0) klip.push_back(tmp);
        selected=ktory(X+dX,Image2->Picture->Bitmap->Height-Y+dY);
        if (selected>=0)
        {
                tmp=klip[selected];
                klip.erase(klip.begin() + selected);
                X0=X;
                S0=tmp.s;
                akcja=4;
        }
        else akcja=-1;
        rysuj();
        upd_status();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Image2MouseMove(TObject *Sender, TShiftState Shift,
                                        int X, int Y)
{
        if (akcja == 4)
        {
                tmp.s = S0+(X-X0);
                tmp.t=floor((Image2->Picture->Bitmap->Height-Y+dY)/32);
                rysuj();
                upd_status();
        }
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Image2MouseUp(TObject *Sender, TMouseButton Button,
                                      TShiftState Shift, int X, int Y)
{
        if (akcja>-1) akcja = 0;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ScrollBar1Change(TObject *Sender)
{
        dX=ScrollBar1->Position;
        rysuj();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormResize(TObject *Sender)
{
        Image2->Picture->Bitmap->Width = this->Width-8;
        Image2->Picture->Bitmap->Height = this->Height-65;
        Edit2->Width = this->Width-120;
        rysuj();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Edit1Change(TObject *Sender)
{
        tmp.s=StrToInt(Edit1->Text);
        rysuj();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Edit2Change(TObject *Sender)
{
        tmp.t=StrToInt(Edit2->Text);
        rysuj();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::BitBtn1KeyDown(TObject *Sender, WORD &Key,
                                       TShiftState Shift)
{
        if (Key==VK_INSERT) klip.push_back(tmp);
        rysuj();
        upd_status;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::BitBtn1Click(TObject *Sender)
{
        MessageBox(Handle,"Zapis danych do pliku.","BitBtn1Click",0);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormMouseWheelDown(TObject *Sender,
        TShiftState Shift, TPoint &MousePos, bool &Handled)
{
        if (dY>0) dY-=16;
        rysuj();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormMouseWheelUp(TObject *Sender,
        TShiftState Shift, TPoint &MousePos, bool &Handled)
{
        dY+=16;
        rysuj();
}
//---------------------------------------------------------------------------
 


najpierw mała instrukcja obsługi. po uruchomieniu programu należy kliknąć na białe pole a następnie wcisnąć klawisz Insert. zostanie wstawiony klocek, który można przesuwać. każde wciśnięcie Insert wstawia kolejny klocek. klocek aktywny ma błękitny kolor i można zmienić jego pozycję klikając na Edity na pasku statusu. jeśli żaden nie jest aktywny to zmiana dotyczy parametrów klocka, który pojawi się po wciśnięciu Insert. kliknięcie ikonki z monitorkiem bądź Enter przy aktywnym trybie "klockowania" powoduje wyskoczenie okna (w pełnej wersji zapis danych).
w wersji okrojonej program wydaje się nie mieć sensu, jednak zawiera kluczowe dla moich pytań elementy pełnej wersji.

moje pytania:
program działa szybko, dopóki wielkość pola dla klocków jest nieduża. po powiększeniu lub zmaksymalizowaniu całość zauważalnie zwalnia. można to sprawdzić szybko ruszając klockiem i obserwując użycie procesora. dodatkowo współrzędne na StatusBar nie odświeżają się wtedy płynnie. początkowo myślałem, że chodzi o rysowanie klocków, ale okazało się, że wąskim gardłem jest DoubleBuffering. niestety bez niego, wiadomo, obraz migocze. próbowałem wykorzystać rysowanie po Canvas, jednak obraz znika po przesłonięciu, a odświeżanie jeszcze bardziej obciąża procesor. próbowałem wykorzystać Panel i inne, a nawet DirectDraw, jednak takie błądzenie po omacku nie na wiele się zdało. stąd moje pytanie - jak najlepiej zrobić, aby obciążenie procesora przy pracy na pełnym ekranie było jak najmniejsze?
następna sprawa - ponieważ Image nie posiada Focusa, wykorzystałem ukryty BitBtn (ikonka monitorka), na którego ustawiam Focus w momencie kliknięcia w Image. dzięki temu mogę obsłużyć OnKeyDown. jednak nie jest to, wydaje mi się, rozwiązanie eleganckie. wolałbym się obyć bez niego, a przynajmniej nauczyć się jak można zrobić (czy też zasymulować) obsługę klawiatury i Focus na obiekcie Image. próbowałem za pomocą PageControl, ale zaprowadziło mnie to na manowce, choć czegoś też przy okazji nauczyło. w związku z tym proszę o poradę.

tyle pytań "głównych", choć będę na pewno pytał o wiele rzeczy w miarę padania odpowiedzi. teraz jednak chciałbym jeszcze zadać kilka mniej istotnych pytań:
kiedy obszar roboczy jest dość duży to współrzędne klocka na StatusBar odświeżają się z opóźnieniem lub przez chwilę nie odświeżają się.
-czy można jakoś wymusić natychmiastowe odświeżanie Edita przy każdym ruchu? bo mimo, iż procedura upd_status wywoływana jest przy każdym ruchu to jest to opóźnienie...
-gdzie należy wpisać, żeby Focus ustawiał się na żądanym elemencie? w tym konkretnym przypadku na BitBlt1. próbowałem w OnCreate formy i innych miejscach ale dostaję błąd, że nie można ustawiać na disabled i na invisible window. wnioskuję, że trzeba to ustawiać już po utworzeniu elementu, ale jak i gdzie?
-czy można zrobić tak, by napisy na StatusBar'ze nie mrugały przy zmianie rozmiarów okna? są to Edity ze zmienionym kolorem tła, gdyż nie znalazłem innego sposobu. czy można to zrobić inaczej?
obecnie rysowanie klocków odbywa się w procedurze rysuj(), gdzie wykorzystuję metodę Rectangle przekazując współrzędne obiektu tmp bądź obiektów z vectora.
-czy jakieś korzyści dałoby umieszczenie rysowania pojedynczego klocka jako metody? nadmienię, że w pełnej wersji programu rysowanie jest bardziej skomplikowane (nakładanie klocków z przezroczystością 50%) i tu następne pytania:
-czy możliwe jest rysowanie obiektów z przezroczystością 50% za pomocą standardowych metod? w tej chwili wykorzystuję swoją funkcję mieszania kolorów.
-czy wykorzystanie Scanline jest konieczne, czy można to obejść? chodzi mi o taką sprawę, że mógłbym wykorzystać instrukcje MMX dla jednej linii i wyniki wstawić do kolejnych 29 linii używając pętli i pitch'a. jednak być może organizacja Bitmap jest inna niż standardowa i spowodowałoby to błędy? pytam, bo nie zdążyłem jeszcze tego sprawdzić.
chciałbym również przerobić nieco program, aby vector zawierał wskaźniki do obiektów, gdyż w pełnej wersji programu obiekty te zawierają nie tylko współrzędne, ale i Stringi, a ponieważ stale elementy są z vectora usuwane i dodawane przez insert, to przy dużej ilości klocków może to niepotrzebnie zajmować procesor. ponieważ wskaźniki nie są dla mnie jeszcze środowiskiem naturalnym chciałbym się dowiedzieć
-jak należy przerobić program, aby wykorzystać w vectorze wskaźniki zamiast obiektów? rozumiem, że usunięcie z vectora wskaźnika nie powoduje usunięcia obiektu z pamięci?
-czy istnieje jakiś elegancki sposób na uniknięcie błędu przy pierwszym sprawdzaniu wielkości pustego vectora niż użyte przeze mnie "klip.push_back(tmp); if (klip.size()) klip.pop_back();"?

to na razie tyle. mam nadzieję, że wyraziłem się dosyć zrozumiale, jednak w razie czego proszę o wskazanie właściwego słownictwa.

pozdrawiam
Nie masz wystarczających uprawnień, aby zobaczyć pliki załączone do tego postu.
Avatar użytkownika
GrassHoppeR
Homos antropiczny
Homos antropiczny
 
Posty: 63
Dołączył(a): wtorek, 4 stycznia 2011, 01:17
Podziękował : 3
Otrzymał podziękowań: 0
System operacyjny: Windows XP
Kompilator: C++ Builder 6 Personal
Gadu Gadu: 2491715
    Windows XPFirefox

Re: Przyspieszenie wyświetlania na ekranie

Nowy postprzez Cyfrowy Baron » niedziela, 9 stycznia 2011, 21:43

Twoje rysowanie opiera się na GDI i jest to w tej chwili najbardziej wydajna metoda rysowania z pominięciem DirecDraw dostępnego w DirectX, ale to już zupełnie inna historia.

Trudno ustosunkować się do Twojego postu, gdyż poruszasz zbyt wiele tematów na raz. Piszesz np.

róbowałem wykorzystać rysowanie po Canvas, jednak obraz znika po przesłonięciu, a odświeżanie jeszcze bardziej obciąża procesor


Rysujesz po TCanvas, tylko nie zdajesz sobie z tego sprawy, gdyż korzystasz z obiektów pośredniczących. Nie mógłbyś zresztą niczego narysować bez klasy TCanvas, no bo i jak. Zresztą spójrz:

KOD cpp:     UKRYJ  
        Form1->Image2->Picture->Bitmap->PixelFormat = pf32bit;
        Form1->Image2->Canvas->Brush->Color = clWhite;
        Form1->Image2->Canvas->FillRect(Form1->Image2->BoundsRect);
        Form1->Image2->Canvas->Brush->Style = bsSolid;


Rysujesz z wykorzystaniem TCanvas. TCanvas udostępnia tylko narzędzia to rysowania, a obiekty po których rysujesz udostępniają powierzchnię do rysowania.

jak najlepiej zrobić, aby obciążenie procesora przy pracy na pełnym ekranie było jak najmniejsze?


Skorzystać z DirectDraw, a obciążenie procesora jest zależne on stosowanych algorytmów. Samo rysowanie wykorzystuje GDI, które z kolei korzysta ze wsparcia sprzętowego, więc sama grafika jest obsługiwana przez procesor karty graficznej.

jednak obraz znika po przesłonięciu,


Ponieważ grafika musi być na bieżąco odświeżana, czyli kod rysujący musi znajdować się w zdarzeniu OnPaint obiektu po którym rysujesz. Jeżeli obiekt nie posiada zdarzenia OnPaint to pomimo iż rysujesz po tym obiekcie kod rysujący umieszczasz w zdarzeniu OnPaint formularza. Zdarzenie OnPaint automatycznie odświeża grafikę gdy zachodzi taka potrzeba. Wyjątek stanowi obiekt typu TImage, który przechowuje narysowaną zawartość i sam zarządza zdarzeniem OnPaint, bez potrzeby umieszczania tam kodu.




KOD cpp:     UKRYJ  
        Form1->Image2->Picture->Bitmap->PixelFormat = pf32bit;
        Form1->Image2->Canvas->Brush->Color = clWhite;


Jeżeli obiekt Image zawiera bitmapę to rysuj Image->Picture->Bitmap->Canvas, a nie Image->Canvas. Mamy tutaj jednak rysowanie po Bitmapie, przez co każdorazowa zmiana zawartości grafiki wymaga również odświeżenia całej bitmapy. Jedyna rozsądne rozwiązanie, w przypadku gdy Image zawiera bitmapę, to tworzenie grafiki álá warstwy, czyli każdy kwadrat jest np. dynamicznie utworzonym obiektem typu TImage, czyli jeden Image na drugim, a przesuwanie Image znajdziesz w serwisie Cyfrowy Baron w dziale: porady -> grafika -> Przesuwanie objektu Image po formularzu.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: Przyspieszenie wyświetlania na ekranie

Nowy postprzez GrassHoppeR » niedziela, 9 stycznia 2011, 23:49

dzięki za wyjaśnienia.

Cyfrowy Baron napisał(a):Skorzystać z DirectDraw,

tego się obawiałem. czyli jeśli dobrze rozumiem, jeśli DirectDraw przejmie choćby samo wyświetlanie bitmapy to problem spowodowany buforowaniem przestanie mieć miejsce?

Cyfrowy Baron napisał(a):Jedyna rozsądne rozwiązanie, w przypadku gdy Image zawiera bitmapę, to tworzenie grafiki álá warstwy,

niestety ten sposób odpada. klocki docelowo są półprzezroczyste z nieprzezroczystą, czarną obwódką. a takie wyświetlanie obrazków jest, zdaje się, niemożliwe. porady w serwisie przejrzałem oczywiście od deski do deski stosując się do nich przy pisaniu powyższego programu.

jednym słowem - klops? nie da się obejść opóźnień przy buforowaniu inną metodą niż wykorzystaniem DD? w związku z tym pytanie - jak umieścić okno DirectDraw w formie analogicznie do Image (np. włącznie ze zmianą rozmiaru przy OnResize)? jak na razie jedyne co uzyskałem to wyświetlenie bitmapy w lewym, górnym rogu ekranu, znikające pod innymi oknami. muszę mieć też obsługę kliknięcia na nim.

a propos innych moich pytań - czy mam zakładać oddzielne tematy (czego chciałem uniknąć)? są to dla mnie pytania istotne, a odpowiedzi szukałem przez ostatnie dni, jednak bezskutecznie, i dalsze tracenie czasu na samodzielne poszukiwania w mrokach internetu mogłoby ostudzić mój zapał w tworzeniu tego programu. ;) dlatego proszę o odpowiedzi, jeśli ktokolwiek mógłby choć słówko skrobnąć. pytań mam znacznie więcej...

pozdrawiam

P.S. może przenieść temat do "Ogólne problemy z programowaniem"?
Avatar użytkownika
GrassHoppeR
Homos antropiczny
Homos antropiczny
 
Posty: 63
Dołączył(a): wtorek, 4 stycznia 2011, 01:17
Podziękował : 3
Otrzymał podziękowań: 0
System operacyjny: Windows XP
Kompilator: C++ Builder 6 Personal
Gadu Gadu: 2491715
    Windows XPFirefox

Re: Przyspieszenie wyświetlania na ekranie

Nowy postprzez polymorphism » poniedziałek, 10 stycznia 2011, 12:33

Pierwszy "błąd" jaki widzę to to, że rysujesz za każdym razem wszystkie klocki jak leci. Powinieneś rysować tylko te, które będą widoczne. Następna rzecz, którą możesz zrobić, to przy przeciąganiu klocka wpierw wygeneruj sobie tło (w postaci bitmapy), czyli wszystkie widoczne klocki z wyjątkiem przeciąganego. Wtedy przy każdym ruchu myszy program nie będzie musiał rysować wszystkiego od nowa, jedynie skopiuje tło i pacnie na nim przeciągany klocek - to jest znacznie szybsze niż rasteryzacja kilku/kilkunastu/kilkuset klocków za każdym razem. Jeśli chodzi o przeźroczystość, to sprawa jest nieciekawa, ponieważ GDI nie obsługuje jej. Dopiero w GDI+ masz możliwość rysowania półprzeźroczystych obiektów. Problem w tym, że pod WinXP wydajność GDI+ jest słaba, więc zastosowanie tej biblioteki może być czynnikiem znacznie spowalniającym rysowanie. Ale być może może metoda, o której pisałem wcześniej polepszy nieco wydajność. Tu trzeba kombinować...
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows XPFirefox

Re: Przyspieszenie wyświetlania na ekranie

Nowy postprzez GrassHoppeR » poniedziałek, 10 stycznia 2011, 12:49

to nie jest niestety kwestia rysowania klocków. nawet narysowanie 100 klocków w ten sposób nie spowalnia tak programu jak włączony DoubleBuffering (no, w tym przykładzie na spółę z FillRect całego obszaru). z początku właśnie kombinowałem z odświeżaniem tylko fragmentu pod klockiem, ale to nie dało praktycznie rezultatu. oczywiście docelowo będzie to tak zrobione, dodatkowo z wykorzystaniem MMX, o ile pójdę w ogóle tą drogą, bo być może opóźnienie przez DoubleBuffering jest z definicji nie do przeskoczenia. zwróć uwagę, że nawet przy jednym klocku zwalnia jak diabli... w tej chwili zgodnie z sugestią CB wróciłem do szukania rozwiązania w DirectDraw. tyle, że jestem w lesie...
Avatar użytkownika
GrassHoppeR
Homos antropiczny
Homos antropiczny
 
Posty: 63
Dołączył(a): wtorek, 4 stycznia 2011, 01:17
Podziękował : 3
Otrzymał podziękowań: 0
System operacyjny: Windows XP
Kompilator: C++ Builder 6 Personal
Gadu Gadu: 2491715
    Windows XPFirefox

Re: Przyspieszenie wyświetlania na ekranie

Nowy postprzez Cyfrowy Baron » poniedziałek, 10 stycznia 2011, 13:08

tego się obawiałem. czyli jeśli dobrze rozumiem, jeśli DirectDraw przejmie choćby samo wyświetlanie bitmapy to problem spowodowany buforowaniem przestanie mieć miejsce?


DirectDraw jest bardzo wydajny i posiada własne bufory, DoubleBuffered nie w tym przypadku żadnego zastosowanie, niemniej tło jest buforowane. Opis DirecDraw znajdziesz w serwisie Cyfrowy Baron w dziale: teoria -> DirectDraw. Kurs tworzyłem dla DirectX 7 więc może być już nieco nieaktualny, nie wiem nie sprawdzałem.

klocki docelowo są półprzezroczyste z nieprzezroczystą, czarną obwódką.


W jaki sposób uzyskałeś w GDI, czyli w TCanvas półprzeźroczystość, bo w Twoim kodzie tego nie widzę i szczerze mówiąc gdybym musiał stworzyć taką półprzeźroczystość, to wymagałoby to kopiowanie do prostokąta tła, który przesłania a potem za pomocą algorytmu zmianę kolorów poszczególnych pikseli. Byłoby to wysoce niewydajne. Problem można by obejść zmieniając styl pędzla na pmNotXor i pmMaskPenNot lub pmMergePenNot, oraz funkcji CopyRect. GDI nie oferuje półprzeźroczystości, więc jedyne co można zrobić to nałożyć maskę - pmMaskPenNot, lub wymieszać kolor prostokąta z tłem - pmMergePenNot. Takie rozwiązanie byłoby dość wydajne, a im większy prostokąt tym wydajniejszy kod. Nie sprawdzałem jak to by się sprawdzało w przypadku wielu prostokątów, ale przypuszczam, że byłby spory problem, nie tyle z wydajnością ile z zarządzaniem tyloma prostokątami, bo po przesłonięciu któregokolwiek, trzeba by go ponownie odrysować.
plik nagłówkowy np. Unit1.h:
KOD cpp:     UKRYJ  
private:        // User declarations
        TWndMethod ResizeWindow;
        void __fastcall GetResizeWindow(TMessage &Msg);

        TRect graphRect;
        int gSize;

        TPoint pbPoint;
        BOOL fDraw;
        Graphics::TBitmap *Buffer;

        void __fastcall DrawRect(int X1, int Y1, int X2, int Y2);
        void __fastcall DrawCopyRect(void);
        BOOL __fastcall FindRect(int X, int Y);


plik źródłowy np. Unit1.cpp:
KOD cpp:     UKRYJ  
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"

TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
 ResizeWindow = this->WindowProc;
 this->WindowProc = GetResizeWindow;

 fDraw = false;
 gSize = 400;
 Buffer = new Graphics::TBitmap();
 Buffer->Assign(Image1->Picture->Bitmap);

 graphRect = Rect(100, 100, 100 + gSize, 100 + gSize);
 Image1->Canvas->Pen->Mode = pmMaskPenNot;
 DrawRect(graphRect.Left, graphRect.Top, graphRect.Right, graphRect.Bottom);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::GetResizeWindow(TMessage &Msg)
{
 /* Przechwytywanie komunikatów o zmianie rorzmiaru okna */
 if(Msg.Msg == WM_SIZE)
 {
  if( Msg.WParam == SIZE_MAXIMIZED || Msg.WParam == SIZE_RESTORED )
  {
   fDraw = false;
   Image1->Canvas->Pen->Mode = pmMaskPenNot;
   DrawRect(graphRect.Left, graphRect.Top, graphRect.Right, graphRect.Bottom);
   DrawRect(graphRect.Left, graphRect.Top, graphRect.Right, graphRect.Bottom);
  }
 }

 ResizeWindow(Msg);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::DrawRect(int X1, int Y1, int X2, int Y2)
{
 TCanvas *pbCanv = Image1->Canvas;
 int pW = 4;

 pbCanv->Pen->Color = clBlack;
 pbCanv->Pen->Width = pW;
 pbCanv->Brush->Color = clBlue;
 pbCanv->Rectangle(X1, Y1, X2, Y2);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::DrawCopyRect(void)
{
 int pW = 4; // grubość pędzla taka sama jak grubość pędzla dla prostokąta
 TRect tmpRect = Rect(graphRect.Left - pW, graphRect.Top - pW,
                       graphRect.Right + pW, graphRect.Bottom + pW) ;

 Image1->Canvas->CopyRect(tmpRect, Buffer->Canvas, tmpRect);
}
//---------------------------------------------------------------------------
BOOL __fastcall TForm1::FindRect(int X, int Y)
{
    if( (X >= graphRect.Left && X <= graphRect.Left + gSize) &&
        (Y >= graphRect.Top && Y <= graphRect.Top + gSize)
      )
    {
      return true;
    }

 return false;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Image1MouseMove(TObject *Sender, TShiftState Shift, int X,
          int Y)
{
 if(fDraw == true)
 {
  /* wymazywanie prostokąta */
  Image1->Canvas->Pen->Mode = pmNotXor;
  DrawRect(graphRect.Left, graphRect.Top, graphRect.Right, graphRect.Bottom);

  DrawCopyRect();

  int left = X - pbPoint.x;
  int top  = Y - pbPoint.y;


  graphRect.Left   = left;
  graphRect.Top    = top;
  graphRect.Right  =  left + gSize;
  graphRect.Bottom =  top + gSize;

  /*rysowanie nowego prostokąta */
  Image1->Canvas->Pen->Mode = pmMaskPenNot;
  DrawRect(graphRect.Left, graphRect.Top, graphRect.Right, graphRect.Bottom);
 }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Image1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift,
          int X, int Y)
{
 if( FindRect(X, Y) )
 {
  pbPoint.x = X - graphRect.Left;
  pbPoint.y = Y - graphRect.Top;

  fDraw = true;
 }
 else
 {
  fDraw = false;
 }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Image1MouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift,
          int X, int Y)
{
  fDraw = false;
  DrawCopyRect();
  Image1->Canvas->Pen->Mode = pmMaskPenNot;
  DrawRect(graphRect.Left, graphRect.Top, graphRect.Right, graphRect.Bottom);
}
//---------------------------------------------------------------------------


Pomocny może być wątek: http://programowanie.cal.pl/forum/viewtopic.php?f=4&t=1170
Nie masz wystarczających uprawnień, aby zobaczyć pliki załączone do tego postu.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: Przyspieszenie wyświetlania na ekranie

Nowy postprzez polymorphism » poniedziałek, 10 stycznia 2011, 13:38

zwróć uwagę, że nawet przy jednym klocku zwalnia jak diabli...

Eeee, u mnie dla 8 klocków w porywach ~45% (1152x864, 2.50GHz).

Co to w ogóle ma być? Bo być może szukasz dziury w całym...
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows XPFirefox

Re: Przyspieszenie wyświetlania na ekranie

Nowy postprzez GrassHoppeR » poniedziałek, 10 stycznia 2011, 13:46

dzięki za kod, na pewno się przyda. w chwili obecnej wykorzystuję własną funkcję operując bezpośrednio na bitmapie półprzezroczystość uzyskując średnią koloru klocka i tłem w tym punkcie. stylów jeszcze nie "rozpykałem", ale na pewno się im przyjrzę. porady dotyczące DirectDraw z serwisu oczywiście przyswoiłem i na razie udało mi się wyświetlić bitmapę na ekranie bez trybu fullscreen, tylko nie potrafię tego jeszcze wrzucić w okienko. szukam właśnie porad odnoście DD w oknie, ale nie jest to chyba popularne podejście do tematu.

polymorphism napisał(a):Co to w ogóle ma być? Bo być może szukasz dziury w całym...

coś takiego jak tu http://www.youtube.com/watch?v=4aYwTvteqIM od 0:45, tylko to zrobiłem w ActionScript. Chcę to rozbudować i konieczna stała się zmiana języka. mogłem od razu zacząć od C++, ale jak zwykle wybrałem złe rozwiązanie...
:roll:
Avatar użytkownika
GrassHoppeR
Homos antropiczny
Homos antropiczny
 
Posty: 63
Dołączył(a): wtorek, 4 stycznia 2011, 01:17
Podziękował : 3
Otrzymał podziękowań: 0
System operacyjny: Windows XP
Kompilator: C++ Builder 6 Personal
Gadu Gadu: 2491715
    Windows XPFirefox

Re: Przyspieszenie wyświetlania na ekranie

Nowy postprzez polymorphism » poniedziałek, 10 stycznia 2011, 13:51

Aha, czyli timeline. Zasadniczo DirectDraw do tego nie jest Ci potrzebny (ja bym nie szedł w tym kierunku).
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows XPFirefox

Re: Przyspieszenie wyświetlania na ekranie

Nowy postprzez GrassHoppeR » poniedziałek, 10 stycznia 2011, 14:02

no ale skoro GDI nie wyrabia?...
Avatar użytkownika
GrassHoppeR
Homos antropiczny
Homos antropiczny
 
Posty: 63
Dołączył(a): wtorek, 4 stycznia 2011, 01:17
Podziękował : 3
Otrzymał podziękowań: 0
System operacyjny: Windows XP
Kompilator: C++ Builder 6 Personal
Gadu Gadu: 2491715
    Windows XPFirefox

Re: Przyspieszenie wyświetlania na ekranie

Nowy postprzez Cyfrowy Baron » poniedziałek, 10 stycznia 2011, 14:06

GDI+ chyba oferuje obsługę półprzeźroczystości, więc mimo iż nie ma wsparcia sprzętowego to może w tym przypadku być wydajniejsze od standardowego GDI, które wymaga stosowania złożonych algorytmów do uzyskania takiego efektu.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: Przyspieszenie wyświetlania na ekranie

Nowy postprzez GrassHoppeR » poniedziałek, 10 stycznia 2011, 14:27

dobrze, rozejrzę się za GDI+, ale to raczej kosmetyka. nie wiem czy będzie szybsze niż bezpośrednie operacje na bitmapie, ale zawsze warto poznać.

dla unaocznienia problemu skompilowałem 3 wersje klocków z włączonym i wyłączonym DoubleBufferingiem (DB, noDB) i czyszczeniem bitmapy (FillRect, noFillrect). wersja w powyłączanymi działa bardzo szybko nawet zmaksymalizowana, a obciążenie procesora (E6300) nie sięga nawet 30%. i o coś takiego by mi chodziło...
Nie masz wystarczających uprawnień, aby zobaczyć pliki załączone do tego postu.
Avatar użytkownika
GrassHoppeR
Homos antropiczny
Homos antropiczny
 
Posty: 63
Dołączył(a): wtorek, 4 stycznia 2011, 01:17
Podziękował : 3
Otrzymał podziękowań: 0
System operacyjny: Windows XP
Kompilator: C++ Builder 6 Personal
Gadu Gadu: 2491715
    Windows XPFirefox

Re: Przyspieszenie wyświetlania na ekranie

Nowy postprzez Cyfrowy Baron » poniedziałek, 10 stycznia 2011, 14:38

ale to raczej kosmetyka. nie wiem czy będzie szybsze niż bezpośrednie operacje na bitmapie, ale zawsze warto poznać.


Operacje na bitmapie to operacje z wykorzystaniem GDI. Nie rozumiesz problemu.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: Przyspieszenie wyświetlania na ekranie

Nowy postprzez GrassHoppeR » poniedziałek, 10 stycznia 2011, 14:40

operuję BEZPOŚREDNIO na bitmapie w pamięci a nie na TBitmap. :x
Avatar użytkownika
GrassHoppeR
Homos antropiczny
Homos antropiczny
 
Posty: 63
Dołączył(a): wtorek, 4 stycznia 2011, 01:17
Podziękował : 3
Otrzymał podziękowań: 0
System operacyjny: Windows XP
Kompilator: C++ Builder 6 Personal
Gadu Gadu: 2491715
    Windows XPFirefox

Re: Przyspieszenie wyświetlania na ekranie

Nowy postprzez polymorphism » poniedziałek, 10 stycznia 2011, 14:43

GrassHoppeR napisał(a):no ale skoro GDI nie wyrabia?...

Wierz mi, GDI wyrabia w znacznie bardziej złożonych sprawach. To, co chcesz zrobić, jest dosyć proste, chyba że jest tam coś znacznie bardziej skomplikowanego, czego nie ma w tym filmiku.

Zresztą wspomniany DirecDraw niewiele Ci da, jeśli chodzi o grafikę wektorową. On był tworzony z myślą o szybkich operacjach rastrowych, co jest istotne przy tworzeniu gier 2D. O ile się orientuje, nie jest już rozwijany, zastąpił go Direct2D.
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows XPFirefox

Następna strona

  • Podobne tematy
    Odpowiedzi
    Wyświetlone
    Ostatni post

Powrót do Aplikacje multimedialne, graficzne

Kto przegląda forum

Użytkownicy przeglądający ten dział: Brak zalogowanych użytkowników i 0 gości