Stencil Buffer

Übersicht BlitzMax, BlitzMax NG Codearchiv & Module

Neue Antwort erstellen

BtbN

Betreff: Stencil Buffer

BeitragFr, Jan 15, 2010 19:58
Antworten mit Zitat
Benutzer-Profile anzeigen
Moinsen.

Für alle, die den Stencil-Buffer nicht kennen: Das ist ein zusätzlicher Zeichen-Bereich, den quasi alle heutigen Grafik-Karten unterstützen. Meistens umfasst er 8 bit.
Man kann nun der GraKa sagen, dass sie nur zeichnen soll, wenn an der stelle, die sie gerade bearbeitet, ein bestimmter Wert im Stencil-Buffer steht. Dadurch wird es sehr einfach möglich, z.B. zerstörrbare Terrains einzubauen.

Zuerst einmal der Modul-Quellcode:

BlitzMax: [AUSKLAPPEN]
SuperStrict

Rem
bbdoc: BtbN.Stencil
about: Allows easy use of OpenGL and D3D9 Stencil Buffers
info: In order to be able to use Stencil-Tests at all, you HAVE TO add the GRAPHICS_STENCILBUFFER flag when calling #brl.graphics.Graphics
EndRem

Module BtbN.Stencil

Import BRL.Graphics
Import BRL.GLMax2D
?Win32
Import BRL.D3D9Max2D
?

Const STENCIL_NEVER:Int = 1
Const STENCIL_LESS:Int = 2
Const STENCIL_EQUAL:Int = 3
Const STENCIL_LESSEQUAL:Int = 4
Const STENCIL_GREATER:Int = 5
Const STENCIL_NOTEQUAL:Int = 6
Const STENCIL_GREATEREQUAL:Int = 7
Const STENCIL_ALWAYS:Int = 8

Private
Global _stencilRef:Int = 1
Global _stencilMask:Int = 1
Global _inStencil:Int = False
Global _tmpBlend:Int = MASKBLEND
Public

Rem
bbdoc: Check if Stencil-Check is enabled or not.
EndRem

Function IsStencilEnabled:Int()
If TGLMax2DDriver(GetGraphicsDriver()) Then
Return IsStencilEnabled_GL()
?Win32
ElseIf TD3D9Max2DDriver(GetGraphicsDriver()) Then
Return IsStencilEnabled_D3D9()
?
Else
Throw "Unsupported Graphics-Driver!"
EndIf
EndFunction

Rem
bbdoc: Enables the Stencil-Check
EndRem

Function EnableStencil()
If TGLMax2DDriver(GetGraphicsDriver()) Then
EnableStencil_GL()
?Win32
ElseIf TD3D9Max2DDriver(GetGraphicsDriver()) Then
EnableStencil_D3D9()
?
Else
Throw "Unsupported Graphics-Driver!"
EndIf
EndFunction

Rem
bbdoc: Disables the Stencil-Check
EndRem

Function DisableStencil()
If TGLMax2DDriver(GetGraphicsDriver()) Then
DisableStencil_GL()
?Win32
ElseIf TD3D9Max2DDriver(GetGraphicsDriver()) Then
DisableStencil_D3D9()
?
Else
Throw "Unsupported Graphics-Driver!"
EndIf
EndFunction

Rem
bbdoc: Clears the Stencil-Buffer ans sets each pixel to 0.
EndRem

Function ClearStencil()
If TGLMax2DDriver(GetGraphicsDriver()) Then
ClearStencil_GL()
?Win32
ElseIf TD3D9Max2DDriver(GetGraphicsDriver()) Then
ClearStencil_D3D9()
?
Else
Throw "Unsupported Graphics-Driver!"
EndIf
EndFunction

Rem
bbdoc: Check if BeginStencil has been called, and if we are before the final EndStencil.
EndRem

Function InStencil:Int()
Return _inStencil
EndFunction

