Seite 1 von 1

Filter nach Maske auf dem Bildschirm

Verfasst: 07.09.2012 14:42
von Bobo-Jack
Hallo :)

Ich suche eine Möglichkeit, einen Filter (einfach die Farben aufm Bildschirm etwas abdunkeln etwa) auf den Bildschirm anzuwenden, so ähnlich wie bei DisplayRGBFilter().

Allerdings gibt's ne Maske die über den Bildschirm passt, und der Maske entsprechend sollen nur bestimmte Bereiche schattiert werden.

Die Formen auf der Maske sind mehr oder weniger beliebig. Der Hintergrund ist, dass auf einer Tilemap einzelne Felder mit unterschiedlichen kleinen Masken schattiert werden sollen. Bisher hab ich kleine Masken für jedes Tile einzeln angezeigt, das geht aber jetzt aus bestimmten Gründen nichtmehr so.

Hab schon einen Versuch gemacht, bei dem direkt im Videospeicher gearbeitet wird, ist aber leider sau langsam... hm.
Ihr braucht zum Testen ein großes Sprite mit Irgendwas, so groß wie der Bildschrim etwa, und eine Maskensprite, bei dem alles was nicht Schwarz ist schattiert wird.

Mich hätte mal interessiert wie DisplayRGBFilter arbeitet, denn der Befehl ist ja Pfeilschnell und vielleicht könnte man die Arbeitsweise irgendwie kopieren mit Maskenunterstützung.

Habt ihr noch ne andere Idee wie man das so umsetzen könnte, dass es möglichst schnell ist?

Vielen Dank für eure Ideen!! <)

Code: Alles auswählen

; Maskensprite:
;
; $000000      -> Filter wirkt nicht
; Alles andere -> Filter wirkt
; 

BG_Path.s = OpenFileRequester("Background Image", "", "", 0)
M_Path.s = OpenFileRequester("Mask File", "", "", 0)

; ---------------

; > procedure coded by STARGÅTE!
; Korrigiert einen zu kleinen oder zu großen Wert für einen Farbwert
Procedure Real255(Wert)
 If Wert < 0
  ProcedureReturn 0
 ElseIf Wert > 255
  ProcedureReturn 255
 Else
  ProcedureReturn Wert
 EndIf
EndProcedure

; > procedure coded by STARGÅTE!
; Gibt die Graufarbe einer Farbe zurück
;  Intensity = 0.0  ->  Farbig
;  Intensity = 1.0  ->  Grau
;  GrayColor :   Graufarbe die erreich werden soll (RGB-Farbe)     
Procedure ColorGray(Color, Intensity.f, GrayColor=$FFFFFF)
 Protected R, G, B, Gray.f
 #GrayColorFactorRed   = 0.299
 #GrayColorFactorGreen = 0.587
 #GrayColorFactorBlue  = 0.114
 Gray = #GrayColorFactorRed*Red(Color) + #GrayColorFactorGreen*Green(Color) + #GrayColorFactorBlue*Blue(Color)
 R =   Red(GrayColor) * Gray/255*Intensity +   Red(Color) * (1-Intensity)
 G = Green(GrayColor) * Gray/255*Intensity + Green(Color) * (1-Intensity)
 B =  Blue(GrayColor) * Gray/255*Intensity +  Blue(Color) * (1-Intensity)
 ProcedureReturn RGB(R,G,B)
EndProcedure

; --------------

InitSprite()
InitKeyboard()

UsePNGImageDecoder()
UseJPEG2000ImageDecoder()
UseJPEGImageDecoder()

ExamineDesktops()
OpenScreen(DesktopWidth(0), DesktopHeight(0), DesktopDepth(0), "")

