Well, to anyone really... The function set pretty much makes it perfect for a modeller, even windows styleeee as in, my GUI system called BGI (Bamboo Gizmo Interface), I have a 3D canvas in there, because I do plan to make my own little tools when needed:
; 3D Multi-Canvas Test - Render multiple 3D scenes in BGI window canvases
; Demonstrates independent canvas rendering at different resolutions
; Uses b3dBindEntityToCanvas() for efficient per-canvas entity filtering
Import "BBRuntime64Ext.decls"
Include "../../BBR_INCLUDE.bam"
Function Main()
Print "BambooBasic 3D Multi-Canvas Test"
Print ""
;Show/Hide debug
b3dShowConsoleOutput(False)
; Initialize 3D graphics system FIRST (bgiCreateCanvas3D needs the 3D device)
Print "Initializing 3D graphics..."
b3dGraphics3D(1, 1, BBR_WINDOW_MODE_HIDDEN)
; Initialize BGI system
bgiInitBGI("Arial", 12)
; Create main BGI window (larger to fit multiple canvases)
Local mainWindow:Int = bgiCreateWindow("3D Multi-Canvas Test", 1100, 1000)
; Create THREE 3D canvases with DIFFERENT resolutions
Print ""
Print "Creating 3D canvases at different resolutions..."
; Canvas 1: 256x256 (top-left)
Local canvas1:Int = bgiCreateCanvas3D(10, 10, 256, 256, mainWindow)
If canvas1 = 0 Then
Print "ERROR: Failed to create canvas 1!"
Return False
EndIf
Print "Canvas 1 created: 256x256 (ID: " & ToString(canvas1) & ")"
; Canvas 2: 512x512 (top-right)
Local canvas2:Int = bgiCreateCanvas3D(280, 10, 512, 512, mainWindow)
If canvas2 = 0 Then
Print "ERROR: Failed to create canvas 2!"
Return False
EndIf
Print "Canvas 2 created: 512x512 (ID: " & ToString(canvas2) & ")"
; Canvas 3: 768x384 (bottom, wider aspect ratio [strected])
Local canvas3:Int = bgiCreateCanvas3D(10, 550, 768, 384, mainWindow)
If canvas3 = 0 Then
Print "ERROR: Failed to create canvas 3!"
Return False
EndIf
Print "Canvas 3 created: 768x384 (ID: " & ToString(canvas3) & ")"
; Create THREE separate cameras (one for each canvas)
Print ""
Print "Creating cameras..."
Local camera1:Int = b3dCreateCamera()
b3dPositionEntity(camera1, 0, 0, -5)
b3dCameraClsColor(camera1, 80, 50, 50) ; Red tint
Local camera2:Int = b3dCreateCamera()
b3dPositionEntity(camera2, 0, 0, -5)
b3dCameraClsColor(camera2, 50, 80, 50) ; Green tint
Local camera3:Int = b3dCreateCamera()
b3dPositionEntity(camera3, 0, 0, -8)
b3dCameraClsColor(camera3, 50, 50, 80) ; Blue tint
;Overlay set up
Print "Setting up canvas overlays...~n"
Local font:Int = b2dLoadFont("consolas_18_2.png","consolas_18_2.txt")
Print "Font: " & ToString(font) & "~n"
; Load test images
Print "Loading test images..."
Local imgBomb:Int = b2dLoadImage("BigBomb.png")
Local imgCrate:Int = b2dLoadImage("crate.png")
Local imgLeaves:Int = b2dLoadImage("../../Extended/Overlay/leaves.png")
Print "BigBomb image: " & ToString(imgBomb)
Print "Crate image: " & ToString(imgCrate)
Print "Leaves image: " & ToString(imgLeaves) & "~n"
; Create THREE different meshes (one for each canvas)
Print "Loading meshes..."
Local sphere:Int = b3dLoadMesh("sphere.glb", BBR_ONE_SLOT, BBR_NO_TEXTURE_UV, 0)
b3dScaleEntity(sphere, 1.2, 1.2, 1.2)
b3dSetEntityColorFX(sphere, 255, 100, 100) ; Red
Local torus:Int = b3dLoadMesh("torus.glb", BBR_ONE_SLOT, BBR_NO_TEXTURE_UV, 0)
b3dScaleEntity(torus, 1.5, 1.5, 1.5)
b3dSetEntityColorFX(torus, 100, 255, 100) ; Green
Local helmet:Int = b3dLoadMesh("helmet.glb", BBR_ONE_SLOT, BBR_NO_TEXTURE_UV, 0)
b3dScaleEntity(helmet, 1.8, 1.8, 1.8)
; Create shared directional light
Print "Creating light..."
Local light:Int = b3dCreateLight(BBR_LIGHT_DIRECTIONAL)
b3dLightColor(light, 255, 255, 255)
b3dRotateEntity(light, 45, -90, 0)
b3dLightIntensity(light, 1.0)
b3dAmbientLight(30, 30, 30)
; Load toon shader (shared by all meshes)
Print "Loading toon shader..."
Local toonShader:Int = b3dLoadEntityShader("ToonShader.hlsl")
If toonShader = 0 Then
Print "ERROR: Failed to load toon shader!"
b3dEnd()
Return False
EndIf
; Configure toon shader
b3dSetEntityShaderFloat(toonShader, "useFlatNormal", 0.0)
b3dSetEntityShaderFloat(toonShader, "toonLevelsParam", 3.0)
b3dSetEntityShaderFloat(toonShader, "rimPowerParam", 3.0)
b3dSetEntityShaderFloat(toonShader, "rimIntensityParam", 0.5)
b3dSetEntityShaderFloat(toonShader, "rimColorR", 1.0)
b3dSetEntityShaderFloat(toonShader, "rimColorG", 1.0)
b3dSetEntityShaderFloat(toonShader, "rimColorB", 1.0)
; Apply shader to all meshes
b3dEntityShader(sphere, toonShader)
b3dEntityShader(torus, toonShader)
b3dEntityShader(helmet, toonShader)
; Load CRT screen shader (post-process effect for canvases)
Print "Loading CRT screen shader..."
Local crtShader:Int = b3dLoadScreenShader("CRT.hlsl")
If crtShader = 0 Then
Print "ERROR: Failed to load CRT screen shader!"
Else
; Configure CRT shader parameters
b3dSetShaderFloat(crtShader, "scanlineIntensity", 0.5)
b3dSetShaderFloat(crtShader, "scanlineCount", 100.0)
b3dSetShaderFloat(crtShader, "vignetteStrength", 0.3)
b3dSetShaderFloat(crtShader, "curvatureAmount", 0.02)
b3dSetShaderFloat2(crtShader, "screenResolution", 512.0, 512.0)
; Apply CRT shader to Canvas 2 (middle canvas, larger size)
bgiApplyCanvasScreenShader(canvas2, crtShader)
Print "CRT shader applied to Canvas 2"
EndIf
; Load TextSheen shader (per-draw text shader)
Print "Loading TextSheen text shader..."
Local sheenShader:Int = b2dLoadTextShader("../../Extended/Overlay/TextSheen.hlsl")
If sheenShader = 0 Then
Print "ERROR: Failed to load TextSheen text shader!"
Else
; Configure TextSheen shader parameters
b2dSetTextShaderFloat(sheenShader, "0", 0.5) ; sheenPosition (middle)
b2dSetTextShaderFloat(sheenShader, "1", 0.3) ; sheenWidth
b2dSetTextShaderFloat(sheenShader, "2", 1.5) ; sheenIntensity
Print "TextSheen shader loaded (will be applied per-draw)"
EndIf
; Load ImageGlow shader (per-draw image shader)
Print "Loading ImageGlow image shader..."
Local glowShader:Int = b2dLoadImageShader("../../Extended/Overlay/ImageGlow.hlsl")
If glowShader = 0 Then
Print "ERROR: Failed to load ImageGlow image shader!"
Else
; Configure ImageGlow shader parameters
b2dSetImageShaderFloat(glowShader, "0", 2.0) ; glowIntensity
b2dSetImageShaderFloat(glowShader, "1", 1.0) ; glowRadius
b2dSetImageShaderFloat3(glowShader, "2", 1.0, 0.8, 0.2) ; glowColor (orange)
Print "ImageGlow shader loaded (will be applied per-draw)"
EndIf
; Bind each entity to its respective canvas
Print "Binding entities to canvases..."
b3dBindEntityToCanvas(sphere, canvas1) ; Sphere only renders in canvas 1
b3dBindEntityToCanvas(torus, canvas2) ; Cube only renders in canvas 2
b3dBindEntityToCanvas(helmet, canvas3) ; Torus only renders in canvas 3
; Create UI labels (positioned to the right of canvases)
Local labelTitle:Int = bgiCreateLabel("3D Multi-Canvas Demo (Shaders)", 810, 20, 250, 25, mainWindow)
Local labelCanvas1:Int = bgiCreateLabel("Canvas 1: TEXT Shader (TextSheen)", 810, 60, 250, 20, mainWindow)
Local labelFPS1:Int = bgiCreateLabel("FPS: 0", 810, 85, 250, 20, mainWindow)
Local labelCanvas2:Int = bgiCreateLabel("Canvas 2: SCREEN Shader (CRT)", 810, 120, 250, 20, mainWindow)
Local labelFPS2:Int = bgiCreateLabel("FPS: 0", 810, 145, 250, 20, mainWindow)
Local labelCanvas3:Int = bgiCreateLabel("Canvas 3: IMAGE Shader (Glow)", 810, 180, 250, 20, mainWindow)
Local labelFPS3:Int = bgiCreateLabel("FPS: 0", 810, 205, 250, 20, mainWindow)
Local labelInfo:Int = bgiCreateLabel("Each entity bound to specific canvas", 810, 250, 250, 60, mainWindow)
Local labelControls:Int = bgiCreateLabel("Arrow keys: Rotate Sphere (Canvas 1)", 810, 320, 250, 40, mainWindow)
Local labelFocus:Int = bgiCreateLabel("Focused Canvas: None", 810, 440, 250, 20, mainWindow)
; Create buttons
Local btnToggleShader:Int = bgiCreateButton("Toggle Toon", 810, 360, 150, 30, mainWindow)
Local btnToggleCRT:Int = bgiCreateButton("Toggle CRT (C2)", 810, 400, 150, 30, mainWindow)
Local btnQuit:Int = bgiCreateButton("Quit", 810, 440, 150, 30, mainWindow)
Print ""
Print "Multi-canvas test ready!"
Print "Using b3dBindEntityToCanvas()"
Print ""
Print "Shader Demo (each canvas shows different shader type):"
Print " Canvas 1 - TEXT SHADER: Per-draw TextSheen on BAMBOO text"
Print " Canvas 2 - SCREEN SHADER: CRT post-process effect"
Print " Canvas 3 - IMAGE SHADER: Per-draw ImageGlow on leaves.png"
Print " All 3D meshes - Toon entity shader"
Print ""
Print "Controls:"
Print " Arrow Keys - Rotate sphere (Canvas 1)"
Print " Torus and helmet auto-rotate"
Print " Toggle Toon button - Enable/disable entity toon shader"
Print " Toggle CRT button - Enable/disable CRT screen shader on Canvas 2"
Print " ESC or Quit button - Exit"
Print ""
Local rotation1Y:Double = 0.0
Local rotation1X:Double = 0.0
Local rotation2:Double = 0.0 ; Auto-rotation for torus
Local rotation3:Double = 0.0 ; Auto-rotation for helmet
Local shaderEnabled:Int = True
Local crtEnabled:Int = True ; CRT shader starts enabled on Canvas 2
Local running:Int = True
; Sheen shader animation
Local sheenPosition:Double = 0.0
Local sheenSpeed:Double = 0.0015
;Mouse variables when inside canvas areas
Local cmx2:Int, cmy2:Int
Local cmx3:Int, cmy3:Int
; Track focused canvas (only update label when focus changes)
Local lastFocusedCanvas:Int = 0
; Main loop
While running
; Handle keyboard input
sysUpdateEvents()
Local eventMsg:Int = bgiGetEventMessage()
Local eventSource:Int = bgiGetEventSource()
; Handle BGI events
If eventMsg = BGI_EVENT_COMMAND_CLOSE Then
running = False
Print "Window closed"
ElseIf eventMsg = BGI_EVENT_COMMAND_CLICK Then
If eventSource = btnToggleShader Then
shaderEnabled = 1 - shaderEnabled
If shaderEnabled Then
b3dEntityShader(sphere, toonShader)
b3dEntityShader(torus, toonShader)
b3dEntityShader(helmet, toonShader)
Print "Toon shader enabled"
Else
b3dEntityShader(sphere, 0)
b3dEntityShader(torus, 0)
b3dEntityShader(helmet, 0)
Print "Toon shader disabled"
EndIf
ElseIf eventSource = btnToggleCRT Then
crtEnabled = 1 - crtEnabled
If crtEnabled Then
bgiApplyCanvasScreenShader(canvas2, crtShader)
Print "CRT screen shader enabled on Canvas 2"
Else
bgiClearCanvasScreenShader(canvas2)
Print "CRT screen shader disabled on Canvas 2"
EndIf
ElseIf eventSource = btnQuit Then
running = False
EndIf
EndIf
bgiFlushEvent()
; Get canvas-relative mouse coordinates for Canvas 2 and 3
; Returns -1 if mouse is outside canvas bounds
cmx2 = bgiGetCanvasMouseX(canvas2)
cmy2 = bgiGetCanvasMouseY(canvas2)
cmx3 = bgiGetCanvasMouseX(canvas3)
cmy3 = bgiGetCanvasMouseY(canvas3)
; ESC is global - works anywhere
If inpIsKeyHit(VKEY_ESCAPE) Then running = False
; Manual rotation for sphere (Canvas 1) - ONLY when Canvas 1 has focus
If bgiGetFocusedCanvas() = canvas1 Then
If inpIsKeyDown(VKEY_LEFT) Then rotation1Y = rotation1Y - 2.0
If inpIsKeyDown(VKEY_RIGHT) Then rotation1Y = rotation1Y + 2.0
If inpIsKeyDown(VKEY_UP) Then rotation1X = rotation1X - 2.0
If inpIsKeyDown(VKEY_DOWN) Then rotation1X = rotation1X + 2.0
EndIf
; Update focus label (only when focus changes)
Local currentFocus:Int = bgiGetFocusedCanvas()
If currentFocus <> lastFocusedCanvas Then
If currentFocus = canvas1 Then
bgiSetGizmoText(labelFocus, "Focused Canvas: Canvas 1 (Sphere)")
ElseIf currentFocus = canvas2 Then
bgiSetGizmoText(labelFocus, "Focused Canvas: Canvas 2 (Torus)")
ElseIf currentFocus = canvas3 Then
bgiSetGizmoText(labelFocus, "Focused Canvas: Canvas 3 (Helmet)")
Else
bgiSetGizmoText(labelFocus, "Focused Canvas: None")
EndIf
lastFocusedCanvas = currentFocus
EndIf
; Update sheen shader animation
sheenPosition = sheenPosition + sheenSpeed
If sheenPosition > 1.2 Then ; Go past right edge
sheenPosition = -0.2 ; Restart from left
EndIf
b2dSetTextShaderFloat(sheenShader, "0", sheenPosition)
; Auto-rotation for cube and torus
rotation2 = rotation2 + 1.0
rotation3 = rotation3 + 0.5
; Update mesh rotations
b3dRotateEntity(sphere, rotation1X, rotation1Y, 0)
b3dRotateEntity(torus, rotation2, rotation2, 0)
b3dRotateEntity(helmet, 0, rotation3, rotation3 * 0.5)
; ---------------
; RENDER CANVAS 1 (256x256, Sphere)
; ---------------
b3dSetRenderTargetCanvas(canvas1)
b3dSetActiveCamera(camera1)
b3dCls3D()
b2dSetCanvasFilter(canvas1)
; Draw "Canvas 1" label without shader
b2dDrawText("Canvas 1", 10, 10, 0, font)
; Draw "BAMBOO" in centre WITH per-draw TextSheen shader
b2dSetColor(255, 255, 255) ; White color for sheen effect
b2dDrawTextEx("BAMBOO", 128, 110, True, font, sheenShader)
b2dSetColor(255, 255, 255) ; Reset to white
; Draw regular images without shaders
b2dDrawImage(imgBomb, 10, 200)
b2dDrawImage(imgCrate, 150, 180)
b2dClearCanvasFilter()
b3dRenderWorld()
bgiFlipCanvas(canvas1)
; ---------------
; RENDER CANVAS 2 (512x512, Torus)
; ---------------
b3dSetRenderTargetCanvas(canvas2)
b3dSetActiveCamera(camera2)
b3dCls3D()
b2dSetCanvasFilter(canvas2)
b2dDrawText("Canvas 2", 10, 10, 0, font)
; Draw regular images without shaders (CRT screen shader applied to entire canvas)
b2dDrawImage(imgCrate, 50, 400)
; Only draw bomb at mouse position if mouse is over this canvas
If cmx2 >= 0 And cmy2 >= 0 Then
b2dDrawImage(imgBomb, cmx2, cmy2)
EndIf
b2dClearCanvasFilter()
b3dRenderWorld()
bgiFlipCanvas(canvas2)
; ---------------
; RENDER CANVAS 3 (768x384, Helmet)
; ---------------
b3dSetRenderTargetCanvas(canvas3)
b3dSetActiveCamera(camera3)
b3dCls3D()
b2dSetCanvasFilter(canvas3)
b2dDrawText("Canvas 3", 10, 10, 0, font)
; Draw leaves WITH image glow shader
b2dDrawImageEx(imgLeaves, 300, 150, glowShader)
If cmx3 >= 0 And cmy3 >= 0 Then
b2dDrawImage(imgCrate, cmx3, cmy3)
EndIf
b2dDrawImage(imgBomb, 650, 300)
b2dClearCanvasFilter()
b3dRenderWorld()
bgiFlipCanvas(canvas3)
; Update FPS displays for all canvases
bgiSetGizmoText(labelFPS1, "FPS: " & ToString(bgiGetCanvasFPS(canvas1)))
bgiSetGizmoText(labelFPS2, "FPS: " & ToString(bgiGetCanvasFPS(canvas2)))
bgiSetGizmoText(labelFPS3, "FPS: " & ToString(bgiGetCanvasFPS(canvas3)))
Wend
; Cleanup
Print ""
Print "Shutting down..."
b3dFreeEntityShader(toonShader)
b3dEnd()
Return False
EndFunction
Very cute! :) hehehe
Dabzy