Files
2025-09-29 00:52:08 +02:00

738 lines
25 KiB
Scheme
Executable File

//////////////////////////////////////////////////////////////////////
/* z_volumes.sch */
/* Author: DJ Jones */
/* By including this file and calling UPDATE_ZVOLUME_WIDGETS each */
/* frame, you will find a set of widgets called Script/Z-Aligned */
/* Volumes. Here, you can draw a variety of volumetric shapes and */
/* grab the data for use with ANGLED_AREA checks or other collision */
/* functionality. */
//////////////////////////////////////////////////////////////////////
// This file contains debug-only functionality.
#IF IS_DEBUG_BUILD
USING "commands_debug.sch"
USING "commands_camera.sch"
USING "commands_object.sch"
USING "script_maths.sch"
USING "script_player.sch"
CONST_INT iMAX_ZVC_VERTS 80
// A volume that rotates freely on the z axis.
// Can be interpreted as a rectangular prism, elliptic cylinder, or elliptoid.
// Does not support negative dimensions.
// fWidth = x, fDepth = y, fHeight = z; fRotation is rotation on z-axis in degrees.
STRUCT zVolume
VECTOR vCenter
FLOAT fWidth
FLOAT fDepth
FLOAT fHeight
FLOAT fRotation
ENDSTRUCT
// A triangle with three vertices.
//STRUCT zTriangle
// VECTOR p1, p2, p3
//ENDSTRUCT
// Control variables for widgets.
FLOAT zvw_fPosX // Center position x
FLOAT zvw_fPosY // Center position y
FLOAT zvw_fPosZ // Center position z
FLOAT zvw_fDimX // Width
FLOAT zvw_fDimY // Depth
FLOAT zvw_fDimZ // Height
FLOAT zvw_fRotZ // Rot on z axis in deg
BOOL zvw_bPosSnapPlr // Snap volume pos to player
BOOL zvw_bRotSnapPlr // Snap volume rot to player
BOOL zvw_bPosSnapCam // Snap volume pos to cam
BOOL zvw_bRotSnapCam // Snap volume rot to cam
BOOL zvw_bPosSnapOrg // Snap volume pos to origin
BOOL zvw_bRotSnapOrg // Snap volume rot to zero
BOOL zvw_bDefaultDim // Back to default dims
BOOL zvw_bDrawMaster // Master draw control
BOOL zvw_bDrawAsRec // Consider as rect prism
BOOL zvw_bDrawAsCyl // Consider as ellip cyl
BOOL zvw_bDrawAsEld // Consider as elliptoid
INT zvw_iSubdiv // Subdivisions (pie pieces)
BOOL zvw_bDrawWire // Wireframe draw control
INT zvw_iAlphaWire // Wireframe alpha
BOOL zvw_bDrawFace // Face draw control
INT zvw_iAlphaFace // Face alpha
BOOL zvw_bDoCollision // Perform collision checks
BOOL zvw_bVolCheckPlr // Player in volume status
BOOL zvw_bVolCheckCam // Camera in volume status
VECTOR zvw_vAngMidpt1 // Midpt 1 for angled area
VECTOR zvw_vAngMidpt2 // Midpt 2 for angled area
FLOAT zvw_fAngMidpt1x // Angled area midpt 1 x
FLOAT zvw_fAngMidpt1y // Angled area midpt 1 y
FLOAT zvw_fAngMidpt1z // Angled area midpt 1 z
FLOAT zvw_fAngMidpt2x // Angled area midpt 2 x
FLOAT zvw_fAngMidpt2y // Angled area midpt 2 y
FLOAT zvw_fAngMidpt2z // Angled area midpt 2 z
FLOAT zvw_fAngWidth // Width for angled area
// Do not touch
WIDGET_GROUP_ID zvw_zVolumeWidgets
WIDGET_GROUP_ID zvw_posDimGroup
WIDGET_GROUP_ID zvw_renderingGroup
WIDGET_GROUP_ID zvw_collisionGroup
WIDGET_GROUP_ID zvw_angledAreaGroup
INT zvw_iMode
BOOL zvw_bInit
zVolume zvw_Volume
//zTriangle zvw_Triangles[512]
// Get the zVolume equivalent of an area check (as in IS_ENTITY_IN_AREA)
PROC GET_ZVOLUME_FROM_AREA(zVolume &vol, VECTOR vCorner1, VECTOR vCorner2, BOOL bDo3DCheck)
vol.vCenter = <<0.5 * (vCorner1.x + vCorner2.x), 0.5 * (vCorner1.y + vCorner2.y), 0.5 * (vCorner1.z + vCorner2.z)>>
vol.fWidth = ABSF(vCorner2.x - vCorner1.x)
vol.fDepth = ABSF(vCorner2.y - vCorner1.y)
vol.fHeight = PICK_FLOAT(bDo3DCheck, ABSF(vCorner2.z - vCorner1.z), 10000.0)
vol.fRotation = 0.0
ENDPROC
// Get the midpoints and width of an angled area based on a z-volume.
PROC GET_ANGLED_AREA_FROM_ZVOLUME(zVolume vol, VECTOR& vMidpt1, VECTOR& vMidpt2, FLOAT& fWidth)
VECTOR vProj
FLOAT fSin = SIN(vol.fRotation)
FLOAT fCos = COS(vol.fRotation)
FLOAT fHalfWidth = 0.5 * vol.fWidth
vProj.x = fCos * fHalfWidth
vProj.y = fSin * fHalfWidth
vMidpt1 = vol.vCenter + vProj
vMidpt2 = vol.vCenter - vProj
fWidth = vol.fDepth
ENDPROC
// Get the bottom center point of a zVolume, usually for a cylinder.
//FUNC VECTOR GET_ZVOLUME_BOTTOM(zVolume vol)
// vol.vCenter.z -= 0.5 * vol.fHeight
// RETURN vol.vCenter
//ENDFUNC
// Debug draw for rectangular prism.
PROC DRAW_ZVOLUME_REC(zVolume vol, BOOL bDrawWire, BOOL bDrawFace)
VECTOR vUNE, vUNW, vUSW, vUSE, vLNE, vLNW, vLSW, vLSE
VECTOR vNProj, vSProj, vWProj, vEProj, vUProj, vDProj
// Quit if there's nothing to do.
IF NOT bDrawWire AND NOT bDrawFace
EXIT
ENDIF
// Create projection vectors.
vEProj = <<COS(vol.fRotation), SIN(vol.fRotation), 0.0>>
vNProj = <<-vEProj.y, vEProj.x, 0.0>>
vEProj *= vol.fWidth * 0.5
vWProj = -vEProj
vNProj *= vol.fDepth * 0.5
vSProj = -vNProj
vUProj = <<0.0, 0.0, 0.5 * vol.fHeight>>
vDProj = <<0.0, 0.0, -0.5 * vol.fHeight>>
// Create vertices.
vUNE = vol.vCenter + vUProj + vNProj + vEProj
vUNW = vol.vCenter + vUProj + vNProj + vWProj
vUSW = vol.vCenter + vUProj + vSProj + vWProj
vUSE = vol.vCenter + vUProj + vSProj + vEProj
vLNE = vol.vCenter + vDProj + vNProj + vEProj
vLNW = vol.vCenter + vDProj + vNProj + vWProj
vLSW = vol.vCenter + vDProj + vSProj + vWProj
vLSE = vol.vCenter + vDProj + vSProj + vEProj
// Draw wireframe.
IF bDrawWire
DRAW_DEBUG_LINE(vUNE, vUNW, 0, 255, 0, zvw_iAlphaWire)
DRAW_DEBUG_LINE(vUNW, vUSW, 0, 255, 0, zvw_iAlphaWire)
DRAW_DEBUG_LINE(vUSW, vUSE, 0, 255, 0, zvw_iAlphaWire)
DRAW_DEBUG_LINE(vUSE, vUNE, 0, 255, 0, zvw_iAlphaWire)
DRAW_DEBUG_LINE(vLNE, vLNW, 0, 255, 0, zvw_iAlphaWire)
DRAW_DEBUG_LINE(vLNW, vLSW, 0, 255, 0, zvw_iAlphaWire)
DRAW_DEBUG_LINE(vLSW, vLSE, 0, 255, 0, zvw_iAlphaWire)
DRAW_DEBUG_LINE(vLSE, vLNE, 0, 255, 0, zvw_iAlphaWire)
DRAW_DEBUG_LINE(vUNE, vLNE, 0, 255, 0, zvw_iAlphaWire)
DRAW_DEBUG_LINE(vUNW, vLNW, 0, 255, 0, zvw_iAlphaWire)
DRAW_DEBUG_LINE(vUSW, vLSW, 0, 255, 0, zvw_iAlphaWire)
DRAW_DEBUG_LINE(vUSE, vLSE, 0, 255, 0, zvw_iAlphaWire)
ENDIF
// Draw faces.
IF bDrawFace
DRAW_DEBUG_POLY(vUNE, vUNW, vUSE, 0, 0, 127, zvw_iAlphaFace)
DRAW_DEBUG_POLY(vUNW, vUSW, vUSE, 0, 0, 127, zvw_iAlphaFace)
DRAW_DEBUG_POLY(vLNW, vLNE, vLSW, 0, 0, 127, zvw_iAlphaFace)
DRAW_DEBUG_POLY(vLNE, vLSE, vLSW, 0, 0, 127, zvw_iAlphaFace)
DRAW_DEBUG_POLY(vLNE, vLNW, vUNE, 0, 0, 127, zvw_iAlphaFace)
DRAW_DEBUG_POLY(vLNW, vUNW, vUNE, 0, 0, 127, zvw_iAlphaFace)
DRAW_DEBUG_POLY(vLNW, vLSW, vUNW, 0, 0, 127, zvw_iAlphaFace)
DRAW_DEBUG_POLY(vLSW, vUSW, vUNW, 0, 0, 127, zvw_iAlphaFace)
DRAW_DEBUG_POLY(vLSE, vLNE, vUSE, 0, 0, 127, zvw_iAlphaFace)
DRAW_DEBUG_POLY(vLNE, vUNE, vUSE, 0, 0, 127, zvw_iAlphaFace)
DRAW_DEBUG_POLY(vLSW, vLSE, vUSW, 0, 0, 127, zvw_iAlphaFace)
DRAW_DEBUG_POLY(vLSE, vUSE, vUSW, 0, 0, 127, zvw_iAlphaFace)
ENDIF
ENDPROC
// Debug draw for elliptic cylinder.
PROC DRAW_ZVOLUME_CYL(zVolume vol, BOOL bDrawWire, BOOL bDrawFace, INT iSubdivisions)
VECTOR vUProj
VECTOR vOffset
VECTOR vNegOffset
VECTOR vVertices[iMAX_ZVC_VERTS]
VECTOR vTopVertexCenter
VECTOR vBottomVertexCenter
VECTOR vTopVertexCur
VECTOR vBottomVertexCur
VECTOR vTopVertexNext
VECTOR vBottomVertexNext
FLOAT fLocalAngle
FLOAT fSubdivisions = TO_FLOAT(iSubdivisions)
INT iHalfSubdivisions = iSubdivisions / 2
INT i
// Quit if there's nothing to do.
IF NOT bDrawWire AND NOT bDrawFace
EXIT
ENDIF
// Check for valid subdivisions.
IF iSubdivisions < 3
SCRIPT_ASSERT("Can't draw a cylinder with less than three subdivisions!")
EXIT
ELIF iSubdivisions > iMAX_ZVC_VERTS / 2
SCRIPT_ASSERT("Too many subdivisions! Check iMAX_ZVC_VERTS and divide by two!")
EXIT
ENDIF
// Create projection vector.
vUProj = <<0.0, 0.0, 0.5 * vol.fHeight>>
// Generate vertices.
REPEAT iHalfSubdivisions i
fLocalAngle = (TO_FLOAT(i) / fSubdivisions) * 360.0
vOffset = <<COS(fLocalAngle) * 0.5 * vol.fWidth, SIN(fLocalAngle) * 0.5 * vol.fDepth, 0.0>>
vOffset = ROTATE_VECTOR_ABOUT_Z(vOffset, vol.fRotation)
vNegOffset = -vOffset
vOffset += vol.vCenter
vNegOffset += vol.vCenter
vVertices[i*2 ] = vOffset + vUProj
vVertices[i*2+1 ] = vOffset - vUProj
vVertices[i*2+iSubdivisions ] = vNegOffset + vUProj
vVertices[i*2+iSubdivisions+1] = vNegOffset - vUProj
ENDREPEAT
vTopVertexCenter = vol.vCenter + vUProj
vBottomVertexCenter = vol.vCenter - vUProj
// Iterate through pie slices and draw wireframe.
IF bDrawWire
REPEAT iSubdivisions i
vTopVertexCur = vVertices[i*2]
vBottomVertexCur = vVertices[i*2+1]
IF i < iSubdivisions - 1
vTopVertexNext = vVertices[i*2+2]
vBottomVertexNext = vVertices[i*2+3]
ELSE
vTopVertexNext = vVertices[0]
vBottomVertexNext = vVertices[1]
ENDIF
// Draw wireframe for this pie piece.
DRAW_DEBUG_LINE(vTopVertexCenter, vTopVertexCur, 0, 255, 0, zvw_iAlphaWire)
DRAW_DEBUG_LINE(vBottomVertexCenter, vBottomVertexCur, 0, 255, 0, zvw_iAlphaWire)
DRAW_DEBUG_LINE(vTopVertexCur, vBottomVertexCur, 0, 255, 0, zvw_iAlphaWire)
DRAW_DEBUG_LINE(vTopVertexCur, vTopVertexNext, 0, 255, 0, zvw_iAlphaWire)
DRAW_DEBUG_LINE(vBottomVertexCur, vBottomVertexNext, 0, 255, 0, zvw_iAlphaWire)
ENDREPEAT
ENDIF
// Iterate through pie slices and draw faces.
// Do a separate loop so wireframe does not get culled out.
IF bDrawFace
REPEAT iSubdivisions i
vTopVertexCur = vVertices[i*2]
vBottomVertexCur = vVertices[i*2+1]
IF i < iSubdivisions - 1
vTopVertexNext = vVertices[i*2+2]
vBottomVertexNext = vVertices[i*2+3]
ELSE
vTopVertexNext = vVertices[0]
vBottomVertexNext = vVertices[1]
ENDIF
// Draw faces for this pie piece.
DRAW_DEBUG_POLY(vTopVertexCenter, vTopVertexCur, vTopVertexNext, 0, 0, 127, zvw_iAlphaFace)
DRAW_DEBUG_POLY(vBottomVertexCenter, vBottomVertexNext, vBottomVertexCur, 0, 0, 127, zvw_iAlphaFace)
DRAW_DEBUG_POLY(vTopVertexCur, vBottomVertexCur, vBottomVertexNext, 0, 0, 127, zvw_iAlphaFace)
DRAW_DEBUG_POLY(vTopVertexCur, vBottomVertexNext, vTopVertexNext, 0, 0, 127, zvw_iAlphaFace)
ENDREPEAT
ENDIF
ENDPROC
// Debug draw for ellipsoid.
/*PROC DRAW_ZVOLUME_ELD(zVolume vol, BOOL bDrawWire, BOOL bDrawFace)
zTriangle curTriangle
FLOAT fSin = SIN(vol.fRotation)
FLOAT fCos = COS(vol.fRotation)
INT i
// Iterate through triangles to draw wireframe.
IF bDrawWire
REPEAT 512 i
// Scale vertices.
curTriangle.p1.x = zvw_Triangles[i].p1.x * vol.fWidth
curTriangle.p1.y = zvw_Triangles[i].p1.y * vol.fDepth
curTriangle.p1.z = zvw_Triangles[i].p1.z * vol.fHeight
curTriangle.p2.x = zvw_Triangles[i].p2.x * vol.fWidth
curTriangle.p2.y = zvw_Triangles[i].p2.y * vol.fDepth
curTriangle.p2.z = zvw_Triangles[i].p2.z * vol.fHeight
curTriangle.p3.x = zvw_Triangles[i].p3.x * vol.fWidth
curTriangle.p3.y = zvw_Triangles[i].p3.y * vol.fDepth
curTriangle.p3.z = zvw_Triangles[i].p3.z * vol.fHeight
// Rotate vertices.
curTriangle.p1 = ROTATE_VECTOR_ABOUT_Z_PRECOMPUTE(curTriangle.p1, fSin, fCos)
curTriangle.p2 = ROTATE_VECTOR_ABOUT_Z_PRECOMPUTE(curTriangle.p2, fSin, fCos)
curTriangle.p3 = ROTATE_VECTOR_ABOUT_Z_PRECOMPUTE(curTriangle.p3, fSin, fCos)
// Translate vertices.
curTriangle.p1 += vol.vCenter
curTriangle.p2 += vol.vCenter
curTriangle.p3 += vol.vCenter
// Draw wireframe.
DRAW_DEBUG_LINE(curTriangle.p1, curTriangle.p2, 0, 255, 0, 210)
DRAW_DEBUG_LINE(curTriangle.p2, curTriangle.p3, 0, 255, 0, 210)
DRAW_DEBUG_LINE(curTriangle.p3, curTriangle.p1, 0, 255, 0, 210)
ENDREPEAT
ENDIF
// Iterate through triangles to draw faces.
// Do this in a separate loop so wireframe doesn't get culled out.
IF bDrawFace
REPEAT 512 i
// Scale vertices.
curTriangle.p1.x = zvw_Triangles[i].p1.x * vol.fWidth
curTriangle.p1.y = zvw_Triangles[i].p1.y * vol.fDepth
curTriangle.p1.z = zvw_Triangles[i].p1.z * vol.fHeight
curTriangle.p2.x = zvw_Triangles[i].p2.x * vol.fWidth
curTriangle.p2.y = zvw_Triangles[i].p2.y * vol.fDepth
curTriangle.p2.z = zvw_Triangles[i].p2.z * vol.fHeight
curTriangle.p3.x = zvw_Triangles[i].p3.x * vol.fWidth
curTriangle.p3.y = zvw_Triangles[i].p3.y * vol.fDepth
curTriangle.p3.z = zvw_Triangles[i].p3.z * vol.fHeight
// Rotate vertices.
curTriangle.p1 = ROTATE_VECTOR_ABOUT_Z_PRECOMPUTE(curTriangle.p1, fSin, fCos)
curTriangle.p2 = ROTATE_VECTOR_ABOUT_Z_PRECOMPUTE(curTriangle.p2, fSin, fCos)
curTriangle.p3 = ROTATE_VECTOR_ABOUT_Z_PRECOMPUTE(curTriangle.p3, fSin, fCos)
// Translate vertices.
curTriangle.p1 += vol.vCenter
curTriangle.p2 += vol.vCenter
curTriangle.p3 += vol.vCenter
// Draw face.
DRAW_DEBUG_POLY(curTriangle.p1, curTriangle.p2, curTriangle.p3, 0, 0, 127, 127)
ENDREPEAT
ENDIF
ENDPROC
*/
// Draw the endpoints for an angled area.
PROC DRAW_ANGAREA_ENDPOINTS()
DRAW_DEBUG_SPHERE(zvw_vAngMidpt1, 0.3, 255, 0, 0)
DRAW_DEBUG_SPHERE(zvw_vAngMidpt2, 0.3, 255, 0, 0)
ENDPROC
// Generate base vertices to use for ellipsoid drawing.
/*PROC GENERATE_NSPHERE()
VECTOR vOctahedron[6]
VECTOR vMidpt1, vMidpt2, vMidpt3
INT iIteration, i, iTriangles, iTrianglesLast
// Start with a uniform octahedron.
vOctahedron[0] = << 0.0, 0.0, 0.5>>
vOctahedron[1] = << 0.0, 0.0, -0.5>>
vOctahedron[2] = << 0.0, -0.5, 0.0>>
vOctahedron[3] = << 0.5, 0.0, 0.0>>
vOctahedron[4] = << 0.0, 0.5, 0.0>>
vOctahedron[5] = <<-0.5, 0.0, 0.0>>
// Assign verts to the triangles.
zvw_Triangles[0].p1 = vOctahedron[0]
zvw_Triangles[0].p2 = vOctahedron[3]
zvw_Triangles[0].p3 = vOctahedron[4]
zvw_Triangles[1].p1 = vOctahedron[0]
zvw_Triangles[1].p2 = vOctahedron[4]
zvw_Triangles[1].p3 = vOctahedron[5]
zvw_Triangles[2].p1 = vOctahedron[0]
zvw_Triangles[2].p2 = vOctahedron[5]
zvw_Triangles[2].p3 = vOctahedron[2]
zvw_Triangles[3].p1 = vOctahedron[0]
zvw_Triangles[3].p2 = vOctahedron[2]
zvw_Triangles[3].p3 = vOctahedron[3]
zvw_Triangles[4].p1 = vOctahedron[1]
zvw_Triangles[4].p2 = vOctahedron[4]
zvw_Triangles[4].p3 = vOctahedron[3]
zvw_Triangles[5].p1 = vOctahedron[1]
zvw_Triangles[5].p2 = vOctahedron[5]
zvw_Triangles[5].p3 = vOctahedron[4]
zvw_Triangles[6].p1 = vOctahedron[1]
zvw_Triangles[6].p2 = vOctahedron[2]
zvw_Triangles[6].p3 = vOctahedron[5]
zvw_Triangles[7].p1 = vOctahedron[1]
zvw_Triangles[7].p2 = vOctahedron[3]
zvw_Triangles[7].p3 = vOctahedron[2]
iTriangles = 8
// Perform three additional subdivisions.
REPEAT 3 iIteration
iTrianglesLast = iTriangles
// Iterate through our current triangles.
REPEAT iTrianglesLast i
// Generate midpoints along edges and place them on the sphere's surface.
vMidpt1 = (zvw_Triangles[i].p1 + zvw_Triangles[i].p2) / 2.0
vMidpt2 = (zvw_Triangles[i].p2 + zvw_Triangles[i].p3) / 2.0
vMidpt3 = (zvw_Triangles[i].p3 + zvw_Triangles[i].p1) / 2.0
vMidpt1 = GET_VECTOR_OF_LENGTH(vMidpt1, 0.5)
vMidpt2 = GET_VECTOR_OF_LENGTH(vMidpt2, 0.5)
vMidpt3 = GET_VECTOR_OF_LENGTH(vMidpt3, 0.5)
// Assign verts to triangles.
zvw_Triangles[iTriangles].p1 = zvw_Triangles[i].p1
zvw_Triangles[iTriangles].p2 = vMidpt1
zvw_Triangles[iTriangles].p3 = vMidpt3
++iTriangles
zvw_Triangles[iTriangles].p1 = vMidpt1
zvw_Triangles[iTriangles].p2 = zvw_Triangles[i].p2
zvw_Triangles[iTriangles].p3 = vMidpt2
++iTriangles
zvw_Triangles[iTriangles].p1 = vMidpt2
zvw_Triangles[iTriangles].p2 = zvw_Triangles[i].p3
zvw_Triangles[iTriangles].p3 = vMidpt3
++iTriangles
zvw_Triangles[i].p1 = vMidpt1
zvw_Triangles[i].p2 = vMidpt2
zvw_Triangles[i].p3 = vMidpt3
ENDREPEAT
ENDREPEAT
ENDPROC
*/
// Set up the widgets for editing volumes.
PROC INIT_ZVOLUME_WIDGETS()
IF zvw_bInit
EXIT
ENDIF
zvw_bInit = TRUE
zvw_fPosX = 0.0
zvw_fPosY = 0.0
zvw_fPosZ = 0.0
zvw_fDimX = 5.0
zvw_fDimY = 5.0
zvw_fDimZ = 4.0
zvw_fRotZ = 0.0
zvw_bPosSnapPlr = FALSE
zvw_bRotSnapPlr = FALSE
zvw_bPosSnapCam = FALSE
zvw_bRotSnapCam = FALSE
zvw_bPosSnapOrg = FALSE
zvw_bRotSnapOrg = FALSE
zvw_bDefaultDim = FALSE
zvw_bDrawMaster = FALSE
zvw_bDrawAsRec = TRUE
zvw_bDrawAsCyl = FALSE
zvw_bDrawAsEld = FALSE
zvw_iSubdiv = 20
zvw_bDrawWire = TRUE
zvw_iAlphaWire = 210
zvw_bDrawFace = TRUE
zvw_iAlphaFace = 127
zvw_bDoCollision = FALSE
zvw_bVolCheckPlr = FALSE
zvw_bVolCheckCam = FALSE
zvw_iMode = 0
zvw_Volume.vCenter.x = zvw_fPosX
zvw_Volume.vCenter.y = zvw_fPosY
zvw_Volume.vCenter.z = zvw_fPosZ
zvw_Volume.fWidth = zvw_fDimX
zvw_Volume.fDepth = zvw_fDimY
zvw_Volume.fHeight = zvw_fDimZ
zvw_Volume.fRotation = zvw_fRotZ
zvw_zVolumeWidgets = START_WIDGET_GROUP("Z-Aligned Volumes")
zvw_posDimGroup = START_WIDGET_GROUP("Position and Dimensions")
ADD_WIDGET_FLOAT_SLIDER("Position x" , zvw_fPosX, -3300.0, 4300.0, 100.0)
ADD_WIDGET_FLOAT_SLIDER("Position y" , zvw_fPosY, -3800.0, 4200.0, 100.0)
ADD_WIDGET_FLOAT_SLIDER("Position z" , zvw_fPosZ, -200.0, 600.0, 15.0)
ADD_WIDGET_FLOAT_SLIDER("Width (x)" , zvw_fDimX, 0.0, 1000.0, 10.0)
ADD_WIDGET_FLOAT_SLIDER("Depth (y)" , zvw_fDimY, 0.0, 1000.0, 10.0)
ADD_WIDGET_FLOAT_SLIDER("Height (z)" , zvw_fDimZ, 0.0, 600.0, 6.0)
ADD_WIDGET_FLOAT_SLIDER("Rotation (z)", zvw_fRotZ, 0.0, 360.0, 3.6)
ADD_WIDGET_BOOL("Snap position to player", zvw_bPosSnapPlr)
ADD_WIDGET_BOOL("Snap rotation to player", zvw_bRotSnapPlr)
ADD_WIDGET_BOOL("Snap position to camera", zvw_bPosSnapCam)
ADD_WIDGET_BOOL("Snap rotation to camera", zvw_bRotSnapCam)
ADD_WIDGET_BOOL("Snap position to origin", zvw_bPosSnapOrg)
ADD_WIDGET_BOOL("Snap rotation to origin", zvw_bRotSnapOrg)
ADD_WIDGET_BOOL("Reset to default dimensions", zvw_bDefaultDim)
STOP_WIDGET_GROUP()
zvw_renderingGroup = START_WIDGET_GROUP("Rendering")
ADD_WIDGET_BOOL("Draw (master)" , zvw_bDrawMaster)
ADD_WIDGET_BOOL("Render as rectangular prism" , zvw_bDrawAsRec)
ADD_WIDGET_BOOL("Render as elliptic cylinder (not supported)" , zvw_bDrawAsCyl)
ADD_WIDGET_BOOL("Render as elliptoid (not supported)" , zvw_bDrawAsEld)
ADD_WIDGET_INT_SLIDER("Subdivisions (cyl)", zvw_iSubdiv, 4, iMAX_ZVC_VERTS / 2, 2)
ADD_WIDGET_BOOL("Draw wireframe", zvw_bDrawWire)
ADD_WIDGET_INT_SLIDER("Wireframe alpha", zvw_iAlphaWire, 0, 255, 2)
ADD_WIDGET_BOOL("Draw faces", zvw_bDrawFace)
ADD_WIDGET_INT_SLIDER("Face alpha", zvw_iAlphaFace, 0, 255, 2)
STOP_WIDGET_GROUP()
zvw_collisionGroup = START_WIDGET_GROUP("Collision Checks")
ADD_WIDGET_BOOL("Peform collision checks", zvw_bDoCollision)
ADD_WIDGET_BOOL("Player in volume", zvw_bVolCheckPlr)
ADD_WIDGET_BOOL("Camera in volume", zvw_bVolCheckCam)
STOP_WIDGET_GROUP()
zvw_angledAreaGroup = START_WIDGET_GROUP("Angled Area")
ADD_WIDGET_FLOAT_READ_ONLY("Point 1 x", zvw_fAngMidpt1x)
ADD_WIDGET_FLOAT_READ_ONLY("Point 1 y", zvw_fAngMidpt1y)
ADD_WIDGET_FLOAT_READ_ONLY("Point 1 z", zvw_fAngMidpt1z)
ADD_WIDGET_FLOAT_READ_ONLY("Point 2 x", zvw_fAngMidpt2x)
ADD_WIDGET_FLOAT_READ_ONLY("Point 2 y", zvw_fAngMidpt2y)
ADD_WIDGET_FLOAT_READ_ONLY("Point 2 z", zvw_fAngMidpt2z)
ADD_WIDGET_FLOAT_READ_ONLY("Width", zvw_fAngWidth)
STOP_WIDGET_GROUP()
STOP_WIDGET_GROUP()
// Generate base triangles for ellipsoids.
//GENERATE_NSPHERE()
ENDPROC
// Use to destroy widgets.
PROC CLEANUP_ZVOLUME_WIDGETS()
IF DOES_WIDGET_GROUP_EXIST(zvw_angledAreaGroup)
DELETE_WIDGET_GROUP(zvw_angledAreaGroup)
ENDIF
IF DOES_WIDGET_GROUP_EXIST(zvw_collisionGroup)
DELETE_WIDGET_GROUP(zvw_collisionGroup)
ENDIF
IF DOES_WIDGET_GROUP_EXIST(zvw_renderingGroup)
DELETE_WIDGET_GROUP(zvw_renderingGroup)
ENDIF
IF DOES_WIDGET_GROUP_EXIST(zvw_posDimGroup)
DELETE_WIDGET_GROUP(zvw_posDimGroup)
ENDIF
IF DOES_WIDGET_GROUP_EXIST(zvw_zVolumeWidgets)
DELETE_WIDGET_GROUP(zvw_zVolumeWidgets)
ENDIF
ENDPROC
// Call once per frame so widgets work.
PROC UPDATE_ZVOLUME_WIDGETS()
VECTOR vPlayerPos
VECTOR vCameraPos
VECTOR vCameraRot
FLOAT fPlayerHeading
CAMERA_INDEX curCam
// Perform one-time init.
IF NOT zvw_bInit
INIT_ZVOLUME_WIDGETS()
ENDIF
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
vPlayerPos = GET_ENTITY_COORDS(PLAYER_PED_ID())
fPlayerHeading = GET_ENTITY_HEADING(PLAYER_PED_ID())
ENDIF
curCam = GET_RENDERING_CAM()
IF DOES_CAM_EXIST(curCam)
vCameraPos = GET_CAM_COORD(curCam)
vCameraRot = GET_CAM_ROT(curCam)
ELSE
vCameraPos = GET_GAMEPLAY_CAM_COORD()
vCameraRot = GET_GAMEPLAY_CAM_ROT()
ENDIF
// Snap to player position.
IF zvw_bPosSnapPlr
zvw_fPosX = vPlayerPos.x
zvw_fPosY = vPlayerPos.y
zvw_fPosZ = vPlayerPos.z
zvw_bPosSnapPlr = FALSE
ENDIF
// Snap to player rotation.
IF zvw_bRotSnapPlr
zvw_fRotZ = fPlayerHeading
zvw_bRotSnapPlr = FALSE
ENDIF
// Snap to camera position.
IF zvw_bPosSnapCam
zvw_fPosX = vCameraPos.x
zvw_fPosY = vCameraPos.y
zvw_fPosZ = vCameraPos.z
zvw_bPosSnapCam = FALSE
ENDIF
// Snap to camera rotation.
IF zvw_bRotSnapCam
zvw_fRotZ = vCameraRot.z
zvw_bRotSnapCam = FALSE
ENDIF
// Snap to origin.
IF zvw_bPosSnapOrg
zvw_fPosX = 0.0
zvw_fPosY = 0.0
zvw_fPosZ = 0.0
zvw_bPosSnapOrg = FALSE
ENDIF
// Zero out rotation.
IF zvw_bRotSnapOrg
zvw_fRotZ = 0.0
zvw_bRotSnapOrg = FALSE
ENDIF
// Back to default dimensions.
IF zvw_bDefaultDim
zvw_fDimX = 5.0
zvw_fDimY = 5.0
zvw_fDimZ = 4.0
zvw_bDefaultDim = FALSE
ENDIF
// Switch to rectangular prism mode.
IF zvw_bDrawAsRec
IF zvw_iMode <> 0
zvw_iMode = 0
zvw_bDrawAsCyl = FALSE
zvw_bDrawAsEld = FALSE
ENDIF
ENDIF
// Switch to elliptic cylinder mode.
IF zvw_bDrawAsCyl
IF zvw_iMode <> 1
zvw_iMode = 1
zvw_bDrawAsRec = FALSE
zvw_bDrawAsEld = FALSE
ENDIF
ENDIF
// Switch to elliptoid mode.
IF zvw_bDrawAsEld
zvw_bDrawAsEld = FALSE
IF zvw_iMode <> 2
zvw_iMode = 2
zvw_bDrawAsRec = FALSE
zvw_bDrawAsCyl = FALSE
ENDIF
ENDIF
// Make sure one mode is selected.
IF NOT zvw_bDrawAsRec
AND NOT zvw_bDrawAsCyl
AND NOT zvw_bDrawAsEld
IF zvw_iMode = 0
zvw_bDrawAsRec = TRUE
ELIF zvw_iMode = 1
zvw_bDrawAsCyl = TRUE
ELSE
zvw_bDrawAsEld = TRUE
ENDIF
ENDIF
// Clamp subdivisions to an even number.
IF IS_BIT_SET(zvw_iSubdiv, 0)
zvw_iSubdiv = IMAX(zvw_iSubdiv - 1, 4)
ENDIF
// Update internal volume.
zvw_Volume.vCenter.x = zvw_fPosX
zvw_Volume.vCenter.y = zvw_fPosY
zvw_Volume.vCenter.z = zvw_fPosZ
zvw_Volume.fWidth = zvw_fDimX
zvw_Volume.fDepth = zvw_fDimY
zvw_Volume.fHeight = zvw_fDimZ
zvw_Volume.fRotation = zvw_fRotZ
// Update angled area stats.
IF zvw_bDrawAsRec
GET_ANGLED_AREA_FROM_ZVOLUME(zvw_Volume, zvw_vAngMidpt1, zvw_vAngMidpt2, zvw_fAngWidth)
zvw_fAngMidpt1x = zvw_vAngMidpt1.x
zvw_fAngMidpt1y = zvw_vAngMidpt1.y
zvw_fAngMidpt1z = zvw_vAngMidpt1.z
zvw_fAngMidpt2x = zvw_vAngMidpt2.x
zvw_fAngMidpt2y = zvw_vAngMidpt2.y
zvw_fAngMidpt2z = zvw_vAngMidpt2.z
ELSE
zvw_vAngMidpt1 = <<0.0,0.0,0.0>>
zvw_vAngMidpt2 = <<0.0,0.0,0.0>>
zvw_fAngMidpt1x = 0.0
zvw_fAngMidpt1y = 0.0
zvw_fAngMidpt1z = 0.0
zvw_fAngMidpt2x = 0.0
zvw_fAngMidpt2y = 0.0
zvw_fAngMidpt2z = 0.0
zvw_fAngWidth = 0.0
ENDIF
// Perform collision checks.
IF zvw_bDoCollision
IF zvw_bDrawAsRec
zvw_bVolCheckPlr = IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), zvw_vAngMidpt1, zvw_vAngMidpt2, zvw_fAngWidth, TRUE, FALSE)
zvw_bVolCheckCam = IS_POINT_IN_ANGLED_AREA(vCameraPos, zvw_vAngMidpt1, zvw_vAngMidpt2, zvw_fAngWidth, FALSE, FALSE)
// ELIF zvw_bDrawAsCyl
// zvw_bVolCheckPlr = IS_ENTITY_IN_CYLINDER(PLAYER_PED_ID(), GET_ZVOLUME_BOTTOM(zvw_Volume), zvw_Volume.fWidth, zvw_Volume.fDepth, zvw_Volume.fHeight, zvw_Volume.fRotation, TRUE)
// zvw_bVolCheckCam = IS_POINT_IN_CYLINDER(vCameraPos, GET_ZVOLUME_BOTTOM(zvw_Volume), zvw_Volume.fWidth, zvw_Volume.fDepth, zvw_Volume.fHeight, zvw_Volume.fRotation, TRUE)
ELSE
zvw_bVolCheckPlr = FALSE
zvw_bVolCheckCam = FALSE
// zvw_bVolCheckPlr = IS_ENTITY_IN_ELLIPSOID(PLAYER_PED_ID(), zvw_Volume.vCenter, zvw_Volume.fWidth, zvw_Volume.fDepth, zvw_Volume.fHeight, zvw_Volume.fRotation)
// zvw_bVolCheckCam = IS_POINT_IN_ELLIPSOID(vCameraPos, zvw_Volume.vCenter, zvw_Volume.fWidth, zvw_Volume.fDepth, zvw_Volume.fHeight, zvw_Volume.fRotation)
ENDIF
ELSE
zvw_bVolCheckPlr = FALSE
zvw_bVolCheckCam = FALSE
ENDIF
// Check the master draw switch.
IF NOT zvw_bDrawMaster
EXIT
ENDIF
// Perform draw.
IF zvw_bDrawAsRec
DRAW_ANGAREA_ENDPOINTS()
DRAW_ZVOLUME_REC(zvw_Volume, zvw_bDrawWire, zvw_bDrawFace)
ELIF zvw_bDrawAsCyl
DRAW_ZVOLUME_CYL(zvw_Volume, zvw_bDrawWire, zvw_bDrawFace, zvw_iSubdiv)
ELSE
//DRAW_ZVOLUME_ELD(zvw_Volume, zvw_bDrawWire, zvw_bDrawFace)
ENDIF
ENDPROC
#ENDIF // IS_DEBUG_BUILD