Rem
bbdoc: Set the Compare-Mode for the Stencil-Buffer.
about: Possible values are: STENCIL_NEVER, STENCIL_LESS, STENCIL_EQUAL, STENCIL_LESSEQUAL, STENCIL_GREATER, STENCIL_NOTEQUAL, STENCIL_GREATEREQUAL, STENCIL_ALWAYS<br />
Most interesting values are STENCIL_EQUAL and STENCIL_NOTEQUAL
info: Furhter information about Stencil-Buffers can be found here: <a href="http://wiki.delphigl.com/index.php/glStencilFunc">http://wiki.delphigl.com/index.php/glStencilFunc</a> (German)
EndRem

Function SetStencilMode(mode:Int)
If TGLMax2DDriver(GetGraphicsDriver()) Then
SetStencilMode_GL(mode)
?Win32
ElseIf TD3D9Max2DDriver(GetGraphicsDriver()) Then
SetStencilMode_D3D9(mode)
?
Else
Throw "Unsupported Graphics-Driver!"
EndIf
EndFunction

Rem
bbdoc: Sets the ref-value which is passed to the corosponding System-Function.
about: For furhter information see <a href="http://wiki.delphigl.com/index.php/glStencilOp">http://wiki.delphigl.com/index.php/glStencilOp</a> and <a href="http://wiki.delphigl.com/index.php/glStencilFunc">http://wiki.delphigl.com/index.php/glStencilFunc</a> (both German)
EndRem

Function SetStencilRef(ref:Int)
_stencilRef = ref
EndFunction

Rem
bbdoc: Returns the current Stencil Ref.
EndRem

Function GetStencilRef:Int()
Return _stencilRef
EndFunction

Rem
bbdoc: Set the mask-value which is passed to the corosponding System-Function.
about: For furhter information see <a href="http://wiki.delphigl.com/index.php/glStencilOp">http://wiki.delphigl.com/index.php/glStencilOp</a> and <a href="http://wiki.delphigl.com/index.php/glStencilFunc">http://wiki.delphigl.com/index.php/glStencilFunc</a> (both German)
EndRem

Function SetStencilMask(mask:Int)
_stencilMask = mask
EndFunction

Rem
bbdoc: Returns the current Stencil Mask.
EndRem

Function GetStencilMask:Int()
Return _stencilMask
EndFunction

Rem
bbdoc: Begin drawing in the Stencil-Buffer. All drawing to the default backbuffer is disabled until call to #EndStencil.
about: Whatever is drawn after this(Doesn__COMMENT1__
EndRem

Function BeginStencil()
_tmpBlend = GetBlend()
SetBlend(MASKBLEND)

If TGLMax2DDriver(GetGraphicsDriver()) Then
BeginStencil_GL()
?Win32
ElseIf TD3D9Max2DDriver(GetGraphicsDriver()) Then
BeginStencil_D3D9()
?
Else
Throw "Unsupported Graphics-Driver!"
EndIf
EndFunction

Rem
bbdoc: Finish drawing into the Stencil-Buffer Default Drawing mode is restored, so you can draw as usual.
about: Remember that Stencil has to be enabled to be able to draw into the stencil buffer itself, AND to se a result at all.
EndRem

Function EndStencil()
If TGLMax2DDriver(GetGraphicsDriver()) Then
EndStencil_GL()
?Win32
ElseIf TD3D9Max2DDriver(GetGraphicsDriver()) Then
EndStencil_D3D9()
?
Else
Throw "Unsupported Graphics-Driver!"
EndIf

SetBlend(_tmpBlend)
EndFunction


' OpenGL Part

Private

Global _stencilModeGL:Int = GL_EQUAL

Function IsStencilEnabled_GL:Int()
Return glIsEnabled(GL_STENCIL_TEST)
EndFunction

Function EnableStencil_GL()
glEnable(GL_STENCIL_TEST)
EndFunction

Function DisableStencil_GL()
glDisable(GL_STENCIL_TEST)
EndFunction

Function ClearStencil_GL()
glClear(GL_STENCIL_BUFFER_BIT)
EndFunction

Function SetStencilMode_GL(mode:Int)
Select mode
Case STENCIL_NEVER
_stencilModeGL = GL_NEVER
Case STENCIL_LESS
_stencilModeGL = GL_LESS
Case STENCIL_EQUAL
_stencilModeGL = GL_EQUAL
Case STENCIL_LESSEQUAL
_stencilModeGL = GL_LEQUAL
Case STENCIL_GREATER
_stencilModeGL = GL_GREATER
Case STENCIL_NOTEQUAL
_stencilModeGL = GL_NOTEQUAL
Case STENCIL_GREATEREQUAL
_stencilModeGL = GL_GEQUAL
Case STENCIL_ALWAYS
_stencilModeGL = GL_ALWAYS
Default
_stencilModeGL = GL_ALWAYS
EndSelect
EndFunction

Function BeginStencil_GL()
glColorMask(False, False, False, False)
glStencilFunc(GL_ALWAYS, _stencilRef, _stencilMask)
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE)
_inStencil = True
EndFunction

