'******************************************************************* 
'  Direct3D retained mode include file for the RapidQ Compiler by William Yu 
'    Last updated 4/2005,   by JohnK 
' 
'  THERE ARE NO WARANTIES OR GUARANTEES, Use at your own risk 
'********************************************************************* 
' 
' 
' 
' ----------  Constants and definitions for DirectX under RapidQ ------- 
'  RapidQ comes from Delphi-X which uses a subset of Direct3D retained mode  
' calls but does not offer the full functionality of retained mode. 
' 
' 
' 
$TYPECHECK ON
$IFNDEF False
	$DEFINE False 0
$ENDIF
$IFNDEF True
	$DEFINE True 1
$ENDIF


$IFNDEF D3DVALUE
	$define D3DVALUE	SINGLE	'actual c declaration is float 
$ENDIF

$IFNDEF D3DVECTOR
	TYPE D3DVECTOR
		X		AS SINGLE
		Y		AS SINGLE
		Z		AS SINGLE
	END TYPE
	$define LPD3DVECTOR		LONG		'pointer to structure 
$ENDIF



' **** IMPORTANT, if you need all QD3DVECTOR values, use this instead!! ***** 
'The real implementation of QD3DVECTOR is a union between DVX &  X, DVY & Y, etc. 
TYPE Q3DVECTOR
	DVX		AS SINGLE
	DVY		AS SINGLE
	DVZ		AS SINGLE
	X		AS SINGLE
	Y		AS SINGLE
	Z		AS SINGLE

END TYPE

'this makes more sense as a 3D vector has only 3 members 
TYPE QD3DORIENTVECTOR
	X		AS SINGLE
	Y		AS SINGLE
	Z		AS SINGLE
	DVX		AS SINGLE
	DVY		AS SINGLE
	DVZ		AS SINGLE
END TYPE


TYPE QD3DRGBA			'different from DirectX D3DRGBA, which return DWORD types 
	R		AS SINGLE
	G		AS SINGLE
	B		AS SINGLE
	A		AS SINGLE
END TYPE



CONST D3DGROUND_ZERO = 0	'Boris added this 


'-- Wrap Types 
CONST D3DRMWRAP_FLAT = 0			'projects the texture along one direction vector 
CONST D3DRMWRAP_CYLINDER = 1		'projects the texture inward to center tangent with one vector 
CONST D3DRMWRAP_SPHERE = 2			'projects the texture inward to center from a sphere 
CONST D3DRMWRAP_CHROME = 3			'mesh normals to camera frame (not available in RapidQ) or other frame to calc texture coord 
CONST D3DRMWRAP_SHEET = 4			'not documented by msdn 
CONST D3DRMWRAP_BOX = 5				'tiles the bitmap? 
'Type 				u coordinate						v coordinate  
'Flat 				1/w to cover width of object  		1/h to cover height of object exactly  
'Cylindrical 		1* 1/h to cover height of object   
'Spherical/chrome 	1* 									1*  
'*Values <> 1 may be used to wrap part of the texture or to tile it but may not be good at the seams. 


'*********************************************************************************** 
' 
'  Light types 
' 
'*********************************************************************************** 

'-- D3DRMLIGHTTYPE light types, use for QD3DLight.SetLightRGB(lightType, R, G, B) 
CONST D3DRMLIGHT_AMBIENT = 0				'light homogenous in all directions 
CONST D3DRMLIGHT_POINT = 1					'point source 
CONST D3DRMLIGHT_SPOT = 2					'spotlight source.  
CONST D3DRMLIGHT_DIRECTIONAL = 3			'directional source 
CONST D3DRMLIGHT_PARALLELPOINT = 4			'parallel source 

'*********************************************************************************** 
' 
'  set rendering quality for the meshbuilder 
' 
'*********************************************************************************** 
' - D3DRMSHADEMODE shading modes how do you fill in shading between vertices on the face? 
CONST D3DRMSHADE_FLAT = 0
CONST D3DRMSHADE_GOURAUD = 1
CONST D3DRMSHADE_PHONG = 2
CONST D3DRMSHADE_MASK = 7
CONST D3DRMSHADE_MAX = 8

'-- fill in faces/vertex mode how do you fill the faces? 
CONST D3DRMFILL_POINTS = 0
CONST D3DRMFILL_WIREFRAME = 64
CONST D3DRMFILL_SOLID = 128
CONST D3DRMFILL_MASK = 448
CONST D3DRMFILL_MAX = 512


' -- D3DRMLIGHTMODE lighting modes 
CONST D3DRMLIGHT_OFF = 0 * D3DRMSHADE_MAX
CONST D3DRMLIGHT_ON = 1 * D3DRMSHADE_MAX
CONST D3DRMLIGHT_MASK = 7 * D3DRMSHADE_MAX
CONST D3DRMLIGHT_MAX = 8 * D3DRMSHADE_MAX


'-- Shade quality		use in QD3DMeshBuilder.SetQuality, can use above alone 
CONST D3DRMRENDER_POINTS =		D3DRMSHADE_FLAT		+ D3DRMLIGHT_OFF	+ D3DRMFILL_POINTS
CONST D3DRMRENDER_WIREFRAME =	D3DRMSHADE_FLAT		+ D3DRMLIGHT_OFF	+ D3DRMFILL_WIREFRAME
CONST D3DRMRENDER_UNLITFLAT =	D3DRMSHADE_FLAT		+ D3DRMLIGHT_OFF	+ D3DRMFILL_SOLID
CONST D3DRMRENDER_FLAT =		D3DRMSHADE_FLAT		+ D3DRMLIGHT_ON		+ D3DRMFILL_SOLID
CONST D3DRMRENDER_GOURAUD =		D3DRMSHADE_GOURAUD	+ D3DRMLIGHT_ON		+ D3DRMFILL_SOLID
CONST D3DRMRENDER_PHONG =		D3DRMSHADE_PHONG	+ D3DRMLIGHT_ON		+ D3DRMFILL_SOLID
CONST D3DRMRENDER_MAX =			D3DRMSHADE_PHONG	+ D3DRMLIGHT_ON		+ D3DRMFILL_MAX

