'SIMPLE 3D TUTORIAL.
'===================
'    NOTES   : ORIGINALLY FOR DOCTOR'S HELPSITE BUT
'              PLEASE DISTRUBITE FREELY.
'    AUTHOR  : NICK SIMPSON (AKA SHOCKWAVE).
'    ALL CODE: NICK SIMPSON (AKA SHOCKWAVE).
'    CATEGORY: PUBLIC DOMAIN, FREEWARE.
'---------------------------------------------------------
'DISTRIBUTION: THIS FILE MAY BE FREELY UPLOADED ANYWHERE
'              PROVIDED THAT ALL IT'S CONTENT REMAINS
'              INTACT.
'---------------------------------------------------------
'REQUIREMENTS: THIS SIMPLE HELP FILE IS AIMED AT THE
'              INTERMEDIATE LEVEL YABASIC USER, TO USE 
'              THIS HELPFILE, YOU WILL NEED TO HAVE AN
'              UNDERSTANDING OF THE FOLLOWING;
'                     ARRAYS.
'                     DATA.
'                     VARIABLES.
'                     LOOPS.
'                     READING THE CONTROLLER.
'                     SIMPLE GRAPHICS.
'
'IF YOU DON'T UNDERSTAND ANY OF THE ABOVE, SEEK HELP FROM:
'
' WWW.YABASIC.CO.UK (FORUM PAGE).
' WWW.PS2-YABASIC.CO.UK
'
'     QUERIES: IF YOU HAVE ANY QUESTIONS ABOUT THIS HELP
'              FILE, PLEASE EITHER POST YOUR QUERY ON THE
'              YABASIC FORUM (PREFERRED) OR EMAIL:
'              SHOCKWAVE@PS2-YABASIC.CO.UK (SLOW RESPONSE)
'---------------------------------------------------------
'
' INDEX;
' ======
'
' 1: WHAT WE ARE GOING TO DO.
' 2: DEFINING OBJECTS.
' 3: PERSPECTIVE.
' 4: MOVING OBJECTS AROUND.
' 5: SCALE.
' 6: DRAWING THE OBJECT.
' 7: RECAP.
' 8: PROGRAM AND NOTES.
' 9: NEGATIVE VALUES.
'10: THE FINISHED PROGRAM.
'---------------------------------------------------------
' 1: WHAT WE ARE GOING TO DO.
' ===========================
' IN THIS TUTORIAL, WE ARE GOING TO INTRODUCE YOU TO THE
' CONCEPT OF CREATING A 3D SHAPE (A CUBE), DRAWING THE
' SHAPE ON A 2D SCREEN WITH PERSPECTIVE AND LINKING IT TO
' THE D-PAD SO THAT IT CAN BE MOVED AROUND THE SCREEN BY
' THE USER. WE ARE NOT GOING TO ROTATE THE OBJECT AS THIS
' IS A LITTLE MORE IN DEPTH TO WHAT WE ARE GOING TO DO 
' HERE.
'---------------------------------------------------------
' 2: DEFINING OBJECTS.
' ====================
' A TELEVISION SCREEN IS A FLAT OBJECT, IT HAS TWO AXIS,
' X AND Y OR HORIZONTAL AND VERTICAL. EVERY POINT ON THE
' TV SCREEN CAN BE REFERRED TO BY AN X AND Y CO-ORDINATE.
' YOU MAY TYPE;
' LINE 100,100 TO 300,400
' TO DRAW A LINE BETWEEN TWO PAIRS OF X AND Y COORDINATES.
' WE CAN'T CHANGE THIS, THERE'S NO WAY OF MAKING THE 
' SCREEN DEEP. WE CAN SIMULATE DEPTH THOUGH.
'
' A 3D OBJECT HAS THREE SETS OF CO-ORDINATES, X,Y AND Z
' Z IS THE DEPTH OF THE OBJECT.
' 3D OBJECTS ARE MADE UP OF POINTS (KNOWN AS VERTICES).
' ON A CUBE, THERE ARE EIGHT VERTICES, ONE FOR EACH CORNER
' THESE CAN BE REPRESENTED LIKE;
'
' (X)(Y)(Z)
' -1,-1, 1
'  1,-1, 1
'  1, 1, 1
' -1, 1, 1
' -1,-1,-1
'  1,-1,-1
'  1, 1,-1
' -1, 1,-1
' 
' YOU'LL NOTICE THAT SOME OF THE NUMBERS ARE NEGATIVE,THIS
' IS BECAUSE THE CUBE IS BEING DEFINED AROUND IT'S CENTER.
' MOST 3D OBJECTS ARE DEFINED THIS WAY. THIS IS BECAUSE 
' YOU WILL MOST PROBABLY WANT TO ROTATE IT AROUND IT'S
' CENTER AT SOME STAGE.
'
' WE NEED TO FIRST OF ALL, CREATE THE OBJECT AND THEN
' STORE IT SO THAT WE CAN MANIPULATE IT LATER.
' THE BEST WAY IN YABASIC IS WITH ARRAYS AND DATA.
' YOU'D DEFINE THE ARRAYS, CREATE THE DATA AND READ THE
' DATA INTO THE ARRAYS.. LIKE THIS;
'
' points=8
' dim x(points),y(points),z(points)
' for a=1 to points
'   read x(a),y(a),z(a)
' next a
' data -1,-1,1,1,-1,1,1,1,1,-1,1,1
' data -1,-1,-1,1,-1,-1,1,1,-1,-1,1,-1
'
' WHICH TAKES THOSE CO-ORDINATES AND STORES THEM IN THE
' RIGHT PLACE SO THAT WE CAN MESS ABOUT WITH THEM :O)
'---------------------------------------------------------
' 3: PERSPECTIVE.
' ===============
' OUR PROBLEM IS THAT FLAT TELEVISION SCREEN. THE CUBE IS
' THREE DIMENSIONAL, THE SCREEN ONLY HAS TWO DIMENSIONS.
' THEREFORE WE NEED TO BE ABLE TO SIMULATE THE THIRD (Z)
' AXIS. AFTER ALL, A PIECE OF PAPER IS TWO DIMENSIONAL AND
' IT'S PERFECTLY NORMAL TO DRAW PICTURES THAT APPEAR TO
' HAVE DEPTH, SO IT MUST BE POSSIBLE.
'
' TO DO THIS WE NEED TO TRANSFORM THE 3D IMAGE INTO A 2D
' ONE AND CALCULATE WHERE THE VERTICES NEED TO BE TO GIVE
' THE CUBE PERSPECTIVE.
'
' WE CAN SIMULATE PERSPECTIVE BY SIMPLY DIVIDING THE X AND
' Y CO-ORDINATES BY THIER RESPECTIVE Z CO-ORDINATES.
' IF WE HAVE A POINT:
' X=100, Y=100, Z=10
' AND THE WINDOW ORIGIN FOR THE SCREEN IS "CC" (CENTERED)
' WE COULD SAY:
' TX=X/Z
' TY=Y/Z
' FILL RECT TX,TY TO TX+1,TY+1
' THIS WOULD DRAW A DOT AT SCREEN POSITION 10,10 OR JUST
' ABOVE AND RIGHT OF THE SCREEN'S CENTER.
' IF WE DECREASE THE Z OF THE POINT TO 5 THEN WE'D GET A
' DOT THAT WAS CLOSER TO THE RIGHT CORNER OF THE SCREEN.
' THIS IS HOW A PERSPECTIVE TRANSFORMATION WORKS.
'
' WE WILL PERFORM THE PERSPECTIVE TRANSFORMATION ON ALL
' THE VERTICES (POINTS) OF THE CUBE TO GET AN IMAGE DRAWN
' IN CORRECT PERSPECTIVE.
'
'---------------------------------------------------------
'
'4: MOVING OBJECTS AROUND. 
'=========================
' WE ARE GOING TO LINK OUR CUBE TO THE DPAD SO THAT IT CAN
' BE MOVED AROUND THE SCREEN, ONE GOOD WAY OF DOING THIS
' IS TO HAVE 3 VARIABLES, LETS SAY;
' XP (X POSITION IN WORLD)
' YP (Y POSITION IN WORLD)
' ZP (Z POSITION IN WORLD)
' AND LINK THESE VARIABLES TO THE CONTROLLER AND THEN ADD
' THEM TO THE CO-ORDINATES OF THE OBJECT.
' LIKE SO;
'
' c=peek("port1")
' if and(c,32)<>0 xp=xp+.1 (RIGHT)
' if and(c,128)<>0 xp=xp-.1 (LEFT)
' if and(c,64)<>0 yp=yp+.1 (DOWN)
' if and(c,16)<>0 yp=yp-.1 (UP)
' if and(c,1024)<>0 zp=zp-.1 (L1)
' if and(c,2048)<>0 zp=zp+.1 (R1)
'
' AND THE PERSPECTIVE TRANSFORMATION THEN BECOMES; 
' 
' TX=(X+XP)/(Z+ZP)
' TY=(Y+YP)/(Z+ZP)
' 
' SIMPLE EH?
'
'---------------------------------------------------------
' 
' 5: SCALE. 
' ========= 
' WE ARE USING NUMBERS LIKE -1,1,0,1 ETC BECAUSE THEY ARE 
' EASY FOR US TO VISUALISE, IN PRACTICE THOUGH THEY WOULD
' PRODUCE SOME ODD LOOKING RESULTS LIKE HIDEOUSLY
' STRETCHED OBJECTS. THIS IS BECAUSE THE Z PART OF THE
' EQUATION IS NOT IN PROPORTION TO THE X AND Y. IT'S 
' FAIRLY SIMPLE TO GET AROUND AND WE CAN DO THIS BY HAVING
' A CONSTANT VARIABLE CALLED, LET'S SAY "SCALE" AND 
' MULTIPLYING THE WHOLE FORMULA BY IT LIKE;
' 
' TX=SCALE*((X+XP)/(Z+ZP))
' TY=SCALE*((Y+YP)/(Z+ZP))
'
' SCALE SHOULD BE A FAIRLY BIG NUMBER, LET'S SAY 1000 
' YOU SHOULD TWEAK THIS UNTIL IT LOOKS RIGHT.
' 
'---------------------------------------------------------
' 
' 6:DRAWING THE OBJECT. 
' =====================
'
' FROM THE ABOVE YOU SHOULD NOW HAVE THE KNOWLEDGE TO BE
' ABLE TO CREATE THE 8 CORNER POINTS OF A CUBE AND MOVE
' THEM AROUND THE SCREEN WITH A PERSPECTIVE TRANSFORMATION
' WHAT WE NEED TO DO NOW IS TO JOIN THE DOTS.
' IF WE USE LINES TO DO THIS WE'LL NEED TO DRAW 12 OF THEM
' TO MAKE THE CUBE AS THERE ARE 12 EDGES TO A CUBE.
' 
' WE NEED TO HAVE MORE STORAGE SPACE FOR THIS. WE'LL BE
' REFERING TO POINT NUMBERS AND AS EACH CONNECTION NEEDS
' TWO POINTS WE'LL NEED TO DEFINE AN ARRAY 24 CELLS BIG.
' 
' THIS IS BECAUSE THERE WILL BE 12 LINES AND EACH LINE
' NEEDS TWO CO-ORDINATE PAIRS, THE START AND FINISH.
'
'
' DIM CONNECTIONS (LINES*2)
' 
' AND INTO THIS WE WILL READ THE 24 POINT NUMBERS.
' 
' for a=1 to 24
'  read connections(a)
' next a
'
' 
' data 1,2
' data 2,3
' data 3,4
' data 4,1
' data 5,6
' data 6,7
' data 7,8
' data 8,5
' data 1,5
' data 2,6
' data 3,7
' data 4,8
' 
' THE DRAW ROUTINE WOULD LOOK SOMETHING LIKE THIS;
' 
' for a=1 to lines step 2
' line tx(connects(a)),ty(connects(a)) to tx(connects(a+1)),ty(connects(a+1))
' next a
'---------------------------------------------------------
' 7 RECAP.
' ========
' 
' SO LET'S SUMMARISE SO FAR AND DISCUSS SOME MISCELLANIOUS
' THINGS.
'
' *- WE ALWAYS DEFINE OUR OBJECTS AROUND THIER MIDDLE.
' *- WE GET PERSPECTIVE BY DIVIDING X AND Y BY Z.
' *- WE HAVE TO SIMULATE DEPTH TO TRANSFORM A REAL 3D
'    CO-ORDINATE INTO A 2D CO-ORDINATE.
' *- WE MAKE OBJECTS USEABLE BY MULTIPLYING BY A CONSTANT.
' *- WE MOVE OBJECTS AROUND BY CHANGING THIER OFFSETS.
'
' THE CODE WILL NEED TO; 
'
'1: OPEN A GRAPHICS SCREEN.
'2: DEFINE ARRAYS TO HOLD;
'   X,Y,Z CO-ORDINATES FOR EACH POINT.
'   TRANSFORMED X AND Y CO-ORDINATES.
'   INFORMATION TO SAY WHAT IS CONNECTED TO WHAT.
'3: HAVE X,Y,Z CO-ORDINATES FOR THE CUBE. 
'4: HAVE A LIST OF 24 CONECTION POINTS 
'   (2 FOR EACH LINE).
'5: DOUBLE BUFFER FOR SMOOTH DISPLAY. 
'6: DO PERSPECTIVE TRANSFORMATIONS ON THE ORIGINAL
'   CO-ORDINATES TAKING OFFSETS INTO ACCOUNT.
'   AND STORE THE TRANSFORMED POINTS TO USE FOR DRAWING.
'7: DRAW THE OBJECT USING THE TRANSFORMED CO-ORDINATES
'   AND CONNECTION DATA.
'8: READ THE CONTROLER TO ALLOW THE OBJECT TO MOVE AROUND.
' 
' IF YOU HAVE UNDERSTOOD THE TUTORIAL YOU SHOULD ALMOST BE
' ABLE TO CODE THE ROUTINE YOURSELF NOW. HOWEVER I HAVE
' WRITTEN IT FOR YOU SO THAT YOU CAN SEE IT WORKING.
' 
' YOU'LL DEFINATELY UNDERSTAND WHAT IT DOES WHEN YOU READ
' IT THOUGH, SO TAKE A LOOK THROUGH THE NEXT SECTION TO
' GAIN AN UNDERSTANDING OF IT;
'---------------------------------------------------------
' 8 SOURCE WITH NOTES.
' ====================
'
'open window 640,512 [OPEN GFX SCREEN]
'window origin "cc"  [SET ORIGIN TO CENTER OF SCREEN]
'xp=0                [X OFFSET IS CENTER]
'yp=0                [Y OFFSET IS CENTER]
'zp=10               [Z OFFSET IS 10 DEEP]
'scale=1000          [SCALE TO MULTIPLY BY]
'points=8            [8 POINTS IN OBJECT]
'lines=12            [12 LINES IN OBJECT]
'
'dim x(points),y(points),z(points) [X,Y,Z STORAGE]
'dim tx(points),ty(points)         [TRANSFORMED STORAGE]
'dim connects(lines*2)             [CONNECTION STORAGE]
'for a=1 to points                 [READ IN X,Y,Z]
'read x(a),y(a),z(a)
'next a
'for a=1 to lines*2                [READ IN CONNECTIONS]
' read connects(a)
'next a
'
'repeat                            [START MAIN LOOP]
'setdrawbuf dw                     [DOUBLE BUFFERING]
'dw=1-dw
'setdispbuf dw
'clear window
'  gosub transform      [CALL ROUTINE TO TRANSFORM POINTS]
'  gosub draw           [CALL ROUTINE TO DRAW OBJECT]
'  gosub control        [CALL ROUTINE TO DRAW OBJECT]
'until (1=2)    [END MAIN LOOP, IMPOSSIBLE VALUE INFINATE]
'
'label control           [READ CONTROLER AND MOVE OFFSETS]
'c=peek("port1")                             [READ PORT 1]
'if and(c,32)<>0 xp=xp+.1             [OFFSET MOVES RIGHT]
'if and(c,128)<>0 xp=xp-.1            [OFFESET MOVES LEFT]
'if and(c,64)<>0 yp=yp+.1              [OFFSET MOVES DOWN]
'if and(c,16)<>0 yp=yp-.1                [OFFSET MOVES UP]
'if and(c,1024)<>0 zp=zp-.1             [OBJECT MOVES OUT]
'if and(c,2048)<>0 zp=zp+.1             [OBJECT MOVES IN]
'return
'
'label draw                             [DRAW THE OBJECT]
'b=1
'setrgb 1,255,255,255             [WHITE COLOUR SELECTED]
'for a=1 to lines             [DRAW EACH LINE ONE BY ONE]
' line tx(connects(b)),ty(connects(b)) to tx(connects(b+1)),ty(connects(b+1))
' b=b+2
'next a
'return
'
'label transform               [CREATE TRANSFORMED POINTS]
'for a=1 to points                 [EACH POINT ONE BY ONE]
' tx(a)=scale*((x(a)+xp)/(z(a)+zp))          [TRANSFORM X]
' ty(a)=scale*((y(a)+yp)/(z(a)+zp))          [TRANSFORM Y]
'next a
'return
'
'   [POINTS DATA IN X,Y,Z ORDER, 8 POINTS OF A CUBE;]
'data -1,-1,1,1,-1,1,1,1,1,-1,1,1
'data -1,-1,-1,1,-1,-1,1,1,-1,-1,1,-1
'
'    [CONNECTIONS DATA I.E CONNECT POINT 1 TO POINT 2]
'    [12 PAIRS OF POINTS FOR 12 LINES, 1 PAIR EACH]
'data 1,2
'data 2,3
'data 3,4
'data 4,1
'data 5,6
'data 6,7
'data 7,8
'data 8,5
'data 1,5
'data 2,6
'data 3,7
'data 4,8
'
'---------------------------------------------------------
' 
' 9: NEGATIVE VALUES. 
' ===================
' 
' IF YOU MOVE THE OBJECT OUT OF THE SCREEN SO THAT A Z
' CO-ORDINATE BECOMES LESS THAN 0 THEN YOU WILL CHANGE THE
' SIGN OF THE RESULTING TRANSFORMATION, THIS IS BECAUSE
' INSTEAD OF DIVIDING BY SAY +1 YOU WILL BE DIVIDING BY -1
' AND THE SIGN OF THE TRANSFORMED POINT WILL BE INVERTED.
' THIS IS PERFECTLY NORMAL AND OK. POSITIVE NUMBERS WILL
' BECOME NEGATIVE AND VICE VERSA.
' IF THE OBJECT IS MOVED OFF TO ONE SIDE AND YOU MOVE THE
' CUBE OUT OF THE SCREEN, IT WILL APPEAR ON THE OPPOSITE 
' SIDE AND MOVE BACK INTO THE SCREEN AS A CONSEQUENCE.
' 
'---------------------------------------------------------
' 
' 10: THE FINISHED PROGRAM;
' =========================
'
' HERE IS THE COMPLETED PROGRAM, I HAVE ADDED A SMALL BIT 
' OF CODE TO SHOW A RED SQUARE AROUND EACH POINT AND ALSO
' SOME TEXT TO SHOW THE POINT NUMBERS.
' AS AN EXERCISE, TRY AND ADD CONNECTIONS SO THAT EACH
' CORNER IS CONNECTED DIAGONALY INSIDE THE BOX TO IT'S
' OPPOSITE CORNER.
' HAVE FUN :O)
'
rem Basic 3D Example by Shockwave. (C) 2002. 
open window 640,512
window origin "cc"
'---------------------------------------------------------
  xp=0
  yp=0
  zp=10
  scale=1000
  points=8
  lines=12
