Effektiv Sprites teilen

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
Xaby
Beiträge: 2144
Registriert: 12.11.2005 11:29
Wohnort: Berlin + Zehdenick
Kontaktdaten:

Effektiv Sprites teilen

Beitrag von Xaby »

Ich spiele mit dem Gedanken, dass ich Bilder jeglicher Größe auf einem Screen als Sprites ausgeben können möchte.

Da ich Sprites mit einem Sprite3D auch drehen und verzerren kann.
So wie einige Effekte realisieren kann, die mit Images nicht möglich sind.
Ich glaube auch, dass Images langsamer sind als Sprites.

In PureBasic 3.94 ist mir aufgefallen, dass ein 640 x 480 großes Sprite langsamer ist also 20 x 15 Sprites, die je 32 x 32 Pixel groß sind.

Ich glaube auch, dass 512 x 512 große Sprites langsamer sind als entsprechend viele kleine 32 x 32 große Sprites. Das wird sicherlich von Grafikkarte zu Grafikkarte unterschiedlich sein.

Noch schlimmer wird es bei Bildern, die 4800 x ... groß sind,
die ja zusätzlich auch noch die Bildschirmgröße überschreiten.

Gibt es eine einfache Möglichkeit, die auch noch schnell und einfach zu handeln ist, nur einen "SpriteBlock" anzusteuern, obwohl dieser "SpriteBlock" aus mehreren Sprites besteht?

Denkbar wäre, dass es Aufgabe des Grafikkartentreibers ist oder PB intern regelt, aber das scheint nicht so zu sein.

Meine Idee waren LinkedLists()

aber wenn man eine unbekannte Anzahl an größeren Sprites benutzen möchte und diese in kleinere Sprites geteilt sind, kommt man wieder zu der Problematik der LinkedLists()
darüber hinaus müssten alle 2D-Drawingbefehle so ausgerichtet sein, dass man auf dem richtigen "Teil-Sprite" zeichnet, wenn man einen SpriteBlock als DrawingOutput angibt.

Diesen Aufwand halte ich für etwas übertrieben.

Klar könnte man auch auf "riesige" Sprites verzichten.
Aber genau das will ich ja nicht.

Ich würde gern eine Art DiaShow machen, wo sich meine Aufnahmen drehen und zoomen lassen. Und wie ihr wisst, sind selbst im Amateurbereich 3000 x 2000 Pixel für Bilder keine Seltenheit mehr.

:roll:

>>>>>>>>>>>>>>>>>>>

Um 640 x 480 große Bilder als kompatible Textur für alle Grafikkarten nutzen können, wäre die Überlegung, dass man 1024 x 1024 als Textur nimmt. Dann fällt einem aber auf, dass die Zahlen ja auch schon Recht hoch sind. Es soll Grafikkarten geben, dir nur 512 x 512 oder sogar noch weniger unterstützen.

Der N64 konnte nur 32 x 32 große Texturen verarbeiten.

Einige Grafikkarten können auch 1024 x 512 oder jede Größe verarbeiten.

Da ich bei einem Text auf einer nVIDEA-Grafikkarte, die vielleicht maximal zwei Jahre alt war, hässliche Streifen bei einem 600 x 900 Bild gesehen habe als mein Screen eine Auflösung von 800 x 600 hatte, hab ich mir gedacht, das ist doof.

:freak:

Sollten die Sprites immer kleiner als der Screen sein?
Clipping-Probleme? Ich würde aber gern eine "SlideShow" machen, wo Bilder auch außerhalb des Screens sein können, die man dann zoomen und verschieben kann.

Auf einer QaudroFX mit 64 MB und auf einer 7500 LE mit 256 MB treten diese Streifen nicht auf.

Es wäre halt nur doof, wenn ein User sich auf "mein Programm" freut und dann genau bei dem das nicht läuft.

:freak:
Kinder an die Macht http://scratch.mit.edu/
Benutzeravatar
dige
Beiträge: 1239
Registriert: 08.09.2004 08:53

Beitrag von dige »

@Xaby: kannst Du Dich nicht mal kurzfassen, oder zum Schluß ein Summary an den Anfang stellen? :wink:

Ehe man hier "Gegeben" und "Gesucht" rausgefischt hat ist der Kaffee kalt. *muahaha* :lol:

