Filter mit exkludierter Farbe [gelöst]

Fragen zu Grafik- & Soundproblemen und zur Spieleprogrammierung haben hier ihren Platz.
Burstnibbler
Beiträge: 55
Registriert: 04.10.2008 12:10

Filter mit exkludierter Farbe [gelöst]

Beitrag von Burstnibbler »

Hallo Miteinander!

Ich programmiere seit ca. 1 Jahr an einem Spiel... aber jetzt brauche ich doch mal etwas Hilfe dabei. :shock:

Folgendes:
In dem Spiel gibt es eine Tag/Nacht-Simulation - soweit kein Problem!
Allerdings kann Nachts eine bestimmte Farbe auftauchen, welche nicht durch den "Dunkel-Filter" verdunkelt werden soll - Problem!

Ich könnte das Problem lösen, indem ich einen "Dunkel-Filter" via 'CustomFilterCallback()' auf die Szene anwende; und dabei diese bestimmte Farbe exkludiere.
ABER: Da das Ganze über die Drawing-Befehle läuft, wäre das für ein Spiel einfach zu langsam - da ja auch noch einiges an Berechnungen(v.a. Pathfinding) im Hintergrund läuft.

Daher die Frage, ob das auch mit den Sprite-Befehlen möglich wäre?
Ich dachte da an 'SpriteBlendingMode()' - habe aber keine Erfahrung damit und auch keinen Schimmer wie ich das anwenden soll.

Vielleicht gibt es ja auch noch andere Möglichkeiten, welche ich noch nicht entdeckt habe.
Wäre schön, wenn da jemand von Euch vielleicht einen Tipp oder Lösungsvorschlag hätte.

Danke, schon mal im Voraus
Burstnibbler(den Namen sollte ich wirklich mal langsam ändern)! :lol:


Der folgende Code hat mit dem Spiel nicht viel gemein, soll aber auch nur grob aufzeigen worum es geht.

Code: Alles auswählen

EnableExplicit
;
#WIN       = 0
#WIN_W     = 640
#WIN_H     = 480
#WIN_T     = "Filter"
#WIN_F     = #PB_Window_ScreenCentered|#PB_Window_MinimizeGadget
;
#COL_TRANS = $FF00FF
#COL_EXCLD = $0000FF; Diese Farbe soll nicht gefiltert werden
#COL_BLACK = 0
;
#BAL_SIZE  = 100
#BAL_HALF  = 50
#BAL_IN    = -#BAL_SIZE
#BAL_OUT   = #WIN_W + #BAL_SIZE
#BAL_Y     = (#WIN_H / 2) - #BAL_SIZE
;
#OBJ_W     = 40
#OBJ_H     = #WIN_H - 100
;
Enumeration
  #SPR_BACK
  #SPR_BALL
  #SPR_FLTR
  #SPR_OBJS
