Hi,
I'm having some problems with an occlusion system.
I've reached the point where I need help from a better programmer than me.
The problem seems to be with the pre-calculated bounding boxes for each zone in the level map - but I'm not sure of this.
The code with level map is here:
http://www.octanedigitalstudios.com/downloads/Occlusion.zip
Here's just the code:
Any help would be much appreciated.
Regards,
Rogue Vector
I'm having some problems with an occlusion system.
I've reached the point where I need help from a better programmer than me.
The problem seems to be with the pre-calculated bounding boxes for each zone in the level map - but I'm not sure of this.
The code with level map is here:
http://www.octanedigitalstudios.com/downloads/Occlusion.zip
Here's just the code:
; *************************************************************** ; PROG: OCCLUSION SYSTEM ; ETHOS: Simple and Fast ; AUTHOR: Rogue Vector ; DATE: Friday 3rd December 2004 ; **** THERE IS A PROBLEM WITH THIS CODE - NEED HELP **** ; The bounding boxes are totally screwed up and I don't know why. ; *************************************************************** ; BASIC DESIGN OVERVIEW ; --------------------- ; The system works by reading the name of each object in the (.b3d) file hierarchy. ; The zone data is extracted from the name and placed into the TZone data structure. ; The Level Designer determines which zones can be seen from a particular vantage point in the level map. ; He records this data in the object name, before exporting to a (.b3d) file. ; Thus, during run-time, if the player is in zone X, simply get the 'can_see' zones from the TZone data. ; No need for portals. ;CONSTANTS Const SUCCESS = 1 Const FAILURE = -1 Const VIS_FORMAT$ = "[ zone: # vis: # ]" ;The basic format of the vis data, in its simplest form. Const VIS_MAX_ZONES = 10 ;The maximum number of zones that can be seen from the current zone. Const VIS_STOP_SYMBOL$ = "]" ;End of line (terminator) used when parsing the vis data. Const VIS_DELIMITER$ = " " ;Words in the vis data are seperated by this character (i.e. space). Const VIS_INFO_START = 5 ;The first vis data begins at the fifth word in. Const ZONE_IDENT_START = 3 ;TYPES Type TZone Field entity Field name$ Field visible Field can_see[VIS_MAX_ZONES] Field max_X# Field max_Y# Field max_Z# Field min_X# Field min_Y# Field min_Z# End Type ;GLOBALS Global g_check_format = True Global g_current_zone.TZone = Null Global g_last_zone = 0 ;TEST PROGRAM ************************ Global g_keytimer, g_wireframe, g_time Global g_gravity# = -0.5 runtest("level_map.b3d") ;DE-ACTIVATE AS DEFAULT ************** ;FUNCTIONS Function Occlusion_Initialise(v_level) Local node = 0 Local node_name$ = "" Local token$ = "" Local surface = 0 Local max_surfaces = 0 Local verts = 0 Local vis_index = VIS_INFO_START ;Iterate through every child object in the mesh hierarchy and populate the TZone objects For i = 1 To CountChildren(v_level) ;Find the zones in the level mesh hierarchy. node = GetChild(v_level,i) ;Get the name of the node. node_name$ = EntityName$(node) ;Check formatting (SLOW - switched off by default). If (g_check_format) CheckZoneInfoFormat(node_name) ;Create zone object to hold data. zone.TZone = New TZone ;Populate object with initial values. zone\entity = node zone\name = node_name ;Create a bounding box around the zone. max_surfaces = CountSurfaces(zone\entity) For k=1 To max_surfaces surface = GetSurface(zone\entity, k) verts = CountVertices(surface) - 1 For m = 0 To verts-1 Vx# = VertexX#(surface, m) Vy# = VertexY#(surface, m) Vz# = VertexZ#(surface, m) If (Vx# > zone\max_X) Then zone\max_X = Vx# If (Vy# > zone\max_Y) Then zone\max_Y = Vy# If (Vz# > zone\max_Z) Then zone\max_Z = Vz# If (Vx# < zone\min_X) Then zone\min_X = Vx# If (Vy# < zone\min_Y) Then zone\min_Y = Vy# If (Vz# < zone\min_Z) Then zone\min_Z = Vz# Next Next ;Check that there is a stopping condition symbol in the zone info string. If Instr(zone\name, VIS_STOP_SYMBOL) ;Parse initial vis data into the internal array. token = GetWord(node_name, vis_index, " ") If Not(Int(token) => 0) RuntimeError("ERROR!... DATA IN VIS ARRAY IS NOT OF THE REQUIRED TYPE.") Repeat zone\can_see[vis_index - VIS_INFO_START] = Int(token) vis_index = vis_index + 1 token = GetWord(zone\name, vis_index, " ") Until (token = VIS_STOP_SYMBOL) ;Reset vis array index vis_index = VIS_INFO_START Else RuntimeError("ERROR!...VIS DATA FORMAT INCORRECT") EndIf Next ;Modify the data in the internal array. Need to convert the zone numbers to the corresponding entity id's. ;This is a preparatory stage to help keep Update function small and fast. Local tmp_entity = 0 For l_tmp.TZone = Each TZone For index=0 To VIS_MAX_ZONES tmp_entity = EntityLookUp(l_tmp\can_see[index]) l_tmp\can_see[index] = tmp_entity Next Next ;Check formatting of zone data structures. If (g_check_format) CheckZoneDataStructure() End Function Function Occlusion_Update(v_playerX#, v_playerY#, v_playerZ#) Text 5,30, "X: " + v_playerX For g_current_zone = Each TZone If (IsInsideZone(v_playerX, v_playerY, v_playerZ, g_current_zone)) Text 5, 60, "Zone name: " + g_current_zone\name ;**** TEMPORARILY DE-ACTIVATED UNTIL CORRECT ZONE IS SHOWN ON SCREEN **** ; HAVEN'T BEEN ABLE TO TEST THIS BIT YET. ;If Not(g_last_zone = Handle g_current_zone) ; HideAllZones() ; ShowEntity g_current_zone\entity ; For l_index = 0 To VIS_MAX_ZONES ; ShowEntity g_current_zone\can_see[l_index] ; Next ; g_last_zone = Handle g_current_zone ; Exit ;EndIf ; *********************************************************************** EndIf Next End Function Function Occlusion_ClearAll() Local l_tmp.TZone = Null For l_tmp = Each TZone Delete l_tmp Next Return SUCCESS End Function Function EntityLookUp(v_zone_lookup) Local l_tmp.TZone = Null Local token$ = "" For l_tmp = Each TZone token = GetWord(l_tmp\name, ZONE_IDENT_START, VIS_DELIMITER) If (Int(token) = v_zone_lookup) Return l_tmp\entity Next Return FAILURE End Function Function HideAllZones() For l_tmp.TZone = Each TZone For l_index = 0 To MAX_VIS_ZONES HideEntity l_tmp\can_see[l_index] HideEntity l_tmp\entity Next Next Return SUCCESS End Function Function EntityAlphaLevel(v_amount#) For tmp.TZone = Each TZone EntityAlpha tmp\entity, v_amount Next End Function Function CheckZoneInfoFormat(v_name$) Print "CHECKING FORMAT OF VIS DATA" Print "Analysing Zone: [ " + GetWord(v_name, 3, VIS_DELIMITER) + " ]" If Not(GetWord(v_name, 1 , VIS_DELIMITER) = GetWord(VIS_FORMAT, 1, VIS_DELIMITER)) Then RuntimeError("ERROR!...VIS DATA FORMAT INCORRECT") If Not(GetWord(v_name, 2 , VIS_DELIMITER) = GetWord(VIS_FORMAT, 2, VIS_DELIMITER)) Then RuntimeError("ERROR!...VIS DATA FORMAT INCORRECT") If Not(GetWord(v_name, 4 , VIS_DELIMITER) = GetWord(VIS_FORMAT, 4, VIS_DELIMITER)) Then RuntimeError("ERROR!...VIS DATA FORMAT INCORRECT") If Not(Int(GetWord(v_name, 3 , VIS_DELIMITER)) => 0) Then RuntimeError("ERROR!...VIS DATA FORMAT INCORRECT") If Not(Int(GetWord(v_name, 5 , VIS_DELIMITER)) => 0) Then RuntimeError("ERROR!...VIS DATA FORMAT INCORRECT") Print " Result: [ PASS ]" Print "------------------------" Delay 500 Return SUCCESS End Function Function CheckZoneDataStructure() Print Print Print "CHECKING ZONE DATA STRUCTURE" For l_tmp.TZone = Each TZone Print "Analysing Zone: [ " + GetWord(l_tmp\name, 3, VIS_DELIMITER) + " ]" Print " Entity Ident: [ " + Str(l_tmp\entity) + " ]" Print " BoundingBox: [ max_X = " + Str(l_tmp\max_X) + " ]" Print " [ max_Y = " + Str(l_tmp\max_Y) + " ]" Print " [ max_Z = " + Str(l_tmp\max_Z) + " ]" Print " [ min_X = " + Str(l_tmp\min_X) + " ]" Print " [ min_Y = " + Str(l_tmp\min_Y) + " ]" Print " [ min_Z = " + Str(l_tmp\min_Z) + " ]" For p=0 To VIS_MAX_ZONES If Not(l_tmp\can_see[p] = -1) Print " Can See: [ " + Str(l_tmp\can_see[p]) + " ]" Next Print "---------------------" ;WaitKey Delay 500 Next Print Print "FINISHED ANALYSIS..." Print Print "HIT A KEY TO CONTINUE" Print Return SUCCESS End Function Function IsInsideZone%(v_objectspaceX#, v_objectspaceY#, v_objectspaceZ#, v_zone.TZone) ; Transform point from global space to object space. TFormPoint v_objectspaceX, v_objectspaceY, v_objectspaceZ, 0, v_zone\entity v_objectspaceX = TFormedX() v_objectspaceY = TFormedY() v_objectspaceZ = TFormedZ() If (v_objectspaceX > v_zone\min_X) And (v_objectspaceX < v_zone\max_X) And (v_objectspaceY > v_zone\min_Y) And (v_objectspaceY < v_zone\max_Y) And (v_objectspaceZ > v_zone\min_Z) And (v_objectspaceZ < v_zone\max_Z) Return True Else Return False EndIf End Function Function GetWord$(InputString$, WordNum, Seperators$=" ") ;by sswift FoundWord = False WordsFound = 0 ; Loop through each character in the input string. For CharLoop = 1 To Len(InputString$) ; Get the character at this location in the string. ThisChar$ = Mid$(InputString$, CharLoop, 1) ; If the character at this position is one of the characters in the seperator list... If Instr(Seperators$, ThisChar$, 1) ; If a word has been started... If FoundWord ; ...then this character must mark the end of a word. ; Increment the number of words we've found. WordsFound = WordsFound + 1 ; Is this word the word we want? If WordsFound = WordNum ; Yes! Exit the function and return the word. Return Word$ Else ; No. Discard this word. Word$ = "" FoundWord = False EndIf Else ; Ignore this character. We have either not reached a word yet, or are between words. EndIf Else ; This is not a character in our seperator list. Add it to our word. FoundWord = True Word$ = Word$ + ThisChar$ EndIf Next ; We have finished looking through the string. Was the last word we were on the one we were looking for? If (WordsFound+1) = WordNum ; Yes! ; Return the word that at the end of the string which didn't have any seperators after it. Return Word$ Else ; No. ; The word number passed to the function was greater than the number of words in the string. ; Return an empty string. Return "" EndIf End Function Function QuickTexture() tex=CreateTexture(512,512) ScaleTexture tex,.2,.5 SetBuffer TextureBuffer(tex) Color 50,50,50 Rect 0,0,512,512 Color 200,200,200 Rect 8,8,496,496 Color 255,255,255 SetBuffer BackBuffer() For tmp.TZone = Each TZone EntityTexture tmp\entity, tex Next Return tex End Function Function SuperCam(cam,ent,cspeed#,dist#,hite#,xrot#,tilt#) ;by PsychicParrot TFormPoint 0,hite#,-dist#,ent,0 cx#=(TFormedX()-EntityX(cam))*cspeed# cy#=(TFormedY()-EntityY(cam))*cspeed# cz#=(TFormedZ()-EntityZ(cam))*cspeed# TranslateEntity cam,cx,cy,cz PointEntity cam,ent RotateEntity cam,xrot#,EntityYaw(cam),tilt# End Function Function DoWireFrame(v_key) g_time = MilliSecs() If (g_KeyTimer + 200 < g_time) If (KeyDown(v_key)) g_wireFrame = 1 - g_wireFrame WireFrame g_wireFrame g_keyTimer = g_time : Return SUCCESS EndIf EndIf End Function Function RunTest(v_level_filename$) AppTitle "Occlusion Test Program","Are you sure you want to quit?" Graphics3D 800,600,16,2 SetBuffer BackBuffer() C_PLAYER = 1 C_LEVEL = 2 C_TRIGGER = 3 Collisions C_PLAYER,C_LEVEL,2,2 level = LoadAnimMesh(v_level_filename) EntityType level,C_LEVEL,True ;Initialise Occlusion system Occlusion_Initialise(level) WaitKey player = CreateSphere(8) ;the player ScaleMesh player, 1,1,1 MoveEntity player, 0,2,0 TurnEntity player, 0,90,0 EntityColor player, 255,0,0 EntityType player,C_PLAYER EntityRadius player, 1 camera = CreateCamera() PositionEntity camera, -200,50,-200 PointEntity camera, player light = CreateLight() RotateEntity light, 60,30,0 texture = QuickTexture() Repeat DoWireFrame(17) ;W for wireframe If (KeyDown(200)) MoveEntity player, 0,0,1 ;Up arrow If (KeyDown(208)) MoveEntity player, 0,0,-1 ;Down arrow If (KeyDown(203)) TurnEntity player, 0,2,0 ;Left arrow If (KeyDown(205)) TurnEntity player, 0,-2,0 ;Right arrow If (KeyDown(57 )) MoveEntity player, 0,1.4, 0 ;Space to jump SuperCam(camera,player,0.5,12,5,0,2) MoveEntity player, 0, g_gravity, 0 UpdateWorld() RenderWorld() Occlusion_Update(EntityX(player),EntityY(player),EntityZ(player)) Text 5,5, "Triangles Rendered: " + TrisRendered() Flip Until KeyHit(1) Occlusion_ClearAll() FreeEntity level FreeTexture texture ClearWorld() End End Function
Any help would be much appreciated.
Regards,
Rogue Vector