Grafiken zwischenspeichern
-
Servus,
ich muss muss für ein Projekt eine bewegte Grafik programmieren, genauer gesagt einen Flipperschlegel. Der Schlegel wird mit Linien auf eine TCanvas gezeichent. Wenn ich den Schlegel nun bewege, wird ja jede Position auf die (der/das) Canvas gezeichnet. Nun möchte ich, bevor der Schlegel übehaupt zum ersten Mal gezeichnet wird, den Hintergrundausschnitt abspeichern, und vor jedem Zeichenvorgang wieder laden, damit der Ausschnit "clear" ist.
Wie mach ich das?
Ich hab schon mit CopyRect rumgespielt, hat aber den Effekt, dass ich den Ausschnitt in einem einzelnen TRect habe und nicht mehr auf eine Canvas zurück bekomme...
-
Hi,
du kannst doch den Schlegel in ein Offscreem- Bitmap zeichnen. Dann diese Bitmap in den Canvas reinkopieren mit CopyRect.
Ich sag dir aber gleich-> Ruckelfrei wirds nicht.Abhilfe:
1. lade diese Kompo runter
2. lese dieses Tutorial
3. lese diese diese Dokumentation
4. kauf dir dieses BuchAlternative wäre DirectX
viel Spaß...
-
wenn du über NOCH einen Umweg gehst wird es Ruckelfrei:
-Hindergrund malen in das TBitmap bgrlayer1(einmalig am Start)
-Ein TBitmap spritelayer1 erzeugen und bei jedem "Frame" neu zeichnen(also Timerintervall oder wie du das machst)
-dann am Ende der Frameberechnung in einem DRITTEN TBitmap beispielsweise namens offscreen_bild das Bild wie es sein soll draufmalen
- und das offscreen_bild schliesslich auf die Form oder wo auchimmer hin malen.also
spritelayer1 bgr1layer1 //können natürlich noch mehr werden \ / \ / \ / offscreen_bild | | Form1 -> Canvas o.ä.
Das ist 100% ruckelfrei, ich hab auf diese Weise sone Art Rpgmaker nur mit Canvas gemacht, da ruckelt nix und das sogar auf meinem alten 500er :o
Ich glaub ich schreib wenn ich Zeit hab mal einen FAQ tauglichen Post dadrüber wenns genehm ist
so oft wie das hier auftaucht...[ Dieser Beitrag wurde am 02.07.2003 um 09:24 Uhr von dreaddy editiert. ]
-
Danke für die Hilfe,
hab aber noch ein weiteres Problem: Da ich windows.h mit in mein Programm einbinde gibts einen Namenskoflikt zwischen TBitmap und Windows::TBitmap.
Wie bring ich den Builder dazu das VCL-Bitmap zu verwenden??
Gibts da einen VCL-namespace??
-
Graphics::TBitmap* Bitmap=new Graphics::TBitmap;
@dreaddy : dat flackert widerlich wenn man fließende Bewegungen umsetzen möchte.
-
Wieso glaubt mir eigentlich nie jemand
Wenn der folgende Quellcode flackert kannst du dir bei mir ne Kiste Bier abholen :pAuf der Form brauchst du nur einen Timer dessen Intervall du beliebig einstellen kannst(hab den auf 50 ms).
Graphics::TBitmap* hintergrund = new Graphics::TBitmap; Graphics::TBitmap* sprite1 = new Graphics::TBitmap; Graphics::TBitmap* sprite2 = new Graphics::TBitmap; Graphics::TBitmap* offscreen_bild = new Graphics::TBitmap; void __fastcall TForm1::FormCreate(TObject *Sender) { //init // hintergrund layer, Inhalt immer Konstant hintergrund -> LoadFromFile("hintergrund.bmp"); // irgendein Bild das optimalerweise grösser als 250*250 ist hintergrund -> Height = 250; hintergrund -> Width = 250; //sprite layer 1, Bewegung kann nach jedem Frame anders sein, Spielerbewegungen beispielsweise oder eine scnelle animation wie ein ein drehendes Rad sprite1 -> Canvas -> Brush -> Color = clWhite; sprite1 -> Height = hintergrund -> Height; sprite1 -> Width = hintergrund -> Width; sprite1 -> Transparent = true; //sprite layer 2, Bewegung nach jedem zehnten Frame anders, Wasseranimationen, Baumbewegungen oder so sprite2 -> Canvas -> Brush -> Color = clWhite; sprite2 -> Height = hintergrund -> Height; sprite2 -> Width = hintergrund -> Width; sprite2 -> Transparent = true; //zwischenspeicher für endgültige Ausgabe(kann dann sofort auf Bildschirm usw gezeichnet werden offscreen_bild -> Height = hintergrund -> Height; offscreen_bild -> Width = hintergrund -> Width; } //--------------------------------------------------------------------------- int framecount = 0; void __fastcall TForm1::Timer1Timer(TObject *Sender) { framecount++; if(framecount > 125)framecount = 0; sprite1 -> Canvas->Brush->Color = clBlack; // löschen sprite1 -> Canvas->Pen->Color = clBlack; sprite1 -> Canvas->FillRect(TRect(0,0,250,250)); sprite1 -> Canvas->Brush->Color = clRed; // kreis zeichnen sprite1 -> Canvas->Pen->Color = clBlue; sprite1 -> Canvas->Font->Color = clBlue; sprite1 -> Canvas->Ellipse(0+framecount*2,0+framecount*2,50+framecount*2,50+framecount*2); sprite1 -> Canvas->Brush->Color = clYellow; // Text Zeichnen TDateTime aktdatum = aktdatum.CurrentDateTime(); sprite1 -> Canvas -> TextOut(5+framecount%25,5,"Hallo Welt, Zeit ist: "+aktdatum.DateTimeString()); // if(framecount%10)aendere_sprite2(); if(framecount%10) { sprite2 -> Canvas->Brush->Color = clBlack; // löschen sprite2 -> Canvas->Pen->Color = clBlack; sprite2 -> Canvas->FillRect(TRect(0,0,250,250)); sprite2 -> Canvas->Brush->Color = clGreen; // Text zeichnen sprite2 -> Canvas->Font->Color = clPurple; sprite2 -> Canvas -> TextOut(5+framecount%25,200,"Ich aktualisiere mich nur jedes 10te mal"); } offscreen_bild -> Canvas -> Draw(0,0,hintergrund); // kram auf zwischenbitmap zeichnen(geht um faktoren schneller als wenn man es direkt auf die Form macht) offscreen_bild -> Canvas -> Draw(0,0,sprite1); offscreen_bild -> Canvas -> Draw(0,0,sprite2); Form1->Canvas->Draw(10,10,offscreen_bild); // zwischenbitmap auf Form1 ausgeben
[ Dieser Beitrag wurde am 02.07.2003 um 11:07 Uhr von dreaddy editiert. ]
-
Danke für die Antworten,
flackern ist kein Problem, da der restliche Flipper auch flackert, das ist kein Bug, sonder ein Feature
Nee, im ernst, ist "nur" für eine Praktikum.Danke nochmals
-
@dreaddy :
ich teste es heut Abend. Ansonsten kannst du man beim Forumtreffen vorbeikommen und ne Kiste Bier mitbringen
-
@ dreaddy
Ich hab deinen code mal probiert, so wie er ist funzt's gut, aber wenn ich das Bild von 250 auf 500 vergrößere, dann ruckelts bei mir auf'm P4/1,8 ganz schön.
Der Einfachheit hab ich den geänderten code nochmal komplett reingesetzt.//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "Unit1.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; Graphics::TBitmap* hintergrund = new Graphics::TBitmap; Graphics::TBitmap* sprite1 = new Graphics::TBitmap; Graphics::TBitmap* sprite2 = new Graphics::TBitmap; Graphics::TBitmap* offscreen_bild = new Graphics::TBitmap; int framecount = 0; const int iWidth = 500; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::FormCreate(TObject *Sender) { //init // hintergrund layer, Inhalt immer Konstant hintergrund -> LoadFromFile("Hintergrund.bmp"); // irgendein Bild das optimalerweise grösser als 250*250 ist hintergrund -> Height = iWidth; hintergrund -> Width = iWidth; //sprite layer 1, Bewegung kann nach jedem Frame anders sein, Spielerbewegungen beispielsweise oder eine scnelle animation wie ein ein drehendes Rad sprite1 -> Canvas -> Brush -> Color = clWhite; sprite1 -> Height = hintergrund -> Height; sprite1 -> Width = hintergrund -> Width; sprite1 -> Transparent = true; //sprite layer 2, Bewegung nach jedem zehnten Frame anders, Wasseranimationen, Baumbewegungen oder so sprite2 -> Canvas -> Brush -> Color = clWhite; sprite2 -> Height = hintergrund -> Height; sprite2 -> Width = hintergrund -> Width; sprite2 -> Transparent = true; //zwischenspeicher für endgültige Ausgabe(kann dann sofort auf Bildschirm usw gezeichnet werden offscreen_bild -> Height = hintergrund -> Height; offscreen_bild -> Width = hintergrund -> Width; } //--------------------------------------------------------------------------- void __fastcall TForm1::Timer1Timer(TObject *Sender) { framecount++; if(framecount > (iWidth/2)) framecount = 0; sprite1 -> Canvas->Brush->Color = clBlack; // löschen sprite1 -> Canvas->Pen->Color = clBlack; sprite1 -> Canvas->FillRect(TRect(0,0,iWidth,iWidth)); sprite1 -> Canvas->Brush->Color = clRed; // kreis zeichnen sprite1 -> Canvas->Pen->Color = clBlue; sprite1 -> Canvas->Font->Color = clBlue; sprite1 -> Canvas->Ellipse(0+framecount*2,0+framecount*2,50+framecount*2,50+framecount*2); sprite1 -> Canvas->Brush->Color = clYellow; // Text Zeichnen TDateTime aktdatum = aktdatum.CurrentDateTime(); sprite1 -> Canvas -> TextOut(5+framecount%150,5,"Hallo Welt, Zeit ist: "+aktdatum.DateTimeString()); // if(framecount%10)aendere_sprite2(); if(framecount%10) { sprite2 -> Canvas->Brush->Color = clBlack; // löschen sprite2 -> Canvas->Pen->Color = clBlack; sprite2 -> Canvas->FillRect(TRect(0,0,iWidth,iWidth)); sprite2 -> Canvas->Brush->Color = clGreen; // Text zeichnen sprite2 -> Canvas->Font->Color = clPurple; sprite2 -> Canvas -> TextOut(5+framecount%150,450,"Ich aktualisiere mich nur jedes 10te mal"); } offscreen_bild -> Canvas -> Draw(0,0,hintergrund); // kram auf zwischenbitmap zeichnen(geht um faktoren schneller als wenn man es direkt auf die Form macht) offscreen_bild -> Canvas -> Draw(0,0,sprite1); offscreen_bild -> Canvas -> Draw(0,0,sprite2); Form1->Canvas->Draw(10,10,offscreen_bild); // zwischenbitmap auf Form1 ausgeben } //--------------------------------------------------------------------------- void __fastcall TForm1::FormDestroy(TObject *Sender) { delete hintergrund; delete sprite1; delete sprite2; delete offscreen_bild; } //---------------------------------------------------------------------------
Gruß WoWe
-
hehe,
hab ich mir doch gedacht. Ich test es trotzdem noch mal.
Ach ja, Copyrect wäre schneller. Hier mal ein Testprojekt:
//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "Unit1.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma link "ExtendedButton" #pragma link "MLCustomControl" #pragma link "TransparentButton" #pragma resource "*.dfm" #pragma inline __int64 diff_G1=0,diff_G2=0,diff_G3=0; int count=0; __int64 rdtsc(){ asm {dw 310Fh} }; TForm1 *Form1; bool temp=false; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { Timer1->Enabled=false; count=0; diff_G1=0; diff_G2=0; Timer1->Interval=StrToInt(Edit1->Text); Timer1->Enabled=true; } //--------------------------------------------------------------------------- void __fastcall TForm1::Button2Click(TObject *Sender) { Timer1->Enabled=false; Memo1->Lines->Add("Anzahl= "+IntToStr(count)); Memo1->Lines->Add("Copy= "+FloatToStr(double(diff_G1)/count)); Memo1->Lines->Add("draw= "+FloatToStr(double(diff_G2)/count)); Memo1->Lines->Add("FILL= "+FloatToStr(double(diff_G3)/count)); } //--------------------------------------------------------------------------- void __fastcall TForm1::Timer1Timer6(TObject *Sender) { __int64 s1,s2,e1,e2,e3,s3; count++; s1=rdtsc(); if(temp) Form1->Canvas->CopyRect(Image2->ClientRect,Image2->Canvas,TRect(0,0,Image2->Width,Image2->Height)); else Form1->Canvas->CopyRect(Image1->ClientRect,Image1->Canvas,TRect(0,0,Image1->Width,Image1->Height)); e1=rdtsc(); s2=rdtsc(); if(temp) Form1->Canvas->StretchDraw(TRect(Image2->Width,Image2->Height,Image2->Width*2,Image2->Height*2),Image2->Picture->Bitmap) ; else Form1->Canvas->StretchDraw(TRect(Image1->Width,0,Image1->Width*2,Image1->Height),Image1->Picture->Bitmap) ; e2=rdtsc(); s3=rdtsc(); if(temp) //Form1->Canvas->CopyRect(Image2->ClientRect,Image2->Canvas,TRect(0,0,Image2->Width,Image2->Height)); Form1->Canvas->Brush->Bitmap=Image2->Picture->Bitmap; else Form1->Canvas->Brush->Bitmap=Image1->Picture->Bitmap; Form1->Canvas->FillRect(TRect(0,0,Image2->Width,Image2->Height)); e3=rdtsc(); temp^=1; diff_G1+=e1-s1; diff_G2+=e2-s2; diff_G3+=e3-s3; }
soll ich euch ne Version mit OpenGL bastel ?
Da ruckelt gar nichts.[ Dieser Beitrag wurde am 02.07.2003 um 13:22 Uhr von AndreasW editiert. ]
-
@ AndreasW
Na, so'n OpenGL Beispiel wär doch bestimmt auch für die FAQ gut
-
Okok, man irgendwo abstriche machen muss, sei es Auflösung, Grösse oder sonstwas wenn man sehr viel mit Canvas zeichnet stimmt schon, sonst wäre dx und opengl ja auch überflüssig
Ich will hier nicht sagen das man alles mit Canvas machen kann, aber das man sehr viel damit machen kann wenn man etwas nachdenkt und optimiert.
Die meisten Bilder sind nämlich eh immer die selben.Also halbwegs laufen ohne das ganze Konzept über Bord zu werfen tut es auf meinem pc mit 500*500 übrigens jetzt so:
//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "Unit1.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; Graphics::TBitmap* hintergrund = new Graphics::TBitmap; Graphics::TBitmap* sprite1 = new Graphics::TBitmap; Graphics::TBitmap* sprite2 = new Graphics::TBitmap; Graphics::TBitmap* offscreen_bild = new Graphics::TBitmap; int framecount = 0; const int iWidth = 500; TDateTime aktdatum = aktdatum.CurrentDateTime(); TRect ausschnitt(0,0,iWidth, iWidth); //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::FormCreate(TObject *Sender) { //init // hintergrund layer, Inhalt immer Konstant hintergrund -> LoadFromFile("Hintergrund.bmp"); // irgendein Bild das optimalerweise grösser als 250*250 ist hintergrund -> Height = iWidth; hintergrund -> Width = iWidth; hintergrund -> PixelFormat = pf8bit; //sprite layer 1, Bewegung kann nach jedem Frame anders sein, Spielerbewegungen beispielsweise oder eine scnelle animation wie ein ein drehendes Rad sprite1 -> Canvas -> Brush -> Color = clWhite; sprite1 -> Height = hintergrund -> Height; sprite1 -> Width = hintergrund -> Width; sprite1 -> Transparent = true; sprite1 -> PixelFormat = pf8bit; //sprite layer 2, Bewegung nach jedem zehnten Frame anders, Wasseranimationen, Baumbewegungen oder so sprite2 -> Canvas -> Brush -> Color = clWhite; sprite2 -> Height = hintergrund -> Height; sprite2 -> Width = hintergrund -> Width; sprite2 -> Transparent = true; sprite2 -> PixelFormat = pf8bit; //zwischenspeicher für endgültige Ausgabe(kann dann sofort auf Bildschirm usw gezeichnet werden offscreen_bild -> Height = hintergrund -> Height; offscreen_bild -> Width = hintergrund -> Width; offscreen_bild -> PixelFormat = pf8bit; } //--------------------------------------------------------------------------- void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action) { delete hintergrund; delete sprite1; delete sprite2; delete offscreen_bild; } //--------------------------------------------------------------------------- int zwischen = 1; void __fastcall TForm1::Timer1Timer(TObject *Sender) { sprite1 -> Canvas->Brush->Color = sprite1 -> TransparentColor; // löschen sprite1 -> Canvas->Pen->Color = sprite1 -> TransparentColor; sprite1 -> Canvas->Font->Color = sprite1 -> TransparentColor; sprite1 -> Canvas->Ellipse(0+framecount*2,0+framecount*2,50+framecount*2,50+framecount*2); sprite1 -> Canvas -> TextOut(5+framecount%150,5,"Hallo Welt, Zeit ist: "+aktdatum.DateTimeString()); framecount++; if(framecount > (iWidth/2))framecount = 0; if(!(framecount%10)) { sprite2 -> Canvas->Brush->Color = sprite2 -> TransparentColor; // löschen sprite2 -> Canvas->Font->Color = sprite2 -> TransparentColor; sprite2 -> Canvas -> TextOut(5+zwischen%150,200,"Ich aktualisiere mich nur jedes 10te mal"); } if(!(framecount%10)) { sprite2 -> Canvas->Brush->Color = clYellow; // löschen sprite2 -> Canvas->Font->Color = clRed; sprite2 -> Canvas -> TextOut(5+framecount%150,200,"Ich aktualisiere mich nur jedes 10te mal"); zwischen = framecount; } aktdatum = aktdatum.CurrentDateTime(); sprite1 -> Canvas->Brush->Color = clRed; // kreis zeichnen sprite1 -> Canvas->Pen->Color = clBlue; sprite1 -> Canvas->Font->Color = clBlue; sprite1 -> Canvas->Ellipse(0+framecount*2,0+framecount*2,50+framecount*2,50+framecount*2); sprite1 -> Canvas->Brush->Color = clYellow; // Text Zeichnen sprite1 -> Canvas -> TextOut(5+framecount%150,5,"Hallo Welt, Zeit ist: "+aktdatum.DateTimeString()); offscreen_bild -> Canvas -> Draw(0,0,hintergrund); // kram auf zwischenbitmap zeichnen(geht um faktoren schneller als wenn man es direkt auf die Form macht) offscreen_bild -> Canvas -> Draw(0,0,sprite1); offscreen_bild -> Canvas -> Draw(0,0,sprite2); Form1->Canvas->CopyRect(ausschnitt,offscreen_bild->Canvas,ausschnitt); // zwischenbitmap auf Form1 ausgeben } //---------------------------------------------------------------------------
Ach und ja ein Opengl Beispiel wäre schon nicht schlecht
-
hm,
wenn ich morgen abend Zeit finde mach ichs fertig...