EndEnumeration
;
Define.i xOff = #BAL_IN
;
InitSprite()
OpenWindow(#WIN, 0, 0, #WIN_W, #WIN_H, #WIN_T, #WIN_F)
OpenWindowedScreen(WindowID(#WIN), 0, 0, #WIN_W, #WIN_H, #True, 0, 0)
;
CreateSprite(#SPR_BACK, #WIN_W, #WIN_H)
CreateSprite(#SPR_BALL, #BAL_SIZE, #BAL_SIZE)
CreateSprite(#SPR_FLTR, #WIN_W, #WIN_H, #PB_Sprite_AlphaBlending)
CreateSprite(#SPR_OBJS, #WIN_W, #WIN_H)
;
TransparentSpriteColor(#SPR_BALL, #COL_TRANS)
TransparentSpriteColor(#SPR_OBJS, #COL_TRANS)
;
StartDrawing(SpriteOutput(#SPR_BACK))
  Box(0, 0, #WIN_W, #WIN_H, RGB($66, $99, 0))
  DrawingMode(#PB_2DDrawing_Gradient)
  BackColor(RGB(0, $66, $FF))
  FrontColor(RGB($66, $CC, $FF))
  LinearGradient(#WIN_W / 2, 0, #WIN_W / 2, #WIN_H / 2)
  Box(0, 0, #WIN_W,  #WIN_H / 2)
StopDrawing()
;
StartDrawing(SpriteOutput(#SPR_BALL))
  Box(0, 0, #BAL_SIZE, #BAL_SIZE, #COL_TRANS)
  Circle(#BAL_HALF, #BAL_HALF, #BAL_HALF, RGB($99, $33, $33))
  Circle(#BAL_HALF, #BAL_HALF, #BAL_HALF / 2, #COL_EXCLD); Innerer Kreis des Balls, hat die auszuschließende Farbe.
StopDrawing()
;
StartDrawing(SpriteOutput(#SPR_FLTR))
  Box(0, 0, #WIN_W, #WIN_H, RGB($32, $32, $32))
StopDrawing()
;
StartDrawing(SpriteOutput(#SPR_OBJS))
  Box(0, 0, #WIN_W, #WIN_H, #COL_TRANS)
  Box(#OBJ_W, 0, #OBJ_W, #OBJ_H, RGB($66, $33, 0))
  Box(#WIN_W / 2, -#OBJ_W, #OBJ_W, #OBJ_H, RGB($66, $33, 0))
  Box(#WIN_W - (#OBJ_W * 2), 0, #OBJ_W, #OBJ_H, RGB($66, $33, 0))
StopDrawing()
;
;
Repeat
  Repeat
    Select WindowEvent()
      Case #PB_Event_CloseWindow : End
      Case #Null                 : Break
    EndSelect
  ForEver
  
  ClearScreen(#COL_BLACK)
  DisplaySprite(#SPR_BACK, 0, 0)
  DisplayTransparentSprite(#SPR_BALL, xOff, #BAL_Y)
  DisplayTransparentSprite(#SPR_OBJS, 0, 0)
  ;SpriteBlendingMode();???
  DisplayTransparentSprite(#SPR_FLTR, 0, 0, 160); "Dunkel-Filter" (welcher aber die Farbe '#COL_EXCLD' excludieren soll)
  ;SpriteBlendingMode();???
  FlipBuffers()
  xOff + 1
  If (xOff > #BAL_OUT) : xOff = #BAL_IN : EndIf
  Delay(16)
ForEver
;
Edit: Topic als 'gelöst' markiert.
Zuletzt geändert von Burstnibbler am 19.02.2021 22:15, insgesamt 1-mal geändert.
Benutzeravatar
Mijikai
Beiträge: 754
Registriert: 25.09.2016 01:42

Re: Filter mit exkludierter Farbe

Beitrag von Mijikai »

Filtering (ohne Shader) ist langsam.
Mit Threads und/oder inline Assemby zwar machbar aber kompliziert.
Blending ist problematisch da das Sprite mehrere Farben hat.
Da Layer berücksichtigt werden müssen hilft auch eine Maske wenig.
Denke die einfachste Lösung wird ein separates Spriteset sein.

Wenn die Auflösung jedoch immer kleiner 720p ist ist würde Filtering
wahrscheinlich sogar noch gut funktionieren.

Eine andere Option wäre eine kleine Sprite Lib/Engine in OpenGL zu schreiben.
Mit OpenGL ist es ziemlich einfach einzelne Sprites 'on the fly' abzudunkeln.
Burstnibbler
Beiträge: 55
Registriert: 04.10.2008 12:10

Re: Filter mit exkludierter Farbe

Beitrag von Burstnibbler »

Hm, schade! Ich hatte ja gedacht, dass es mit den Sprite-Befehlen eine einfache und performante Möglichkeit dafür gibt.

Naja, dann werde ich wohl auf CustomFilterCallback() zurückgreifen(und dafür andere Dinge in einen Thread auslagern) - denn eine eigene Sprite-Lib zu programmieren, wäre ein bisschen zu viel Aufwand dafür(das Gleiche gilt auch für ein separates Spriteset, da eine Szene aus mehreren Spritesets zusammengebaut wird).

Danke, dass Du dir Gedanken darüber gemacht hast; und für deine Vorschläge! :allright:

Gruß
Burstnibbler
Burstnibbler
Beiträge: 55
Registriert: 04.10.2008 12:10

Re: Filter mit exkludierter Farbe

Beitrag von Burstnibbler »

Addendum

Ich habe eine Weile herumexperimentiert und eine Lösung gefunden, welche eine doch recht gute Performance hat.
D.h. auf Threads kann ich wohl vorerst verzichten. :D
Falls noch mal jemand das Problem haben sollte, stelle ich den Code mal zur Verfügung.

Code: Alles auswählen

EnableExplicit
;
#WIN       = 0
#WIN_W     = 640
#WIN_H     = 480
#WIN_T     = "Filter"
#WIN_F     = #PB_Window_ScreenCentered|#PB_Window_MinimizeGadget
;
#COL_TRANS = $FF00FF
#COL_EXCLD = $0000FF; Diese Farbe soll nicht gefiltert werden
#COL_BLACK = 0
;
#BAL_SIZE  = 100
#BAL_HALF  = 50
#BAL_IN    = -#BAL_SIZE
#BAL_OUT   = #WIN_W + #BAL_SIZE
#BAL_Y     = (#WIN_H / 2) - #BAL_SIZE
;
#OBJ_W     = 40
#OBJ_H     = #WIN_H - 100
;
#IMG_MASK  = 0
;
Enumeration
  #SPR_BACK
  #SPR_BALL
  #SPR_OBJS
  #SPR_FLTR
EndEnumeration
;
Declare   FilterMaskedRGB(filterCol.i, maskX.i, maskY.i, maskW.i, maskH.i)
Declare.i MaskCB(x.i, y.i, src.i, dst.i)
;
Define.i x = #BAL_IN
;
InitSprite()
OpenWindow(#WIN, 0, 0, #WIN_W, #WIN_H, #WIN_T, #WIN_F)
OpenWindowedScreen(WindowID(#WIN), 0, 0, #WIN_W, #WIN_H, #True, 0, 0)
;
CreateSprite(#SPR_BACK, #WIN_W, #WIN_H)
CreateSprite(#SPR_BALL, #BAL_SIZE, #BAL_SIZE)
CreateSprite(#SPR_OBJS, #WIN_W, #WIN_H)
CreateSprite(#SPR_FLTR, #WIN_W, #WIN_H, #PB_Sprite_AlphaBlending)
;
TransparentSpriteColor(#SPR_BALL, #COL_TRANS)
TransparentSpriteColor(#SPR_OBJS, #COL_TRANS)
;
StartDrawing(SpriteOutput(#SPR_BACK))
  Box(0, 0, #WIN_W, #WIN_H, RGB($66, $99, 0))
  DrawingMode(#PB_2DDrawing_Gradient)
  BackColor(RGB(0, $66, $FF))
  FrontColor(RGB($66, $CC, $FF))
  LinearGradient(#WIN_W / 2, 0, #WIN_W / 2, #WIN_H / 2)
  Box(0, 0, #WIN_W,  #WIN_H / 2)
StopDrawing()
;
StartDrawing(SpriteOutput(#SPR_BALL))
  Box(0, 0, #BAL_SIZE, #BAL_SIZE, #COL_TRANS)
  Circle(#BAL_HALF, #BAL_HALF, #BAL_HALF, RGB($99, $33, $33))
  Ellipse(#BAL_HALF, #BAL_HALF, #BAL_HALF / 5, #BAL_HALF / 2, #COL_EXCLD)
  Ellipse(#BAL_HALF, #BAL_HALF, #BAL_HALF / 2, #BAL_HALF / 5, #COL_EXCLD)
StopDrawing()
;
StartDrawing(SpriteOutput(#SPR_OBJS))
  Box(0, 0, #WIN_W, #WIN_H, #COL_TRANS)
  Box(#OBJ_W, 0, #OBJ_W, #OBJ_H, RGB($66, $33, 0))
  Box(#WIN_W / 2, -#OBJ_W, #OBJ_W, #OBJ_H, RGB($66, $33, 0))
  Box(#WIN_W - (#OBJ_W * 2), 0, #OBJ_W, #OBJ_H, RGB($66, $33, 0))
StopDrawing()
;
;
Repeat
  Repeat
    Select WindowEvent()
      Case #PB_Event_CloseWindow : End
      Case #Null                 : Break
    EndSelect
  ForEver
  
  DisplaySprite(#SPR_BACK, 0, 0)
  DisplayTransparentSprite(#SPR_BALL, x, #BAL_Y)
  DisplayTransparentSprite(#SPR_OBJS, 0, 0)
  FilterMaskedRGB(RGB(0, 0, 32), x, #BAL_Y, #BAL_SIZE, #BAL_SIZE)
  DisplayTransparentSprite(#SPR_FLTR, 0, 0, 200)
  FlipBuffers()
  x + 1
  If (x > #BAL_OUT) : x = #BAL_IN : EndIf
  Delay(16)
ForEver
;
;
Procedure FilterMaskedRGB(filterCol.i, maskX.i, maskY.i, maskW.i, maskH.i)
;
StartDrawing(ScreenOutput())
  GrabDrawingImage(#IMG_MASK, maskX, maskY, maskW, maskH)
StopDrawing()
;
StartDrawing(SpriteOutput(#SPR_FLTR))
  DrawingMode(#PB_2DDrawing_AllChannels)
  Box(0, 0, SpriteWidth(#SPR_FLTR), SpriteHeight(#SPR_FLTR), filterCol | $FF000000)
  DrawingMode(#PB_2DDrawing_CustomFilter)
  CustomFilterCallback(@MaskCB())
  DrawImage(ImageID(#IMG_MASK), maskX, maskY)
StopDrawing()
;
EndProcedure
;
Procedure.i MaskCB(x.i, y.i, src.i, dst.i)
;
If (src & $FFFFFF = #COL_EXCLD) : ProcedureReturn 0 : EndIf
;
ProcedureReturn dst
EndProcedure
;

Gruß
Burstnibbler
Antworten