#-----------------------------------------------------------------------
#                 Primitive tsxPython sample script
#                         Wind (flip book)
# 
# $Id: book1_22.py 41 2019-03-18 17:10:18Z 3DfromNULL $
#-----------------------------------------------------------------------
import ptsxpy as p
import ptsxgp
import math

if tscode >= 60:
    p.SceneNew()

p.AnimSetActiveTime( 0.0 )

#--------------------
# Create a skeleton
#--------------------
def create1skel( pskel, ploc, ptabterm, ptab_a ):
    pskel1wk  = ptsxgp.alloc_long( 1 )
    pjoint1wk = ptsxgp.alloc_long( 1 )
    pBone1wk  = ptsxgp.alloc_long( 1 )
    pBone2wk  = ptsxgp.alloc_long( 1 )
    loc1 = Vec3f( 0., 0., 1. )
    p.SkeletonCreate( pskel1wk, pjoint1wk, e_tsxJOINT_HINGE, \
     loc1.p, pBone1wk, pBone2wk )
    skel1 = ptsxgp.loadptr( pskel1wk )
    p.SceneAddObject( skel1, 0 )
    # The created skeleton consists of two vertical bones. These bone are
    # connected by a hinge type joint. Higher bone, pBone2, is pinned by a
    # nail. Lower bone, pBone1, can revolve around the joint.
    #
    # Add new joints (and bones) below the last movable bone, one after
    # another.
    pjoint2wk = ptsxgp.alloc_long( 1 )
    pBone3wk  = ptsxgp.alloc_long( 1 )
    # The first movable bone is bone1 for tS4, but is bone 2 for tS5, tS6.
    if tscode == 43:
        lastbone = ptsxgp.loadptr( pBone1wk )
    else:
        lastbone = ptsxgp.loadptr( pBone2wk )
    nbone = 14
    loc2 = Vec3f( 0., 0., 0. )
    i_for_tab1 = int( nbone * 0.2 )
    print( "i_for_tab1=", i_for_tab1  )
    for i in range(nbone):
        loc2.set_z( 0. - i )
        ###p.SkeletonAddBranch( skel1, pjoint2, e_tsxJOINT_HINGE, loc2.p, lastbone, pBone3 )
        p.SkeletonAddBranch( skel1, pjoint2wk, e_tsxJOINT_HINGE, loc2.p, lastbone, pBone3wk )
        if i == i_for_tab1:
            ###ptab_a[ 0 ] = pBone3[ 0 ]
            ptab_a[ 0 ] = ptsxgp.loadptr( pBone3wk )
        #if tscode != 43  and \
        #   i < nbone - 1:
        #    # Don't replace lastbone at the end of loop
        #    lastbone = pBone3[ 0 ]
        ###lastbone = pBone3[ 0 ]
        lastbone = ptsxgp.loadptr( pBone3wk )
    # Remove unnecessary bone
    #if tscode != 43:
    #    p.IKgroupDeleteJoint( skel1, pjoint2[ 0 ] );
    ptabterm[ 0 ] = lastbone
    p.GNodeDraw( skel1 )
    # Each bone bends (rotates) along with x-axis of the joints.
    #
    # Rotate the skeleton 180 degree.
    ax1 = Vec3f( 1., 0., 0. )
    p.GNodeRotate( skel1, loc1.p, ax1.p, 2 * pi_half, e_tsxModelFrame )
    # At this time, the skeleton's length is 3.5.  Scale it down.
    scale1 = Vec3f( 0.3, 0.3, 0.3 )
    p.GNodeScale( skel1, scale1.p, e_tsxModelFrame )
    # Move the skeleton lower
    loc1 = Vec3f( ploc.x(), ploc.y(), ploc.z() - 0.1 )
    p.GNodeSetLocation( skel1, loc1.p )
    # Draw it
    p.GNodeDraw( skel1 )
    pskel[ 0 ] = skel1

