Copyright (C) 2000  Sony Computer Entertainment Inc.

Basic sample programs for the basic3d VU1 version 
==================================================

Aim in the basic3d VU1 version
--------------------------------------------------------------------------
These sample programs show the examples of the process for the perspective
transformation and packet generation implemented in EECore and VU0 with
the VU1 micro mode for fast processing. They also implement the double 
buffer processing of VUMem1 and provide the basics for realize the
faster geometry processing.
 

Description for the program
--------------------------------------------------------------------------
<Files>
	main.c		Main program
	mathfunc.c	Matrix operation functions for a transparent
			transformation etc. (CPUcore version)
	mathfunc.h	Header file
	cube.dsm	Object data (Cube)(VU1 packet format)
	sjoy.c		Controller utility functions
	sjoy.c		Header file of controller utility functions
	torus.dsm	Object data (Torus/data divided)
			(VU1 packet format)
	torus1.dsm	Object data (Torus/data divided)
			(VU1 packet format)
	flower.dsm	Texture data
	basic.vcl	Execution instruction file in the VU1 micro mode 
			(using VCL syntax)
	basic.vsm.orig	Original hand written VU1 micro mode code for
			comparison with VSM generated by vcl.
	vu1dump.c	Dump function in the local memory

<Compilation>
	% make

<Execution>
	% make run

<Specification>
	Display a cube of a Triangle Strip with texture 
	Display a torus of a Triangle with texture
	(Switching with the select button)

	24-bit Z buffer
	3 light sources
	32-bit texture

<Controller operation>
	Up/Down directional button	:Rotation around x-axis (object)
	Right/Left directional button	:Rotation around y-axis (object)
	L1L2 button			:Rotation around z-axis (object)
        Square/Circle button		:Rotation around y-axis of the 
					 camera toward the world 
					 coordinate system
        Triangle/Cross button		:Rotation around x-axis of the 
					 camera toward the world 
					 coordinate system
        R1R2 button			:Forward and backward rotation of 
					 the camera
        select button			:Object switching

<Outline of the processing>
	1.Load texture
	2.Open the pad
	3.Set the matrix and light source matrix in the packet passed to
	  the VU1
	4.DMA kick to the GS
	5.Return 2.


	The following processing are executed in the VU1 micro program.
	1. Set the transparent transformation matrix for rotation x.
	2. Load some parameters (e.g. matrix) into the VU1 register.
	3. Load the normal line vector, two coordinates interpolated, the 
	   value of ST and the color.
	4. Calculate the coordinate interpolation, transparent 
	   transformation and light source and store the result in VU1mem.
	5. Return 3. Repeat the process the vertex number of times.
	6. XGKICK the stored data (Gif Packet) to GS

	Double buffering is executed in VU1Mem.


Data flow
--------------------------------------------------------------------------
<Initializing process>
Main RAM                                GS built-in RAM(4M)
  Texture data -----------------------> Expansion of the texture data 
  Expansion of the object data
  Expansion of the transparent transformation matrix etc.

<Execution process>
Main RAM                              VUMem1(16K)
  Object data -----------------------> Expansion of the packet data for 
  (Various matrixes    DMA transfer    the GS transfer(Geometry operation 
  and data before     	               and double buffer)
  geometry processing)	               (Primitive data(STQ,RGBA,XYZF))
 		  	                                |
                                                        |
					        	|
   					 	        |
GS built-in RAM(4M)    <--------------------------------+
 Writing to the frame and Z buffer            Data kick to GIF
 (Rendering)