'---------------------------------------------------------
  dim x(points),y(points),z(points),tx(points),ty(points)
  dim connects(lines*2)
'---------------------------------------------------------
  for a=1 to points
   read x(a),y(a),z(a)
   next a
  for a=1 to lines*2
   read connects(a)
  next a
'---------------------------------------------------------
repeat
  setdrawbuf dw
  dw=1-dw
  setdispbuf dw
  clear window
   gosub transform
   gosub draw
   gosub control
until (1=2)
'---------------------------------------------------------
label control
 c=peek("port1")
  if and(c,32)<>0 xp=xp+.1
  if and(c,128)<>0 xp=xp-.1
  if and(c,64)<>0 yp=yp+.1
  if and(c,16)<>0 yp=yp-.1 
  if and(c,1024)<>0 zp=zp-.1 
  if and(c,2048)<>0 zp=zp+.1 
return
'---------------------------------------------------------
label draw
 b=1
 setrgb 1,255,255,255
for a=1 to lines
 line tx(connects(b)),ty(connects(b)) to tx(connects(b+1)),ty(connects(b+1))
 b=b+2
next a
return
'---------------------------------------------------------
label transform
for a=1 to points
'---------------------------------------------------------
 tx(a)=scale*((x(a)+xp)/(z(a)+zp))
 ty(a)=scale*((y(a)+yp)/(z(a)+zp))
'---------------------------------------------------------
 setrgb 1,255,0,0
 rect tx(a)-5,ty(a)-5 to tx(a)+5,ty(a)+5
'---------------------------------------------------------
 setrgb 1,0,255,0
 text tx(a),ty(a),str$(a),"cc"
next a
return
'---------------------------------------------------------
data -1,-1,1,1,-1,1,1,1,1,-1,1,1
data -1,-1,-1,1,-1,-1,1,1,-1,-1,1,-1
'---------------------------------------------------------
data 1,2
data 2,3
data 3,4
data 4,1
data 5,6
data 6,7
data 7,8
data 8,5
data 1,5
data 2,6
data 3,7
data 4,8
'---------------------------------------------------------