#---------------------------------------------------------------
# Create a thin cube as a sheet. It is thin but has thickness.
#---------------------------------------------------------------
def create1sheet( skel1, ploc1, sheet1, imgnum ):
    sh1szx = 3.
    sh1szy = 4.
    sh1szz = 0.01
    sheet1[ 0 ] = p.CreateCube( 1, sh1szx, sh1szy, sh1szz )
    p.SceneAddObject( sheet1[ 0 ], 0 )
    # In order to quad-divide ONLY top and bottom faces of the sheet (cube),
    # search for the two faces in all (six) faces.
    # number of the vertex of the sheet (should be 8)
    nvert = p.PolyhGetNbrVxs( sheet1[ 0 ] )
    #print( "nvert=",nvert )
    # vertex array
    vertary = p.PolyhGetVxArray( sheet1[ 0 ] )
    # number of faces (should be 6)
    nface = p.PolyhGetNbrFaces( sheet1[ 0 ] )
    #print( "nface=", nface )
    # Search top and bottom faces
    faceary = p.PolyhGetFaceptrArray( sheet1[ 0 ] )
    for i in range( nface ):
        wkp = ptsxgp.loadptr( faceary + 4 * i )
        fap1 = FaceArray_p( wkp )
        #print( "fap1=", fap1.prt() )
        nvertinface = fap1.nbrVxs()	# Number of vertex ia the face. (should be 4 for a rectangle)
        #print( "nvertinface=", nvertinface )
        #print( "fap1.pFVxs()=0x%08x" % fap1.pFVxs() )
        found = 1
        for j in range( nvertinface ):
            fvp1 = FaceVxArray_p( fap1.pFVxs() + sizeof_CtsxFaceVx * j )
            #print( "fvp1=", fvp1.prt() )
            vx1 = Vec3f_p( vertary + sizeof_CtsxVector3f * fvp1.vix() )
            #print( "i=", i, ", j=", j, ", vx1=", vx1.prt() )
            if vx1.z() < 0:
                found = 0		# not the top face
                break
        if found:
            topfaceidx = i
        found = 1
        for j in range( nvertinface ):
            fvp1 = FaceVxArray_p( fap1.pFVxs() + sizeof_CtsxFaceVx * j )
            vx1 = Vec3f_p( vertary + sizeof_CtsxVector3f * fvp1.vix() )
            if vx1.z() > 0:
                found = 0		# not the bottom face
                break
        if found:
            btmfaceidx = i
    #print( "top=", topfaceidx, "btm=", btmfaceidx )
    ## Select the top and bottom faces only
    ia1 = IntArray( 2 )
    ia1[ 0 ] = topfaceidx
    ia1[ 1 ] = btmfaceidx
    p.PolyhSelectFaces( sheet1[ 0 ], 2, ia1.p )
    #p.GNodeDraw( sheet1[ 0 ] )
    # Quad-divide only the two faces.
    p.PointsQuadDiv()
    p.PointsQuadDiv()
    p.PointsQuadDiv()
    p.PointsQuadDiv()
    # Search the indices to be painted with ech texture image in the
    # upper face, and add them to a list
    nvert = p.PolyhGetNbrVxs( sheet1[ 0 ] )
    #print( "nvert=",nvert )
    vertary = p.PolyhGetVxArray( sheet1[ 0 ] )
    dvdnface = p.PolyhGetNbrFaces( sheet1[ 0 ] )
    #print( "dvdnface=", dvdnface )
    faceary = p.PolyhGetFaceptrArray( sheet1[ 0 ] )
    ufaceidxs = []
    ufacecnt = 0
    for i in range( dvdnface ):
        wkp = ptsxgp.loadptr( faceary + 4 * i )
        fap1 = FaceArray_p( wkp )
        fvp0 = FaceVxArray_p( fap1.pFVxs() + sizeof_CtsxFaceVx * 0 )
        fvp2 = FaceVxArray_p( fap1.pFVxs() + sizeof_CtsxFaceVx * 2 )
        # vx1, vx2: opposite vertex of the divided small face
        vx1 = Vec3f_p( vertary + sizeof_CtsxVector3f * fvp0.vix() )
        vx2 = Vec3f_p( vertary + sizeof_CtsxVector3f * fvp2.vix() )
        # Is the divided small face on upper face and within 90% of
        # width and 90% of height?
        if vx1.z() > 0 and \
           vx2.z() > 0 and \
           abs( vx1.x() ) <= sh1szx * .45 and \
           abs( vx2.x() ) <= sh1szx * .45 and \
           abs( vx1.y() ) <= sh1szy * .45 and \
           abs( vx2.y() ) <= sh1szy * .45:
            # Add the face index to a list
            ufaceidxs.append( i )
            ufacecnt = ufacecnt + 1
    #print( "ufacecnt=", ufacecnt )
    p.GNodeDraw( sheet1[ 0 ] )
    # Rotate the sheet 90 degree.
    ax1 = Vec3f( 1., 0., 0. )
    p.GNodeRotate( sheet1[ 0 ], ploc1.p, ax1.p, pi_half, e_tsxModelFrame )
    #print( "ploc1=", ploc1 )
    # Move the sheet to upper
    loc1 = Vec3f( ploc1.x(), ploc1.y(), ploc1.z() + 2.0 )
    p.GNodeSetLocation( sheet1[ 0 ], loc1.p )
    #---------------------------------------------------------------
    # Attach the sheet as a skin to the skeleton.
    #---------------------------------------------------------------
    p.SkeletonAttachSkin( skel1, sheet1[ 0 ] )
    #--------------------------------
    # Create and initiate Material
    #--------------------------------
    #print( "tsxTEXTURE_IMAGE=", tsxTEXTURE_IMAGE )
    mtrl1wk = ptsxgp.alloc_long( 1 )
    p.MaterialCreate( mtrl1wk )
    mtrl1 = ptsxgp.loadptr( mtrl1wk )
    p.MaterialSetTextureType( mtrl1, tsxTEXTURE_IMAGE )
    # (If you use SetMaterialShaderByName() and specify the shader name in
    # non-English language, you need describe the code "coding=xxxx" as a
    # comment line at the beginning of this script.
    #p.SetMaterialShaderByName( mtrl1, "shadernamehere" )
    shdr1 = p.ShaderGetFirst()
    nams = ""
    while shdr1 != NULL:
        if p.CheckAbort() == e_tsxTRUE:
            quit = 1
            print( "aborted." )
            break
        ########################################
        # You may remove "#" from following 4 lines for debug. However,
        # if you use tS Non-English version, the .ShaderGetName() may
        # cause a unicode decode error with the characters
        # for "plain color" or "texture map".
        ########################################
        #nam1 = p.ShaderGetName( shdr1 )
        #print( "nam1=", nam1 )  #.encode('unicode-escape')
        #if nam1 != "":
        #    nams = nams + "," + nam1

        # It may be better to search by not the name but by the id
        #  with CSHID_C_CALTEXTURE.
        # (see the sample in SDK, "setlayeredtexture.cpp")
        shdrid1 = p.ShaderGetID( shdr1 )
        if shdrid1 == CSHID_C_CALTEXTURE:
            print( "shdrid1=%s" % ( shdrid1 ) )
            break
        shdr1 = p.ShaderGetNext( shdr1 )
    #print( "nams=[%s]" % ( nams ) )
    #----
    # Setting materials
    # (according to the procedure of setmaterial.cpp in SDK)
    #
    # Note: The setting texture file name followed by MaterialSetActive()
    # and PolyhInitializeMaterials(), or PolyhPaint() cannot paint well.
    # To verify this, we must restart tS or reset materials before the test.
    #p.SetMaterialShader( mtrl1, shdrid1 )
    #p.MaterialSetTextureFilename( mtrl1, imgdir + "Fdfv0020.jpg" )
    #p.MaterialFixColor( mtrl1 )
    #----
    pInfo = p.ShaderInfoCreate();
    p.ShaderInfoSetShader( pInfo, shdr1 );
    #print( "(1)" )
    nshparam = p.ShaderInfoGetParametersNumber( pInfo );
    paraname1 = ptsxgp.alloc_long( 1 )
    #print( "(2)" )
    for i in range( nshparam ):
        paramID = p.ShaderInfoGetParameterID( pInfo, i );
        #print( "i=", i, ", paramID=", paramID )
        if paramID == CSPID_C_CALTEXTURE_FILENAME:
            #print( "(a) CSPID_C_CALTEXTURE_FILENAME" )
            pVal = p.ShaderInfoGetParameterValue( pInfo, i );
            #print( "(a2)" )
            p.ParameterValueGetData( pVal, paraname1 );
            #print( "pVal=", pVal )
            #print( "paraname1=", paraname1 )
            #ptsxgp.mkstr200( imgdir + "testa" + "%04d" % ( imgnum ) + ".jpg", wkcharp1, 0 )
            wks1 = imgdir + "sheep_a" + "%04d" % ( imgnum ) + ".jpg"
            #print( "wkcharp1[0]=",  wkcharp1[ 0 ] )
            print( "wks1=",  wks1 )
            s1 = String( wks1 )
            p.ParameterValueSetData( pVal, s1.p )
        elif paramID == CSPID_C_CALTEXTURE_REPTS_U:   # U repetitions
            #print( "(b) CSPID_C_CALTEXTURE_REPTS_U" )
            pVal = p.ShaderInfoGetParameterValue( pInfo, i );
            #ptsxgp.mkfloatp( 4.4, wkfloatp1, 0 )
            wkf1 = Float( 4.4 )
            p.ParameterValueSetData( pVal, wkf1.p );
        elif paramID == CSPID_C_CALTEXTURE_REPTS_V:   # V repetitions
            #print( "(c) CSPID_C_CALTEXTURE_REPTS_V" )
            pVal = p.ShaderInfoGetParameterValue( pInfo, i );
            #ptsxgp.mkfloatp( 3.2, wkfloatp1, 0 )
            wkf1 = Float( 3.2 )
            p.ParameterValueSetData( pVal, wkf1.p );
        elif paramID == CSPID_C_CALTEXTURE_OFFSET_U:   # U offset
            #print( "(d) CSPID_C_CALTEXTURE_OFFSET_U" )
            pVal = p.ShaderInfoGetParameterValue( pInfo, i );
            #ptsxgp.mkfloatp( 0.14, wkfloatp1, 0 ) # inc to move pict right
            wkf1 = Float( 0.14 ) # inc to move pict right
            p.ParameterValueSetData( pVal, wkf1.p );
        elif paramID == CSPID_C_CALTEXTURE_OFFSET_V:   # V offsest
            #print( "(e) CSPID_C_CALTEXTURE_OFFSET_V" )
            pVal = p.ShaderInfoGetParameterValue( pInfo, i );
            #ptsxgp.mkfloatp( -0.05, wkfloatp1, 0 )
            wkf1 = Float( -0.05 )
            p.ParameterValueSetData( pVal, wkf1.p );
    p.MaterialSetShaderInfo( mtrl1, pInfo );
    p.MaterialFixColor( mtrl1 );
    p.MaterialSetFacetingType( mtrl1, tsxFACET_AUTO )
    p.ShaderInfoDestroy( pInfo );
    #-----
    # We want to select only upper faces divided and paint them here.
    #
    # Using the face ID of undivided upper faces may not be the right way
    # because the faces have already been divided. Tried and got the same
    # with the case of all-faces-paint. That's how it is for texture map?
    #ret = p.PolyhPaintFace( sheet1[ 0 ], topfaceidx , mtrl1 ,e_tsxTRUE )
    #print( "ret=", ret )
    #
    # We can select all divided upper faces, but there is no function to
    # paint the selected faces.
    #wkheap1 = p.Malloc( ufacecnt * 4 )   # allocate memory
    #print( "wkheap1=", wkheap1  )
    #print( "ufaceidxs[ 0 ]=", ufaceidxs[ 0 ] # indices of the upper faces got in the above sequence.
    #for i in range( ufacecnt ):
    #  ptsxgp.storeptr( wkheap1 + 4 * i, ufaceidxs[ i ] )
    #p.PolyhSelectFaces( sheet1[ 0 ], ufacecnt, wkheap1 ) # select faces
    #p.Free( wkheap1 )                    # free the allocated memory
    #
    # PointsPaint() and PointsUVMap()
    # These are not described in the apiXX.doc and defined in header files.
    # Triese but nothing was painted. Are they for index paint?
    #p.MaterialSetActive( mtrl1 )
    #p.PointsPaint()
    #p.PointsUVMap()
    #
    # NPatchGetUVProjection()
    # There is a function to get UV, but it's for a NURBS patch and there
    # is not a function to set.
    #
    # p.PolyhPaint( sheet1[ 0 ], mtrl1 )
    # This paints all feces.
    #
    # Trying to paint each divided face.
    for i in range( ufacecnt ):
        p.PolyhPaintFace( sheet1[ 0 ], ufaceidxs[ i ], mtrl1 ,e_tsxTRUE )
    # Done! Each facet is painted as a component of a picture.
    #stop #############
    p.MaterialDestroy( mtrl1 );
    p.AllViewRefreshSelObject();
    #
    #print( "is shdr box null=", p.MaterialIsShaderBoxNull( mtrl1 ) )
    #print( "is shdr box valid=", p.MaterialIsShaderBoxValid( mtrl1 ) )
    #p.MaterialSetActive( mtrl1 )
    #p.PolyhInitializeMaterials( sheet1[ 0 ] )
    ##p.PolyhPaint( sheet1[ 0 ], mtrl1 )
    #p.GNodeDraw( sheet1[ 0 ] )
    #
    # It would be wrong to use topfaceidx because the face has been already
    # divided.
    #ret = p.PolyhPaintFace( sheet1[ 0 ], topfaceidx , mtrl1 ,e_tsxTRUE )
    #print( "ret=", ret )
    print( "e_tsxFALSE=", e_tsxFALSE )