' IDirect3DRMDevice::GetWireframeOptions  API 
CONST D3DRMWIREFRAME_CULL = 1 
CONST D3DRMWIREFRAME_HIDDENLINE = 2 

'********************************************************************************* 

'-- Renderer modes		 use for QDXscreen.SetRenderMode, but they don't have any effect? 
CONST D3DRMRENDERMODE_BLENDEDTRANSPARENCY = 1
CONST D3DRMRENDERMODE_SORTEDTRANSPARENCY = 2
CONST D3DRMRENDERMODE_LIGHTINMODELSPACE = 8
CONST D3DRMRENDERMODE_VIEWDEPENDENTSPECULAR = 16
CONST D3DRMRENDERMODE_DISABLESORTEDALPHAZWRITE = 32

'Most of the functionality of Direct3D would be through  D3DOP_STATERENDER opcodes 
'This only works in Immediate Mode not in RapidQ's Retained Mode, so we are limited 
' if you need more rendering options you will HAVE to go OpenGL, or other engine. 


' the following constants are not described by rapidQ 

' -- Textures definitions may not work 
CONST D3DRMTEXTURE_FORCERESIDENT  = &H00000001 			'texture should be kept in video memory */ 
CONST D3DRMTEXTURE_STATIC  = &H02 						'texture will not change */ 
CONST D3DRMTEXTURE_DOWNSAMPLEPOINT  = &H00000004 		'point filtering should be used when downsampling 
CONST D3DRMTEXTURE_DOWNSAMPLEBILINEAR  = &H00000008 	'bilinear filtering should be used when downsampling 
CONST D3DRMTEXTURE_DOWNSAMPLEREDUCEDEPTH  = &H00000010 	'reduce bit depth when downsampling 
CONST D3DRMTEXTURE_DOWNSAMPLENONE  = &H00000020 		'texture should never be downsampled 
CONST D3DRMTEXTURE_CHANGEDPIXELS  = &H00000040 			'pixels have changed 
CONST D3DRMTEXTURE_CHANGEDPALETTE  = &H00000080 		'palette has changed 
CONST D3DRMTEXTURE_INVALIDATEONLY  = &H00000100 		'dirty regions are invalid 

' texture quality (D3DRMTEXTUREQUALITY) use for QDXscreen.SetTextureQuality 
CONST D3DRMTEXTURE_NEAREST = 0							'Choose the nearest pixel in the texture.  (default) 
CONST D3DRMTEXTURE_LINEAR = 1							'Linearly interpolate the four nearest pixels.  
CONST D3DRMTEXTURE_MIPNEAREST = 2						'like D3DRMTEXTURE_NEAREST, but uses the mipmap instead of texture.  
CONST D3DRMTEXTURE_MIPLINEAR = 3						'Like D3DRMTEXTURE_LINEAR, but uses the appropriate mipmap instead of texture 
CONST D3DRMTEXTURE_LINEARMIPNEAREST = 4					'Like D3DRMTEXTURE_MIPNEAREST, but interpolates between the two nearest mipmaps 
CONST D3DRMTEXTURE_LINEARMIPLINEAR = 5					'Like D3DRMTEXTURE_MIPLINEAR, but interpolates between the two nearest mipmaps 


' --Shadows 
CONST D3DRMSHADOW_TRUEALPHA  = &H00000001 				'shadow should render without artifacts when true alpha is on 


' --fog mode, use for QD3DFrame.FogMode and DXscreen.Fog...--fog color is a DWORD 
CONST D3DRMFOG_LINEAR = 0								'linear between start and end */ 
CONST D3DRMFOG_EXPONENTIAL = 1							' density * exp(-distance) */ 
CONST D3DRMFOG_EXPONENTIALSQUARED = 2					'* density * exp(-distance*distance) */ 



' --- D3DRMFRAMECONSTRAINT  frame constrain for QD3DFrame.LookAt (F AS QD3DFrame, Constraint AS INTEGER)  
CONST D3DRMCONSTRAIN_Z = 0
CONST D3DRMCONSTRAIN_Y = 1
CONST D3DRMCONSTRAIN_X = 2


' -- Combination types  _D3DRMCOMBINETYPE, use for QD3DFrame.AddScale SUB (CombineType%, X#, Y#, Z#) 
' Scales a frame's local transformation by (rvX, rvY, rvZ) 
'Specifies how to combine the new scale with any current frame transformation.  
CONST D3DRMCOMBINE_REPLACE = 0		'in matrix replaces the frame's current matrix.  
CONST D3DRMCOMBINE_BEFORE = 1		'in matrix is multiplied with the frame's current matrix and precedes the current matrix in the calculation. 
CONST D3DRMCOMBINE_AFTER = 2		'in matrix is multiplied with the frame's current matrix and follows the current matrix in the calculation. 




'textures are obtained by QDXSCREEN.CreateTexture (Tex as QD3DTexture) or QD3DMeshBuilder.SetTexture only? 
'There is a QD3DTexture object that should be the same as IDirect3DRMTexture but RapidQ doesn't support it 

''Additional commands possible: 
' 
'QD3DANIMATION 
'QDXSCREEN.CREATEANIMATION 
'QD3DANIMATION.PARENT 
'Example: 
'DIM ANI AS QD3DANIMATION 
'QDXSCREEN.CREATEANIMATION(ANI) 
'ANI.PARENT = QDXscreen `-- no effect? 
'ANI.PARENT = QD3Dframe `—causes strange things and changes the 
'QD3Dframe settings!) 
'-------------------------------------------------------------------- 