Detail description of the program
--------------------------------------------------------------------------
<Variable/Structure/Function> (the function of mathfunc.c is excluded.)

        My_dma_start            :The leading element of the packet group 
				 sent to the VU1
        My_dma_next             :The second leading element of the packet 
				 sent to the VU1
        My_matrix               :The local_screen matrix in the packet
        My_rot_trans_matrix     :The local_world matrix in the packet
        My_light_matrix         :The local_light matrix in the packet
        My_cube_start           :The leading element of the cube packet 
				 data
        My_torus_start          :The leading element of the torus packet 
				 data
        My_texture1             :The head of the texture data

   	TexEnv          : The structure for generating the packet to 
			  transfer the ps2_gs_texenv structure

        camera_p        : The position of the camera
        camera_zd       : The eye direction vector of the camera
        camera_yd       : The downward direction vector of the camera
        camera_rot      : The vector for rotation of the camera

        light0          : Light 0
        light1          : Light 1
        light2          : Light 2
        color0          : The color of the light 0
        color1          : The color of the light 1
        color2          : The color of the light 2

	ambient		: Ambient light

        obj_trans       : Translation vector of the object
        obj_rot         : Rotation vector of the object

        local_world     : The matrix converting the object Local 
			  coordinate into the World coordinate system
        world_view      : The matrix converting the World coordinate 
			  system into the View coordinate system
        view_screen     : The matrix converting the View coordinate system
	                  into the Screen coordinate system
        local_screen    : The matrix converting the Local coordinate into 
			  the Screen coordinate (Product of above 3 
			  matrixes)

        normal_light    : The matrix calculating the inner product between
             		  a normal line of the vertex and the light 
			  direction vector in the World coordinate system
                          (The light direction vector will be set).
	local_light     : The matrix that allows to calculate the inner 
			  product between the normal line of the vertex 
			  and the light direction vector in the Local 
			  coordinate system by multiplying the normal_
			  light matrix by the local_world matrix.
       	light_color     : The matrix produced by multiply-accumulating the
	                  inner product, generated by multiplying the 
			  local_light matrix by the normal line of the 
			  vertex, 
			  by each color of light (3 colors plus ambient 
			  light) 
         local_color     : The matrix generated by multiplying local_light
			   by light_color

        work            : The matrix for temporary work

        ps2_gs_dbuff g_db	: The structure for implementing the 
				  double buffer
        ps2_image g_image	: The structure for transferring the 
                                  texture into the GS local memory
        TexEnv texenv		: The structure generating the packet for 
				  transferring the texture data

        void SetVu1PacketMatrix(void)
                        :The function setting the matrix in the packet 
			 sent to VU1

<Variables in the main function>

        frame           : The switch for flipping the double buffer
	delta		: The variable for setting the angle of rotation
        obj_switch      : The toggle switch for switching the object
        toggle          : The variable for controlling the reading of the 
			  select button with the toggle

<The variables and functions provided with mathfunc.c> 

	ps2Samp0IVECTOR[4]      : The int type array located in 128-bit 
				  boundary (element 4)
        ps2Samp0FVECTOR[4]      : The float type array located in 128-bit 
				  boundary (element 4)
        ps2Samp0FMATRIX[4][4]   : The float type array located in 128-bit
				  boundary (element 4x4)

See mathfunc.c for the detail description of the function. Most of the 
functions written in mathfunc.c are written by the Vu0 macro and are 
provided with libvu0.
In the VU1 version, the ps2Samp0... function executed in the Core is used 
for a matrix calculation. The processing will be faster by converting the 
function as the VU0 version.
Note that the array type of the matrix is different between the Core 
version and VU0/VU1 versions. The Core version uses a general array, but
the VU0/VU1 versions adopt the transposed type to make use of the 
arithmetic function effectively.


Description of the programs (for initializing)
---------------------------------------------------------------------------
Description of the programs (for initializing)

	In the VU1 version, the object data is linked when compiling and 
	expanded to the memory. The file of *.dsm format is a packet 
	format that can be sent to VU1 directly. It can use the My_dma_
	start pointer as it is.

- Initialize the device
    g_fd_gs = ps2_gs_open(-1);	// open GS
    g_vpu0 = ps2_vpu_open(0);	// open vpu0
    g_vpu1 = ps2_vpu_open(1);	// open vpu1

    ps2_gs_vc_graphicsmode();	// set virtual console to graphicsmode

    ps2_gs_reset(0, g_inter, g_out_mode, g_ff_mode, g_resolution,
		 g_refresh_rate);

	In the head of the program, all devices are to used are 
	initialized.

- Set the drawing environment
    ps2_gs_set_dbuff(&db, g_psm, gp->width, gp->height,
		     (g_zbits == 0) ? 0 : PS2_GS_ZGREATER, g_zpsm, 1);
    *(__u64 *)&db.clear0.rgbaq = PS2_GS_SETREG_RGBAQ(0x10, 0x10, 0x20, 0x80,
						     0x3f800000);
    *(__u64 *)&db.clear1.rgbaq = PS2_GS_SETREG_RGBAQ(0x10, 0x10, 0x20, 0x80,
						     0x3f800000);

	The program sets the drawing environment for the GS

- Image transfer for the texture
    load_teximages(void);
	| ps2_gs_set_image(&g_img, g_textop64, IMAGE_SIZE / 64, PS2_GS_PSMCT32,
	| 		 0, 0, IMAGE_SIZE, IMAGE_SIZE, My_texture1);
	| ps2_gs_load_image(&g_img);

	The function sets the LoadImage information to transfer the 
	texture image into the GS local memory. Then, by executing the 
	ps2_gs_load_image(), specified image will be transferred to the
	GS local memory.
	To support virtual console, it has to be loaded on switching
	virtual console.

