'---- PLY FILE READER AND RENDERER ----


'-- INITIALIZE PLY ARRAYS --

SUB INIT_PLY_ARRAYS

 MAXP=500

 'FOR READ VERTEX POINTS FROM PLY FILE
 DIM VX%(MAXP),VY%(MAXP),VZ%(MAXP)

 'NUMBER OF VERTEX POINTS FROM A FACE
 DIM FACEN%(MAXP,10)

 'VERTEX POINT START OF A FACE
 DIM VSTART%(MAXP,10)

 'COORDINATES X,Y AND SIZE OF A ELEMENT
 DIM PLY_X(10),PLY_Y(10),PLY_S(10)

 'RGB COLOR MULTIPLIER OF A ELEMENT
 DIM PLY_R(10),PLY_G(10),PLY_B(10)

 'COLOR DEPTH ADJUST
 DIM PLY_CP(10)

 'FOR CALCULATE DEPTH FROM THE Z AXYS
 DIM INTEGER DEPTH(MAXP,10)

 'TOTAL NUMBER OF VERTEX POINTS OF A ELEMENT
 DIM POL_VTX(10)

 'TOTAL NUMBER OF FACES OF A ELEMENT
 DIM EL_FAC(10)

 'TOTAL NUMBER OF VERTEX GROUP OF A ELEMENT
 DIM EL_VTX(10)

 'TEMPORARY VERTEX POINT TO BUILD A SINGLE FACE
 DIM FACEX%(30),FACEY%(30),FACEZ%(30)

 'LOAD THE VERTEX POINTS FROM ALL ELEMENTS
 DIM FACETX%(MAXP*3), FACETY%(MAXP*3), FACETZ%(MAXP*3)

END SUB


'---- READ PLY FILE AND WRITE ON ELEMENT "NUM" ----

