Schnellere Ovalfunktion

Übersicht BlitzBasic Codearchiv

Neue Antwort erstellen

Noobody

Betreff: Schnellere Ovalfunktion

BeitragFr, Sep 19, 2008 13:14
Antworten mit Zitat
Benutzer-Profile anzeigen
Da mich die langsame Ovalfunktion von Blitz schon immer genervt hat, habe ich eine schnellere Alternative geschrieben.
Insbesondere bei leeren Ellipsen ist sie um einiges schneller als Blitz, bei gefüllten Ellipsen ungefähr gleichschnell.
Von der Handhabung her ist sie gleich wie die die Standardfunktion, man muss also bei bereits bestehenden Codes lediglich 'Oval' durch 'DrawOval' ersetzen.

Hier die Funktion zusammen mit einer kleinen Testumgebung, mit der man die Geschwindigkeit vergleichen kann:
BlitzBasic: [AUSKLAPPEN]
Graphics 800, 600, 0, 2
SetBuffer BackBuffer()

Const DRAW_BLITZ = 0
Const DRAW_NOOBODY = 1
Const DRAW_EMTPY = 0
Const DRAW_FILLED = 1

Global FunctionName$[ 1 ]
FunctionName[ DRAW_BLITZ ] = "Blitzfunktion"
FunctionName[ DRAW_NOOBODY ] = "Neue Funktion"
Global FillName$[ 1 ]
FillName[ DRAW_BLITZ ] = "Leer"
FillName[ DRAW_NOOBODY ] = "Gefüllt"

Timer = CreateTimer( 60 )

Global StartX = 50, StartY = 50, EndX = 250, EndY = 250
Global DrawFunction, DrawMode

While Not KeyHit( 1 )
Cls

Rect StartX, StartY, EndX - StartX, EndY - StartY, 0

Counter = MilliSecs()
If DrawFunction = DRAW_BLITZ Then
Oval StartX, StartY, EndX - StartX, EndY - StartY, ( DrawMode = DRAW_FILLED )
Else
DrawOval StartX, StartY, EndX - StartX, EndY - StartY, ( DrawMode = DRAW_FILLED )
EndIf
Timestep = MilliSecs() - Counter

If MouseHit( 1 ) Then
StartX = MouseX()
StartY = MouseY()
ElseIf MouseHit( 2 ) Then
EndX = MouseX()
EndY = MouseY()
EndIf

If KeyHit( 57 ) Then DrawFunction = Not DrawFunction
If KeyHit( 28 ) Then DrawMode = Not DrawMode

Text 0, 0, "Leertaste zum Wechseln zwischen Blitzinterner und neuer Ovalfunktion. Momentan: " + FunctionName[ DrawFunction ]
Text 0, 15, "Enter zum Wechseln zwischen gefülltem/leerem Oval. Momentane Einstellung: " + FillName[ DrawMode ]
Text 0, 30, "Linke/Rechte Maustaste zum setzen von Anfangs/Endpunkt des Ovals. Benötigte Zeit: " + TimeStep + " ms"

Flip 0
WaitTimer Timer
Wend
End

