' Direct3D model viewer for Rapid-Q by William Yu
' Only loads mesh objects.

$TYPECHECK ON
$INCLUDE "RAPIDQ.INC"

'-- fill in faces/vertex mode
CONST D3DRMFILL_POINTS = 0
CONST D3DRMFILL_WIREFRAME = 64
CONST D3DRMFILL_SOLID = 128
CONST D3DRMFILL_MASK = 448
CONST D3DRMFILL_MAX = 512

'-- Wrap Types
CONST D3DRMWRAP_FLAT = 0
CONST D3DRMWRAP_CYLINDER = 1
CONST D3DRMWRAP_SPHERE = 2
CONST D3DRMWRAP_CHROME = 3
CONST D3DRMWRAP_SHEET = 4
CONST D3DRMWRAP_BOX = 5

'--lights, use for QD3DLight.SetLightRGB(lightType, R, G, B)
CONST D3DRMLIGHT_AMBIENT = 0
CONST D3DRMLIGHT_POINT = 1
CONST D3DRMLIGHT_SPOT = 2
CONST D3DRMLIGHT_DIRECTIONAL = 3
CONST D3DRMLIGHT_PARALLELPOINT = 4
' OR with these?
CONST D3DRMLIGHT_OFF = 0
CONST D3DRMLIGHT_ON = 8
CONST D3DRMLIGHT_MASK = 56
CONST D3DRMLIGHT_MAX = 64

'-- Shades
CONST D3DRMSHADE_FLAT = 0
CONST D3DRMSHADE_GOURAUD = 1
CONST D3DRMSHADE_PHONG = 2
CONST D3DRMSHADE_MASK = 7
CONST D3DRMSHADE_MAX = 8



'-- Shade quality
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


'-- Renderer modes		 use for QDXscreen.SetRenderMode
CONST D3DRMRENDERMODE_BLENDEDTRANSPARENCY = 1
CONST D3DRMRENDERMODE_SORTEDTRANSPARENCY = 2
CONST D3DRMRENDERMODE_LIGHTINMODELSPACE = 8
CONST D3DRMRENDERMODE_VIEWDEPENDENTSPECULAR = 16
CONST D3DRMRENDERMODE_DISABLESORTEDALPHAZWRITE = 32

' 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 = 1							'choose nearest texel */
CONST D3DRMTEXTURE_LINEAR = 2							'interpolate 4 texels */
CONST D3DRMTEXTURE_MIPNEAREST = 3						'nearest texel in nearest mipmap  */
CONST D3DRMTEXTURE_MIPLINEAR = 4						'interpolate 2 texels from 2 mipmaps */
CONST D3DRMTEXTURE_LINEARMIPNEAREST = 5					'interpolate 4 texels in nearest mipmap */
CONST D3DRMTEXTURE_LINEARMIPLINEAR = 6					'interpolate 8 texels from 2 mipmaps */

' --Shadows
CONST D3DRMSHADOW_TRUEALPHA  = &H00000001 				'shadow should render without artifacts when true alpha is on


' --fog mode, use for QD3DFrame.FogMode
CONST D3DRMFOG_LINEAR = 1								'linear between start and end */
CONST D3DRMFOG_EXPONENTIAL = 2							' density * exp(-distance) */
CONST D3DRMFOG_EXPONENTIALSQUARED = 3					'* density * exp(-distance*distance) */

'--fog color



DECLARE SUB dxInitialize(sender AS QDXSCREEN)
DECLARE SUB dxInitializeSurface(sender AS QDXSCREEN)
DECLARE SUB dxTimerExpired
DECLARE SUB exitItemClick(sender AS QMENUITEM)
DECLARE SUB openItemClick(sender AS QMENUITEM)
DECLARE SUB rotateButtonClick(sender AS QBUTTON)
DECLARE SUB rotateStopButtonClick(sender AS QBUTTON)
DECLARE SUB upButtonMouseDown(button%, x%, y%, shift%, sender AS QBUTTON)
DECLARE SUB upButtonMouseUp(button%, x%, y%, shift%, sender AS QBUTTON)
DECLARE SUB textureButtonClick(sender AS QBUTTON)


CONST Max3DObjects = 12
DIM dxTimer AS QDXTIMER
    dxTimer.enabled = 1
    dxTimer.interval = 0
    dxTimer.activeOnly = 0
    dxTimer.onTimer = dxTimerExpired
DIM frameView AS DOUBLE
    frameView = 10
DIM wrapType AS LONG
    wrapType = D3DRMWRAP_SPHERE
DIM T! 				AS SINGLE
DIM TheObjectNum	AS INTEGER
	TheObjectNum = 0