'QD3DANIMATIONSET 
'QD3DANIMATIONSET.PARENT 
'QDXSCREEN.CREATEANIMATIONSET 
'Example: 
'DIM AniSet AS QD3DANIMATIONSET 
'QDXSCREEN.CREATEANIMATIONSET(AniSet) 
'AniSet.PARENT = QDXscreen 
'AniSet.Parent = QD3Dframe`—causes strange things and changes the 
'QD3Dframe settings!) 
' 
'-------------------------------------------------------------------- 
'QDXSCREEN___FONT methods: 
'QDXSCREEN.FONT.COLOR__ 
'QDXSCREEN.FONT.NAME___ 
'QDXSCREEN.FONT.SIZE___ 
'QDXSCREEN.FONT.ADDSTYLES__ 
'QDXSCREEN.FONT.DELSTYLES__ 
'QDXSCREEN.FONT.FONTCOUNT__ 
'QDXSCREEN.FONT.FONTNAME___ 
'QDXSCREEN.FONT.HANDLE_ 
'QDXSCREEN.FONT.CHARSET____ 
'QDXSCREEN.FONT.PITCH__ 
'QDXSCREEN.FONT.BOLD___ 
'QDXSCREEN.FONT.ITALIC_ 
'QDXSCREEN.FONT.UNDERLINE__ 
'QDXSCREEN.FONT.STRIKEOUT__ 
' 


'************************************************************************ 
'WINDOWS COM API for Direct3D retained mode and substitues if fail 


Declare Sub D3DRMVectorCrossProduct Lib "d3drm.dll" ALIAS "D3DRMVectorCrossProduct"_
	(ByRef d As D3DVECTOR, ByRef s1 As D3DVECTOR, ByRef s2 As D3DVECTOR)
	'returns result in d 

DECLARE SUB CrossProduct(BYREF Norm AS QD3DVECTOR, BYREF a AS QD3DVECTOR, BYREF b AS QD3DVECTOR)
SUB CrossProduct(BYREF a AS QD3DVECTOR, BYREF b AS QD3DVECTOR, BYREF Norm AS QD3DVECTOR)
	'returns the Normal 
	Norm.x = a.y * b.z - a.z * b.y 
	Norm.y = a.z * b.x - a.x * b.z 
	Norm.z = a.x * b.y - a.y * b.x 
END SUB


Declare Function D3DRMVectorDotProduct Lib "d3drm.dll" ALIAS "D3DRMVectorDotProduct" _
	(ByRef s1 As D3DVECTOR, ByRef s2 As D3DVECTOR) AS D3DVALUE

DECLARE FUNCTION VectorDotProduct(BYREF a AS QD3DVECTOR, BYREF b AS QD3DVECTOR) AS SINGLE
FUNCTION VectorDotProduct(BYREF a AS QD3DVECTOR, BYREF b AS QD3DVECTOR) AS SINGLE
	VectorDotProduct = a.x * b.x + a.y * b.y + a.z * b.z 
END FUNCTION



Declare Function D3DRMVectorNormalize Lib "d3drm.dll" ALIAS "D3DRMVectorNormalize"_
	(ByRef lpD3DVECTOR As D3DVECTOR ) AS LPD3DVECTOR

DECLARE SUB VectorNormalize(BYREF VecIn AS QD3DVECTOR)
SUB VectorNormalize(BYREF VecIn AS QD3DVECTOR)
	DIM VLength AS SINGLE
	VLength = VecIn.x * VecIn.x + VecIn.y * VecIn.y + VecIn.z * VecIn.z	'square 
	If VLength = 0 Then VecIn.x = 0: VecIn.y = 0: VecIn.z = 0: EXIT SUB
	VLength = Sqr(VLength)
	VecIn.x = VecIn.x / VLength
	VecIn.y = VecIn.y / VLength
	VecIn.z = VecIn.z / VLength
END SUB


'these are in D3DRM.DLL but will do ok under rapidQ 

DECLARE SUB VectorAdd(BYREF VectAdd AS QD3DVECTOR, BYREF a AS QD3DVECTOR, BYREF b AS QD3DVECTOR)
SUB VectorAdd(BYREF VectAdd AS QD3DVECTOR, BYREF a AS QD3DVECTOR, BYREF b AS QD3DVECTOR)
  VectAdd.x = a.x + b.x
  VectAdd.y = a.y + b.y
  VectAdd.z = a.z + b.z
END SUB


DECLARE SUB VectorSubtract(BYREF VectSub AS QD3DVECTOR, BYREF a AS QD3DVECTOR, BYREF b AS QD3DVECTOR)
SUB VectorSubtract(BYREF VectSub AS QD3DVECTOR, BYREF a AS QD3DVECTOR, BYREF b AS QD3DVECTOR)
  VectSub.x = a.x - b.x
  VectSub.y = a.y - b.y
  VectSub.z = a.z - b.z
END SUB



' 
' 
' -------  Custom Components that help direct 3d programs  ------- 
' 
$DEFINE null ""