Function DrawOval( X, Y, B#, A#, Filled = False )
LockBuffer BackBuffer()

ARGB = ( ColorRed() Shl 16 ) + ( ColorGreen() Shl 8 ) + ColorBlue()

If B# < 0 Then
X = X + B#
B# = Abs( B# )
EndIf

If A# < 0 Then
Y = Y + A#
A# = Abs( A# )
EndIf

B2 = B# Shr 1
A2 = A# Shr 1

If Filled Then
For XPos# = X To X + B2
YPos# = Sin( ACos( ( XPos - X - B2 )/B2 ) )*B2
YPos# = Abs( ( YPos*A2 )/B2 )

Line XPos, Y - YPos + A2, XPos, Y + YPos + A2
Line ( X Shl 1 ) + B - XPos, Y - YPos + A2, ( X Shl 1 ) + B - XPos, Y + YPos + A2
Next
Else
For XPos# = X To X + B2
YPos# = Sin( ACos( ( XPos - X - B2 )/B2 ) )*B2
YPos# = ( YPos*A2 )/B2
XPos2 = ( X Shl 1 ) + B - XPos

WritePixel XPos, YPos# + Y + A2, ARGB
WritePixel XPos, -YPos# + Y + A2, ARGB

WritePixel XPos2, YPos# + Y + A2, ARGB
WritePixel XPos2, -YPos# + Y + A2, ARGB
Next

For YPos = Y To Y + A2
XPos# = Sin( ACos( ( YPos - Y - A2 )/A2 ) )*A2
XPos# = ( XPos*B2 )/( A2 )
YPos2 = ( Y Shl 1 ) + A - YPos

WritePixel XPos + X + B2, YPos#, ARGB
WritePixel -XPos + X + B2, YPos#, ARGB

WritePixel XPos + X + B2, YPos2, ARGB
WritePixel -XPos + X + B2, YPos2, ARGB
Next
EndIf

UnlockBuffer BackBuffer()
End Function


Übrigens funktioniert diese Funktion auch bei negativer Breite und Höhe, währen das die Blitzfunktion nicht tut Wink
Aber das nur mal so am Rande.
  • Zuletzt bearbeitet von Noobody am Di, Sep 22, 2009 8:34, insgesamt 5-mal bearbeitet

ToeB

BeitragFr, Sep 19, 2008 13:49
Antworten mit Zitat
Benutzer-Profile anzeigen
Is ja geil :
Blitz : 5~6
Deine : 0~1
^^

Aber nur im "Filled = 0" modus. Filled = 1 isses genau andersrum, das is Blizt schneller Wink

mfg ToeB
Religiöse Kriege sind Streitigkeiten erwachsener Männer darum, wer den besten imaginären Freund hat.
Race-Project - Das Rennspiel der etwas anderen Art
SimpleUDP3.0 - Neuste Version der Netzwerk-Bibliothek
Vielen Dank an dieser Stelle nochmal an Pummelie, welcher mir einen Teil seines VServers für das Betreiben meines Masterservers zur verfügung stellt!

aMul

Sieger des Minimalist Compo 01/13

BeitragFr, Sep 19, 2008 16:09
Antworten mit Zitat
Benutzer-Profile anzeigen
Bei mir ist deine Funktion selbst gefüllt noch doppelt so schnell wie die von Blitz.
Eine überraschende Tatsache, dass man die Blitzbefehle mit anderen Blitzbefehlen schneller nachschreiben kann.

Wenn man übrigens die WritePixel durch WritePixelFast ersetzt, wir es nochmal ein gutes Stück schneller. Ich vermute einfach mal spontan, dass das ein Fehler deinerseits war, oder?
Panic Pong - ultimate action mashup of Pong and Breakout <= aktives Spiele-Projekt, Downloads mit vielen bunten Farben!
advASCIIdraw - the advanced ASCII art program <= aktives nicht-Spiele-Projekt, must-have für ASCII/roguelike/dungeon-crawler fans!
Alter BB-Kram: ThroughTheAsteroidBelt - mit Quelltext! | RGB-Palette in 32²-Textur / Farbige Beleuchtung mit Dot3 | Stereoskopie in Blitz3D | Teleport-Animation Screensaver

Mr.Keks

BeitragFr, Sep 19, 2008 16:27
Antworten mit Zitat
Benutzer-Profile anzeigen
Bei mir braucht das gefüllte Blitzoval nur 1-2 ms, wenn ich es auf die ganze Bildgröße ziehe im Vergleich zu 12 ms mit der neuen Version. Filled=False ist aber tatsächlich schneller. Komischerweise braucht Blitz bei mir dafür auch länger als für Filled. Ich habe bei dem neuen Filled mal Rect statt der Schleife eingesetzt und damit wird es zumindest auf meinem Rechner fast gleichschnell zu Blitz' FilledOval.

@amul: Dann musst du aber noch eine Abfrage reinsetzen, damit nicht außerhalb des Bildschirms gezeichnet wird. Und die kostet dann wiederum Zeit.
MrKeks.net

FireballFlame

Betreff: Re: Schnellere Ovalfunktion

BeitragFr, Sep 19, 2008 16:32
Antworten mit Zitat
Benutzer-Profile anzeigen
Noobody hat Folgendes geschrieben:
Von der Handhabung her ist sie gleich wie die die Standartfunktion, lediglich beim letzten Parameter muss man noch eine Farbe (im ARGB - Format) angeben, wenn man was anderes als weiss will.

Wenn du den Anfang der Funktion in Code: [AUSKLAPPEN]
Function Oval( X, Y, B#, A#, Filled = True)
   LockBuffer BackBuffer()
   
   Local ARGB=-16777216+65536*ColorRed()+256*ColorGreen()+ColorBlue()
änderst, dann kannst du sie genau wie die Originalfunktion verwenden Wink

Bei mir ist aber beim Füllen die Originalfunktin auch schneller.
PC: Intel Core i7 @ 4x2.93GHz | 6 GB RAM | Nvidia GeForce GT 440 | Desktop 2x1280x1024px | Windows 7 Professional 64bit
Laptop: Intel Core i7 @ 4x2.00GHz | 8 GB RAM | Nvidia GeForce GT 540M | Desktop 1366x768px | Windows 7 Home Premium 64bit

aMul

Sieger des Minimalist Compo 01/13

BeitragFr, Sep 19, 2008 16:43
Antworten mit Zitat
Benutzer-Profile anzeigen
Mr.Keks hat Folgendes geschrieben:
@amul: Dann musst du aber noch eine Abfrage reinsetzen, damit nicht außerhalb des Bildschirms gezeichnet wird. Und die kostet dann wiederum Zeit.

Bisher werden in der Funktion WritePixel und WritePixelFast zusammen benutzt, ich wollte nur anmerken, dass es Sinn macht, sich zu entscheiden. Wink

Und ihr habt recht, bei großen ausgefüllten Flächen hat die Blitzfunktion in der Tat wieder die Nase vorn.
Panic Pong - ultimate action mashup of Pong and Breakout <= aktives Spiele-Projekt, Downloads mit vielen bunten Farben!
advASCIIdraw - the advanced ASCII art program <= aktives nicht-Spiele-Projekt, must-have für ASCII/roguelike/dungeon-crawler fans!
Alter BB-Kram: ThroughTheAsteroidBelt - mit Quelltext! | RGB-Palette in 32²-Textur / Farbige Beleuchtung mit Dot3 | Stereoskopie in Blitz3D | Teleport-Animation Screensaver

Noobody

BeitragFr, Sep 19, 2008 18:17
Antworten mit Zitat
Benutzer-Profile anzeigen
Huppsalla, da habe ich wohl die alte Version hochgeladen Confused
Das sollte durchgehend WritePixel heissen, da man ansonsten den wohlbekannten MAV erhält, wenn das Oval ausserhalb des Bildschirms liegt; WritePixel ist hierbei schneller als WritePixelFast mit einer entsprechenden Schutzabfrage.
Ich habe die Funktion bisher bei drei verschiedenen PCs getestet, und im gefüllten Modus war die neue Funktion immer exakt gleichschnell wie die von Blitz; schade, dass sie dann doch bei den meisten langsamer ist.

@Fireball: Danke für den Tipp!
Die Funktionen Color...() waren mir bisher gar nicht bekannt.
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun

hectic

Sieger des IS Talentwettbewerb 2006

BeitragFr, Sep 19, 2008 19:49
Antworten mit Zitat
Benutzer-Profile anzeigen
Da hier ein kontrollierter Bereich gezeichnet wird, kann man getrosst eine ''is-in-screen'' -Abfrage machen. Danach wird dann endschieden, ob komplett mit WritePixel oder WritePixelFast gezeichnet wird. Die Aussage das WritePixelFast nicht schneller ist als WritePixel bezog sich (im anderem Beitrag) auf die Überprüfung jedes einzelnen Pixels allein. Eventuell kann man hier noch ein bischen was an Speed raus holen.

----

Da du jeden Pixel einzelnd zeichnest, kannst du das Oval auch vierteln (jetzt nur halbiert). Dann müsstest du jeweils für die 1/4-Teile das X- und Y-Offset tauschen. Das würde auf jeden Fall die Sin(ACos -Berechnungen noch halbieren.

----

Ich habe auch mal sowas ähnliches gemacht. Vielleicht hilft es:

Code: [AUSKLAPPEN]
Graphics 800,600,0,2
SetBuffer FrontBuffer()

radius#=200
xp=250
yp=250

For x#=0 To radius Step 1
   wt%=Sin(ACos(x/radius))*radius
   Rect xp+x,yp-wt,1,wt*2,1
   Rect xp-x,yp-wt,1,wt*2,1
Next

WaitKey



Edit1: Ach geil, ich sehe gerade, dass unsere beiden Berechnungen im grunde identisch sind. Laughing

Bei mir ist Fill=0 schneller als die Blitzeigene. Beim Fill=1 hängt es von der größe des Ovales ab. Ab einer größe von etwa 200x200 ist die Blitzeigene schneller, sonst die neue Version.

edit2: unter mir SpinAtom: Sehr schöner Code. Leider ist dieser aber für ausgefüllte Kreise nicht wirklich gut zu gebrauchen. Bei nicht ausgefüllten Kreisen kann man sicherlich noch was an Ideen mitnehmen.
  • Zuletzt bearbeitet von hectic am Fr, Sep 19, 2008 20:04, insgesamt einmal bearbeitet

SpionAtom

BeitragFr, Sep 19, 2008 19:57
Antworten mit Zitat
Benutzer-Profile anzeigen
Kein Oval (nur Kreis), aber dafür auch kein Sinus, Cosinus und dergleichen:

Code: [AUSKLAPPEN]
;aus WIKIPEDIA: Bresenham-Algorithmus
; REM Bresenham-Algorithmus für einen Achtelkreis in Pseudo-Basic
; REM gegeben seien r, xmittel, ymittel
; REM Initialisierungen für den ersten Oktanten
; x = r
; y = 0
; fehler = r
; REM "schnelle" Richtung ist hier y!
; SETPIXEL xmittel + x, ymittel + y
;
; REM Pixelschleife: immer ein Schritt in schnelle Richtung, hin und wieder auch einer in langsame
; While y < x
;    REM Schritt in schnelle Richtung
;    dy = y*2+1 : REM bei Assembler-Implementierung *2 per Shift
;    y = y+1
;    fehler = fehler-dy
;    If fehler<0 Then
;       REM Schritt in langsame Richtung (hier negative x-Richtung)
;       dx = 1-x*2 : REM bei Assembler-Implementierung *2 per Shift
;       x = x-1
;       fehler = fehler-dx
;    End If
;    SETPIXEL  xmittel+x, ymittel+y
;    REM Wenn es um einen Bildschirm und nicht mechanisches Plotten geht,
;    REM kann man die anderen Oktanten hier gleich mit abdecken:
;    REM SETPIXEL xmittel-x, ymittel+y
;    REM SETPIXEL xmittel-x, ymittel-y
;    REM SETPIXEL xmittel+x, ymittel-y
;    REM SETPIXEL xmittel+y, ymittel+x
;    REM SETPIXEL xmittel-y, ymittel+x
;    REM SETPIXEL xmittel-y, ymittel-x
;    REM SETPIXEL xmittel+y, ymittel-x
; Wend

Graphics 800, 600, 0, 2
SetBuffer BackBuffer()

   r = 100

   Repeat
   
      If sz + 1000 > MilliSecs() Then
         fps = fps + 1
      Else
         sz = MilliSecs()
         showfps = fps
         fps = 0
      End If
   
      Cls
      mx = MouseX()
      my = MouseY()
      r = r + MouseZSpeed()
      x = r
      y = 0
      f = r
      Plot mx - x, my
      Plot mx + x, my
      Plot mx, my - x
      Plot mx, my + x
      While y < x
         dy = y * 2 + 1
         y = y + 1
         f = f - dy
         If f < 0 Then
            dx = 1 - x * 2
            x = x - 1
            f = f - dx
         End If
         Plot mx - x, my + y
         Plot mx - x, my - y
         Plot mx + x, my - y
         Plot mx + x, my + y
         Plot mx + y, my + x
         Plot mx - y, my + x
         Plot mx + y, my - x
         Plot mx - y, my - x
      Wend
      
      Text 0, 0, showfps
      Flip(0)
   
   Until KeyDown(1)
   End   
os: Windows 10 Home cpu: Intel Core i7 6700K 4.00Ghz gpu: NVIDIA GeForce GTX 1080

Noobody

BeitragDi, Sep 22, 2009 8:32
Antworten mit Zitat
Benutzer-Profile anzeigen
So, ich habe das Ding mal wieder ausgegraben und nochmals beschleunigt.

Die Pixel werden nun sowohl vertikal wie auch horizontal gespiegelt, was dazu führt, dass schlussendlich nur ein Viertel des Ovals berechnet werden muss. Ausserdem habe ich in der Füllroutine die Schleife durch Line ersetzt (was bei gesperrtem Buffer sehr schnell ist), womit die Funktion nun auch bei gefüllten Ovalen schneller ist als die Originalfunktion von Blitz.

Nur bei kleinen Ovalen ist die Funktion langsamer, was daher kommt, dass immer zwei Millisekunden für das Sperren des Buffers draufgehen. Falls man also viele Ovale hat, wäre es unbedingt anzuraten, den Buffer vor dem Zeichnen ein einziges Mal zu sperren, alle Ovale zu zeichnen und nachher wieder entzusperren (dafür dann einfach das LockBuffer/UnlockBuffer aus der Funktion rausnehmen und selber setzen).
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun
 

Kruemelator

BeitragMi, Sep 30, 2009 19:00
Antworten mit Zitat
Benutzer-Profile anzeigen
Die Neue Funktion hat bei mir einen größeren Radius, sie mal den Kreis auserhalb des Rechtecks.

Noobody

BeitragMi, Sep 30, 2009 19:10
Antworten mit Zitat
Benutzer-Profile anzeigen
Das ist jeweils ein einziger Pixel auf Breite und Höhe, der macht den Braten auch nicht fett Wink
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun

Nicdel

BeitragMi, Sep 30, 2009 20:42
Antworten mit Zitat
Benutzer-Profile anzeigen
Schöne Sache Smile
Nur leider ist die Blitzfunktion bei gefüllten Ovalen noch schneller (Blitz: 9ms, Neu: 34ms), bei leeren aber klar langsamer. Also für leere Ovale eine sehr gute Alternative.
Desktop: Intel Pentium 4 2650 Mhz, 2 GB RAM, ATI Radeon HD 3850 512 MB, Windows XP
Notebook: Intel Core i7 720 QM 1.6 Ghz, 4 GB DDR3 RAM, nVidia 230M GT, Windows 7

Noobody

BeitragMi, Sep 30, 2009 22:37
Antworten mit Zitat
Benutzer-Profile anzeigen
Eigenartig, bei mir ist die neue Funktion auch bei gefüllten Ovalen immer schneller.

Ich schätze, das kommt wohl auf den Rechner drauf an Razz
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun

hazumu-kun

BeitragDo, Okt 01, 2009 20:07
Antworten mit Zitat
Benutzer-Profile anzeigen
Wenn du line durch ein Rect mit Breite1 ersetztz müsste es noch schneller gehen, leider geht dann der boost durch lockbuffer berloren.
Warum kann es keine omnipotente Macht geben?
Weil diese omnipotente Macht in der Lage sein müsste, einen so schweren Stein zu schaffen, dass sie ihn nicht heben kann
-> nicht omnipotent

Noobody

BeitragDo, Okt 01, 2009 20:28
Antworten mit Zitat
Benutzer-Profile anzeigen
Line auf gelocktem Buffer ist um einiges schneller als Rect Wink
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun

Nicdel

BeitragDo, Okt 01, 2009 21:12
Antworten mit Zitat
Benutzer-Profile anzeigen
Auch das kommt auf den PC an. Auf meinem Laptop ist Rect knapp schneller, beim Desktopp ist es genau andersherum. Sie sind aber beide schon recht alt...
Desktop: Intel Pentium 4 2650 Mhz, 2 GB RAM, ATI Radeon HD 3850 512 MB, Windows XP
Notebook: Intel Core i7 720 QM 1.6 Ghz, 4 GB DDR3 RAM, nVidia 230M GT, Windows 7

Neue Antwort erstellen


Übersicht BlitzBasic Codearchiv

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group