DIM meshFrame 		AS QD3DFRAME
DIM meshBuilder(1 to Max3DObjects) AS QD3DMESHBUILDER
DIM wrap AS QD3DWRAP


CREATE form AS QFORM
    caption = "Direct3D Model Viewer"
    width = 640
    height = 480
    center
    CREATE panel AS QPANEL
        width = 150
        align = alRight
        bevelOuter = bvLowered
        CREATE upButton AS QBUTTON
            caption = "/\"
            hint = "up"
            width = 30
            left = 60
            top = 10
            tabOrder = 0
            onMouseDown = upButtonMouseDown
            onMouseUp = upButtonMouseUp
        END CREATE
        CREATE downButton AS QBUTTON
            caption = "\/"
            hint = "down"
            left = 60
            width = 30
            top = 40
            tabOrder = 0
            onMouseDown = upButtonMouseDown
            onMouseUp = upButtonMouseUp
        END CREATE
        CREATE textureImage AS QIMAGE
            left = 25
            width = 100
            top = 70
            onClick = textureButtonClick
        END CREATE
        CREATE textureButton AS QBUTTON
            caption = "Texture..."
            left = 50
            width = 60
            top = 180
            onClick = textureButtonClick
        END CREATE
        CREATE rotateLabelAngle AS QLABEL
            top = 273
            left = 15
            caption = "Angle:"
        END CREATE
        CREATE rotateEditAngle AS QEDIT
            top = 270
            left = 60
            width = 40
            text = "1"
        END CREATE
        CREATE rotateLabelX AS QLABEL
            top = 303
            left = 15
            caption = "X:"
        END CREATE
        CREATE rotateEditX AS QEDIT
            top = 300
            left = 60
            width = 40
            text = "1"
        END CREATE
        CREATE rotateLabelY AS QLABEL
            top = 333
            left = 15
            caption = "Y:"
        END CREATE
        CREATE rotateEditY AS QEDIT
            top = 330
            left = 60
            width = 40
            text = "1"
        END CREATE
        CREATE rotateLabelZ AS QLABEL
            top = 363
            left = 15
            caption = "Z:"
        END CREATE
        CREATE rotateEditZ AS QEDIT
            top = 360
            left = 60
            width = 40
            text = "1"
        END CREATE
        CREATE rotateButton AS QBUTTON
            left = 10
            top = 390
            width = 60
            caption = "&Rotate"
            onClick = rotateButtonClick
        END CREATE
        CREATE rotateStopButton AS QBUTTON
            left = 80
            top = 390
            width = 60
            caption = "&Stop"
            onClick = rotateStopButtonClick
        END CREATE
    END CREATE
    CREATE dxScreen AS QDXSCREEN
        align = alClient
        bitCount = 32
        use3D = 1
        useHardware = 1
        onInitialize = dxInitialize
        onInitializeSurface = dxInitializeSurface
    END CREATE
    CREATE mainMenu AS QMAINMENU
        CREATE fileMenu AS QMENUITEM
            caption = "&File"
            CREATE openItem AS QMENUITEM
                caption = "&Open..."
                onClick = openItemClick
            END CREATE
            CREATE breakItem1 AS QMENUITEM
                caption = "-"
            END CREATE
            CREATE exitItem AS QMENUITEM
                caption = "E&xit"
                onClick = exitItemClick
            END CREATE
        END CREATE
    END CREATE
    showModal
END CREATE



SUB exitItemClick(sender AS QMENUITEM)
	dim i as integer

	for i = 1 to TheObjectNum
		meshFrame.deleteVisual(meshBuilder(TheObjectNum))' possible not released
	next i
    form.close
END SUB


SUB openItemClick(sender AS QMENUITEM)
    DIM openDialog AS QOPENDIALOG

    openDialog.filter = "*.x (X models)|*.x"
    IF openDialog.execute THEN
       '-- Remove previous object from frame
'       meshFrame.deleteVisual(meshBuilder(TheObjectNum))		'use this to always overwrite the current 3D Object
		INC TheObjectNum
       '-- Rebuilds mesh, removing the old object
       dxScreen.createMeshBuilder(meshBuilder(TheObjectNum))
       '-- Load a new object
       meshBuilder(TheObjectNum).load(openDialog.fileName)
       '-- Add this new object to the frame
		meshBuilder(TheObjectNum).SetQuality(D3DRMRENDER_PHONG)	' possible- D3DRMRENDER_WIREFRAME, D3DRMRENDER_UNLITFLAT, D3DRMRENDER_FLAT, D3DRMRENDER_GOURAUD, D3DRMRENDER_PHONG 
		'meshBuilder(1).SetRGB(R#, G#, B#) 						'Set object's color 3 
		'meshBuilder(TheObjectNum).SetRGBA(1, 1, 1, 1)		' Add color w/alphablending  R, G, B,  Ascale from 0 to 1.0
		meshFrame.addVisual(meshBuilder(TheObjectNum))
    END IF