'======================================================================================================== 
'    QD3DCAMERA component version 1.1 
' 
' useful alternative to DXSCREEN.SetCameraXXXX 
' 10/2004 JohnK 
'======================================================================================================== 
TYPE QD3DCamera EXTENDS QOBJECT
	PRIVATE:
	PushMouseX		AS INTEGER
	PushMouseY		AS INTEGER

	PUBLIC:
	Pos				AS QD3DVECTOR				'xyz position 
	Orient			AS QD3DOrientVector			'6 element vector for d3d retained mode camera 
	Height			AS SINGLE					'offset in up direction 
	ZoomFactor		AS SINGLE
	AngleX			AS INTEGER					'for holding of sin/cos integration in look-up tables 
	AngleY			AS INTEGER					'and also for Up-Down vector from sin/cos look-up tables 
	MouseDownButton	AS INTEGER					'signal which mouse button down for dynamic zooming 
	MouseDownX		AS INTEGER					'where mouse is down for dynamic zooming 
	MouseDownY		AS INTEGER					' and y 
	MouseZooming	AS INTEGER					'signal mouse was used for zooming 

	FUNCTION GetRadius() AS SINGLE				'vector length (radius) of the camera from origin 
		QD3DCamera.GetRadius = SQR(QD3DCamera.Pos.x * QD3DCamera.Pos.x +_
							QD3DCamera.Pos.y * QD3DCamera.Pos.y +_
							QD3DCamera.Pos.z * QD3DCamera.Pos.z)
	END FUNCTION

	FUNCTION GetXZRadius() AS SINGLE			'radius in x-z plane of the camera from origin 
		QD3DCamera.GetXZRadius = SQR(QD3DCamera.Pos.x * QD3DCamera.Pos.x +_
								QD3DCamera.Pos.z * QD3DCamera.Pos.z)
	END FUNCTION

	FUNCTION GetXYRadius() AS SINGLE			'radius in x-z plane of the camera from origin 
		QD3DCamera.GetXYRadius = SQR(QD3DCamera.Pos.x * QD3DCamera.Pos.x +_
								QD3DCamera.Pos.y * QD3DCamera.Pos.y)
	END FUNCTION

	SUB Translate(dx AS SINGLE, dy AS SINGLE, dz AS SINGLE)
		QD3DCamera.Pos.x = QD3DCamera.Pos.x + dx
		QD3DCamera.Pos.y = QD3DCamera.Pos.y + dy
		QD3DCamera.Pos.z = QD3DCamera.Pos.z + dz
	END SUB

	SUB ZoomXZ(Mag AS SINGLE)
		QD3DCamera.Pos.x = QD3DCamera.Pos.x + (QD3DCamera.Orient.x * Mag)	'move forward by orientation 
		QD3DCamera.Pos.z = QD3DCamera.Pos.z + (QD3DCamera.Orient.z * Mag)
	END SUB

	SUB Zoom(Mag AS SINGLE)
		QD3DCamera.Pos.x = QD3DCamera.Pos.x + (QD3DCamera.Orient.x * Mag)	'zoom forward/back by orientation 
		QD3DCamera.Pos.z = QD3DCamera.Pos.z + (QD3DCamera.Orient.z * Mag)
		QD3DCamera.Pos.y = QD3DCamera.Pos.y + (QD3DCamera.Orient.y * Mag)
	END SUB


	SUB ResetView
		QD3DCamera.Orient.x = 0.0				'These vectors set the orientation of camera axis (-1 to 1) 
		QD3DCamera.Orient.y = 0.0				'point straight down the z-axis 
		QD3DCamera.Orient.z = 1.0				'since all others are 0 and z is 1 
		QD3DCamera.Orient.dvx = 0.0			'this sets the "up" vector or roll 
		QD3DCamera.Orient.dvy = 1.0			'camera is standing straight up 
		QD3DCamera.Orient.dvz = 0.0			'this has no purpose, should be set to 0 
		QD3DCamera.AngleX = 0
		QD3DCamera.AngleY = 0
	END SUB

	SUB FaceCamera(BYREF Orient AS QD3DOrientVector, ObjPosX AS SINGLE, ObjPosY AS SINGLE, ObjPosZ AS SINGLE)
		'Finds the angles required for orientation vectors to 
		'face the camera. Also known as "Billboarding" 
		DIM Delta		AS QD3DVECTOR
		DIM Radi		AS SINGLE

		Delta.X = ObjPosX - QD3DCamera.Pos.x		'vector difference in position between camera & object 
		Delta.Y = ObjPosY - QD3DCamera.Pos.y
		Delta.Z = ObjPosZ - QD3DCamera.Pos.z
		Orient.dvx = QD3DCamera.Orient.dvx			'this sets the "up" vector or roll 
		Orient.dvy = QD3DCamera.Orient.dvy			'camera is standing straight up 
		Orient.dvz = QD3DCamera.Orient.dvz			'this has no purpose, should be set to 0 
		Radi = SQR(Delta.x*Delta.x + Delta.y*Delta.y + Delta.z*Delta.z)		'get magnitude 
		IF Radi < 0.01 THEN EXIT SUB				'too close don't change 
		Orient.x = Delta.X/Radi
		Orient.z = Delta.z/Radi
		Orient.y = Delta.Y/Radi
	END SUB


	SUB Update (DxScrn AS QDXSCREEN)
		DxScrn.SetCameraPosition(QD3DCamera.Pos.x, QD3DCamera.Pos.y, QD3DCamera.Pos.z)
		DxScrn.SetCameraOrientation(QD3DCamera.Orient.x, QD3DCamera.Orient.y, QD3DCamera.Orient.z,_		'orientation axis vector 
								  QD3DCamera.Orient.dvx, QD3DCamera.Orient.dvy, QD3DCamera.Orient.dvz)	'up axis vector 
		'DxScrn.Render 
		'DxScrn.Flip			'may not want these... 
	END SUB

	SUB SaveMouse
		QD3DCamera.PushMouseX = QD3DCamera.MouseDownX		'store the original mouse location (Push/pop) 
		QD3DCamera.PushMouseY = QD3DCamera.MouseDownY
	END SUB


	SUB RestoreMouse
		SetCursorPos(QD3DCamera.PushMouseX, QD3DCamera.PushMouseY)	'restore mouse by Win API 
	END SUB


	CONSTRUCTOR
		Pos.x = 0.0					' 
		Pos.y = 0.0					'set it to middle 
		Pos.z = 0.0					' 
		Orient.x = 0.0				'These vectors set the orientation of camera axis (-1 to 1) 
		Orient.y = 0.0				'point straight down the z-axis 
		Orient.z = 1.0				'since all others are 0 and z is 1 
		Orient.dvx = 0.0			'this sets the "up" vector or roll 
		Orient.dvy = 1.0			'camera is standing straight up 
		Orient.dvz = 0.0			'this has no purpose, should be set to 0 
		Height = 1.0				'offset camera from ground in y direction 
		ZoomFactor = 1.0			'how much to zoom the camera 
		AngleX = 0					'integers for look up of sin/cos tables 
		AngleY = 0
		MouseDownButton = MouseNotDown		'signal no button, can't use false!! 
		MouseDownX = 0
		MouseDownY = 0
		MouseZooming = False
	END CONSTRUCTOR
END TYPE





'======================================================================================================== 
'    QD3DPrimitive component version 1.1 
'   
' make simple polygon mesh objects -- can't  extend a QD3DMeshbuilder 
' 9/2005 JohnK 
'======================================================================================================== 