- Generate the packet for setting the environment for the texture
    // set texture env
    ps2_gs_set_texenv(&texenv.gs_tex, 0, &g_img, 8, 8, 0, 0, 0, 0, 1);

    PS2_GIFTAG_CLEAR_TAG(&texenv.giftag);
    texenv.giftag.NLOOP = sizeof(texenv) / 16 - 1;
    texenv.giftag.EOP = 1;
    texenv.giftag.PRE = 0;
    texenv.giftag.NREG = 1;
    texenv.giftag.REGS0 = PS2_GIFTAG_REGS_AD;

    ps2_gs_set_alphaenv(&texenv.gs_alpha, 0);
    *(__u64 *)&texenv.gs_alpha.alpha1 = PS2_GS_SETREG_ALPHA(0, 1, 0, 1, 0);

    texenv.gs_test1addr = PS2_GS_TEST_1;
    *(__u64 *)&texenv.gs_test =  PS2_GS_SETREG_TEST(0, 0, 0, 0, 0, 0, 1,
		(g_zbits == 0) ? PS2_GS_ZALWAYS : PS2_GS_ZGREATER);
    *(__u64 *)&texenv.gs_tex.clamp1 = PS2_GS_SETREG_CLAMP(0, 0, 0, 0, 0, 0);

	The function generates the packet for setting the GS general 
	purpose	register TEX0_1 and CLAMP_1 related to the texture using 
	the ps2_gs_texenv().

- Transfer the packet for setting the environment for the texture
    ps2_dma_start_n(g_fd_gs, &texenv.giftag, texenv.size + 1);

	The program transfers the generated packet for setting the texture
	environment by executing DMA.

- Initialize the controller
    sjoy_open();

	Initialize controllers(game pad).  (You can treat them as normal
	joysticks) The data of the controllers are acquired using
	sjoy_get_ps2_button().  The state of the controllers are updated
	by calling sjoy_poll().


Description of the programs (for the main loop)
--------------------------------------------------------------------------
Acquiring the controller information, generating the matrix and packet
(a coordinate and transparent transformation, UV->STQ transformation and 
light source calculation) executed in the main loop 
will be described in the following section.

- Generate the View-Screen matrix
    ps2Samp0ViewScreenMatrix(view_screen, 512.0f, 1.0f, gp->pixel_ratio,
			     gp->center_x, gp->center_y,
			     1.0f, (g_zbits == 0) ? 2 : ((1 << g_zbits) - 1),
			     1.0f, 65536.0f);

	The function calculates the View-Screen matrix.  In this
	example, the distance from the viewpoint to the projection
	screen is 512, the aspect ratio of the screen is
	1:gp->pixel_ratio, the central point of the screen is
	(gp->center_x, gp->center_y), the value of the maximum z on Z
	buffer and the range of z is 1.0-65536.0.

- Lock virtual console
    ps2_gs_vc_lock();

	Lock virtual console and prohibit switch to other graphics
	program.  All context on GS/VPU0/VPU1 won't be saved/restored,
	it has to be care when you permit virtual console switching by
	calling ps2_gs_vc_unlock().

- Switch the drawing environment
    ps2_gs_set_half_offset((frame & 1) ? &g_db.draw1 : &g_db.draw0, odev);
    ps2_gs_swap_dbuff(&g_db, frame);

	Prepare drawing environment and swap draw/display buffers.
	For NTSC interlaced mode, prepare env half pixel shifted.

