;/* ; Hazel McKendrick ; v0.1 added a single point light, replacing directional and ambient lighting ; v0.2 point light works with directional lighting ; v0.3 improved lighting effect, attempted to add light which drops off after a certain distance ; v0.4 support for up to 4 point lights ; v0.5 corrected light so they only affect a certain distance ; ;* "PS2" Application Framework ;* ;* University of Abertay Dundee ;* May be used for educational purposed only ;* ;* Author - Dr Henry S Fortuna ;* ;* $Revision: 1.2 $ ;* $Date: 2007/08/19 12:45:13 $ ;* ;*/ ; Initialise data in the static buffer, which won't change each frame Scales .assign 0 LightDirs .assign 1 ; directional light * 3 LightCols .assign 5 ; directional and ambient light colours PointPos .assign 9 ; point light positions * 4 PointCol .assign 13 ; point light colours Transform .assign 17 ; transformation matrix LightTrans .assign 21 ; light transformation matrix ; The input buffer (relative the the start of one of the double buffers) NumVerts .assign 0 ; number of vertices GifPacket .assign 1 UVStart .assign 2 NormStart .assign 3 VertStart .assign 4 ; The output buffer (relative the the start of one of the double buffers) GifPacketOut .assign 248 UVStartOut .assign 249 NormStartOut .assign 250 VertStartOut .assign 251 ; Note that we have 4 data buffers: InputBuffer0, OutputBuffer0, InputBuffer1, and OutputBuffer1. ; Each buffer is 252 quad words. The different buffers are selected by reading the current offset ; from xtop (which is swapped automatically by the PS2 after each MSCALL / MSCNT). .include "vcl_sml.i" .init_vf_all .init_vi_all .syntax new .vu --enter --endenter ; The START code ; This will be called once per frame START: fcset 0x000000 lq fTransform[0], Transform+0(vi00) ; load transforms lq fTransform[1], Transform+1(vi00) lq fTransform[2], Transform+2(vi00) lq fTransform[3], Transform+3(vi00) lq fLightTrans[0], LightTrans+0(vi00) lq fLightTrans[1], LightTrans+1(vi00) lq fLightTrans[2], LightTrans+2(vi00) lq fLightTrans[3], LightTrans+3(vi00) lq fScales, Scales(vi00) ; This will be called once per batch begin: xtop iDBOffset ; Load the address of the current buffer (will either be QW 16 or QW 520) ilw.x iNumVerts, NumVerts(iDBOffset) iadd iNumVerts, iNumVerts, iDBOffset iadd Counter, vi00, iDBOffset loop: lq fVert, VertStart(Counter) ; Load the vertex from the input buffer mul acc, fTransform[0], fVert[x] ; Transform it madd acc, fTransform[1], fVert[y] madd acc, fTransform[2], fVert[z] madd Vert, fTransform[3], fVert[w] clipw.xyz Vert, Vert ; clip it fcand vi01, 0x3FFFF iaddiu iADC, vi01, 0x7FFF ilw.w iNoDraw, UVStart(Counter) ; Load the iNoDraw flag. If true we should set the ADC bit so the vert isn't drawn iadd iADC, iADC, iNoDraw isw.w iADC, VertStartOut(Counter) div q, vf00[w], Vert[w] lq UV, UVStart(Counter) ; Handle the tex-coords mul UV, UV, q sq UV, UVStartOut(Counter) mul.xyz Vert, Vert, q ; Scale the final vertex to fit to the screen. mula.xyz acc, fScales, vf00[w] madd.xyz Vert, Vert, fScales ftoi4.xyz Vert, Vert sq.xyz Vert, VertStartOut(Counter) ; And store in the output buffer ; directional lights - HM lq Norm, NormStart(Counter) ; Load the normal mul.xyz acc, fLightTrans[0], Norm[x] ; Transform by the rotation part of the world matrix madd.xyz acc, fLightTrans[1], Norm[y] madd.xyz Norm, fLightTrans[2], Norm[z] lq.xyz fLightDirs[0], LightDirs+0(vi00) ; Load the light directions lq.xyz fLightDirs[1], LightDirs+1(vi00) lq.xyz fLightDirs[2], LightDirs+2(vi00) mula.xyz acc, fLightDirs[0], Norm[x] ; "Transform" the normal by the light direction matrix madd.xyz acc, fLightDirs[1], Norm[y] ; This has the effect of outputting a vector with all madd.xyz fIntensities, fLightDirs[2], Norm[z] ; four intensities, one for each light. mini.xyz fIntensities, fIntensities, vf00[w] ; Clamp the intensity to 0..1 max.xyz fIntensities, fIntensities, vf00[x] ; point lights - HM lq Norm, NormStart(Counter) ; Load the normal lq PointPos[0], PointPos+0(vi00) ; load the light potions lq PointPos[1], PointPos+1(vi00) lq PointPos[2], PointPos+2(vi00) lq PointPos[3], PointPos+3(vi00) MatrixMultiplyVertex Norm, fLightTrans, Norm ; Transform the normal into world space (important that norm.w is 0) MatrixMultiplyVertex Vert, fLightTrans, fVert ; Transform the vertex into world space sub.xyz ToLight[0], PointPos[0], Vert ; Get the vector from the vert to the light sub.xyz ToLight[1], PointPos[1], Vert sub.xyz ToLight[2], PointPos[2], Vert sub.xyz ToLight[3], PointPos[3], Vert ; This section replaced by section below ;mul.xyz fDistance, ToLight, ToLight ; calculate the distance (squared) between the vertex and the light ;add.x fDistance, vf00, fDistance[y] ; I don't think this works, and the division (later) would be too slow even if it did ;add.x fDistance, vf00, fDistance[z] ; but if you want to put this in later, use ERSADD instead ; end section ersadd p, ToLight[0] ; replaces code above mfp.x fDistance, p ; calculate distances from the light to the vertex ersadd p, ToLight[1] mfp.y fDistance, p ersadd p, ToLight[2] mfp.z fDistance, p ersadd p, ToLight[3] mfp.w fDistance, p VectorNormalizeXYZ Norm, Norm ; Normalise the normal because model exporter doesn't always do it right VectorNormalizeXYZ ToLight[0], ToLight[0] ; Normalise this vector VectorNormalizeXYZ ToLight[1], ToLight[1] VectorNormalizeXYZ ToLight[2], ToLight[2] VectorNormalizeXYZ ToLight[3], ToLight[3] VectorDotProduct fIntensity, ToLight[0], Norm ; Get the intensity add.x fPIntensities, vf00, fIntensity[x] VectorDotProduct fIntensity, ToLight[1], Norm ; Get the intensity add.y fPIntensities, vf00, fIntensity[x] VectorDotProduct fIntensity, ToLight[2], Norm ; Get the intensity add.z fPIntensities, vf00, fIntensity[x] VectorDotProduct fIntensity, ToLight[3], Norm ; Get the intensity ;mul.w fPIntensities, vf00, fIntensity[x] ; don't know why this doesn't work :( - use fIntensity[x] instead of fPIntensities[w] for now loi 6 ; increase the intensity for clearer effects mul.xyz fPIntensities, fPIntensities, i mul.x fIntensity, fIntensity, i mul.xyz fPIntensities, fPIntensities, fPIntensities ; make the bright bits brighter (multiply intensity by itself repeatedly) mul.xyz fPIntensities, fPIntensities, fPIntensities mul.xyz fPIntensities, fPIntensities, fPIntensities mul.x fIntensity, fIntensity, fIntensity ; do the same for the 4th light mul.x fIntensity, fIntensity, fIntensity mul.x fIntensity, fIntensity, fIntensity mul.xyz fPIntensities, fPIntensities, fDistance ; light is less intense as distance squared increases mul.x fIntensity, fIntensity, fDistance[w] ; let it tail off max.xyz fPIntensities, fPIntensities, vf00 ; Clamp to > 0 mini.xyz fPIntensities, fPIntensities, vf00[w] ; Clamp to < 1 max.x fIntensity, fIntensity, vf00 mini.x fIntensity, fIntensity, vf00[w] ; combine lights - HM lq.xyz fLightCols[0], LightCols+0(vi00) ; Load the directional/ambient light colours lq.xyz fLightCols[1], LightCols+1(vi00) lq.xyz fLightCols[2], LightCols+2(vi00) lq.xyz fAmbient, LightCols+3(vi00) lq fPointCol[0], PointCol+0(vi00) ; Load the point light colours lq fPointCol[1], PointCol+1(vi00) lq fPointCol[2], PointCol+2(vi00) lq fPointCol[3], PointCol+3(vi00) mula.xyz acc, fLightCols[0], fIntensities[x] ; Transform the intensities by the light colour matrix madda.xyz acc, fLightCols[1], fIntensities[y] ; This gives the final total directional light colour madda.xyz acc, fLightCols[2], fIntensities[z] madda.xyz acc, fPointCol[0], fPIntensities[x] madda.xyz acc, fPointCol[1], fPIntensities[y] madda.xyz acc, fPointCol[2], fPIntensities[z] madda.xyz acc, fPointCol[3], fIntensity[x] madd.xyz fIntensities, fAmbient, vf00[w] loi 128 ; Load 128 and put it into the alpha value addi.w fIntensities, vf00, i ftoi0 iIntensities, fIntensities ; Convert to ints sq iIntensities, NormStartOut(Counter) ; And write to the output buffer iaddiu Counter, Counter, 3 ibne Counter, iNumVerts, loop ; Loop until all of the verts in this batch are done. iaddiu iKick, iDBOffset, GifPacketOut lq GP, GifPacket(iDBOffset) ; Copy the GIFTag to the output buffer sq GP, GifPacketOut(iDBOffset) xgkick iKick ; and render! --cont ; --cont is like end, but it really means pause, as this is where the code ; will pick up from when MSCNT is called. b begin ; Which will make it hit this code which takes it back to the start, but ; skips the initialisation which we don't want done twice. --exit --endexit