Function EndStencil_GL()
glColorMask(True, True, True, True)
glStencilFunc(_stencilModeGL, _stencilRef, _stencilMask)
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP)
_inStencil = False
EndFunction

' D3D9 Part
?Win32
Global _stencilModeD3D9:Int = D3DCMP_EQUAL

Function IsStencilEnabled_D3D9:Int()
Local dev:IDirect3DDevice9 = TD3D9Max2DDriver(GetGraphicsDriver()).GetD3DDevice()
Assert dev
Local res:Int
dev.GetRenderState(D3DRS_STENCILENABLE, res)
Return res
EndFunction

Function EnableStencil_D3D9()
Local dev:IDirect3DDevice9 = TD3D9Max2DDriver(GetGraphicsDriver()).GetD3DDevice()
Assert dev
dev.SetRenderState(D3DRS_STENCILENABLE, True)
EndFunction

Function DisableStencil_D3D9()
Local dev:IDirect3DDevice9 = TD3D9Max2DDriver(GetGraphicsDriver()).GetD3DDevice()
Assert dev
dev.SetRenderState(D3DRS_STENCILENABLE, False)
EndFunction

Function ClearStencil_D3D9()
Local dev:IDirect3DDevice9 = TD3D9Max2DDriver(GetGraphicsDriver()).GetD3DDevice()
Assert dev
dev.Clear(0, Null, D3DCLEAR_STENCIL, 0, 0, 0)
EndFunction

Function SetStencilMode_D3D9(mode:Int)
Select mode
Case STENCIL_NEVER
_stencilModeD3D9 = D3DCMP_NEVER
Case STENCIL_LESS
_stencilModeD3D9 = D3DCMP_LESS
Case STENCIL_EQUAL
_stencilModeD3D9 = D3DCMP_EQUAL
Case STENCIL_LESSEQUAL
_stencilModeD3D9 = D3DCMP_LESSEQUAL
Case STENCIL_GREATER
_stencilModeD3D9 = D3DCMP_GREATER
Case STENCIL_NOTEQUAL
_stencilModeD3D9 = D3DCMP_NOTEQUAL
Case STENCIL_GREATEREQUAL
_stencilModeD3D9 = D3DCMP_GREATEREQUAL
Case STENCIL_ALWAYS
_stencilModeD3D9 = D3DCMP_ALWAYS
Default
_stencilModeD3D9 = D3DCMP_ALWAYS
EndSelect
EndFunction

Function BeginStencil_D3D9()
Local dev:IDirect3DDevice9 = TD3D9Max2DDriver(GetGraphicsDriver()).GetD3DDevice()
Assert dev

