gclip.s
15.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
##########################################################################
#
# Triangle Clip Routine.
#
# When entering this code we have a points buffer full of points,
# and registers r1, r2, r3 point to the three vertices of a triangle.
#
##########################################################################
/* scalar registers: */
.name minp, $1
.name midp, $2
.name maxp, $3
.name tmp, $8
############################ CLIPPING ###################################
###################
# CONSTANTS NEEDED:
# POINTLIST1: address of 10 free halfwords in DMEM
# POINTLIST2: address of 10 free halfwords in DMEM
# CLIPMASKS: address of 6 CC masks (halfwords) in DMEM, initialized
# CLIP_STATE_TABLE: address of state jumptable (4 halfwords)
# CLIP_SELECT: address of clip select table, 1 halfword for each plane (6 hw)
# FREEPOINTS: address of 12 empty point structures (40 * 12 bytes)
#define POINTLIST1 (RSP_CLIP_TMP_OFFSET)
#define POINTLIST2 (POINTLIST1+20)
#define POINTSWAP (POINTLIST1^POINTLIST2)
#define FREEPOINTS ((RSP_SCRATCH_OFFSET+7)&0xfff8)
#define C_OUT 0
#define C_IN 2
#define C_FIRSTOUT 4
#define C_FIRSTIN 6
.name oldlist, $5 # old list of vertices
.name plane, $6 # plane (0-10 by 2's) we are currently clipping
.name ccor, $11 # OR of all points' clip codes
.name ccand, $12 # AND of all points' clip codes
.name voutp, $7 # where the newly generated points will go
#
.unname return_save # $30
.name newlist, $30 # new list of vertices
.ent doClip
doClip:
# ########################### FIND 2 EDGES TO CLIP #######################
# bne ccand, zero, clipKill # trivial reject?
sh maxp, POINTLIST1(zero) # put point ptrs in list
sh midp, (POINTLIST1+2)(zero) # ending with 0
sh minp, (POINTLIST1+4)(zero) #
sh zero, (POINTLIST1+6)(zero) #
#-----------------------
.unname maxp # reuse until setup time
#-----------------------
ori voutp,$0,(FREEPOINTS - RSP_PTS_LEN) # free scratch points
ori newlist,$0,POINTLIST1 # pointer to new list
ori plane,$0,12 # start at plane 6
#-----------------------
.unname ccor # done with this
.name clipmask, $11 # bit in cc which we are
# clipping against
#-----------------------
nextClip: #
or oldlist,newlist,newlist # swap oldlist & newlist
xori newlist,newlist,POINTSWAP #
#-----------------------
nextPlane: #
beq plane,$0,drawItAll # did all planes?
#-----------------------
findClipPlane: #
lh clipmask,(CLIPMASKS - 2)(plane) # cur clipplane mask bit
#
### JUMP OCCURS to drawItAll: IF all plenes have been clipped
#
addi plane,plane,-2 # next clip plane
.unname ccand #
.unname midp #
.name prevpoint, $20 # point preceding current point
.name pointptr, $10 # point to current point
.name inoutcheck, $18 # =clipmask if look for in, =0 if look for out
.name pointhdl, $2 # point to current point in point list
.name newhdl, $14 # build new list of points
.name state, $17 # looking for C_OUT, C_FIRSTIN, or C_FIRSTOUT
clipToPlane: #
ori state,$0,C_OUT # first look for a clipped vtx
or inoutcheck,$0,$0 # looking for inside
foundIn: #
ori pointhdl,oldlist,0 # start @ 1st pt to find in pt
foundOut: #
j checkNextPoint # find next appropriate point
addi newhdl,newlist,2 # start @ 1st new point
### JUMP OCCURS to checkNextPoint
#
#
findInOutLoop: #
and tmp,tmp,clipmask # 0 if plane doesn't clip point
beq tmp,inoutcheck,nextState # increment state if cross plane
addi pointhdl,pointhdl,2 # prepare to check next point
### JUMP OCCURS to nextState IF plane boundary was crossed
checkNextPoint: #
or prevpoint,pointptr,$0 # current point becomes previous
sh pointptr,0(newhdl) # move point to new list
addi newhdl,newhdl,2 # next element of new list
checkFirstPoint: #
lh pointptr,0(pointhdl) # pointer to point
bne pointptr,$0,findInOutLoop # went throug whole list?
lh tmp,RSP_PTS_CC(pointptr) # point's clip code
### JUMP OCCURS to findInOutLoop IF didn't go through whole list yet
endedList: #
addi tmp,state,(-C_IN) # no in or no out points?
bgtz tmp,checkFirstPoint # continue if both in & out
ori pointhdl,oldlist,0 # handle to 1st point
### JUMP OCCURS to checkFirstPoint IF there are points inside & outside plane
beq tmp,$0,nextPlane # not clipped by this plane
nop #
### JUMP OCCURS to return IF triangle is completely rejected
j clipKill # plane rejected triangle
#
nextState: #
xor inoutcheck,inoutcheck,clipmask # found out(in); now find in(out
lh tmp,CLIP_STATE_TABLE(state) # get state routine
addi state,state,2 # increment to next state
jr tmp # jump to state routine
lh tmp,NEXTCLIP($0) # nxt plane loop address
### JUMP OCCURS to state routine
# ########################### PERFORM THE CLIP ###########################
# clip between lastout and firstin
# also clip between prevpoint and pointptr
.name ini, $v4 # non clipped points vector
.name inf, $v5
.name outi, $v9 # clipped points vector
.name outf, $v10
.name topi, $v11 # numerator of n calculation
.name topf, $v12
.name boti, $v27 # denominator of n calculation
.name botf, $v26
.name selp, $v1 # select which plane we are clipping against
.name seln, $v0 # negative of selp
.name nf, $v15 # parameter of clip (0.16)
.name negnf, $v8 # 1 - parameter of clip (0.16)
.name vtmpi, $v29 # temporary vector
.name vtmpf, $v28 # temporary vector
.name ptptrhold, $v13 # remembers pointptr
foundFirstIn: # now clip can occur
#
mtc2 pointptr,ptptrhold[0] # swap pointptr & prevpt
or pointptr,prevpoint,$0 #
mfc2 prevpoint,ptptrhold[0] #
ori newhdl,newlist,0 # start @ 1st new point
lh tmp,FOUND_OUT($0) # Return to foundOut:
#
#
foundFirstOut: # now clip can occur
#
sh tmp,RETURNJUMP($0) # save return address
addi voutp,voutp,RSP_PTS_LEN # new point addr
sh voutp,0(newhdl) # ...into list
sh $0,2(newhdl) # zero @ end of new list
#
ldv outi[0],RSP_PTS_X_INT(pointptr) # get XYZW of in and out
ldv outf[0],RSP_PTS_X_FRAC(pointptr) # vertices
ldv ini[0],RSP_PTS_X_INT(prevpoint) #
ldv inf[0],RSP_PTS_X_FRAC(prevpoint) #
#
sll tmp,plane,2 # plane to select
ldv selp[0],(CLIP_SELECT)(tmp) # select vector
vmudh seln,selp,vconst[3] # negative select vector
# ----------------------------
# CALCULATE n (comments assume
# positive x plane clipping,
# so selp=[1 0 0 -1])
# xyz= in point; XYZ=out point
#-----------------------------
vmudn topf,inf,selp # top=[x 0 0 -w]
vmadh topi,ini,selp #
vmadn topf,vconst,vconst[0] #
#-----------------------------
vmadn vtmpf,outf,seln # bot= [-X 0 0 W] + top =
vmadh vtmpi,outi,seln # [(x-X) 0 0 (W-w)]
vmadn vtmpf,vconst,vconst[0] #
#-----------------------------
vaddc botf,vtmpf,vtmpf[0q] # add all componants together
vadd boti,vtmpi,vtmpi[0q] # (2 of X,Y,Z are zero)
vaddc vtmpf,botf,botf[1h] # ... into element 3
#
vadd vtmpi,boti,boti[1h] # result = [? ? ? (x-X)-(w-W)]
#
#-----------------------------
#
.name wsclf, $v3 # calculate scalefactor to
.name wscli, $v7 # improve reciprical precision
#
mfc2 tmp,vtmpi[6] # sign of bot
#
vrcph wscli[3], vtmpi[3] # scalefactor wscl
vrcpl wsclf[3], vtmpf[3] # for greater precision in
vrcph wscli[3], vconst[0] # reciprical
#
#
vmudn wsclf, wsclf, vconst[2] # *2 to complete reciprical
bgez tmp, clampWscl # branch if non negative
vmadh wscli, wscli, vconst[2] # *2 to complete reciprical
#
### BRANCH OCCURS TO clampWscl: IF wscl>=0 #
#------------------------------
vmudn wsclf, wsclf, vconst[3] # *-1 for absolute value
vmadh wscli, wscli, vconst[3] # *-1 for absolute value
clampWscl: #------------------------------
veq wscli,wscli,vconst[0] # if wscl >= 1.0
vmrg wsclf,wsclf,vconst[3] # then wsclf = 0.99999
# (only wsclf used; not wscl)
#------------------------------
vmudl vtmpf, vtmpf, wsclf[3] # use scalefactor wsclf for 1/x
vmadm vtmpi, vtmpi, wsclf[3] # (improves 1/x precicion)
jal NewtonDiv #
vmadn vtmpf, vconst, vconst[0] #
#------------------------------
### JUMP OCCURS to subroutine NewtonDiv: # bot= 1/vtmp
#------------------------------
vaddc vtmpf,topf,topf[0q] # add all componants together
vadd vtmpi,topi,topi[0q] # (2 of X,Y,Z are zero)
vaddc topf,vtmpf,vtmpf[1h] # ... into element 3
vadd topi,vtmpi,vtmpi[1h] # result = [? ? ? (x-w)]
#------------------------------
vmudl nf,topf,botf # n= top * 1/bot
vmadm nf,topi,botf #
vmadn nf,topf,boti #
vmadh negnf,topi,boti #
#------------------------------
vmudl vtmpf, vconst, vconst[5] # add 0.0003fffc (~0.0004)
# to ensure outside of frustum
#
vmadl nf, nf, wsclf[3] # remove scalefcator wsclf
vmadm negnf, negnf, wsclf[3] #
vmadn nf, vconst, vconst[0] #
#------------------------------
.unname wscli # done with scalefactor
.unname wsclf #
#------------------------------
veq negnf,negnf,vconst[0] # if number >=1
#ww j skipWMul
vmrg nf,nf,vconst[3] # then number = 0.99999
#wwnegWLoop:
#ww mfc2 tmp, nf[6] # get nf
#ww addi tmp, tmp, -1 # compare to 1
#ww beq tmp, zero, skipWLoop # too small
#ww nop
#ww vmudl nf, nf, vconst1[1] # make smaller
#ww
#wwskipWMul:
vne nf,nf,vconst[0] # if number =0
vmrg nf,nf,vconst[1] # then number = 0.00001
#---------------------------
vnxor negnf,nf,vconst[0] # negnf[0h] = 1-n (0.16)
vaddc negnf,negnf,vconst[1] # ones complement + 1 of frac
vadd vtmpi,vtmpi,vtmpi # VCO=0
########### SET UP REGISTERS TO MATCH screenCalc: in gvtx.s ##############
#-----------------------------------------------------------------------
# THESE NEED TO BE LOADED WITH APPROPRIATE DATA TO SAVE TO VERTICES
#......................................#
.unname boti # bot now called persp12
.unname botf #
.name invW12f, $v26 #
.name invW12i, $v27 #
.name st12, $v18 # S and T
#......................................#
.name clr1, $15 # RGBA new point 1
#......................................#
.name clr2, $16 # NOT TOUCHED !!!!
#
#-----------------------------------------------------------------------
# THESE NEED TO BE SET UP FOR THE VTX ROUTINE TO WORK
#......................................#
.unname selp #
.name vptrans, $v1 # loaded by getScaleTrans subroutine
#......................................#
.unname seln #
.name vpscale, $v0 # loaded by getScaleTrans subroutine
#......................................#
.name i, $9 # indicate 1 vertex to process
# (the clipped vertex)
#-----------------------------------------------------------------------
# THESE NEED TO BE AVAILABLE #
#......................................#
.unname newhdl #
.name flg2, $14 #
#......................................#
.unname vtmpi #
.name vout12i, $v29 #
#......................................#
.unname vtmpf #
.name vout12f, $v28 #
#......................................#
.name flg1, $13 #
.name vtmp, $v3 #
.name scrn12f, $v7 #
.name scrn12i, $v6 #
.name vin12, $v2 #
#......................................#
.unname tmp # No change here
.name tmp, $8 #
#......................................#
.name vnewton1, $v22 # used for newton raphson subroutine
.name vnewton2, $v23 #
.name vnewton3, $v24 #
.name vnewton4, $v25 #
# .name vnewton5, $v26 # invW12f
# .name vnewton6, $v27 # invW12i
# .name vnewton7, $v28 # vout12f
# .name vnewton8, $v29 # vout12i
#......................................
# CALCULATE new values for
# coordinates & attributes
#---------------------------
vmudl vout12f,inf,negnf[3h] # in * (1-n)
vmadm vout12i,ini,negnf[3h] #
vmadl vout12f,outf,nf[3h] # ... + (out * n)
vmadm vout12i,outi,nf[3h] #
vmadn vout12f,vconst,vconst[0] # = new xyzw
#---------------------------
######### START W>0 LOOP ####################
# mfc2 tmp, vout12i[6] # sign of resultant W
# blez tmp, negWLoop # loop if W<=0
#ww vch topf, vout12i, vout12i[3h] # is z > -w ?
#ww vcl topf, vout12f, vout12f[3h] #
#ww cfc2 tmp, $vcc # get result from VCC
#ww andi tmp, tmp, 0x0004 # is z > -w ?
#ww bne tmp, zero, negWLoop # make smaller
# NOTE DELAY SLOT BELOW
######### END W>0 LOOP ####################
#......................................#
.unname inf #
.name persp12f, $v5 #
#......................................#
.unname ini #
.name persp12i, $v4 #
#......................................#
#wwskipWLoop:
#---------------------------
luv topf[0],RSP_PTS_R_NX(pointptr) # topf[0-6] = RGBAout
luv topi[0],RSP_PTS_R_NX(prevpoint) # topi[0-6] = RGBAin
#---------------------------
llv topf[8],RSP_PTS_S(pointptr) # topf[8,10] = STout
llv topi[8],RSP_PTS_S(prevpoint) # topi[8,10] = STin
#---------------------------
vmudm st12,topf,nf[3] # st12 = new ST & RGBA
vmadm st12,topi,negnf[3] #
#---------------------------
suv st12[0],0(voutp) # temp store new RGBA
sdv st12[8],8(voutp) #
ldv st12[0],8(voutp) #
jal getScaleTrans # get screen scale & trans
lw clr1,0(voutp) # new RGBA 1
#---------------------------
### BRANCH OCCURS to subroutine getScaleTrans: # load regs for screenCalc
#---------------------------
mfc2 pointptr,ptptrhold[0] # restore pointptr
j screenCalc # calc screen coord & store
ori i,$0,1 # setup for vtx routine
#
### JUMP OCCURS to screenCalc: subroutine; return to nextPlane:
#---------------------------
.unname vout12i #
.unname vout12f #
.unname flg1 #
.unname flg2 #
.unname clr1 #
.unname clr2 #
.unname st12 #
.unname vptrans #
.unname vpscale #
.unname i #
.unname vtmp #
.unname invW12f #
.unname invW12i #
.unname scrn12f #
.unname scrn12i #
.unname vin12 #
.unname vnewton1 #
.unname vnewton2 #
.unname vnewton3 #
.unname vnewton4 #
#
.unname voutp #
.unname persp12i #
.unname persp12f #
.unname outi #
.unname outf #
.unname topi #
.unname topf #
.unname nf #
.unname negnf #
#
.unname pointhdl #
.unname prevpoint #
.unname pointptr #
.unname plane #
.unname clipmask #
.unname state #
.unname inoutcheck #
.unname ptptrhold #
#
#
.name maxp, $3 #
.name midp, $2 #
#
.unname newlist # $30
.name return_save, $30 #
#
#---------------------------
# DRAW THE CLIPPED POLYGON
#---------------------------
drawItAll: #
lh tmp,0(oldlist) # 1st point (anchor)
sh tmp,ANCHOR($0) # remember it
sh oldlist,RETURNJUMP($0) # pointer to list of points
lh return_save,CLIPDRAWLOOP($0) # loop address
#---------------------------
clipDrawLoop: #
lh tmp,RETURNJUMP($0) # pointer to list of points
lh maxp,ANCHOR($0) # start with anchor point
lh midp,2(tmp) # ...then next point
lh minp,4(tmp) # ...then point following
addi tmp,tmp,2 # next time use next 2 points
bne minp,$0,beginSetup # setup & draw if not last point
sh tmp,RETURNJUMP($0) # store next point handle
### JUMP OCCURS to beginSetup: if not all triangles have been processed
#
clipKill: #
j GfxDone # return
#
# NOTE DELAY SLOT!!!!
# the first instruction of gsetup.s
# (which follows this) is a load
# halfword into a register I do not
# care about.
#
.end doClip #
.unname oldlist #
.unname tmp #
# ########################### END CLIPPING ###############################
.unname minp #
.unname midp #
.unname maxp #
#
.align 8 # even out the end for DMA's