daedalus/Source/SysPSP/HLEGraphics/VectorClipping.S
2019-02-27 17:04:51 +11:00

169 lines
4.5 KiB
ArmAsm

#include "as_reg_compat.h"
.set noat
.global _ClipToHyperPlane
.text
.set push
.set noreorder
###############################################################################
#
# a0 dest vertices - must be aligned to 16 bytes
# a1 source vertices - must be aligned to 16 bytes
# a2 plane - must be aligned to 16 bytes
# a3 in_vertex_count - must be > 0 or we need to re apply check
#
# v0 out_vertex_count
#
# Trashes M000, M100, M200, M300
#
_ClipToHyperPlane:
#
# a0 - current_dest
# a1 - current_source
# a2 - source (copy of original)
# a3 - verts_remaining
# t0 - temp
# t1 - source_end
# R000 - plane
# S003,013 - aDotPlane, bDotPlane, ...
# M100 - clipped_out
# M200 - a
# M300 - b
#
//beq $a3, $0, finished_all_vertices // verts_remaining == 0 --> finished_all_vertices
//nop
lv.q R000, 0($a2) // load plane equation (we reuse a2 for another purpose)
or $a2, $a1, $0 // take a copy of the original source pointer
sll $t1, $a3, 6 // t1 = num_verts*64
addu $t1, $a1, $t1 // source_end = source + num_verts*64
// load initial values for b
lv.q R300, 0($a1) // TransformedPos(V4)
lv.q R301, 16($a1) // ProjectedPos(V4)
lv.q R302, 32($a1) // Color(V4)
lv.q R303, 48($a1) // Texture(V2) + Clipflags + 1/w
addiu $a1, $a1, 64 // skip the first vertex
vdot.q S013, R301, R000 // bDotPlane = dot( b.ProjectedPos, plane )
or $v0, $0, $0 // out_count = 0
get_next_vertex:
// Wrap around the source pointer if necessary
bne $a1, $t1, load_a
nop
or $a1, $a2, $0 // current_source = source
load_a:
lv.q R201, 16($a1)
lv.q R200, 0($a1) // load a
vdot.q S003, R201, R000 // aDotPlane = dot( a.ProjectedPos, plane )
lv.q R202, 32($a1)
vcmp.s GT, S003, S003[0]
lv.q R203, 48($a1)
bvt 0, a_is_outside // aDotPlane > 0 --> a_is_outside
nop
a_is_inside:
vcmp.s LE, S013, S013[0]
bvt 0, a_is_inside_copy // bDotPlane <= 0 --> a_is_inside_copy
nop
// Calculate the parametric intersection point
vsub.q R001, R301, R201 // R001 = b.ProjectedPos - a.ProjectedPos
vdot.q S001, R001, R000 // S001 = dot( (b.ProjectedPos - a.ProjectedPos), plane )
vrcp.s S001, S001
vmul.s S001, S013, S001
// Interpolate a/b, output point
vsub.q R100, R200, R300 // (a-b)
vsub.q R101, R201, R301 //
vsub.q R102, R202, R302 //
vsub.q R103, R203, R303 //
vmscl.q M100, M100, S001 // (a-b)*x
//vscl.q R100, R100, S001 // (a-b)*x
//vscl.q R101, R101, S001 //
//vscl.q R102, R102, S001 //
//vscl.q R103, R103, S001 //
vadd.q R100, R300, R100 // b + (a-b)*x
vadd.q R101, R301, R101 //
sv.q R100, 0($a0) // *out = *tmp
vadd.q R102, R302, R102 //
sv.q R101, 16($a0)
vadd.q R103, R303, R103 //
sv.q R102, 32($a0)
addiu $v0, $v0, 1 // outcout++
sv.q R103, 48($a0)
addiu $a0, $a0, 64 // out++
a_is_inside_copy:
sv.q R200, 0($a0) // *out = *a
sv.q R201, 16($a0)
sv.q R202, 32($a0)
sv.q R203, 48($a0)
addiu $a0, $a0, 64 // out++
b finished_vertex
addiu $v0, $v0, 1 // outcout++
a_is_outside:
vcmp.s GT, S013, S013[0]
bvt 0, finished_vertex // bDotPlane <= 0 --> a_is_outside_copy
nop
// Calculate the parametric intersection point
vsub.q R001, R301, R201 // R001 = b.ProjectedPos - a.ProjectedPos
vdot.q S001, R001, R000 // S001 = dot( (b.ProjectedPos - a.ProjectedPos), plane )
vrcp.s S001, S001
vmul.s S001, S013, S001
// Interpolate a/b, output point
vsub.q R100, R200, R300 // (a-b)
vsub.q R101, R201, R301 //
vsub.q R102, R202, R302 //
vsub.q R103, R203, R303 //
vmscl.q M100, M100, S001 // (a-b)*x
//vscl.q R100, R100, S001 // (a-b)*x
//vscl.q R101, R101, S001 //
//vscl.q R102, R102, S001 //
//vscl.q R103, R103, S001 //
vadd.q R100, R300, R100 // b + (a-b)*x
vadd.q R101, R301, R101 //
sv.q R100, 0($a0) // *out = *tmp
vadd.q R102, R302, R102 //
sv.q R101, 16($a0)
vadd.q R103, R303, R103 //
sv.q R102, 32($a0)
addiu $v0, $v0, 1 // outcout++
sv.q R103, 48($a0)
addiu $a0, $a0, 64 // out++
finished_vertex:
vmmov.q M300, M200 // b = lat_point
vmov.s S013, S003 // move old aDotPlane as new bDotPlane
addiu $a3, $a3, -1 // verts_remaining--
bne $a3, $0, get_next_vertex // verts_remaining != 0 --> get_next_vertex
addiu $a1, $a1, 64 // source++
finished_all_vertices:
jr $ra
nop
.set pop