So das nur um den Text ein bischen "voll" zu machen ... und hier kommt
jetzt erst die eigentliche Antwort, die sich eingebettet in weiteren Füllwörten versteckt.

Sprites sollten immer kleiner als Deine ScreenSize sein und idealerweise
quadratisch mit einer Seitenlänge 2^x entsprechen. Damit stellst Du sicher
das es auch auf alten GraKas läuft..

Das ganze erübrigt sich allerdings mit DirectX9 .. das aber in PB4.20 noch
nicht richtig funktioniert.
"Papa, ich laufe schneller - dann ist es nicht so weit."
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

> Sprites sollten immer kleiner als Deine ScreenSize sein
das ist wichtig.

> idealerweise quadratisch mit einer Seitenlänge 2^x entsprechen.
> Damit stellst Du sicher das es auch auf alten GraKas läuft..
stimmt so nicht ganz, das gilt nur für sprites aus denen man Sprite3D machen will.
"normale" 2D sprites sind flexibler.


das kleinere sprites schneller sind liegt daran, dass bei ihnen weniger
geclippt werden muss, wenn ein stück über den screen übersteht.
außerdem kannst du das gesamtlayout so einrichten,
dass du eine minimale überlappung herstellst.

also, wenn du einen Hintergrund für einen 1024x768 screen darstellen willst,
und du setzt ihn aus 32² sprites zusammen, brauchst du nur 33x25 sprites zu nehmen,
also insgesamt 1056x800 pixel darstellen.
wenn du sprites der größe 512x384 nimmst, brauchst du 3x3 sprites insgesamt,
und musst 1536x1152 pixel darstellen.

außerdem sind transparente pixel langsamer als nicht transparente,
wenn du also möglichst wenig transparenz in den tiles hast,
sparst du ebenfalls zeit.

ein eklatanter Geschwindigkeitsunterschied entsteht aus dem Speicherort:
Sprites die im Speicher der Graka stehen sind wesentlich schneller als welche, die im Hauptspeicher stehen.

um ein tileset zu erzeugen, kannst du life clippen, oder besser noch vorab.
wenn du ein großes bild nimmst, das du zerlegen willst, mach den zerlegevorgang
vorab separat, und zur darstellung nimm dann einzelne kleine sprites.


grundsätzlich ist es auch wesentlich einfacher, ein Array zu verwenden als ein LinkedList.
eine kleine Tile-Engine kannst du dir hier mal ansehen:
http://www.purebasic.fr/german/viewtopi ... 634#116634

weitere Diskussionen und Beispiele findest du im ganzen Forum unter den Suchbegriffen
"Tile", "Tileengine", "Tile-Engine", "2D Engine", usw.


PS:
wenn du von einem Objekt Teilsprites erstellen willst,
lohnt es sich oft, mit unregelmäßigen größen zu arbeiten,
dann kannst du weitläufige transparente Bereiche vermeiden.
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Benutzeravatar
Xaby
Beiträge: 2144
Registriert: 12.11.2005 11:29
Wohnort: Berlin + Zehdenick
Kontaktdaten:

Beitrag von Xaby »

Arrays würde ich ja gern benutzen, aber wie kann ich ein geteiltes Objekt in eine Struktur packen?

Als Beispiel:
"Haus" ist 640 x 480 Pixel
"Baum" ist 50 x 200 Pixel

Objekt-Struktur:
Name
Höhe
Breite
Menge der Teile

Die Menge der Teile ist aber bei Baum und Haus unterschiedlich

:roll:

Ich hoffe auch, dass ihr euch bei den Überlegungen nicht zu sehr auf "Tile" versteift.

Ich möchte gern größere Bilder drehen.
Die Wahrscheinlichkeit, dass meine Sprites nicht doppelt sind, ist sehr groß, weil es ja Fotos sind und keine zusammengebastelten Maps.
Kinder an die Macht http://scratch.mit.edu/
Benutzeravatar
dige
Beiträge: 1239
Registriert: 08.09.2004 08:53

Beitrag von dige »

Wenn Du Überblendeffekte machen willst (drehen, schieben etc.) würde
ich das nicht mit nem Tileset machen. Sondern ein möglichst großes Sprite
erstellen, da in etwas der Bildschirmgröße entspricht und dann damit
arbeiten.