TYPE QD3DPrimitive EXTENDS QOBJECT		'use for floor, sky box, clouds, boxes, pyramids, whatever 
  PRIVATE:								'don't mess with these 
	xc 	AS SINGLE						'quick draw center 
	yc	AS SINGLE
	zc	AS SINGLE
	
  PUBLIC:
	Mesh			AS QD3DMESHBUILDER	'mesh holds all polygon faces,colors, material, render quality 
	Frame			AS QD3DFRAME		'Frame for independent orientation, position 
	RenderQuality	AS LONG				'Rendering quality of the Mesh (eg D3DRMRENDER_GOURAUD) 
	TextureFile		AS STRING
	TexOriginX		AS SINGLE			'texture origin 
	TexOriginY		AS SINGLE			'in model space 
	TexOriginZ		AS SINGLE			'These are the first 3 args for the D3Dwrap function 
	TexOriginU		AS SINGLE			'coordinates on bmp (u,v) for texture origin 
	TexOriginV		AS SINGLE			'of the last args in D3Dwrap function 
	TexScaleU		AS SINGLE			'u,v texture scaling, for whole mesh = 1/size mesh 
	TexScaleV		AS SINGLE			'2nd to last args in D3Dwrap function 
	TexWrapType		AS SHORT			'See wrap type codes above 
	Color			AS QD3DRGBA			'rgb and alphablend 
	DrawCenter		AS QD3DVector		'center for drawing primitives freely vary for each new polygon 
	BoxSides		AS INTEGER			'number of sides for the MakeBox function 
	ViewFromOutside	AS INTEGER			'poly faces orient outside the box 
    Visible         AS INTEGER          'Flag any object / polygons created 

	FUNCTION New() AS INTEGER
		WITH QD3DPrimitive
		.RenderQuality	= D3DRMRENDER_FLAT
		.TextureFile	= null
		.TexOriginX		= 0.0
		.TexOriginY		= 0.0
		.TexOriginZ		= 0.0
		.TexOriginU		= 0.0
		.TexOriginV		= 0.0
		.TexScaleU		= 1.0
		.TexScaleV		= 1.0
		.TexWrapType	= D3DRMWRAP_SPHERE
		.Color.R		= 1.0
		.Color.G		= 1.0
		.Color.B		= 1.0
		.Color.A		= 1.0
		.DrawCenter.x	= 0.0
		.DrawCenter.y	= 0.0
		.DrawCenter.z	= 0.0
		.BoxSides		= 5			'don't render the bottom 
		.ViewFromOutside = True		'look at the box from the outside (inside is transparent) 
        .Visible        = False     'nothing loaded 
		END WITH
	END FUNCTION


	SUB LoadTextureFile
		DIM openDialog 	AS QOPENDIALOG

		IF QD3DPrimitive.TextureFile = null THEN
			openDialog.Caption = "select a bitmap for the texture"
			openDialog.filter = "*.bmp (bitmaps)|*.bmp"
   			IF openDialog.execute THEN
				IF FILEEXISTS(openDialog.fileName) THEN 
					QD3DPrimitive.TextureFile = openDialog.fileName
				ELSE
					ShowMessage "Texture file does not exist"
					EXIT SUB
				END IF
			END IF	'fileopen execute 
		END IF		'no file name 
		QD3DPrimitive.Mesh.loadTexture(QD3DPrimitive.TextureFile)
	END SUB




	SUB MakeHorizPlane(DXScreen AS QDXSCREEN)	'simple horizontal plane 
		DIM Face	AS QD3DFace
		DIM	xc		AS SINGLE						'quick draw center 
		DIM	yc		AS SINGLE
		DIM	zc		AS SINGLE

		xc = QD3DPrimitive.DrawCenter.x			'looks silly but easier to read/debug 
		yc = QD3DPrimitive.DrawCenter.y
		zc = QD3DPrimitive.DrawCenter.z
		DXScreen.CreateFace(Face)
		IF QD3DPrimitive.ViewFromOutside THEN
			Face.AddVertex(-1+xc, 0+yc, -1):	Face.AddVertex( 1+xc, 0+yc, -1)
			Face.AddVertex( 1+xc, 0+yc, 1):		Face.AddVertex(-1+xc, 0+yc, 1)
		ELSE
			Face.AddVertex(-1+xc, 0+yc, 1):		Face.AddVertex( 1+xc, 0+yc, 1)
			Face.AddVertex( 1+xc, 0+yc, -1):	Face.AddVertex(-1+xc, 0+yc, -1)
		END IF
		QD3DPrimitive.Mesh.AddFace(Face)
		QD3DPrimitive.Visible = True        
	END SUB


	SUB MakeVertZPlane(DXScreen AS QDXSCREEN)		'simple vertical plane down the z-axis (x = 0) 
		DIM Face 	AS QD3DFace
		DIM	xc		AS SINGLE						'quick draw center 
		DIM	yc		AS SINGLE
		DIM	zc		AS SINGLE

		xc = QD3DPrimitive.DrawCenter.x			'looks silly but easier to read/debug 
		yc = QD3DPrimitive.DrawCenter.y
		zc = QD3DPrimitive.DrawCenter.z
		DXScreen.CreateFace(Face)
		IF QD3DPrimitive.ViewFromOutside THEN
			Face.AddVertex(xc, 0+yc, -1+zc):	Face.AddVertex(xc, 1+yc, -1+zc)
			Face.AddVertex(xc, 1+yc,  1+zc):	Face.AddVertex(xc, 0+yc,  1+zc)
		ELSE
			Face.AddVertex(xc, 0+yc,  1+zc):	Face.AddVertex(xc, 1+yc,  1+zc)
			Face.AddVertex(xc, 1+yc, -1+zc): 	Face.AddVertex(xc, 0+yc, -1+zc)
		END IF
		QD3DPrimitive.Mesh.AddFace(Face)
		QD3DPrimitive.Visible = True
	END SUB



	SUB MakeVertXPlane(DXScreen AS QDXSCREEN)		'simple vertical plane down the x-axis (z = 0) 
		DIM Face 	AS QD3DFace
		DIM	xc		AS SINGLE						'quick draw center 
		DIM	yc		AS SINGLE
		DIM	zc		AS SINGLE

		xc = QD3DPrimitive.DrawCenter.x			'looks silly but easier to read/debug 
		yc = QD3DPrimitive.DrawCenter.y
		zc = QD3DPrimitive.DrawCenter.z
		DXScreen.CreateFace(Face)
		IF QD3DPrimitive.ViewFromOutside = True THEN
			Face.AddVertex( 1+xc, 0+yc, zc):  	Face.AddVertex( 1+xc, 1+yc, zc)
			Face.AddVertex(-1+xc, 1+yc, zc): 	Face.AddVertex(-1+xc, 0+yc, zc)
		ELSE
			Face.AddVertex(-1+xc, 0+yc, zc): 	Face.AddVertex(-1+xc, 1+yc, zc)
			Face.AddVertex( 1+xc, 1+yc, zc):	Face.AddVertex( 1+xc, 0+yc, zc)
		END IF
		QD3DPrimitive.Mesh.AddFace(Face)
		QD3DPrimitive.Visible = True
	END SUB



	SUB MakeBox(DXScreen AS QDXSCREEN)			'must pass in DXscreen for COM operation 
		DIM Face 	AS QD3DFace
		DIM tmp		AS QD3DVECTOR				'keep track of DrawCenter 
		DIM tmpView	AS INTEGER					'and view state 

		WITH QD3DPrimitive
		tmp.x = .DrawCenter.x					'store them 
		tmp.y = .DrawCenter.y
		tmp.z = .DrawCenter.z
		tmpView = .ViewFromOutside

		.DrawCenter.z = 1
		.MakeVertXPlane(DXScreen)				'back plane 

		IF .ViewFromOutside = True THEN .ViewFromOutside = False ELSE .ViewFromOutside = True
		.DrawCenter.z = -1
		.MakeVertXPlane(DXScreen)				'front plane 
		.ViewFromOutside = tmpView

		IF .ViewFromOutside = True THEN .ViewFromOutside = False ELSE .ViewFromOutside = True
		.DrawCenter.z = 0
		.DrawCenter.x = -1
		.MakeVertZPlane(DXScreen)				'left plane 
		.ViewFromOutside = tmpView
		.DrawCenter.x = 1						'right plane 
		.MakeVertZPlane(DXScreen)

		IF .BoxSides > 4 THEN					'ceiling 
		IF .ViewFromOutside = True THEN .ViewFromOutside = False ELSE .ViewFromOutside = True
			.DrawCenter.z = 0
			.DrawCenter.x = 0
			.DrawCenter.y = 1
			.MakeHorizPlane(DXScreen)
    		.ViewFromOutside = tmpView
		END IF

		IF .BoxSides > 5 THEN					'floor 
			.DrawCenter.y = 0
			.MakeHorizPlane(DXScreen)
		END IF

		.DrawCenter.x = tmp.x					'restore 
		.DrawCenter.y = tmp.y
		.DrawCenter.z = tmp.z
		.ViewFromOutside = tmpView
		.Visible = True
		END WITH
	END SUB



	SUB MakePyramid(DXScreen AS QDXSCREEN)	'simple pyramid from center 
		DIM Face 	AS QD3DFace

		WITH QD3DPrimitive
		DXScreen.CreateFace(Face)

		Face.AddVertex(0,  0, 0) 
		Face.AddVertex(1,  1, 1)
   		Face.AddVertex(1, -1, 1)
		IF .ViewFromOutside = False THEN
			Face.AddVertex(1,  1, 1)		'add extra vert to avoid culling 
		END IF
		.Mesh.AddFace(Face)

		Face.AddVertex( 0, 0, 0) 
		Face.AddVertex( 1, 1, 1)
		Face.AddVertex(-1, 1, 1)
		IF .ViewFromOutside = False THEN
		Face.AddVertex( 1, 1, 1)
		END IF
		.Mesh.AddFace(Face)

		Face.AddVertex( 0,  0, 0) 
		Face.AddVertex(-1,  1, 1)
		Face.AddVertex(-1, -1, 1)
		IF .ViewFromOutside = False THEN
		Face.AddVertex(-1,  1, 1)
		END IF
		.Mesh.AddFace(Face)

		Face.AddVertex( 0,  0, 0) 
		Face.AddVertex(-1, -1, 1)
		Face.AddVertex( 1, -1, 1)
		IF .ViewFromOutside = False THEN
		Face.AddVertex(-1, -1, 1)
		END IF
		.Mesh.AddFace(Face)
		.Visible = True
		END WITH
	END SUB



    SUB MakeSphere(DXScreen AS QDXSCREEN, NumFaces AS INTEGER)   'simple sphere from center 
        DIM Phi         AS SINGLE
        DIM Theta       AS SINGLE
        DIM theStep     AS SINGLE
        DIM theStep2    AS SINGLE
        DIM x1 as SINGLE, y1 AS SINGLE, z1 AS SINGLE
        DIM x2 as SINGLE, y2 AS SINGLE, z2 AS SINGLE
        DIM x3 as SINGLE, y3 AS SINGLE
        DIM x4 as SINGLE, y4 AS SINGLE
        DIM Face        AS QD3DFace
        DIM pi          AS SINGLE: pi = 3.14159265359
        DIM pi2         AS SINGLE: pi2 = 6.2831853072

		WITH QD3DPrimitive
        .xc = .DrawCenter.x
        .yc = .DrawCenter.y
        .zc = .DrawCenter.z
        theStep = pi/SQR(NumFaces)
        theStep2 = 2* TheStep

        FOR Phi = 0 TO pi STEP TheStep
        FOR Theta = 0 TO pi2 STEP TheStep2
            DXScreen.CreateFace(Face)
            y1 = SIN(Phi) * COS(Theta)
            x1 = SIN(Phi) * SIN(Theta)
            z1 = COS(Phi)
    
            y2 = SIN(Phi) * COS(Theta + TheStep2)
            x2 = SIN(Phi) * SIN(Theta + TheStep2)
            z2 = COS(Phi + TheStep)
    
            y3 = SIN(Phi + TheStep) * COS(Theta + TheStep2)
            x3 = SIN(Phi + TheStep) * SIN(Theta + TheStep2)
    
            y4 = SIN(Phi + TheStep) * COS(Theta)
            x4 = SIN(Phi + TheStep) * SIN(Theta)
    		IF .ViewFromOutside = False THEN
                 Face.AddVertex(x4  + .xc,  y4  + .yc, z2  + .zc)
                 Face.AddVertex(x3  + .xc,  y3  + .yc, z2  + .zc)
                 Face.AddVertex(x2  + .xc,  y2  + .yc, z1  + .zc)
                 Face.AddVertex(x1  + .xc,  y1  + .yc, z1  + .zc)
            ELSE
                 Face.AddVertex(x1  + .xc,  y1  + .yc, z1  + .zc)
                 Face.AddVertex(x2  + .xc,  y2  + .yc, z1  + .zc)
                 Face.AddVertex(x3  + .xc,  y3  + .yc, z2  + .zc)
                 Face.AddVertex(x4  + .xc,  y4  + .yc, z2  + .zc)
            END IF

            .Mesh.AddFace(Face)
        NEXT Theta
        NEXT Phi
		.Visible = True
 		END WITH
    END SUB




    SUB MakeCylinder(DXScreen AS QDXSCREEN, NumFaces AS INTEGER)   'simple sphere from center 
        DIM Theta       AS SINGLE
        DIM Theta2      AS SINGLE
        DIM TheStep     AS SINGLE
        DIM x as SINGLE,  y AS SINGLE,  z AS SINGLE
        DIM x2 as SINGLE, y2 AS SINGLE, z2 AS SINGLE
        DIM Face        AS QD3DFace
        DIM pi2         AS SINGLE: pi2 = 6.2831853072

		WITH QD3DPrimitive
        .xc = .DrawCenter.x
        .yc = .DrawCenter.y
        .zc = .DrawCenter.z
        y = 1.0
        y2 = -1.0
        TheStep = pi2/NumFaces
        FOR Theta = 0.0 TO pi2 STEP TheStep
            DXScreen.CreateFace(Face)                           'recreate to null prior faces 
            Theta2 = Theta + TheStep
            x = COS(Theta):     z = SIN(Theta)
            x2 = COS(Theta2):   z2 = SIN(Theta2)
    		IF .ViewFromOutside = False THEN
                Face.AddVertex(x  + .xc,  y2 + .yc, z  + .zc)
                Face.AddVertex(x2 + .xc,  y2 + .yc, z2 + .zc)
                Face.AddVertex(x2 + .xc,  y  + .yc, z2 + .zc)
                Face.AddVertex(x  + .xc,  y  + .yc, z  + .zc)
            ELSE
                Face.AddVertex(x  + .xc,  y  + .yc, z  + .zc)
                Face.AddVertex(x2 + .xc,  y  + .yc, z2 + .zc)
                Face.AddVertex(x2 + .xc,  y2 + .yc, z2 + .zc)
                Face.AddVertex(x  + .xc,  y2 + .yc, z  + .zc)
            END IF
            .Mesh.AddFace(Face)
        NEXT Theta
		.Visible = True
 		END WITH
    END SUB



    SUB MakeCone(DXScreen AS QDXSCREEN, NumFaces AS INTEGER)   'simple sphere from center 
        DIM Theta       AS SINGLE
        DIM Theta2      AS SINGLE
        DIM TheStep     AS SINGLE
        DIM x as SINGLE,  y AS SINGLE,  z AS SINGLE
        DIM x2 as SINGLE, y2 AS SINGLE, z2 AS SINGLE
        DIM Face        AS QD3DFace
        DIM pi2         AS SINGLE: pi2 = 6.2831853072

		WITH QD3DPrimitive
        .xc = .DrawCenter.x
        .yc = .DrawCenter.y
        .zc = .DrawCenter.z
        y = 1.0
        y2 = -1.0
        TheStep = pi2/NumFaces
        FOR Theta = 0.0 TO pi2 STEP TheStep                 'work in a circle radian 
            DXScreen.CreateFace(Face)                       'recreate to null prior faces 
            Theta2 = Theta + TheStep                        'next vert of circle 
            x = COS(Theta):     z = SIN(Theta)
            x2 = COS(Theta2):   z2 = SIN(Theta2)
    		IF .ViewFromOutside = False THEN
                Face.AddVertex(x  + .xc,  y2 + .yc, z  + .zc)
                Face.AddVertex(x2 + .xc,  y2 + .yc, z2 + .zc)
                Face.AddVertex(0.0+ .xc,  y  + .yc, 0.0 + .zc)
            ELSE
                Face.AddVertex(0.0+ .xc,  y  + .yc, 0.0 + .zc)
                Face.AddVertex(x2 + .xc,  y2 + .yc, z2 + .zc)
                Face.AddVertex(x  + .xc,  y2 + .yc, z  + .zc)
            END IF
            .Mesh.AddFace(Face)
        NEXT Theta
		.Visible = True
 		END WITH
    END SUB


	CONSTRUCTOR
		New()
	END CONSTRUCTOR