SUB LOADPLY(PLY$,NUM,X,Y,Z)

 LOCAL T,CNT,CNT_VTX,CNT_FAC,PCNT,F$

 'OPEN PLY FILE ON FOLDER 
 OPEN "./PLY/"+PLY$ FOR INPUT AS #1 

 'RESET VERTEX AND FACE COUNTER
 CNT_VTX=0
 CNT_FAC=0
 POL_VTX(NUM)=0
 CNT=0

 PCNT=0
 'ADD NEW START POINT FROM PREVIOUS LOADED POLYGON
 IF NUM>0 THEN PCNT=POL_VTX(NUM-1)+1

 DO WHILE EOF(#1)=0
  INPUT #1,F$

  'GET VERTEXES
  IF CNT_VTX>0 THEN
   VX%(CNT)=(VAL(FIELD$(F$,1," "))+X)*100000000
   VY%(CNT)=(VAL(FIELD$(F$,2," "))+Y)*100000000
   VZ%(CNT)=(VAL(FIELD$(F$,3," "))+Z)*100000000

   '? F$;" : ";VX%(CNT);" - ";VY%(CNT);" - ";VZ%(CNT)

   CNT=CNT+1
   CNT_VTX=CNT_VTX-1
   IF CNT_VTX=0 THEN
    CNT_FAC = EL_FAC(NUM): CNT=0
   ENDIF
  ENDIF

  'GET FACES
  IF CNT_FAC>0 THEN
   'GET NUMBER OF POINTS OF A FACE
   FACEN%(CNT,NUM)=VAL(FIELD$(F$,1," "))

   'GET THE START POINT FOR EACH FACE (FOR DEPTH SORT)
   VSTART%(CNT,NUM)=POL_VTX(NUM)

   'ADD THE START POINT FROM PREVIOUS LOADED POLYGON
   IF NUM>0 THEN VSTART%(CNT,NUM)=VSTART%(CNT,NUM)+POL_VTX(NUM-1)+1

   'NUMBER OF POINTS
   POL_VTX(NUM)=POL_VTX(NUM)+FACEN%(CNT,NUM)

   'CREATE FACE
   FOR T=1 TO FACEN%(CNT,NUM)
    FACETX%(PCNT)=VX%(VAL(FIELD$(F$,T+1," ")))
    FACETY%(PCNT)=VY%(VAL(FIELD$(F$,T+1," ")))
    FACETZ%(PCNT)=VZ%(VAL(FIELD$(F$,T+1," ")))
    PCNT=PCNT+1
   NEXT T

   CNT=CNT+1
   CNT_FAC=CNT_FAC-1
  ENDIF

  'GET VERTEX AND FACES TOTAL ELEMENTS FOR READ FILE
  IF UCASE$(LEFT$(F$,14))="ELEMENT VERTEX" THEN EL_VTX(NUM)=VAL(MID$(F$,16,20))   
  IF UCASE$(LEFT$(F$,12))="ELEMENT FACE" THEN EL_FAC(NUM)=VAL(MID$(F$,14,20))

  'START THE COUNTER
  IF UCASE$(LEFT$(F$,12))="END_HEADER" THEN CNT_VTX=EL_VTX(NUM)+1: CNT=0
 LOOP

 '? "VERTEXES:";EL_VTX(NUM)
 '? "FACES:";EL_FAC(NUM)

 'CLOSE FILE
 CLOSE #1

END SUB


'-- MOVE AND SCALE ELEMENT "NUM" --

SUB PLY_MOVE(NUM,X,Y,SIZ)

 PLY_X(NUM)=X
 PLY_Y(NUM)=Y
 PLY_S(NUM)=SIZ/10000000

END SUB


'-- DEFINE ELEMENT "NUM" COLOR MULTIPLIER --
SUB PLY_RGB(NUM,R,G,B)
 
 PLY_R(NUM)=R
 PLY_G(NUM)=G
 PLY_B(NUM)=B

END SUB


'-- ADJUST DEPTH COLOR --
SUB PLY_ADJUST_COLOR(NUM,COLDEP)

 PLY_CP(NUM)=COLDEP

END SUB


'-- ROTATE POLYGON OF ELEMENT "NUM" --
'-- IN THIS VERSION DX AND DY ARE APPLIED TO TEMPORARY COORDINATES --

SUB PLY_ROT(NUM,DX,DY,W,APL)

 LOCAL SW,CNT,T,I,F,CX,SX,CY,SY,X%,Y%,Z%,RT,GT,BT

 'PRE-CALCULATE COS E SIN
 CX=COS(RAD(DX))
 SX=SIN(RAD(DX))
 CY=COS(RAD(DY))
 SY=SIN(RAD(DY))

 'ROTATE X AND Y AXYS
 VERT=0
 FOR F=0 TO EL_FAC(NUM)-1

  T=0
  DEPTH(F,NUM)=0

  FOR I=VSTART%(F,NUM) TO VSTART%(F,NUM)+FACEN%(F,NUM)-1

   X%=FACETX%(I)*PLY_S(NUM)
   Y%=FACETY%(I)*PLY_S(NUM)
   Z%=FACETZ%(I)*PLY_S(NUM)

   FACEX%(T)=X%*CX-Z%*SX + PLY_X(NUM)
   FACEZ%(T)=Z%*CX+X%*SX

   Z%=FACEZ%(T)

   FACEY%(T)=Y%*CY-Z%*SY + PLY_Y(NUM)
   FACEZ%(T)=Z%*CY+Y%*SY
   T=T+1

   DEPTH(F,NUM)=DEPTH(F,NUM)+INT(FACEZ%(T-1))

   'TRANSFORM THE MAIN POLYGON ARRAY
   IF APL=1 THEN
    FACETX%(I)=FACEX%(T-1)/PLY_S(NUM)
    FACETY%(I)=FACEY%(T-1)/PLY_S(NUM)
    FACETZ%(I)=FACEZ%(T-1)/PLY_S(NUM)
   ENDIF

  NEXT I
  LIMIT=LIMIT+(T-1)

  'GET CENTROID OF Z AXYS FROM FACE
  T=(DEPTH(F,NUM)/FACEN%(F,NUM))*0.5+PLY_CP(NUM)

  'DRAW POLYGON WITH COLOR DEPTH
  RT=T*PLY_R(NUM)
  IF RT>255 THEN RT=255
  IF RT<20 THEN RT=20
  GT=T*PLY_G(NUM)
  IF GT>255 THEN GT=255
  IF GT<20 THEN GT=20
  BT=T*PLY_B(NUM)
  IF BT>255 THEN BT=255
  IF BT<20 THEN BT=20
  I=RGB(RT,GT,BT)
 
  IF W=0 THEN
   POLYGON FACEN%(F,NUM),FACEX%(),FACEY%(),I,I
  ELSE
   POLYGON FACEN%(F,NUM),FACEX%(),FACEY%(),I
  ENDIF

  VERT=VERT+FACEN%(F,NUM)

 NEXT F

 'USE A SLOW BUBBLE SORT ALGORITHM TO CALCULATE DEPTH
 '* fix this later?
 OK=0: I=0: IF W=1 THEN OK=1
 DO WHILE OK=0

  OK=1
  FOR F=0 TO EL_FAC(NUM)-2
   IF DEPTH(F,NUM)>DEPTH(F+1,NUM) THEN
    OK=0:I=0
    SW=DEPTH(F,NUM):   DEPTH(F,NUM)=DEPTH(F+1,NUM):     DEPTH(F+1,NUM)=SW
    SW=FACEN%(F,NUM):  FACEN%(F,NUM)=FACEN%(F+1,NUM):   FACEN%(F+1,NUM)=SW
    SW=VSTART%(F,NUM): VSTART%(F,NUM)=VSTART%(F+1,NUM): VSTART%(F+1,NUM)=SW
   ENDIF
  NEXT F
  IF OK=0 THEN I=I+1: IF I>2 THEN OK=1
 LOOP

END SUB


'-- ROTATE POLYGON OF ELEMENT "NUM" - OPTIMIZED VERSION --
'-- IN THIS VERSION DX AND DY ARE APPLYED TO MAIN POLYGON DIRECTLY! --

SUB PLY_ROT_OPT(NUM,DX,DY,W,APL)

 LOCAL SW,CNT,T,I,F,CX,SX,CY,SY,X%,Y%,Z%,RT,GT,BT

 'PRE-CALCULATE COS E SIN
 CX=COS(RAD(DX))
 SX=SIN(RAD(DX))
 CY=COS(RAD(DY))
 SY=SIN(RAD(DY))

 'ROTATE X AND Y AXYS AND STORE
 FOR F=0 TO EL_FAC(NUM)-1

  DEPTH(F,NUM)=0

  FOR I=VSTART%(F,NUM) TO VSTART%(F,NUM)+FACEN%(F,NUM)-1

   X%=FACETX%(I)
   Y%=FACETY%(I)
   Z%=FACETZ%(I)

   FACETX%(I)=X%*CX-Z%*SX
   FACETZ%(I)=Z%*CX+X%*SX

   Z%=FACETZ%(I)

   FACETY%(I)=Y%*CY-Z%*SY
   FACETZ%(I)=Z%*CY+Y%*SY

   DEPTH(F,NUM)=DEPTH(F,NUM)+FACETZ%(I)

  NEXT I

 NEXT F
 
 'USE A SLOW BUBBLE SORT ALGORITHM TO CALCULATE DEPTH
 '* fix this later?
 OK=0: I=0: IF W=1 THEN OK=1
 DO WHILE OK=0
  OK=1
  FOR F=0 TO EL_FAC(NUM)-2
   IF DEPTH(F,NUM)>DEPTH(F+1,NUM) THEN
    OK=0:I=0
    SW=DEPTH(F,NUM):   DEPTH(F,NUM)=DEPTH(F+1,NUM):     DEPTH(F+1,NUM)=SW
    SW=FACEN%(F,NUM):  FACEN%(F,NUM)=FACEN%(F+1,NUM):   FACEN%(F+1,NUM)=SW
    SW=VSTART%(F,NUM): VSTART%(F,NUM)=VSTART%(F+1,NUM): VSTART%(F+1,NUM)=SW
   ENDIF
  NEXT F
  IF OK=0 THEN I=I+1: IF I>2 THEN OK=1
 LOOP

 'DRAW POLYGONS
 FOR F=0 TO EL_FAC(NUM)-1

  T=0
  FOR I=VSTART%(F,NUM) TO VSTART%(F,NUM)+FACEN%(F,NUM)-1
   FACEX%(T)=FACETX%(I)*PLY_S(NUM) + PLY_X(NUM)
   FACEY%(T)=FACETY%(I)*PLY_S(NUM) + PLY_Y(NUM)
   T=T+1
  NEXT I

   'GET CENTROID OF Z AXYS FROM FACE
   T=DEPTH(F,NUM)/FACEN%(F,NUM)/10000000+PLY_CP(NUM)

   'DRAW POLYGON WITH COLOR DEPTH
   RT=T*PLY_R(NUM)
   IF RT>255 THEN RT=255
   IF RT<20 THEN RT=20
   GT=T*PLY_G(NUM)
   IF GT>255 THEN GT=255
   IF GT<20 THEN GT=20
   BT=T*PLY_B(NUM)
   IF BT>255 THEN BT=255
   IF BT<20 THEN BT=20
   I=RGB(RT,GT,BT)

  IF W=0 THEN
   POLYGON FACEN%(F,NUM),FACEX%(),FACEY%(),I,I
  ELSE
   POLYGON FACEN%(F,NUM),FACEX%(),FACEY%(),I
  ENDIF

 NEXT F

END SUB



'-- ROTATE POLYGON OF ELEMENT "NUM" - SHADOW 
'-- IN THIS VERSION DX AND DY ARE APPLYED TO MAIN POLYGON DIRECTLY! --

SUB PLY_SHADOW(NUM,DX,DY,CO)

 LOCAL SW,CNT,T,I,F,CX,SX,CY,SY,X%,Y%,Z%,RT,GT,BT

 'PRE-CALCULATE COS E SIN
 CX=COS(RAD(DX))
 SX=SIN(RAD(DX))
 CY=COS(RAD(DY))
 SY=SIN(RAD(DY))

 'ROTATE X AND Y AXYS AND STORE
 FOR F=0 TO EL_FAC(NUM)-1

  DEPTH(F,NUM)=0

  FOR I=VSTART%(F,NUM) TO VSTART%(F,NUM)+FACEN%(F,NUM)-1

   X%=FACETX%(I)
   Y%=FACETY%(I)
   Z%=FACETZ%(I)

   FACETX%(I)=X%*CX-Z%*SX
   FACETZ%(I)=Z%*CX+X%*SX

   Z%=FACETZ%(I)

   FACETY%(I)=Y%*CY-Z%*SY
   FACETZ%(I)=Z%*CY+Y%*SY

   DEPTH(F,NUM)=DEPTH(F,NUM)+FACETZ%(I)

  NEXT I

 NEXT F
 
 'DRAW POLYGONS
 FOR F=0 TO EL_FAC(NUM)-1

  T=0
  FOR I=VSTART%(F,NUM) TO VSTART%(F,NUM)+FACEN%(F,NUM)-1
   FACEX%(T)=FACETX%(I)*PLY_S(NUM) + PLY_X(NUM)
   FACEY%(T)=FACETY%(I)*PLY_S(NUM) + PLY_Y(NUM)
   T=T+1
  NEXT I

  POLYGON FACEN%(F,NUM),FACEX%(),FACEY%(),CO,CO

 NEXT F

END SUB


' -- ONLY A TEST TO USE IT AS A BAS FILE --

SUB DEMO_PLY_TEST

 MODE 2,16: CLS: PAUSE(2000)

 X=0: Y=0
 'LOADPLY("ARWING SNES.PLY",0)
 LOADPLY("X-MINI.PLY",0,-1,0,-1)
 PLY_ADJUST_COLOR(0,50)
 PLY_RGB(0,2,2,6)

 PLAY MODFILE "./ASSETS/flow1.mod",22050

 TIMENOW=Timer: DIST=0

 DO WHILE 1=1
  PAGE WRITE 1
  BOX 0,0,MM.HRES,MM.VRES,0,,RGB(0,0,0)
  DIST=DIST+0.5: IF DIST>3 THEN DIST=3
  PLY_MOVE(0,MM.HRES/2,MM.VRES/2,DIST)
  PLY_ROT(0,I+X+90,Y-90,0)
  I=I+8
  X=COS(RAD(I))*90:Y=SIN(RAD(I))*90

  FPS=1000\(Timer-TIMENOW): TIMENOW=Timer
  print@(0,0) FPS 

  PAGE COPY 1 TO 0,I
 LOOP

END SUB

'DEMO_PLY_TEST

