Okay, here's a cut-down version of my UI that illustrates the ortho camera use. I've left out nice button structures and interface loading, and scaling of objects etc. for different resolutions as these'll want to be designed for the end UI. My clunky solutions won't be wanted! But that's what some of the pointer type's fields are for though not used in this example.
Save this code as "_lib_ToodeeGooey.bb"
; Shifty's New Toodee-Gooey Library basics
; Constucts a UI from rectangular sprites.
; Positions them from an orthogonal camera.
; USE : Call TG_Initialse() to set up UI. Follow with TG_SetPointer() to set mouse pointer
; Use TG_Load_Sprite to create a 2D button sprite from a texture
; Use Scene_cam as your main program camera
; Use TG_Draw_UI() instead of UpdateWorld+RenderWorld
; Placment of UI components is in screen pixel coords
; - Z value determines z order. High values have higer priority (front of interface). Float values
; - add UI_distance to objects to move them in front of UI camera
; - Range of Z defined by TG_Initialise/CameraRange TG_camera\camera,1,xxx
; - default is 100 for a range of 1-100. Mouse placed at 20. Fractional
; eg. PositionEntity button,100,100,UI_distance+5
Const UI_distance=-10000 ; Camera distance for UI camera
Global TG_pointer.TG_point
Global TG_camera.TG_cam
Global Scene_cam
Global TG_sprite ; rectangle mesh
Type TG_point
; Rectangle for pointer
Field sprite% ; Pointer to rectangle mesh
Field texture% ; pointer to texture
Field pos_x% ; x position
Field pos_y% ; y position
Field prev_x% ; previous x position
Field prev_y% ; previous y position
Field siz_x% ; x size
Field siz_y% ; y size
; Field buffer% ; Buffer of underlying image to be restored
End Type
Type TG_cam
Field camera% ; Pointer to camera entity
Field pos_x%
Field pos_y%
Field siz_x%
Field siz_y%
End Type
TG_pointer.TG_point = New TG_point
TG_camera.TG_cam = New TG_cam
; UI constructors
Function TG_Initialise()
; FUNCTION : initialise UI camera and mouse pointer
; loads rectangular mesh that's basis of all UI sprites
HidePointer()
TG_sprite = CreateMesh()
surf = CreateSurface(TG_sprite)
v0 = AddVertex (surf, 0,0,0, 0,0)
v1 = AddVertex (surf, 10,0,0, 1,0)
v2 = AddVertex (surf, 10,-10,0, 1,1)
v3 = AddVertex (surf, 0,-10,0, 0,1)
AddTriangle (surf,v0,v1,v2)
AddTriangle (surf,v0,v2,v3)
TG_camera\camera=CreateCamera()
PositionEntity TG_camera\camera,0,0,UI_distance
CameraProjMode(TG_camera\camera,0) ; 0 to hide, 2 to render
CameraClsMode(TG_camera\camera,0,1)
CameraRange TG_camera\camera,1,100
End Function
Function TG_SetPointer(img$)
; FUNCTION : sets pointer image
TG_pointer\texture= LoadTexture(img$,2)
TG_pointer\sprite=TG_Create_Sprite(TG_pointer\texture)
TG_pointer\pos_x=MouseX()
TG_pointer\pos_y=MouseY()
TG_pointer\siz_x=TextureWidth(TG_pointer\texture)
TG_pointer\siz_y=TextureHeight(TG_pointer\texture)
PositionEntity TG_pointer\sprite, TG_pointer\pos_x, TG_pointer\pos_y, UI_distance+20
End Function
Function TG_Create_Sprite(texture,x_size#=0,y_size#=0)
; Doctored sprite code from Skidracer
; 'texture' is a pointer to a texture object, in sizes of squared powers of 2. eg. 128x128 or 256x256
; this is because GPU's work fastest with power of 2 textures
; optional x_size and y_size values crop the sprite to fit
; eg. for a 27x18 button, create a 32x32 source image, load as texture, and call TG_Load_Sprite(texture,27,18)
; No x_size or y_size values uses texture proportions
width=TextureWidth(texture)
If Not x_size
x_size=width
EndIf
height=TextureHeight(texture)
If Not y_size
y_size=height
EndIf
; change these for viewports
viewwidth=GraphicsWidth()
viewheight=GraphicsHeight()
; find existing pixiespace parented to camera
magic=0
n=CountChildren(TG_camera\camera)
For i=1 To n
If EntityName(GetChild(TG_camera\camera,i))="pixiespace"
magic=GetChild(GetChild(TG_camera\camera,i),1)
EndIf
Next
If magic=0
magic=CreatePivot(TG_camera\camera)
NameEntity(magic,"pixiespace")
aspect#=Float(viewheight)/viewwidth
PositionEntity magic,-1,aspect,1
scale#=2.0/viewwidth
ScaleEntity magic,scale,-scale,-scale
magic=CreatePivot(magic)
PositionEntity magic,-.5,-.5,0
EndIf
; create sprite from texture as child of magic overlay
sprite=CopyMesh(TG_sprite)
EntityParent sprite,magic ;cludge for blitz bug in createsprite(parent)
scale#=0.2/viewwidth
ScaleMesh sprite,x_size*scale,y_size*scale,1
ScaleTexture texture,width/x_size, height/y_size
EntityTexture sprite,texture
EntityFX sprite,1
Return sprite
End Function
; UI control
Function TG_Draw_UI()
; cam is a pointer to the scene camera
UpdateWorld
RenderWorld
PositionEntity TG_pointer\sprite,MouseX(),MouseY(),UI_distance+20
CameraProjMode (Scene_cam,0)
CameraProjMode (TG_camera\camera,2)
RenderWorld
CameraProjMode (Scene_cam,1)
CameraProjMode (TG_camera\camera,0)
End Function
; Misc functions
Function texture_mask_colour(texture,r1,g1,b1)
buf= TextureBuffer(texture)
LockBuffer buf
For loop=0 To TextureWidth(texture)-1
For loop1=0 To TextureHeight(texture)-1
RGB1=ReadPixelFast(loop,loop1,TextureBuffer(texture)) ; read the RGB value from the texture
r=(RGB1 And $FF0000)Shr 16;separate out the red
g=(RGB1 And $FF00) Shr 8;green
b=RGB1 And $FF;and blue parts of the color
a=255
If r=r1 And g=g1 And b=b1; check RGB lies with the tolerance
a=0
End If
newrgb= (a Shl 24) Or (r Shl 16) Or (g Shl 8) Or b ; combine the ARGB back into one value
WritePixelFast(loop,loop1,newrgb,buf); write back to the texture
Next
Next
UnlockBuffer buf
End Function
Here's an example program that uses it, with a mouse pointer and two 'buttons' (just 2D sprites).
; Example of using the UI code.
Include "_lib_ToodeeGooey.bb"
;Graphics3D 800,600,0,0
Graphics3D 1024,768,0,1
TG_Initialise()
TG_SetPointer("textures\pointer.png")
; Add a 'button' to the 2D UI. "texelchallenge.png" is a 128x128 checkered B&W square to prove pixel-perfect textures
Button_texture=LoadTexture("textures\texelchallenge.png")
Button_sprite=TG_Create_Sprite(Button_texture,40,120)
PositionEntity Button_sprite,400,200,UI_distance+2
; Add another button with alpha blending
Button_2_texture=LoadTexture("textures\texelchallenge.png")
Button_2_sprite=TG_Create_Sprite(Button_2_texture)
PositionEntity Button_2_sprite,500,200,UI_distance+2
EntityAlpha Button_2_sprite,0.75
;#Region *** Create scene with random 3D junk
Scene_cam=CreateCamera()
PositionEntity Scene_cam,0,0,0
CameraZoom Scene_cam,2
Scene_light=CreateLight(2,Scene_cam)
LightColor Scene_light,64,64,64
PositionEntity Scene_light,100,0,-100
For n=0 To 150
cube=CreateCube()
ScaleEntity cube,Rnd(1,10),Rnd(1,10),Rnd(1,10)
PositionEntity cube,Rnd(-200,200),Rnd(-200,200),Rnd(-200,200)
EntityColor cube,Rnd(0,2)*128,Rnd(0,2)*128,Rnd(0,2)*128
EntityShininess cube,1
Next
;#End Region
While Not KeyHit(1)
TurnEntity Scene_cam,0.01,0.005,0.02
TG_Draw_UI()
Flip False
Wend
You will need textures for the example obviously. Pointer was a 32x32 hand with transparent background. Anyone and their mother can easily create a basic UI from this, by checking for button clicks based on sprite positions. I use a button type with the structure...
Type TG_button
; Individual 'sprites' for controls
Field sprite% ; Pointer to rectangle mesh
Field texture% ; pointer to texture
Field pos_x% ; x position
Field pos_y% ; y position
Field siz_x% ; x size
Field siz_y% ; y size
Field ref_num% ; Reference number
Field state% ; State, relating to anim number
End Type
I use a Create_Button() function that loads a texture into button\texture, followed by "button\sprite=TG_Create_Sprite(button\texture). Changing this design to incorporate 3D meshes as buttons shouldn't be too hard, and maybe add a String field with an animation string, like model movement?