- Acquire the controller information
    // --- read pad ---
    sjoy_poll();
    paddata = sjoy_get_ps2_button(0);

    // --- object rotate & change view point ---
    if (paddata & SJOY_PS2_L_DOWN) {
	obj_rot[0] += delta;
	    :	:
	    :	:

	The controller button information is acquired using the
	sjoy_get_ps2_button(). In this example, the object, the angle of
	rotation for both sides of the camera and the shift amount are
	updated based on the acquired data. A left-hand side button for
	the controller is for the object operation while a right-hand
	side button for that is for the camera operation. The select
	button is for object switching.

- Generate the Local-World matrix (rotation only)
    ps2Samp0UnitMatrix(work);                   //Unit matrix 
    ps2Samp0RotMatrix(local_world, work, rot);  //Rotating matrix 

	The Local-World matrix should be calculated for every object held 
	in the Local coordinate system. The affine transformation, such as
	the rotational and parallel translation, is used. In this sample 
	program, the rotating and parallel translation matrix is 
	calculated and the result from multiplying these two matrixes is 
	used as the Local-World matrix.
	In this sample program, however, the Local_Light matrix should be 
	set before setting the parallel translation (obj_trans) of the 
	third line. If the Local_Light matrix is generated using the 
	matrix including the parallel translation, the ambient light is 
	not correctly calculated. This is because the parallel translation
	and the ambient light are calculated using the forth column of the
	matrix. Therefore, generate the Local_Light matrix immediately 
	after setting the rotating matrix.
	Note that the forth element of the obj_trans should be set to 0.
	Otherwise, very critical value set in [4,4] element of the matrix
	will change.

- Generate the Local_Light matrix
    ps2Samp0NormalLightMatrix( normal_light, light0,light1,light2);
    ps2Samp0MulMatrix(local_light, normal_light,local_world);

	The function calculates the Normal-Light matrix from the three 
	light sources using the ps2Samp0NormalLightMatrix(). Further, the 
	matrix is multiplied by the Local-World matrix to generate the 
	Local-Light matrix. As mentioned above, in the Local-World matrix 
	used here, do not set the obj_trans.

- Generate the Light_Color matrix
   ps2Samp0LightColorMatrix(light_color, color0, color1, color2, ambient);
	The function calculates the Light_Color matrix from the light 
	source and environmental color using the 
	ps2Samp0LightColorMatrix(). In the light source calculation, the 
	final vertex color on the screen is determined by multiplying the 
	Light_Color matrix after each lighting effect color is calculated.

- Generate the World-View matrix
    ps2Samp0RotCameraMatrix(world_view, camera_p, camera_zd, camera_yd,
                                                         camera_rot);

	The function ps2Samp0RotCameraMatrix() calls 
	ps2Samp0CameraMatrix() internally. The function calculates 
	World-View matrix using the ps2Samp0CameraMatrix(). The View 
	coordinate system defines the viewpoint (eye) as the origin point 
	(0,0,0), the eye direction as Z+, the rightward direction as X+ 
	and the downward direction as Y+ (right hand coordinate system).
	In this sample, it defines the viewpoint camera_p as (0,0,-25),
	viewpoint camera_zd as (0,0,1) and vertical camera_yd as (0,1,0)
	toward the World and generates the World-View matrix using these 
	vectors. The ps2Samp0RotCameraMatrix() function internally rotates
	these vectors using the camera_rot in advance. The rotation of the
	camera is enabled by passing the result to the 
	ps2Samp0CameraMatrix().

- Generate the Local-World matrix (rotational and parallel translation)
    ps2Samp0TransMatrix(local_world, local_world, obj_trans);
        //Rotational and parallel translation

	As the generation of the Local_Light matrix is finished, the real 
	Local_World matrix is generated by adding the Local_World matrix 
	to the parallel translation elements (obj_trans).

- Generate the Local-Screen matrix
    ps2Samp0MulMatrix(world_screen, view_screen, world_view);
    ps2Samp0MulMatrix(local_screen, world_screen, local_world);

	First, calculate the World-Screen matrix using the View-Screen
	and the World-View matrix already calculated. The Local-Screen 
	matrix is calculated by multiplying the World-Screen matrix by the
	Local-World matrix. In the Local_World matrix used at this point,
	the elements of the rotation and the parallel translation should 
	be properly set.

- Set and transfer the data in the packet to VUMem1
    SetVu1PacketMatrix();
    if (obj_switch == 0) {
	((ps2_dmatag *)My_dma_next)->ADDR = (__u32)My_cube_start;
    } else if (obj_switch == 1) {
	((ps2_dmatag *)My_dma_next)->ADDR = (__u32)My_torus_start;
    }
    ps2_dma_start(ps2_vpu_fd(g_vpu1), vfd, (ps2_dmatag *)My_dma_start);

	Set the value to the matrix transferred to VU1 with 
	SetVu1PacketMatrix() function. The address of the object data
	that is to transferred to VU1 is set in DMAtag in the packet.

- Unlock virtual console
    ps2_gs_vc_unlock();

	Unlock virtual console to permit other graphics
	applications to be switched.


Data processing in VU1 and VIF
--------------------------------------------------------------------------
Describe the summary of data flow sent to VU1

	Main RAM ---> DMA ---> VIF1 ---> MicroMem1 or VUMem1

The outline of the data flow is above. Describe the processing process in 
the following.
First, control the DMA to transfer the data with DMA. The DMA is 
controlled with sending DMAtag. The addition and generation processing 
for DMA is executed in *.dsm internally (e.g."DMAcnt *" and  "EndDmaData")
and the main loop. 

    if (obj_switch == 0) {
	((ps2_dmatag *)My_dma_next)->ADDR = (__u32)My_cube_start;
    } else if (obj_switch == 1) {
	((ps2_dmatag *)My_dma_next)->ADDR = (__u32)My_torus_start;
    }

For example, in this processing, the transfer object is exchanged by
specifying next in DMAtag for object switching and switching the
address in DMAtag.

Then the data pass VIF1. Many functions that can control the VU1 are 
implemented in VIF1. The codes for controlling VIF are implemented with
VIFcode and can be incorporated into the packet. In this sample program,
they are used in *.dsm file.

	Example:

	MPG    :Load the micro program (Send the data to uMem)
	-- data --
	.EndMPG

	unpack 4, 4, V4_32, 0, *    :Expand the following data and write
				     to VUMem
	-- data --
	.EndUnpack

In this sample program, the double buffer processing is executed with the 
micro code and the function of VIFcode in the following order.

	MSCAL 0       :Execute the micro program(Start from address 0)
	BASE 0        :Specify one of the leading addresses of the double
		       buffer to 0 (Set vif1 base register)
	OFFSET 512    :Specify another side of the leading address to 512
                       (Set vif1 offset register)

	unpack ......
	-- object data --
	.EndUnpack
	MSCNT     :Resume the execution of the micro code (drawing 
		   process)

  Show the process flow of the micro simply	

      Preparation --+-> Transparent transformation and light source
			processing (Generate and transfer the GIF packet) 
                 |                              |
                 |               |              |
                 +<----<----<----|<----<----<---+
                         restart | stop
                               MSCNT
                          (switch buffer)

The micro code waits until the following MSCNT instruction comes after the
preparation or one loop is processed. And a value is set in the following
buffer. When the MSCNT instruction is executed, the execution is resumed
(or the MSCNT instruction stalls until the micro program finishes) and 
data is processed.

When the MSCNT instruction is executed, the offset address is switched, or
the memory area for processing is switched, which allows the double buffer
processing.


Basic3d VU1 micro code
--------------------------------------------------------------------------
<Outline of the operation>
	1. Coordinate transformation in the World coordinate system 
	2. Transparent transformation 
	3. Lighting by the normal line vector of the vertex and parallel
	   light source 
	4. Texture mapping with perspective correction 


<Data placement in VUMem1>

   Address       Stored data                          Description
  ---------------------------------------------------------------------
    0 - 3      - Transparent transformation        Matrix data etc. shared
         	 matrix			    	   with the entire model
    4 - 7      - Coordinate transformation              
		 matrix
    8 - 11     - Parallel light source vector
   12 - 15     - Lighting color
  ----------------------------------------------------------------------
    0 - 511     [Source data]
                - GIFtag
                - Vertex coordinate
                - Normal line vector
                - Vertex color
                - Texture coordinate
                                                Double buffer area 0 in 
						VU1
                [The packet XGKICKed to GIF]
                - GIFtag
                - ST
                - RGBAQ
                - XYZF2
  -----------------------------------------------------------------------
   512 - 1023
                [Source data]
                - GIFtag
                - Vertex coordinate
                - Normal line vector
                - Vertex color
                - Texture coordinate
                                                Double buffer area 1 in
						VU1              
		[The packet XGKICKed to GIF]
                - GIFtag
                - ST
                - RGBAQ
                - XYZF2

  ---------------------------------------------------------------------

<Micro code>

;
;
; vu1 micro code for basic sample
;
; [Contents of the main registers]
;
; Transform[0..3] : Transparent transformation matrix x : rotational and 
		    translation matrix in the world coordinate system
; LightMatrix[0..3] : Directional vector of the parallel light source
; LightColor[0..3] : Colors of each light source
; GifTag  : gif tag 
; vert_in : The vertex coordinate processed
; normal  : The normal line vector in the vertex processed
; ST      : The texture coordinate of the vertex processed
; color   : The color of vertex processed
;
;
; iKick       : The Leading data transferred from VUMEM to GIF with XGKICK (gif 
                tag is attached.)
; iVert_in    : The lead pointer to the vertex data in VUMEM processed
; iNorm       : The lead pointer to the normal line vector in VUMEM processed
; iST_in      : The lead pointer to the texture coordinate in VUMEM processed
; iColor_in   : The lead pointer to the color of the vertex in VUMEM processed
; iRGBAQ_out  : The store pointer to RGBAQ data transferred to GIF
; iST_out     : The store pointer to ST data transferred to GIF
; iXYZF2_out  : The store pointer to XYZF2 data transferred to GIF
;
; iVert_count : The number vertex processed (Loop counter)
;
;
; ---------------------------------------------------------------------

lq ScreenMat[0], kScreenMat0(vi00); (0) load screen matrix
lq ScreenMat[1], kScreenMat1(vi00)
lq ScreenMat[2], kScreenMat2(vi00)
lq ScreenMat[3], kScreenMat3(vi00)
lq LocalWorld[0], kLocalWorld0(vi00); (4) load local world matrix
lq LocalWorld[1], kLocalWorld1(vi00)
lq LocalWorld[2], kLocalWorld2(vi00)
lq LocalWorld[3], kLocalWorld3(vi00)
 
mat_x_mat Transform, LocalWorld, ScreenMat      ;  nm = lm x rm
			;Transparent transformation matrix x : Calculate
			  the rotational and translation matrix in the 
			  world coordinate system

lq LightColor[0], kLightColor0(vi00);  Load colors of each light source (8)
lq LightColor[1], kLightColor1(vi00)
lq LightColor[2], kLightColor2(vi00)
lq LightColor[3], kLightColor3(vi00)
lq LightMatrix[0], kLightMatrix0(vi00)  ;Load parallel light vector matrix (12) 
lq LightMatrix[1], kLightMatrix1(vi00)
lq LightMatrix[2], kLightMatrix2(vi00)
lq LightMatrix[3], kLightMatrix3(vi00)

--cont	; Insert NOP[E] to stop the program ready for a restart with MSCNT

START0:
xtop iBase			; Read the value in TOP register in VIF for
				; double buffering
ilwr.x iVert_count, (iBase)x    ; Read the value of nloop from GIFtag
iaddiu iTmp, vi00, 0x7fff       ; Set the mask to acquire the loop
				  counter (the number of vertex)
iand iVert_count, iTmp, iVert_count	; Set the loop counter including the
					; number of vertex with masking
lq GifTag, 0(iBase)             ; Read gif tag
iaddiu iVert_in, iBase, 1  	; The pointer to the vertex data read
iadd iNorm, iVert_in, iVert_count 	; pointer for normal data
iadd iColor_in, iNorm, iVert_count 	; pointer for color data
iadd iST_in, iColor_in, iVert_count	; pointer for texture coordinate data
iadd iKick, iST_in, iVert_count         ; set XGKICK pointer
sq GifTag, 0(iKick)             ; Store gif tag
iaddiu iRGBAQ_out, iKick, 2 	; The pointer to the position storing
				; calculated RGBAQ
iaddiu iST_out, iKick, 1 	;The pointer to the position storing
				 calculated ST
iaddiu iXYZF2_out, iKick, 3  	; The pointer to the position storing
 				  calculated XYZF2 
LOOP:
lqi vert_in, (iVert_in++) 	; Read the vertex data 
lqi normal, (iNorm++)		; Read the normal line vector
lqi color, (iColor_in++)	; Read the color of the vertex
lqi ST, (iST_in++)		; Read the texture coordinate
; --- Coordinate and transparent transformation ---
vec_x_mat trans_vert, vert_in, Transform	; Execute the coordinate
						; and transparent transformation
						; SEE vumacros.m

div q, vf00[w], trans_vert[w]	; Calculate 1/w

; ---Inner product between parallel light source and normal line vector---
vec_x_mat light_vec, normal, LightMatrix	; see vumacros.m

max light_vec, light_vec, vf00[x]	; Set the value less than 0.0f to 0.0f
; --- Multiply 1/w and store ---
mulq floatScreenVec, trans_vert, q	; Multiply 1/w 
ftoi4 ScreenVec, floatScreenVec		; Convert to fixed point
sq ScreenVec, 0(iXYZF2_out)		; Store XYZF2 (unpacked mode)
iaddiu iXYZF2_out, iXYZF2_out, 3	; Increment the store pointer

; Read st, multiply it by Q and store(for perspective correction)
mulq persST, ST, q		; Multiply ST by 1/w and set 1/w to Q
sq persST, 0(iST_out)		; Store STQ (unpacked mode)
iaddiu iST_out, iST_out, 3	; Increment the store pointer

; --- Calculate the color of the material in which illumination is 
      calculated and store ---
vec_x_mat light_col, light_vec, LightColor	; see vumacros.m
					; Multiply the inner product by the 
					  color of the light source
 
mul floatCol, color, light_col		; Multiply calculated color of light
					; color of the material
ftoi0 screenCol, floatCol		; Convert to integer
sq screenCol, 0(iRGBAQ_out)		; Store RGBAQ (unpacked mode) 
iaddiu iRGBAQ_out, iRGBAQ_out, 3	; Increment the store pointer 
 
; --- Loop ---
iaddi iVert_count, iVert_count, -1	; Decrement the loop counter
ibne iVert_count, vi00, LOOP		; Repeat the loop 

; --- Send the calculation result to GIF (XGKICK) and stop the execution 
      of the micro ---
xgkick iKick		; XGKICK
--cont			; insert NOP[E] to stop VU1 ready for an MSCNT
b START0		; After MSCNT, Jump to the next set of execution
.END			; GASP directive

Comparison of VCL generated VSM and hand written VSM
---------------------------------------------------------

The above VCL program basic.vcl is processed to give basic.vsm
The original hand written VSM code is in the file basic.vsm.orig

The first thing to note is how much more readable the VCL code is. The 
register names are symbolic and there is only a single stream of 
instructions rather than an UPPER and LOWER.

Looking at basic.vsm, you will see that the generated code is not meant
to be human readable although the same labels are retained and there
are some comments on the code generation.

In this example, the key thing to note is the main loop which will have 
a special VCL label including the phrase "MAIN_LOOP". Just under the loop
label, VCL inserts a comment which gives the number of cycles for the loop.
In this case, the number of cycles is 18. The original hand written VSM
code was about 57 cycles. Of course the original VSM code was not optimized,
but this optimization process would have taken a skilled programmer some
time and would also yield human un-readable code.

Description of the packet
--------------------------------------------------------------------------
Describe the packet (.dsm format) transferred to VU1 to calculate the 
transparent transformation and parallel light source with VU1 micor code.
An independent triangle and triangle strip are also allowed to use with  
setting GIFtag. When drawing many vertexes, transfer the packets from
GIFtag to MSCNT in parallel, which enables double buffer processing in 
VU1.
 <Example> Triangle strip cube ------------------------------------
.include "vumacros.h"
.global My_dma_start
.global My_matrix
.global My_light_matrix
.global My_rot_trans_matrix

My_dma_start:
.align 0
DMAcnt *     ; Transfer the micro code itself to VU1
MPG 0, *
.include "basic.vsm" 
.EndMPG
.EndDmaData

DMAcnt *
unpack 4, 4, V4_32, 0, *  ; Screen matrix
My_matrix:
fwzyx 0.000000, 0.000000, 0.000000, 35.752483
fwzyx 0.000000, 0.000000, -14.765776, 0.000000
fwzyx 0.050000, 4995000.000000, 102.400002, 102.400002
fwzyx 1.000000, 100000000.000000, 2048.000000, 2048.000000
.EndUnpack

unpack 4, 4, V4_32, 4, * ; Rotational and translation matrix in the 
			   world coordinate system
My_rot_trans_matrix:
fwzyx 0.0, -0.000000, -0.000000, 1.000000
fwzyx 0.0, -0.000000, 1.000000, 0.000000
fwzyx 0.0, 1.000000, 0.000000, 0.000000
fwzyx 1.0, 0.000000, 0.000000, 0.000000
.EndUnpack

unpack 4, 4, V4_32, 8, * ; Light source color (Parallel light source x3
			   and ambient light x1)
fxyzw 1.0, 0.0, 0.0, 0.0 ; Parallel light source1 (R,G,B)=(1.0, 0.0, 0.0)
fxyzw 0.0, 0.0, 1.0, 0.0 ; Parallel light source2 (R,G,B)=(1.0, 0.0, 0.0)
fxyzw 0.0, 0.0, 0.0, 0.0 ; Parallel light source3 (R,G,B)=(1.0, 0.0, 0.0)
fxyzw 0.2, 0.2, 0.2, 1.0 ; Ambient light (R,G,B) = (0.2, 0.2, 0.2)
.EndUnpack

unpack 4, 4, V4_32, 12, * ; Parallel light source vector(x3)
My_light_matrix:
fxyzw 0.0, -1.0, 0.0, 0.000000 ; Each column shows vector. In this 
example, Light1=(0.0, 1.0, 0.0). 
fxyzw 1.0, 0.0, 0.0, 0.000000  ; Light2 = (-1.0, 0.0, 0.0),
Light3=(0.0, 0.0, 0.0)
fxyzw 0.0, 0.0, 0.0, 0.000000  ; The forth column is for setting ambient
				 light.
fxyzw 0.0, 0.0, 0.0, 1.000000
.EndUnpack

MSCAL 0 ; Execute the micro
BASE 0 ; Set the base register of vif1 base 
OFFSET 512 ; Set the vif1 offset register
.EndDmaData


; ------------------------------------------------------------------------
; The model data that are to be drawn
; This is a cube (triangle strip) here.

DMAcnt *
unpack[r] 4, 4, V4_32, 0, *
iwzyx 0x00000000, 0x00000412, 0x300a4000, 0x0000800e ; giftag (with 
texture)
.EndUnpack
unpack[r] 4, 4, V4_32, 1, *
; The position of the vertex of the strip in the world coordinate system
fxyzw -5.0, -5.0, 5.0, 1.0
fxyzw -5.0, -5.0, -5.0, 1.0
fxyzw -5.0, 5.0, 5.0, 1.0
fxyzw -5.0, 5.0, -5.0, 1.0
fxyzw 5.0, 5.0, -5.0, 1.0
fxyzw -5.0, -5.0, -5.0, 1.0
fxyzw 5.0, -5.0, -5.0, 1.0
fxyzw -5.0, -5.0, 5.0, 1.0
fxyzw 5.0, -5.0, 5.0, 1.0
fxyzw -5.0, 5.0, 5.0, 1.0
fxyzw 5.0, 5.0, 5.0, 1.0
fxyzw 5.0, 5.0, -5.0, 1.0
fxyzw 5.0, -5.0, 5.0, 1.0
fxyzw 5.0, -5.0, -5.0, 1.0

; Normal line vector
fxyzw -1.0, 0.0, 0.0, 1.0
fxyzw -1.0, 0.0, 0.0, 1.0
fxyzw -1.0, 0.0, 0.0, 1.0
fxyzw -1.0, 0.0, 0.0, 1.0
fxyzw 0.0, 1.0, 0.0, 1.0
fxyzw 0.0, 0.0, -1.0, 1.0
fxyzw 0.0, 0.0, -1.0, 1.0
fxyzw 0.0, -1.0, 0.0, 1.0
fxyzw 0.0, -1.0, 0.0, 1.0
fxyzw 0.0, 0.0, 1.0, 1.0
fxyzw 0.0, 0.0, 1.0, 1.0
fxyzw 0.0, 1.0, 0.0, 1.0
fxyzw 1.0, 0.0, 0.0, 1.0
fxyzw 1.0, 0.0, 0.0, 1.0

; Color
fxyzw 200.0, 200.0, 200.0, 128.0
fxyzw 200.0, 200.0, 200.0, 128.0
fxyzw 200.0, 200.0, 200.0, 128.0
fxyzw 200.0, 200.0, 200.0, 128.0
fxyzw 200.0, 200.0, 200.0, 128.0
fxyzw 200.0, 200.0, 200.0, 128.0
fxyzw 200.0, 200.0, 200.0, 128.0
fxyzw 200.0, 200.0, 200.0, 128.0
fxyzw 200.0, 200.0, 200.0, 128.0
fxyzw 200.0, 200.0, 200.0, 128.0
fxyzw 200.0, 200.0, 200.0, 128.0
fxyzw 200.0, 200.0, 200.0, 128.0
fxyzw 200.0, 200.0, 200.0, 128.0
fxyzw 200.0, 200.0, 200.0, 128.0

; Texture coordinate
fxyzw 0.0, 0.0, 1.0, 0.0
fxyzw 0.0, 1.0, 1.0, 0.0
fxyzw 1.0, 0.0, 1.0, 0.0
fxyzw 1.0, 1.0, 1.0, 0.0
fxyzw 0.0, 1.0, 1.0, 0.0
fxyzw 1.0, 0.0, 1.0, 0.0
fxyzw 0.0, 0.0, 1.0, 0.0
fxyzw 1.0, 1.0, 1.0, 0.0
fxyzw 0.0, 1.0, 1.0, 0.0
fxyzw 1.0, 0.0, 1.0, 0.0
fxyzw 0.0, 0.0, 1.0, 0.0
fxyzw 0.0, 1.0, 1.0, 0.0
fxyzw 1.0, 0.0, 1.0, 0.0
fxyzw 1.0, 1.0, 1.0, 0.0

.EndUnpack
MSCNT  ; Resume the micro code (Drawing process)
.EndDmaData

DMAend