END SUB


SUB textureButtonClick(sender AS QBUTTON)
    DIM openDialog AS QOPENDIALOG

    openDialog.filter = "*.bmp (Bitmap files)|*.bmp"
    IF openDialog.execute THEN
        textureImage.BMP = openDialog.fileName
        meshBuilder(TheObjectNum).loadTexture(openDialog.fileName)
        dxScreen.createWrap(wrapType, 0,0,0, 0,0,1, 0,1,0, 0,0, 1,1, wrap)'args-[1,2,3] wrap origin, [4,5,6] z-axis vector, [7,8,9] y-axis vector, [10,11] and [12,13] origin and scale factor of texture
        wrap.apply(meshBuilder(TheObjectNum))
    END IF
END SUB


SUB upButtonMouseDown(button%, x%, y%, shift%, sender AS QBUTTON)
    DEFSNG T!

    T! = TIMER
    IF button% = 0 THEN
        sender.tabOrder = 0
        DO
            IF sender.hint = "up" THEN
                INC(frameView)
            ELSE
                DEC(frameView)
            END IF
            meshFrame.setPosition(0, 0, frameView)
            doEvents
            dxTimerExpired
        LOOP UNTIL sender.tabOrder = 1
    END IF
END SUB

SUB upButtonMouseUp(button%, x%, y%, shift%, sender AS QBUTTON)
    IF button% = 0 THEN
        sender.tabOrder = 1
    END IF
END SUB


SUB rotateButtonClick(sender AS QBUTTON)
    meshFrame.setRotation(VAL(rotateEditX.text), _
                          VAL(rotateEditY.text), _
                          VAL(rotateEditZ.text), _
                          VAL(rotateEditAngle.text)/10)
END SUB


SUB rotateStopButtonClick(sender AS QBUTTON)
    meshFrame.setRotation(0, 0, 0, 0)
END SUB

SUB ChangeZoomFactor (TheSelectedObjectNum as integer)
	'meshBuilder(TheObjectNum).Scale(X#,Y#,Z#) 
END SUB

SUB TranslateMoveMeshs (TheSelectedObjectNum as integer)
	'meshBuilder(TheObjectNum).Translate(TX#, TY#, TZ#) 
END SUB

SUB ChangeAlphaBlend (TheSelectedObjectNum as integer)
	meshBuilder(TheObjectNum).SetRGBA(1, 1, 1, 1)		' Add color w/alphablending  R, G, B,  Ascale from 0 to 1.0
	meshFrame.addVisual(meshBuilder(TheObjectNum))
END SUB


SUB ChangeRenderQuality (TheSelectedObjectNum as integer)
		meshBuilder(TheObjectNum).SetQuality(D3DRMRENDER_PHONG)	' possible- D3DRMRENDER_WIREFRAME, D3DRMRENDER_UNLITFLAT, D3DRMRENDER_FLAT, D3DRMRENDER_GOURAUD, D3DRMRENDER_PHONG 
		meshFrame.addVisual(meshBuilder(TheObjectNum))
END SUB



SUB dxInitialize(sender AS QDXSCREEN)
   DIM light AS QD3DLIGHT, ambient AS QD3DLIGHT
   DIM lightFrame AS QD3DFRAME

   dxScreen.createFrame(lightFrame)
   dxScreen.createFrame(meshFrame)

   dxScreen.createLightRGB(D3DRMLIGHT_DIRECTIONAL, 0.9, 0.9, 0.9, light)
   lightFrame.addLight(Light)

   dxScreen.createLightRGB(D3DRMLIGHT_AMBIENT, 0.1, 0.1, 0.1, ambient)
   dxScreen.addLight(ambient)

   meshFrame.setPosition(0, 0, frameView)

   dxScreen.setCameraPosition(0, 0, 0)
END SUB


SUB dxInitializeSurface(sender AS QDXSCREEN)
   dxScreen.setRenderMode(D3DRMRENDERMODE_BLENDEDTRANSPARENCY OR D3DRMRENDERMODE_SORTEDTRANSPARENCY)
END SUB


SUB dxTimerExpired
   dxScreen.forceUpdate(0,0,50,40)    '-- Update FPS text only
   meshFrame.Move(1)                   '-- whatever move parameters are set, this line does the animation
   dxScreen.render						'draw the scene on the back screen buffer
   dxScreen.textOut(10,10,"FPS: "+str$(dxTimer.frameRate), &HFFFFFF, -1)
   dxScreen.flip						'bring back buffer to screen by bitBlt
END SUB