Denke mal der Aufwand für das rotieren eines Bildes, zerlegt in ein Tileset
dürfte ziemlich aufwendig werden..
"Papa, ich laufe schneller - dann ist es nicht so weit."
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

yo eine z-rotation würde ich auch nicht mit einzelteilen machen.
das ist nahezu unmöglich, die ganzen einzelkoordinaten zu berechnen.
bedenke auch, dass die rechnerisch nicht immer bei ganzzahligen
pixel-positionen liegen, aber setzen kannst du nur ganzzahlig.

du kannst ein 1024x768 Bild mittig auf ein 1024² sprite aufsetzen, und daraus ein Sprite3D machen.
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Benutzeravatar
Xaby
Beiträge: 2144
Registriert: 12.11.2005 11:29
Wohnort: Berlin + Zehdenick
Kontaktdaten:

Beitrag von Xaby »

Ihr seht also das Problem, da bin ich ja schon mal beruhigt.

Nun aber das Problem, ich möchte eine Bildschirmauflösung von 800 x 600 nutzen, wir haben aber festgestellt, dass ein Sprite für Sprite3D nicht größer als die Bildschirmauflösung sein darf.

Dazu kommt, dass ich unter Umständen das Bild auch rein und raus zoomen möchte. Also nicht nur ein 512 x 512 großes Sprite auf einem 800 x 600 Screen rotieren lassen will, sondern eher ein 4096 x 4096 großes Sprite auch auf 256 x 256 runter skalieren möchte, aber auch wieder Details sehen will.

Möglichst ohne dass ich ständig Festplattenzugriff habe und ein Image lade und das dann auf Sprites verteile.

Code: Alles auswählen

; English forum: http://www.purebasic.fr/english/viewtopic.php?t=9263 
; Author: einander (updated for PB 4.00 by Andre + edel) 
; Date: 22. January 2004 
; OS: Windows 
; Demo: No 


; Problem: innerhalb der Event-Rountine wird zwar offensichtlich die Maus abgefragt, es passiert aber nichts... 


;Stretching grid by Einander  (updated Sizes() procedure included) 
;PB 3.81 - jan 22-2004 

Enumeration 
  #grid 
  #IMG 
EndEnumeration 

Global Xmin, Ymin, Xmax, Ymax 
Global _X, _Y, XX, YY, s$, MX, MY, MK, mxant, myant 
Global  Xpoints, Ypoints 

Global Dim Xgrid(0, 0) : Global Dim Ygrid(0, 0) : Global Dim Xstep.f(0) : Global Dim Ystep.f(0) 