END TYPE





'======================================================================================================== 
'    QD3DCloneMesh component version 1.0 
' 
' make multiple objects from the same mesh 
' 10/2004 JohnK 
'======================================================================================================== 



CONST MaxD3DClones	= 100						'Multiply up to 100 D3Dframes in the scene 

TYPE QD3DCloneMesh		EXTENDS QOBJECT			'can't make arrays of custom objects 
PRIVATE:
	Initialized			AS INTEGER
	RangeX				AS SINGLE
	RangeZ				AS SINGLE
PUBLIC:
	Visible				AS INTEGER	PROPERTY SET Set_Visible		'toggle visible on-off 
	CloneNum			AS INTEGER	PROPERTY SET Set_CloneNum			'how many times to clone 
	File				AS STRING				'filename  of X or 3DS 3d model 
	Mesh				AS QD3DMESHBUILDER		'one mesh to multiply 
	Frame(MaxD3DClones) AS QD3DFrame
	Range				AS QRECT				'set a box volume range to place all the cloned objects 
	RandPos				AS INTEGER	PROPERTY SET Set_RandPos		'randomly generate positions? 
	Pos(MaxD3DClones)	AS QD3DVECTOR			'position 
	Orient(MaxD3DClones) AS QD3DOrientVector		'6 element vector for d3d retained mode camera 
	RandScale			AS INTEGER 	PROPERTY SET Set_RandScale		'randomly generate sizes? 
	Scale				AS QD3DVECTOR			'allow x,y,z scaling each frame 
	TextureFile			AS STRING				'the texture file (.bmp or .ppm) 
	TexOriginX			AS SINGLE				'texture origin 
	TexOriginY			AS SINGLE				'in model space 
	TexOriginZ			AS SINGLE				'These are the first 3 args for the D3Dwrap function 
	TexOriginU			AS SINGLE				'u,v texture origin 
	TexOriginV			AS SINGLE				'of the last args in D3Dwrap function 
	TexScaleU			AS SINGLE				'u,v texture scaling 
	TexScaleV			AS SINGLE				'2nd to last args in D3Dwrap function 
	TexWrapType			AS LONG					'd3drm wrapping type code 
	Color				AS QD3DRGBA				'(0 - 1) color whole mesh, if < 0 then don't modify -- if you set alpha you must set rgb... sorry 


	PROPERTY SET Set_Visible(VisibleValue AS INTEGER)   'Property Set for Visible property 
		DIM i AS INTEGER
		This.Visible = VisibleValue
		IF VisibleValue = 1 THEN                      'If Visible property is set to True 
			IF This.Initialized THEN
			FOR i = 1 TO This.CloneNum
				This.Frame(i).AddVisual(This.Mesh)			'load the frames 
			NEXT i
			ELSE
				ShowMessage "Initialize CloneObject first"
			END IF
	    ELSE                                          'Otherwise 
			IF This.Initialized THEN
			FOR i = 1 TO This.CloneNum
				This.Frame(i).DeleteVisual(This.Mesh)		'unload the frames 
			NEXT i
			END IF
		END IF
	END PROPERTY


	PROPERTY SET Set_CloneNum(TheCloneNum AS INTEGER)
		IF TheCloneNum < = MaxD3DClones THEN
			This.CloneNum = TheCloneNum		'it needs to be set! 
		END IF
	END PROPERTY



	PROPERTY SET Set_RandPos(RandPosValue AS INTEGER)   'Property Set for Visible property 
		DIM i AS INTEGER
		This.RandPos = RandPosValue
   		IF RandPosValue <> 0 THEN
			WITH This
			.RangeX = .Range.Right - .Range.Left
			.RangeZ = .Range.Top - .Range.Bottom
			FOR i = 1 TO .CloneNum
				This.Pos(i).x = RND * .RangeX + (.Range.Left/1)	'convert to single 
				This.Pos(i).y = RND
				This.Pos(i).z = RND * .RangeZ + (.Range.Bottom/1)
			NEXT i
			END WITH
		END IF
	END PROPERTY


	PROPERTY SET Set_RandScale(RandScaleValue AS INTEGER)   'Property Set for Visible property 
		WITH This
		.RandScale = RandScaleValue
   		IF RandScaleValue <> 0 THEN
			.Scale.x = RND
			.Scale.y = RND
			.Scale.z = .Scale.x
		ELSE
			.Scale.x = 1.0!
			.Scale.y = 1.0!
			.Scale.z = 1.0!
		END IF
		END WITH
	END PROPERTY



	SUB Init(DXscreen AS QDXSCREEN)
		DIM i	AS INTEGER

		IF This.Initialized THEN
		FOR i = 1 TO This.CloneNum
			This.Frame(i).DeleteVisual(This.Mesh)		'remove old ones first 
		NEXT i
		END IF

		DXScreen.CreateMeshbuilder(This.Mesh)
		IF This.File <>"" THEN This.Mesh.Load(This.File)
		This.Mesh.Scale(This.Scale.x, This.Scale.y, This.Scale.z)' this works on each new load..but you can't remove them 
		FOR i = 1 TO This.CloneNum
			DXScreen.CreateFrame(This.Frame(i))
			This.Frame(i).AddVisual(This.Mesh)
			This.Frame(i).SetPosition(This.Pos(i).x, This.Pos(i).y, This.Pos(i).z)