#---------------------------------------------------------------
# Pull free side of the clone sheet to the initial position.
#---------------------------------------------------------------
def pullfreeside( skel1, tm1, tabterm1, sheet1, tab_a1, prevsheet ):
    # Pull the bone to the initial position.
    pltbl1 = (
     ( 0.0, 0.0,  0.0,    0.0, -0.5,  -0.00,  tabterm1 ),
     ( 0.0, 0.0,  0.0,    0.0, -0.5,   0.01,  tabterm1 ),
     ( 0.0, 0.0,  0.0,    0.0, -1.1,  -0.19,  tabterm1 ),
     ( 0.0, 0.0,  0.0,    0.0, -1.1,  -0.35,  tabterm1 ),
     ( 0.0, 0.0,  0.0,    0.0, -1.5,  -0.230, tabterm1 ) )
    for i in range( len( pltbl1 ) ):
      wk = pltbl1[ i ]
      ofst1 = Vec3f( wk[ 0 ], wk[ 1 ], wk[ 2 ] )
      move1 = Vec3f( wk[ 3 ], wk[ 4 ], sign1 * wk[ 5 ] )
      p.IKgroupTranslateEffector( \
       skel1, wk[ 6 ], ofst1.p, move1.p, e_tsxWorldFrame )
    #----------
    # Setup animation path of sheet1 before pulling the bone
    # and record the 1st keyframe of sheet1
    #----------
    p.SobjCreateScript( skel1 )
    print( "tm1[ 0 ]=", tm1[ 0 ] )
    p.AnimSetActiveTime( tm1[ 0 ] )
    p.GNodeDraw( sheet1 )
    p.SobjSetFrame( skel1, e_tsxKFT_MOVE )
    #----------
    # Record 2nd keyframe for sheet1
    #----------
    tm1[ 0 ] = tm1[ 0 ] + 5
    p.AnimSetActiveTime( tm1[ 0 ] )
    # Pull the bone
    pltbl1 = (
     ( 0.0,   0.0,  0.0,    0.0,   0.00,   0.20, tabterm1 ),
     ( 0.0,   0.0,  0.0,    0.0,   0.00,   0.30, tab_a1   ),
     ( 0.0,   0.0,  0.0,    0.0,   0.00,  -2.10, tabterm1 ),
     ( 0.0,   0.0,  0.0,    0.0,   0.40,   0.00, tab_a1   ),
     ( 0.0,   0.0,  0.0,    0.0,   -0.20, -0.20, tabterm1 ) )
    for i in range( len( pltbl1 ) ):
      wk = pltbl1[ i ]
      ofst1 = Vec3f( wk[ 0 ], wk[ 1 ], wk[ 2 ] )
      move1 = Vec3f( wk[ 3 ], wk[ 4 ], sign1 * wk[ 5 ] )
      p.IKgroupTranslateEffector( \
       skel1, wk[ 6 ], ofst1.p, move1.p, e_tsxWorldFrame )
    # Record that
    p.SobjSetFrame( skel1, e_tsxKFT_MOVE )
    #----------
    # Record 3rd keyframe for sheet1
    #----------
    tm1[ 0 ] = tm1[ 0 ] + 5
    p.AnimSetActiveTime( tm1[ 0 ] )
    # Pull the bone
    pltbl1 = (
     ( 0.0,   0.0,  0.0,    0.0,   0.30,  0.00, tab_a1   ),
     ( 0.0,   0.0,  0.0,    0.0,   0.60,  0.00, tabterm1 ),
     ( 0.0,   0.0,  0.0,    0.0,   0.40,  0.00, tabterm1 ),
     ( 0.0,   0.0,  0.0,    0.0,   0.90,  0.00, tabterm1 ),
     ( 0.0,   0.0,  0.0,    0.0,   0.40, -0.10, tabterm1 ),
     ( 0.0,   0.0,  0.0,    0.0,   0.50,  0.10, tabterm1 ),
     ( 0.0,   0.0,  0.0,    0.0,   0.50,  0.10, tabterm1 ) )
    for i in range( len( pltbl1 ) ):
      wk = pltbl1[ i ]
      ofst1 = Vec3f( wk[ 0 ], wk[ 1 ], wk[ 2 ] )
      move1 = Vec3f( wk[ 3 ], wk[ 4 ], sign1 * wk[ 5 ] )
      p.IKgroupTranslateEffector( \
       skel1, wk[ 6 ], ofst1.p, move1.p, e_tsxWorldFrame )
    # Make the previous sheet invisible before pulling the last sheet
    # to avoid visual glitches. 
    if prevsheet != 0:
        p.MNodeSetInvisible( prevsheet)
    # Do the last pull for the sheet
    ofst1 = Vec3f( 0.0,   0.0,  0.0 )
    move1 = Vec3f( 0.0,   0.10, -0.03 )
    p.IKgroupTranslateEffector( \
     skel1, tab_a1, ofst1.p, move1.p, e_tsxWorldFrame )
    # Record that
    p.SobjSetFrame( skel1, e_tsxKFT_MOVE )
    # Draw the sheet
    p.GNodeDraw( sheet1 )


#--------
# main
#--------
# definition of constances
imgdir = ptsxgp.scrdir() + "\\imgs\\"
print( "imgdir=", imgdir )
pi_half = math.pi / 2.

nsheet = 64

tm0 = [ 0.0 ]
skel0 = [ 0 ]
ploc0 = Vec3f( 2.0, 7.0, 0.0 )
tabterm0 = [ 0 ]
sheet0 = [ 0 ]
tab_a0 = [ 0 ]
prevsheet = 0
sign1 = -1 if tscode == 43 else 1
for i in range( nsheet ):
    if p.CheckAbort() == e_tsxTRUE:
        print( "aborted." )
        break
    create1skel( skel0, ploc0, tabterm0, tab_a0 )
    create1sheet( skel0[ 0 ], ploc0, sheet0, i )
    pullfreeside(  skel0[ 0 ], tm0, tabterm0[ 0 ], \
                 sheet0[ 0 ], tab_a0[ 0 ], prevsheet )
    prevsheet = sheet0[ 0 ]
print( "tm0=", tm0 )

print( "Push \"Play\" button to start the generated animation." )

#stop ####