_X = GetSystemMetrics_(#SM_CXSCREEN) - 8 : _Y = GetSystemMetrics_(#SM_CYSCREEN) - 68 
XX = _X / 2 : YY = _Y / 2 
Global Dim PX(3) : Global Dim PY(3) 

Procedure VarL(DIR, i) ; RET ELEM I DEL ARRAY CON DIRECCION DIR 
  ProcedureReturn PeekL(DIR + i * 4) ; VALE COMO REEMPLAZO PARA PASAR ARRAYS A PROCS 
EndProcedure 

Procedure Near(x, y, ArrSize, DIR1, DIR2) ; ; retorna indice del elem de LOS ARRAYS EN DIR1, DIR2 mas Near a x,y 
  min = $FFFF 
  For i = 0 To ArrSize 
    A = Sqr(Pow(x - VarL(DIR1, i), 2) + Pow(y - VarL(DIR2, i), 2)) 
    If A < min : min = A : IN = i: EndIf 
  Next i 
  ProcedureReturn IN 
EndProcedure 

Procedure.s LoadIMG() 
  Show$ = "c:\" 
  Pat$ = "BitMap (*.BMP)|*.bmp;*.bmp|Jpg (*.jpg)|*.bmp|All files (*.*)|*.*" 
  File$ = OpenFileRequester("Choose file to load", Show$, Pat$, 0) 
  If File$ 
    ProcedureReturn File$ 
  Else 
    End 
  EndIf 
EndProcedure 

Procedure MOU(Ev) 
  Select Ev 
    Case #WM_LBUTTONDOWN 
      If MK = 2 : MK = 3 : Else : MK = 1 : EndIf 
    Case #WM_LBUTTONUP 
      If MK = 3 : MK = 2 : Else : MK = 0 : EndIf 
    Case #WM_RBUTTONDOWN 
      If MK = 1 : MK = 3 : Else : MK = 2 : EndIf 
    Case #WM_RBUTTONUP 
      If MK = 3 : MK = 1 : Else : MK = 0 : EndIf 
    Case #WM_MOUSEMOVE 
      MX = WindowMouseX(0) - GetSystemMetrics_(#SM_CYSIZEFRAME) 
      MY = WindowMouseY(0) - GetSystemMetrics_(#SM_CYCAPTION) - GetSystemMetrics_(#SM_CYSIZEFRAME) 
  EndSelect 
EndProcedure 

Procedure Sizes() 
  Xmax = 0 : Xmin = _X : Ymax = 0 : Ymin = _Y 
  For i = 0 To 3 
    x = PX(i) : y = PY(i) 
    If x < Xmin : Xmin = x : EndIf 
    If x > Xmax : Xmax = x : EndIf 
    If y < Ymin : Ymin = y : EndIf 
    If y > Ymax : Ymax = y : EndIf 
  Next 
  
  Xstep(0) = (PX(1) - PX(0)) / Xpoints ; step X horiz sup 
  Ystep(0) = (PY(1)-PY(0)) / Xpoints ; step Y HOR SUP 
  
  Xstep(1) = (PX(2) - PX(3)) / Xpoints ; stepX HOR INF 
  Ystep(1) = (PY(2)-PY(3)) / Xpoints ; step Y HOR INF 
  
  Xstep(2) = (PX(3) - PX(0)) / Ypoints ; step X VER IZQ 
  Ystep(2) = (PY(3)-PY(0)) / Ypoints ; step Y VER IZQ 
  
  Xstep(3) = (PX(2) - PX(1)) / Ypoints ; step X VER DER 
  Ystep(3) = (PY(2)-PY(1)) / Ypoints ; step Y VER DER 
  
  DXstep1.f=(Xstep(1)-Xstep(0))/Ypoints  ; para calcular posic horiz de cruces internos 
  DpX1.f=(PX(3)-PX(0))/Ypoints 
  DXstep2.f=(Ystep(1)-Ystep(0))/Ypoints 
  DpX2.f=(PY(3)-PY(0))/Ypoints 
  
  For j=0 To Ypoints 
    For i = 0 To Xpoints  ; posic x  para verticales 
      Xgrid(i, j) = (Xstep(0)+DXstep1*j)*i+PX(0)+DpX1*j : Ygrid(i, j) = (Ystep(0)+DXstep2*j)*i+PY(0)+DpX2*j 
    Next 
  Next 
  
  DYstep1.f=(Xstep(3)-Xstep(2))/Xpoints  ; para calcular posic vert de cruces internos 
  DpY1.f=(PX(1)-PX(0))/Xpoints 
  DYstep2.f=(Ystep(3)-Ystep(2))/Xpoints 
  DpY2.f=(PY(1)-PY(0))/Xpoints 
  
  For j = 1 To Xpoints 
    For i = 1 To Ypoints  ; posic Y  para horizontales 
      Xgrid( j,i) = (Xstep(2)+DYstep1*j)*i+PX(0)+DpY1*j  :  Ygrid( j,i) = (Ystep(2)+DYstep2*j)*i+PY(0)+DpY2*j 
    Next 
  Next 
EndProcedure ; _______________________________ 

Procedure ShowGrid() 
  hIMG = CreateImage(#IMG, _X,_Y) 
  StartDrawing (ImageOutput(#IMG)) 
  DrawingMode(4) 
  BackColor(RGB(0,0,0)) 
  
  For i = 0 To 3 
    Circle (PX(i) , PY(i) , 8,#Yellow) 
    DrawText(PX(i) + 10, PY(i), Str(i)) 
  Next 
  Box(Xmin, Ymin, Xmax-Xmin, Ymax-Ymin, #Blue) 
  
  For i = 0 To Xpoints ; vertical lines 
    LineXY(Xgrid( i, 0), Ygrid( i, 0), Xgrid(i, Ypoints ), Ygrid(i, Ypoints ),  #Green) 
  Next 
  
  For i = 0 To Ypoints ;horizontal lines 
    LineXY(Xgrid(0,i), Ygrid(  0,i), Xgrid( Xpoints,i ), Ygrid( Xpoints,i ),  #Magenta) 
  Next 
  
  StopDrawing() 
  StartDrawing(WindowOutput(0)) 
  SetGadgetState(#grid, ImageID(#IMG)) 
  StopDrawing() 
EndProcedure 
; ____________________________________________________________________________________________________ 

OpenWindow(0, 0, 0, _X, _Y, "", #WS_OVERLAPPEDWINDOW | #WS_MAXIMIZE) 
CreateGadgetList(WindowID(0)) 
ImageGadget(#grid,0,0,0,0,0) 

DisableGadget(#grid,#True) 

Xpoints = 28 : Ypoints = 14; Here you can choose how many grid lines********************************* 
Dim Xgrid (Xpoints , Ypoints ) 
Dim Ygrid (Xpoints , Ypoints ) 
Dim Xstep.f(3 ) : Dim Ystep.f(3 ) 

PX(0) = _X / 2-100 : PY(0) = _Y / 2-100 : PX(1) = PX(0) + 200 : PY(1) = PY(0) 
PX(2) = PX(1) : PY(2) = PY(1) + 200 : PX(3) = PX(0) : PY(3) = PY(2) 

Sizes() 
ShowGrid() 

Repeat 
  Ev = WaitWindowEvent(10) 
  
  MOU(Ev) 
  
  If mx <> mxant Or MY <> myant Or MK <> mkant 
    If sel=0 :   C = Near(mx, MY, 3, @PX(), @PY()):sel=1:EndIf 
    If MK = 1 
      PX(C) = mx : PY(C) = MY 
      Sizes() 
      ShowGrid() 
    Else 
      sel=0 
    EndIf 
  EndIf 
  mxant = mx : myant = MY : mkant = MK 
Until Ev = #PB_Event_CloseWindow 
End 

Nur halt mit Sprites und Sprite3D für jedes "Kästchen"

Ich frage mich nur, wenn man nun 100 Bilder verwalten möchte, oder wenigstens eine Hand voll, wie man da vernünftig die Sprites ansteuern kann.

Jedes Bild müsste ein Objekt sein, welches eine bestimmte Anzahl von Sprites und 3DSprites beherbergt.

Das Objekt selbst bräuchte ja nur die Eckpunkte dieses Gitternetzes haben und bei jeder Darstellung würden die LinienKreuzungen die Eckpunkte der 3D-Sprites darstellen.

:roll:

>>>>>>>>>>>>>>>>>

Es ist wichtig, dass ich mehr als ein Bild gleichzeitig darstellen kann.
So dass man auch diese "TimeMashine"-Effekte machen kann.
Also im Hintergrund Bilder sind, die später kommen.

Gut, da müsste man dann vielleicht auch noch ausgeklügelte Preloader haben.

Kennt hier das hier:

http://de.youtube.com/watch?v=jjXcuzY3xAQ

und die Eingabe entweder mit Maus, oder
http://www.purebasic.fr/german/viewtopic.php?t=16871
(ermöglicht auch zwei Cursor, Maus und Stift gleichzeitig unabhängig von einander, oder:
http://de.youtube.com/watch?v=pQpr3W-YmcQ

Und dann irgendwie mit AviCap32.DLL oder so :roll:

Können das gern auch als Projekt machen 8)
Kinder an die Macht http://scratch.mit.edu/
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

wenn ich mich recht entsinne, gilt die sprite-maximal-screensize-einschränkung hauptsächlich für 2D sprites, die du clippen willst.

eine 4096²-texture zu verwenden funktioniert sowieso erst ab neueren Grafikkarten.
bis zur Generation von GF3 oder GF4 war 1024² die Obergrenze.

ich würde an deiner stelle mal einen testlauf fahren, eine kleine exe herstellen,
die aus einem 4096²-Sprite ein Sprite3D macht, und das zoomt und rotiert,
und mal die Kollegen in den Foren (auch im internationalen!) fragen,
wo es zuverlässig funktioniert und was für eine Grafikkarte sie haben.

letztendlich lohnt es sich nicht, zu weit abwärtskompatibel zu arbeiten.
auf dem alten Lappi von meinem Dad würde das vielleicht nicht funktionieren,
aber dort würde auch die getilete lösung keinen spaß machen,
weil die bestimmt mit ner Framerate von 5-10 rüberkommt.
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Antworten