;:tabSize=4:indentSize=4:noTabs=true: ;:folding=explicit:collapseFolds=1: ;+ ; NAME: ; CAMDEMO_DI_CULLNFLY ; ; PURPOSE: ; The purpose of this routine is to provide an example of ; navigating 3 space using the keyboard and mouse along with my ; Win32 only directInput DLM and it also serves as an example of ; using the view frustum culling feature of RHTgrCamera. ; ; Use the NORBS and ORBDENSITY keywords to explore how object ; numbers and complexity affect rendering performace. ; ; *NOTE* ; ; This example REQUIRES my modified orb class. Use of the ; standard IDL orb will severly diminish culling performance ; since the standard orb class rebuilds the orb vertices upon ; every call to SetProperty. ; ; ; Controls: ; ; Forward: Up arrow ; Back: Down arrow ; Right: Right arrow ; Left: Left arrow ; Pan: Left mouse click and drag ; Zoom: Right mouse click and drag up/down ; Up: Page Up ; Down: Page Down ; Speed Up: Mouse wheel up ; Slow Down: Mouse wheel down ; MicroStep: Hold shift ; ; ; Camera menu: ; ; The camera drop down menu has a few items which you can select ; to alter how the camera is operating: ; ; Reset: Resets your location, orientation and zoom level. ; ; Force Aspect Ratio: Selecting this toggles the "Force ; aspect ratio" mode. Force AR forces the view to ; match the original pixel aspect ratio based upon the ; initial view settings and the dimensions of the destination ; device at the time of the first draw. If enabled, ; the pixel aspect ratio is preserved regardles of the ; aspect ratio of the destination device. ; ; In this example, the pixel aspect ratio is set at 1:1. ; So, when changing window dimensions with force AR enabled ; the orbs will still appear round. Disabling force AR and ; changing the window dimensions will distort the orbs (and ; everything else in the scene). ; ; Culling: The culling menu allows you to alter the view frustum ; culling mode of the camera. Application performance will ; depend on the number and density of the orb objects and ; the current culling mode. ; ; ; This version *requires* my win32 only directInput DLM. ; ; ; There are issues with this demo and the software renderer. ; Lighting seems to be the big one, the "floor" is very dark ; unless you are looking directly down. There are a number of ; stitching artifacts too. ; ; ; ; DISCLAIMER: The camdemo_* programs are quick examples of some ; of the features of my camera object. They are ; NOT provided as examples of proper programming ; technique. Use at your own risk! ; ; ; AUTHOR: ; Rick Towler ; NOAA National Marine Fisheries Service ; Alaska Fisheries Science Center ; Midwater Assesment/Conservation Engineering Group ; 7600 Sand Point Way NE ; Seattle, WA 98115 ; rick.towler@noaa.gov ; www.acoustics.washington.edu\~towler ; ; ; CATEGORY: ; Object Graphics ; ; ; KEYWORDS: ; nOrbs: Set this keyword to a scalar value defining the number ; of orbs that will be sprinkled about the scene. ; ; orbDensity: Set this keyword to a scaler value defining the density ; of the individual orb vertices. Small values will ; generate orbs with fewer vertices while larger values ; will generate orbs with many more vertices. Reasonable ; values are 0.3 - 15.0. ; ; software: Set this keyword to force rendering the scene using IDL's ; software renderer. Note that there are issues with this ; demo and the software renderer. ; ; ; DEPENDENCIES: RHTgrCamera__define.pro ; directInput.dlm ; ; ; LIMITATIONS: This program requires my Win32 only directInput.dlm. ; ; ; MODIFICATION HISTORY: ; Written by: Rick Towler, 17 February 2004. ; ; ; LICENSE ; ; CAMDEMO_DI_CULLNFLY.PRO Copyright (C) 2004 Rick Towler ; ; This program is free software; you can redistribute it and/or ; modify it under the terms of the GNU General Public License ; as published by the Free Software Foundation; either version 2 ; of the License, or (at your option) any later version. ; ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with this program; if not, write to the Free Software ; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ; ; A full copy of the GNU General Public License can be found on line at ; http://www.gnu.org/copyleft/gpl.html#SEC1 ; ;- ; camdemo_draw_event {{{ pro camdemo_draw_event, event ; Handle oWindow events WIDGET_CONTROL, event.top, GET_UVALUE=info, /NO_COPY ; Poll the mouse. mouseData = DI_PollMouse(info.diMouseID) if (SIZE(mouseData, /TYPE) eq 8) then begin ; Device is acquired and application has focus. case 1 of ; Pan the camera if button0 is down. (mouseData.buttons[0]):begin ; Calculate the pan amount relative to zoom level mouseX = mouseData.X / $ (4.0 > info.cameraZoom * 4.) mouseY = mouseData.Y / $ (4.0 > info.cameraZoom * 4.) ; Pan the camera info.camera -> Pan, -mouseX, -mouseY ; Get the camera's orientation info.camera -> GetProperty, PITCH=pitch, YAW=yaw, $ ROLL=roll ; Update the camera orientation values in the HUD. info.panText -> SetProperty, STRINGS= $ STRING([pitch,yaw,roll], format='(3(I3.3,1x))') end ; Zoom on right mouse click and drag up/down (mouseData.buttons[1]):begin mouseY = -mouseData.Y / 14. info.cameraZoom = info.cameraZoom + mouseY info.camera -> Zoom, info.cameraZoom ; Update the camera zoom value in the HUD info.zoomText -> SetProperty, STRINGS=STRING(info.cameraZoom, $ FORMAT='(f6.2)') end ; Middle mouse button handler (mouseData.buttons[2]):begin if (not info.dep[1]) then begin endif info.dep[1] = 1 end ; Left-alt (back) mouse button handler (mouseData.buttons[3]):begin if (not info.dep[2]) then begin endif info.dep[2] = 1 end else: info.dep[*] = [0B,0B,0B] endcase ; Change navigation speed on mouse wheel. if (mouseData.Z ne 0) then $ info.truckStep = info.truckStep + (mouseData.Z / 4.) > 0 endif ; Poll the keyboard. keys = DI_PollKeyboard(info.diKeyboardID) ; Determine which keys are depressed. keyCodes = WHERE(keys gt 0, nKeys) ; Process depressed keys. if (nkeys gt 0) then begin truckStep = info.truckStep for n=0, nKeys-1 do begin case keyCodes[n] of ; Check if the ESC key was pressed - exit. 1:begin ok = DIALOG_MESSAGE('Exit camdemo_DI_CullnFly?', /QUESTION, $ DIALOG_PARENT=event.top, TITLE='Exit camdemo_DI_CullnFly?') if (ok) then begin WIDGET_CONTROL, event.top, SET_UVALUE=info WIDGET_CONTROL, event.top, /DESTROY RETURN endif end ; Left Shift - micro steps 54:truckStep = truckStep / 20. ; Up arrow - forward 200:info.Camera -> truck, [0,0,1], truckStep ; Page Up - slide up 201:info.Camera -> truck, [0,1,0], truckStep ; Down arrow - back 208:info.Camera -> truck, [0,0,-1], truckStep ; Page Down - slide down 209:info.Camera -> truck, [0,-1,0], truckStep ; Left arrow - slide left 203:info.Camera -> truck, [-1,0,0], truckStep ; Right arrow - slide right 205:info.Camera -> truck, [1,0,0], truckStep else: endcase endfor ; Clamp camera location to bounding box. info.camera -> GetProperty, CAMERA_LOCATION=camLoc camLoc[0] = info.boxBounds[0,0] > camLoc[0] < info.boxBounds[0,1] camLoc[1] = info.boxBounds[1,0] > camLoc[1] < info.boxBounds[1,1] camLoc[2] = info.boxBounds[2,0] > camLoc[2] < info.boxBounds[2,1] ; Update the camera position. info.camera -> SetProperty, CAMERA_LOCATION=camLoc ; Update the camera position in the HUD info.locText -> SetProperty, STRINGS= $ STRING(camLoc,format='(3(F6.1,1x))') endif ; Calculate frames drawn per second. thisframe = SYSTIME(/SECONDS) info.count = info.count + (thisframe-info.lastframe) info.lastframe = thisframe info.frame = info.frame + 1 ; Average FPS values over ~0.5 second intervals. if (info.count gt 0.5D) then begin info.fpstext -> setproperty, strings = $ STRING((info.frame / info.count), FORMAT='(f5.1)') info.count = 0D info.frame = 0 endif ; Draw the scene. info.oWindow -> Draw, info.viewgroup ; Set another timer event. WIDGET_CONTROL, info.fileID, TIMER=0.0001 WIDGET_CONTROL, event.top, SET_UVALUE=info end ; }}} ; camdemo_camprop_event {{{ pro camdemo_camprop_event, event WIDGET_CONTROL, event.top, GET_UVALUE=info, /NO_COPY WIDGET_CONTROL, event.id, GET_UVALUE=uval case uval of 'RESET':begin ; Reset the camera's orientation info.camera -> SetProperty, PITCH=0., YAW=0., ROLL=0., $ CAMERA_LOCATION=[0,10,130] ; Reset the zoom level info.camera -> zoom, 0.0 info.cameraZoom = 0.0 ; Update the camera orientation values in the HUD info.panText -> SetProperty, STRINGS=STRING([0,0,0], $ FORMAT='(3(I3.3,1x))') info.locText -> SetProperty, STRINGS=STRING([0,10,130], $ FORMAT='(3(F5.1,1x))') ; Update the camera zoom value in the HUD info.zoomtext -> SetProperty, STRINGS=STRING(info.cameraZoom, $ FORMAT='(f5.2)') end 'FORCE':begin info.forceMode = info.forceMode xor 1 info.camera -> SetProperty, FORCE_AR=info.forceMode case info.forceMode of 1:info.forceText -> SetProperty, STRINGS='On' 0:info.forceText -> SetProperty, STRINGS='Off' endcase end 'NONE':begin ; Remove the orbs from the camera. info.camera -> Remove, info.orbArray ; Add the content as non-culled content and update interface. info.camera -> Add, info.orbArray info.cullText -> SetProperty, STRINGS='None' end 'STATIC':begin ; Remove the orbs from the camera. info.camera -> Remove, info.orbArray ; Add the content as statically culled content ; and update interface. info.camera -> Add, info.orbArray, /STATIC info.cullText -> SetProperty, STRINGS='Static' end 'DYNAMIC':begin ; Remove the orbs from the camera. info.camera -> Remove, info.orbArray ; Add the content as statically culled content ; and update interface. info.camera -> Add, info.orbArray, /DYNAMIC info.cullText -> SetProperty, STRINGS='Dynamic' end endcase ; Draw the scene info.oWindow -> draw, info.viewgroup WIDGET_CONTROL, event.top, SET_UVALUE=info end ; }}} ; camdemo_event {{{ pro camdemo_event, event ; Handle oWindow resize events WIDGET_CONTROL, event.top, GET_UVALUE=info, /NO_COPY if (event.id eq event.top) then begin ; Resize the tlb - set min and max dimensions xsize = 300 > event.x < 3200 ysize = 300 > event.y < 1200 WIDGET_CONTROL, event.top, XSIZE=xsize, YSIZE=ysize ; Resize the draw oWindow - compensate for any other widgets in oWindow info.oWindow -> SetProperty, DIMENSIONS=[xsize - 6,ysize - 6] ; Scale HUD text relative to default oWindow size text_scale = MIN([xsize,ysize]) / 600. info.titleFont -> SetProperty, SIZE = 18. * text_scale info.statsFont -> SetProperty, SIZE = 8. * text_scale ; Redisplay the graphic. info.oWindow -> draw, info.viewgroup endif WIDGET_CONTROL, event.top, SET_UVALUE=info end ; }}} ; camdemo_exit {{{ pro camdemo_exit, event WIDGET_CONTROL, event.top, /Destroy end ; }}} ; camdemo_cleanup {{{ pro camdemo_cleanup, tlb WIDGET_CONTROL, tlb, GET_UVALUE=info ; Free our direct input objects. ok = di_ReleaseKeyboard(info.diKeyboardID) ok = di_ReleaseMouse(info.diMouseID) ok = di_DestroyInterface(info.diID) OBJ_DESTROY, info.oContainer end ; }}} ; camdemo_di_cullnfly {{{ pro camdemo_di_cullnfly, nOrbs=nOrbs, $ orbDensity=orbDensity, $ software=software ; Set initial application defaults. forceMode = 1B cullMode = 2B truckStep = 0.8 ; Check IDL version. useDepthTest = (FLOAT(!version.release) ge 6.0) ? 1B : 0B ; Check our keywords. nOrbs = (N_ELEMENTS(nOrbs) eq 0) ? 20 : FIX(nOrbs) orbDensity = (N_ELEMENTS(orbDensity) eq 0) ? 4.0 : FLOAT(orbDensity) renderer = (N_ELEMENTS(software) eq 0) ? 0 : KEYWORD_SET(software) ; Create a oContainer for easy cleanup. oContainer = OBJ_NEW('IDL_Container') ; Define the top level base widget and some menu bar items. tlb=WIDGET_BASE(COLUMN=1, MBAR=menuid, TITLE='Camera Cull-N-Fly Demo', $ /TLB_SIZE_EVENTS) ; Menus. fileID=WIDGET_BUTTON(menuID, VALUE='File', EVENT_PRO='camdemo_draw_event') null=WIDGET_BUTTON(fileID, VALUE='Exit', EVENT_PRO='camdemo_exit') campropID=WIDGET_BUTTON(menuID, VALUE='Camera', $ EVENT_PRO='camdemo_camprop_event') null=WIDGET_BUTTON(campropID, VALUE='Reset', UVALUE='RESET') null=WIDGET_BUTTON(campropID, VALUE='Force Aspect Ratio', $ UVALUE='FORCE') cullID=WIDGET_BUTTON(campropID, VALUE='Culling', /MENU) null=WIDGET_BUTTON(cullID, VALUE='None', UVALUE='NONE') null=WIDGET_BUTTON(cullID, VALUE='Static', UVALUE='STATIC') null=WIDGET_BUTTON(cullID, VALUE='Dynamic', UVALUE='DYNAMIC') ; Create our graphics oWindow. ; Force software renderer if software keyword is set. drawID=widget_draw(tlb, XSIZE=600, YSIZE=600, /EXPOSE_EVENTS, $ GRAPHICS_LEVEL=2, RENDERER=renderer, /BUTTON_EVENTS, $ EVENT_PRO='camdemo_draw_event', /KEYBOARD_EVENTS) ; Realize the widget heirarchy. WIDGET_CONTROL, tlb, /realize ; Acquire the directInput devices. diID = di_InitInterface() if (TOTAL(diID) le 0) then begin ok = DIALOG_MESSAGE('Error creating direct input interface', /ERROR) WIDGET_CONTROL, tlb, /DESTROY RETURN endif diKeyboardID = di_acquireKeyboard(diID, EXCLUSIVE=1) diMouseID = di_acquireMouse(diID, EXCLUSIVE=0) ; Get the oWindow object reference and add to our oContainer. WIDGET_CONTROL, drawID, get_value = oWindow oContainer -> add, oWindow ; Create the camera. Note that the depth of the frustum is large to ; give a sense of depth to the scene and we also set a wide field of ; view. Position the camera in what will become one end of the viewer's ; domain. camera = OBJ_NEW('RHTgrCamera', COLOR=[0,0,0], FRUSTUM_DIMS=[120,120,400], $ CAMERA_LOCATION=[0,10,130], DEPTH_CUE=[250,400], $ FORCE_AR=forceMode, LOCK=1) oContainer -> add, camera ; Create something to look at... ; Create a "floor" to orient user and define bounds. idata = REPLICATE(255B, 4,2,2) idata[*,0,1]=[175,175,175,255] idata[*,1,0]=[175,175,175,255] oSurfTexture = OBJ_NEW('IDLgrImage', idata) oContainer -> Add, oSurfTexture verts = [[-1,0,-1], $ [1,0,-1], $ [1,0,1], $ [-1,0,1]] * 550 polys = [4,0,1,2,3] texcoords = [[0,0],[100,0],[100,100],[0,100]] oSurf = OBJ_NEW('IDLgrPolygon', verts, POLYGONS=polys, $ COLOR=[255,255,255], TEXTURE_COORD=texcoords, $ TEXTURE_MAP=oSurfTexture) ; Create a bounding box to contain the user. verts = [[-1.,0,-1.], $ [1.,0.,-1.], $ [1.,2.,-1.], $ [-1.,2.,-1.], $ [-1.,0.,1], $ [1.,0.,1.], $ [1.,2.,1.], $ [-1.,2.,1.]] verts[0:1,*] = verts[0:1,*] * 50. verts[2,*] = verts[2,*] * 150. polys = [4,2,3,7,6,4,2,1,5,6,4,0,3,7,4,4,5,4,7,6,4,1,0,3,2] texcoords = [[0,0],[1,0],[1,1],[0,1],[1,0],[1,1],[0,1],[0,0]] idata = REPLICATE(255B, 4,2,2) idata[3,*,*]=80B oBoxTexture = OBJ_NEW('IDLgrImage', idata) oContainer -> Add, oBoxTexture oSurfBox = OBJ_NEW('IDLgrPolygon', verts, POLYGONS=polys, $ COLOR=[255,30,30], STYLE=2, TEXTURE_COORD=texcoords, $ TEXTURE_MAP=oBoxTexture) oBoxEdge = OBJ_NEW('IDLgrPolygon', verts, POLYGONS=polys, $ COLOR=[255,30,30], STYLE=1, THICK=2, DEPTH_OFFSET=2) ; Store the bounding box information boxBounds = FLTARR(3,2) boxBounds[0,*] = [MIN(verts[0,*]), MAX(verts[0,*])] boxBounds[1,*] = [MIN(verts[1,*]), MAX(verts[1,*])] + $ [0.2, 0.0] boxBounds[2,*] = [MIN(verts[2,*]), MAX(verts[2,*])] boxBounds = (boxBounds) * 0.99 ; Add these items to a model oSurfModel = OBJ_NEW('IDLgrModel') oSurfModel -> Add, [oSurf, oBoxEdge, oSurfBox] ; Add the surfModel to the camera camera -> Add, oSurfModel ; Sprinkle a few orbs about orbArray = OBJARR(nOrbs) orbColor = BYTE(RANDOMU(seed,3,nOrbs) * 255) orbLocation = [[(RANDOMU(seed,nOrbs) - 0.5) * 50], $ [RANDOMU(seed,nOrbs) * 50], $ [(RANDOMU(seed,nOrbs) - 0.5) * 150]] for n=0, nOrbs-1 do begin orbArray[n] = OBJ_NEW('orb', COLOR=orbColor[*,n], STYLE=1, $ POS=orbLocation[n,*], radius=(RANDOMU(seed)+1.) * 2., $ DENSITY=orbDensity) endfor ; Add the orbs to the camera. The initial culling mode is ; set by the cullMode variable defined above. case cullMode of 0:camera -> Add, orbArray 1:camera -> Add, orbArray, /STATIC 2:camera -> Add, orbArray, /DYNAMIC endcase ; Create the "Heads up display" ; Create the HUD view - set the transparent keyword hudview = OBJ_NEW('IDLgrView', viewplane_rect=[0.,0.,1,1], $ zclip=[1,-1], color=[0,0,0], eye=2, projection=1, $ /transparent) oContainer -> add, hudview ; Create a model to put all of our HUD atoms in hudmodel = OBJ_NEW('IDLgrModel') ; Add this model to our hud view hudview->add, hudmodel ;create the HUD billboard verts = [[.005,.005,0.5],[.995,.005,0.],[.995,.15,0.],[.005,.15,0.]] polys = [4,0,1,2,3] image = BYTARR(4,10,10) image[3,*,*] = 120B texcoord = [[0,0],[1,0],[1,1],[0,1]] billboardTexmap = OBJ_NEW('IDLgrImage', image, INTERLEAVE=0, $ blend_function=[3,4], name='billboard') ; Disable depth tests (if available) to force billboard to top. ; At extreme view dimensions the billboard can drop behind the floor. ; Disabling deth tests on the billboard prevents this. if (useDepthTest) then begin billboard = OBJ_NEW('IDLgrPolygon', verts, POLYGONS=polys, $ COLOR=[255,255,255], TEXTURE_COORD=texcoord, TEXTURE_MAP= $ billboardTexmap, /DEPTH_TEST_DISABLE) endif else begin billboard = OBJ_NEW('IDLgrPolygon', verts, POLYGONS=polys, $ COLOR=[255,255,255], TEXTURE_COORD=texcoord, TEXTURE_MAP= $ billboardTexmap) endelse oContainer -> add, [billboardTexmap] hudmodel -> Add, billboard ; Create the text that we'll stick in our hud titleFont = OBJ_NEW('idlgrfont', 'Helvetica', size=18) statsFont = OBJ_NEW('idlgrfont', 'Helvetica', SIZE=8.) oContainer -> add, [titleFont, statsFont] title = OBJ_NEW('IDLgrText','Camera Cull-N-Fly Demo', $ COLOR=[255,255,255], /ONGLASS, LOCATIONS=[.5,.95], $ FONT=titleFont, ALIGNMENT=0.5) render = OBJ_NEW('IDLgrText','Renderer:', $ COLOR=[255,255,255], /ONGLASS, LOCATIONS=[.2,.12], $ FONT=statsFont, ALIGNMENT=1.0) oWindow -> getproperty, renderer=renderer if (renderer) then text='Software' else text='Hardware(OpenGL)' renderText = OBJ_NEW('IDLgrText',text, $ COLOR=[255,255,255], /ONGLASS, LOCATIONS=[.21,.12], $ FONT=statsFont, ALIGNMENT=0.0) panLabel = OBJ_NEW('IDLgrText','Pitch, Yaw, Roll:', $ COLOR=[255,255,255], /ONGLASS, LOCATIONS=[.2,.09], $ FONT=statsFont, ALIGNMENT=1.0) panText = OBJ_NEW('IDLgrText','000 000 000',LOCATIONS=[.21,.09], $ COLOR=[255,255,255], /ONGLASS,FONT=statsFont, ALIGNMENT=0.0) locLabel = OBJ_NEW('IDLgrText','X, Y, Z:', $ COLOR=[255,255,255], /ONGLASS, LOCATIONS=[.2,.06], $ FONT=statsFont, ALIGNMENT=1.0) locText = OBJ_NEW('IDLgrText',' 0.0 0.0 0.0',LOCATIONS=[.21,.06], $ COLOR=[255,255,255], /ONGLASS,FONT=statsFont, ALIGNMENT=0.0) zoomLabel = OBJ_NEW('IDLgrText','Zoom Level:', $ COLOR=[255,255,255], /ONGLASS, LOCATIONS=[.2,.03], $ FONT=statsFont, ALIGNMENT=1.0) zoomText = OBJ_NEW('IDLgrText',' 1.0',LOCATIONS=[.21,.03], $ COLOR=[255,255,255], /ONGLASS,FONT=statsFont, ALIGNMENT=0.0) forceLabel = OBJ_NEW('IDLgrText','Force Aspect Ratio:', $ COLOR=[255,255,255], /ONGLASS, LOCATIONS=[.7,.09], $ FONT=statsFont, ALIGNMENT=1.0) if (forceMode) then blurb='On' else blurb='Off' forceText = OBJ_NEW('IDLgrText', blurb, LOCATIONS=[.71,.09], $ COLOR=[255,255,255], /ONGLASS,FONT=statsFont, ALIGNMENT=0.0) cullLabel = OBJ_NEW('IDLgrText','Culling Mode:', $ COLOR=[255,255,255], /ONGLASS, LOCATIONS=[.7,.06], $ FONT=statsFont, ALIGNMENT=1.0) case cullMode of 0:blurb='None' 1:blurb='Static' 2:blurb='Dynamic' endcase cullText = OBJ_NEW('IDLgrText', blurb, LOCATIONS=[.71,.06], $ COLOR=[255,255,255], /ONGLASS,FONT=statsFont, ALIGNMENT=0.0) fpslabel = OBJ_NEW('idlgrtext','FPS:', $ COLOR=[255,255,255], /ONGLASS, LOCATIONS=[.09,.96], $ FONT=statsFont, ALIGNMENT=1.0) fpstext = OBJ_NEW('idlgrtext',' 0.0',LOCATIONS=[.1,.96], $ COLOR=[255,255,255], /ONGLASS,FONT=statsFont, ALIGNMENT=0.0) hudModel -> add, [title, render, renderText, panLabel, panText, $ zoomLabel, zoomtext, locText, locLabel, fpsLabel, fpsText, $ forceLabel, forceText, cullLabel, cullText] ; Create a viewgroup ; ; Viewgroups contain other views and allow us to draw both ; the HUD and the camera view in the same window. ; viewgroup = OBJ_NEW('IDLgrViewgroup') oContainer -> add, viewgroup ; Add the camera and HUD views to the viewgroup. ; ; Viewgroups must be odered back to front with the ; opaque view in back. ; viewgroup -> add, [camera, hudview] info={ oContainer:oContainer, $ oWindow:oWindow, $ camera:camera, $ viewgroup:viewgroup, $ orbArray:orbArray, $ diID:diID, $ diKeyboardID:diKeyboardID, $ diMouseID:diMouseID, $ panText:panText, $ locText:locText, $ zoomText:zoomText, $ titleFont:titleFont, $ statsFont:statsFont, $ fpsText:fpsText, $ cullText:cullText, $ forceText:forceText, $ boxBounds:boxBounds, $ ;button:0S, $ cameraZoom:0., $ count:0D, $ dep:BYTARR(3), $ drawID:drawID, $ fileID:fileID, $ forceMode:forceMode, $ frame:0L, $ lastframe:0D, $ mouseButtons:BYTARR(8), $ truckStep:truckStep $ } ; Insert our data structure into the tlb widget WIDGET_CONTROL, tlb, SET_UVALUE=info ; Set a timer event WIDGET_CONTROL, fileID, TIMER=0.0001 ; Fire up xmanager XMANAGER, 'camdemo_di_cullnfly', tlb, CLEANUP='camdemo_cleanup', /NO_BLOCK, $ EVENT_HANDLER='camdemo_event' end ; }}}