dev.SetRenderState(D3DRS_COLORWRITEENABLE, 0)
dev.SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS)
dev.SetRenderState(D3DRS_STENCILREF, _stencilRef)
dev.SetRenderState(D3DRS_STENCILMASK, _stencilMask)
dev.SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE)

_inStencil = True
EndFunction

Function EndStencil_D3D9()
Local dev:IDirect3DDevice9 = TD3D9Max2DDriver(GetGraphicsDriver()).GetD3DDevice()
Assert dev

dev.SetRenderState(D3DRS_COLORWRITEENABLE, $F)
dev.SetRenderState(D3DRS_STENCILFUNC, _stencilModeD3D9)
dev.SetRenderState(D3DRS_STENCILREF, _stencilRef)
dev.SetRenderState(D3DRS_STENCILMASK, _stencilMask)
dev.SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP)

_inStencil = False
EndFunction
?

Public


Achtung, ich werde diesen Code nicht laufend aktualisieren. Wer das aktuelle Modul haben möchte, sollte es aus meinem git auschecken: http://git.oromit.de/btbn.mod....tencil.mod

Hier ein kleines Verwendungs-Beispiel:

BlitzMax: [AUSKLAPPEN]
SuperStrict

Framework BRL.GLMax2D
Import BtbN.Stencil
Import BRL.JpgLoader
Import BRL.RamStream

Incbin "bild.jpg"

SetGraphicsDriver(GLMax2DDriver())
SetGraphicsDriver(D3D9Max2DDriver())
Graphics(800, 600, 0, 60, GRAPHICS_BACKBUFFER|GRAPHICS_DEPTHBUFFER|GRAPHICS_STENCILBUFFER)
EnableStencil()
SetStencilMode(STENCIL_NOTEQUAL)

Global bild:TImage = LoadImage("incbin::bild.jpg")
Local fps:Int, fpsCnt:Int
Local lastFps:Int = MilliSecs()

Repeat
Cls
If MouseHit(2) Then ClearStencil()

DrawImage(bild, 0, 0)
EnableStencil()

BeginStencil()
If MouseDown(1) Then
SetHandle(25,25)
DrawOval(MouseX(), MouseY(), 50, 50)
SetHandle(0,0)
EndIf
EndStencil()

SetColor(0,0,255)
DrawRect(0,0, GraphicsWidth(), GraphicsHeight())
SetColor(255,255,255)

DisableStencil()

If MilliSecs()-lastFps >= 1000 Then
fps = fpsCnt
fpsCnt = 0
lastFps = MilliSecs()
EndIf

DrawText(fps, 5, 5)

fpsCnt :+ 1

Flip 0
Until KeyHit(KEY_ESCAPE) Or AppTerminate()

End


Funktioniert mit D3D9 und OpenGL. Ich plane nicht, support für D3D7 einzubauen.

Um das ganze überhaupt kompilieren zu können, muss man ein BRL Modul anpassen. Damit es dann auch noch funktioniert, noch ein weiteres.

In BRL.DXGraphics muss man in der d3d9graphics.bmx in der funktion OpenD3DDevice folgende zeilen unterhalb von "Local pp..." hinzufügen:
BlitzMax: [AUSKLAPPEN]
If flags & GRAPHICS_STENCILBUFFER Then
pp.EnableAutoDepthStencil = True
pp.AutoDepthStencilFormat = D3DFMT_D24S8
EndIf


In BRL.D3D9Max2D muss man zum Type TD3D9Max2DDriver folgende Methode hinzufügen:
BlitzMax: [AUSKLAPPEN]
	Method GetD3DDevice:IDirect3DDevice9()
Return _d3dDev
EndMethod


Hoffe, das Mark da was in einer der nächsten BMax versionen dran tut.


Was vllt. noch wichtig zu erwähnen wäre ist, dass man beim aufruf von Graphics unter flags das GRAPHICS_STENCILBUFFER Flag mit angeben muss, damit das ganze überhaupt erst funktioniert.

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Codearchiv & Module

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group