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] [EINKLAPPEN] SuperStrict
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
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
Function EnableStencil() If TGLMax2DDriver(GetGraphicsDriver()) Then EnableStencil_GL() ?Win32 ElseIf TD3D9Max2DDriver(GetGraphicsDriver()) Then EnableStencil_D3D9() ? Else Throw "Unsupported Graphics-Driver!" EndIf EndFunction
Function DisableStencil() If TGLMax2DDriver(GetGraphicsDriver()) Then DisableStencil_GL() ?Win32 ElseIf TD3D9Max2DDriver(GetGraphicsDriver()) Then DisableStencil_D3D9() ? Else Throw "Unsupported Graphics-Driver!" EndIf EndFunction
Function ClearStencil() If TGLMax2DDriver(GetGraphicsDriver()) Then ClearStencil_GL() ?Win32 ElseIf TD3D9Max2DDriver(GetGraphicsDriver()) Then ClearStencil_D3D9() ? Else Throw "Unsupported Graphics-Driver!" EndIf EndFunction
Function InStencil:Int() Return _inStencil EndFunction
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
Function SetStencilRef(ref:Int) _stencilRef = ref EndFunction
Function GetStencilRef:Int() Return _stencilRef EndFunction
Function SetStencilMask(mask:Int) _stencilMask = mask EndFunction
Function GetStencilMask:Int() Return _stencilMask EndFunction
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
Function EndStencil() If TGLMax2DDriver(GetGraphicsDriver()) Then EndStencil_GL() ?Win32 ElseIf TD3D9Max2DDriver(GetGraphicsDriver()) Then EndStencil_D3D9() ? Else Throw "Unsupported Graphics-Driver!" EndIf SetBlend(_tmpBlend) EndFunction
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
?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] [EINKLAPPEN] 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] [EINKLAPPEN] 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] [EINKLAPPEN] 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.
|