'			This.Frame.AddScale(D3DRMCOMBINE_BEFORE,This.Scale(i).x, This.Scale(i).y, This.Scale(i).z) 'this crashes 
		NEXT i
		This.Initialized = True
	END SUB



	FUNCTION New()		AS INTEGER
	DIM i AS INTEGER
		WITH QD3DCloneMesh
		.Initialized	= False	'need to setup with QDXScreen 
		.Visible 		= True
		.File			= null
		.CloneNum		= 0
		.RandPos		= False
		.Range.Left		= -1
		.Range.Top		= 1
		.Range.Right	= 1
		.Range.Bottom	= -1
		.RangeX			= 2 'total range left-right 
		.RangeZ			= 2 'same for top-bottom 
		.RandScale		= False
		.Scale.x		= 1.0!
		.Scale.y		= 1.0!		'can't scale each frame! Bug in program? 
		.Scale.z		= 1.0!

		FOR i = 0 TO MaxD3DClones
			.Pos(i).x		= 0.0!
			.Pos(i).y		= 0.0!
			.Pos(i).z		= 0.0!
			.Orient(i).x 	= 0.0!
			.Orient(i).y 	= 1.0!
			.Orient(i).z 	= 1.0!
			.Orient(i).dvx 	= 0.0!
			.Orient(i).dvy 	= 1.0!
			.Orient(i).dvz 	= 0.0!
		NEXT i

		.TextureFile	= null
		.TexOriginX		= 0.0!
		.TexOriginY		= 0.0!
		.TexOriginZ		= 0.0!
		.TexOriginU		= 0.0!
		.TexOriginV		= 0.0!
		.TexScaleU		= 0.0!
		.TexScaleV		= 0.0!
		.TexWrapType	= D3DRMWRAP_SPHERE
		.Color.R		= 0.0!
		.Color.G		= 0.0!
		.Color.B		= 0.0!
		.Color.A		= 0.0!
		END WITH
	END FUNCTION

	CONSTRUCTOR
		New
	END CONSTRUCTOR
END TYPE



$UNDEF null
$TYPECHECK OFF