Global BG_Spr = LoadSprite(#PB_Any, BG_Path)
Global M_Spr = LoadSprite(#PB_Any, M_Path)

Procedure FPS()
   Static NextSecond
   Static Counter
   Static FPS
   Protected Now
   
   Now = ElapsedMilliseconds()
   If Now >= NextSecond
      FPS = Counter
      If NextSecond = 0 : NextSecond = Now : EndIf
      NextSecond + 1000
      Counter = 1
   Else
      Counter + 1
   EndIf
   
   ProcedureReturn FPS
EndProcedure

Procedure DisplayShadedSprite(Sprite, x, y, MaskSprite=-1)
  
  Protected UseMask.b
  
  If IsSprite(MaskSprite)
    UseMask = #True
  EndIf
  
  DisplayTransparentSprite(Sprite, x, y)
  
  ; /// Get Information
  
  StartDrawing(ScreenOutput())
  Protected s_mem = DrawingBuffer()
  Protected s_pitch = DrawingBufferPitch()
  Protected s_format = DrawingBufferPixelFormat()
  Protected s_width = OutputWidth()
  Protected s_height = OutputHeight()
  StopDrawing()
  Protected *s_line.long
  
  If UseMask
    StartDrawing(SpriteOutput(M_Spr))
    Protected m_mem = DrawingBuffer()
    Protected m_pitch = DrawingBufferPitch()
    Protected m_format = DrawingBufferPixelFormat()
    Protected m_width = OutputWidth()
    Protected m_height = OutputHeight()
    StopDrawing()
    Protected *m_line.long
  EndIf
  
  ; /// Do it
  
  Protected.u x_max, y_max
  If UseMask
    y_max = m_height-1
    x_max = m_width-1 
  Else
    y_max = s_height-1
    x_max = s_width-1
  EndIf
    
  For y = 0 To y_max
    
    If UseMask
      *m_line = m_mem+m_pitch*y
    EndIf
    
    *s_line = s_mem+s_pitch*y
    
    For x = 0 To x_max 
      
      If UseMask = #False Or *m_line\l > 0
        *s_line\l = ColorGray(*s_line\l, 0.5)
      EndIf
        
      
      *s_line + 4
      
      If UseMask
        *m_line + 4
      EndIf
        
    Next
    
  Next
      
  
EndProcedure

Repeat
  FlipBuffers()
  ClearScreen($000000)
  ExamineKeyboard()
  
  DisplayShadedSprite(BG_Spr, 10, 10, M_Spr)
  
  StartDrawing(ScreenOutput())
  DrawText(OutputWidth()-100, 10, Str(FPS()))
  StopDrawing()
  
Until KeyboardPushed(#PB_Key_Escape)
End


Re: Filter nach Maske auf dem Bildschirm

Verfasst: 07.09.2012 15:53
von STARGÅTE
Du kannst doch mit Sprite3D() arbeiten.
Dann kannst du dein Masken-Sprite mit Alpha-Kanal und dem passenden BlendingMode() direkt mit dem Hintergrund "verschmelzen".

Ansonsten kannst du noch den CustomFilterCallback() nutzen.

"ist aber leider sau langsam... "
Vermutlich weil du mit Debugger laufen lässt, der bremst natürlich diese doppelschleife der Pixel extrem aus.

EDIT: hier mal ein gekürztes Beispiel zum CustomFilterCallback() mit Masken

Code: Alles auswählen


Enumeration
	#DrawingFilter_Desaturate
EndEnumeration


Structure DrawingFilterInclude
	Filter.i
	StructureUnion
		Parameter.i
		Mode.i
	EndStructureUnion
EndStructure

Global DrawingFilterInclude.DrawingFilterInclude


Procedure DrawingFilter_Desaturate(X.i, Y.i, SourceColor.i, DestinationColor.i)
	
	Protected Gray.i = (DestinationColor>>16&$FF + DestinationColor>>8&$FF + DestinationColor&$FF) / 3
	Protected Factor.f = Red(SourceColor)/255
	Protected Color.i = RGBA(Red(DestinationColor)*(1-Factor)+Gray*Factor, Green(DestinationColor)*(1-Factor)+Gray*Factor, Blue(DestinationColor)*(1-Factor)+Gray*Factor, Alpha(DestinationColor))
	ProcedureReturn Color
	
EndProcedure

Procedure DrawingFilter(Filter.i, Parameter.i=#Null)
	
	DrawingFilterInclude\Filter = Filter
	
	Select Filter
		Case #DrawingFilter_Desaturate
			DrawingFilterInclude\Mode = Parameter
			CustomFilterCallback(@DrawingFilter_Desaturate())
	EndSelect
	
EndProcedure



Enumeration
	#Window
	#Gadget
	#Image
	#SourceImage
	#MaskImage
EndEnumeration



InitNetwork()
UsePNGImageDecoder()

If FileSize(GetTemporaryDirectory()+"earth-icon.png") = -1
	Define URL.s = "http://icons.iconarchive.com/icons/treetog/junior/256/earth-icon.png"
	ReceiveHTTPFile(URL, GetTemporaryDirectory()+"earth-icon.png")
EndIf
If FileSize(GetTemporaryDirectory()+"Mask.png") = -1
	Define URL.s = "http://data.unionbytes.de/Mask.png"
	ReceiveHTTPFile(URL, GetTemporaryDirectory()+"Mask.png")
EndIf

LoadImage(#SourceImage, GetTemporaryDirectory()+"earth-icon.png")
LoadImage(#MaskImage,  GetTemporaryDirectory()+"Mask.png")

CopyImage(#SourceImage, #Image)
If StartDrawing(ImageOutput(#Image))
	DrawingMode(#PB_2DDrawing_CustomFilter)
	DrawingFilter(#DrawingFilter_Desaturate)
	DrawImage(ImageID(#MaskImage), 0, 0)
	StopDrawing()
EndIf

OpenWindow(#Window, 0, 0, 768, 256, "Image", #PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)
ImageGadget(#PB_Any, 0, 0, 256, 256, ImageID(#SourceImage))
ImageGadget(#PB_Any, 256, 0, 256, 256, ImageID(#MaskImage))
ImageGadget(#PB_Any, 512, 0, 256, 256, ImageID(#Image))

Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow

Re: Filter nach Maske auf dem Bildschirm

Verfasst: 07.09.2012 18:16
von Bobo-Jack
Danke für die antwort :D
STARGÅTE hat geschrieben:Vermutlich weil du mit Debugger laufen lässt, der bremst natürlich diese doppelschleife der Pixel extrem aus.
Stimmt (dumm von mir das zu vergessen).

Würde Sprite3D in der Hauptschleife nicht ziemlich auf Kosten der Geschwindigkeit gehen?
Dieser Filter muss ja für jedes Frame neu angewendet werden.
Habs bisher gemieden, Sprite3D zu verwenden und versucht alles mit normalen Sprites zu realisieren..

CustomFilterCallback() ist ne gute Idee und das Beispiel sieht echt klasse aus, ist doch aber laut der Hilfe nur auf Images anwendbar?
(2DDrawing in meiner Hauptschleife hab ich ebenfalls gemieden, weils ja oft heißt wie langsam das ist... oder täusch ich mich da)

Weißt du oder irgendjemand noch etwas zum DisplayRGBFilter() und warum das so schnell funktioniert?
Man musste den Filter eben auch auf andere Formen anwenden können... hmm.

Re: Filter nach Maske auf dem Bildschirm

Verfasst: 07.09.2012 23:48
von STARGÅTE
Würde Sprite3D in der Hauptschleife nicht ziemlich auf Kosten der Geschwindigkeit gehen?
[...]
Habs bisher gemieden, Sprite3D zu verwenden und versucht alles mit normalen Sprites zu realisieren..
Ganz im gegenteil. Sprite3D läuft mit Hardwereunterstützung (ist ja eine Art Mini-3D-Engine für 2D-Sprites), ist also um Längen schneller als das normale Sprite.
(2DDrawing in meiner Hauptschleife hab ich ebenfalls gemieden, weils ja oft heißt wie langsam das ist... oder täusch ich mich da)
Du verwendest doch 2DDrawing in deiner DisplayShadedSprite()-Prozedur.
Das "langsamme" bei 2DDrawing ist das StartDrawing()/StopDrawing(), und das ist ja eh schon bei dir drin!
Und gegenüber der Doppelschleife ist CustomFilterCallback() schneller.

Re: Filter nach Maske auf dem Bildschirm

Verfasst: 08.09.2012 10:34
von Bobo-Jack
STARGÅTE hat geschrieben:Sprite3D läuft mit Hardwereunterstützung (ist ja eine Art Mini-3D-Engine für 2D-Sprites), ist also um Längen schneller als das normale Sprite.
Tatsächlich, grade getestet. :o Wenn ich das zu Beginn meines Projekts gewusst hätte.. werd ich wohl nochmal komplett umschreiben.
Immerhin schon stolze ~17000 Zeilen, na super aber danke fürs mich drauf aufmerksam machen! :)

Werd das jetzt mit Sprite3D und BlendingMode() umsetzen.
Ist das dann eigentlich wirklich so tragisch, dass das Sprite3D kein Quadrat ist?

Wegen dem Start/StopDrawing(), da hab ich die Zeichenbufferadresse, Pitch, Format usw. einmal gespeichert um zu vermeiden, jedesmal Zeichenfunktionen verwenden zu müssen.

Naja, also besten Dank :allright:

Re: Filter nach Maske auf dem Bildschirm

Verfasst: 08.09.2012 11:55
von Drago
Bobo-Jack hat geschrieben:Ist das dann eigentlich wirklich so tragisch, dass das Sprite3D kein Quadrat ist?
Hi, nicht wirklich. Es sei denn das Programm soll auch noch auf uralte Mühlen rennen, aber fast alle Grafikkarten können mittlerweile
auch andere Formate....

Lg Klaus