mirror of
https://github.com/nzp-team/dquakeplus.git
synced 2024-12-11 21:01:19 +00:00
562 lines
No EOL
23 KiB
C++
562 lines
No EOL
23 KiB
C++
/*
|
|
Copyright (C) 2007 Peter Mackay and Chris Swindle.
|
|
Copyright (C) 2021 Sergey Galushko
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
#define CLIPPING_DEBUGGING 0
|
|
#define CLIP_LEFT 1
|
|
#define CLIP_RIGHT 1
|
|
#define CLIP_BOTTOM 1
|
|
#define CLIP_TOP 1
|
|
#define CLIP_NEAR 0
|
|
#define CLIP_FAR 0
|
|
|
|
#include "clipping.hpp"
|
|
|
|
#include <algorithm>
|
|
#include <pspgu.h>
|
|
#include <pspgum.h>
|
|
|
|
#include "math.hpp"
|
|
|
|
extern "C"
|
|
{
|
|
#include "../quakedef.h"
|
|
}
|
|
|
|
namespace quake
|
|
{
|
|
namespace clipping
|
|
{
|
|
// Plane types are sorted, most likely to clip first.
|
|
enum plane_index
|
|
{
|
|
#if CLIP_BOTTOM
|
|
plane_index_bottom,
|
|
#endif
|
|
#if CLIP_LEFT
|
|
plane_index_left,
|
|
#endif
|
|
#if CLIP_RIGHT
|
|
plane_index_right,
|
|
#endif
|
|
#if CLIP_TOP
|
|
plane_index_top,
|
|
#endif
|
|
#if CLIP_NEAR
|
|
plane_index_near,
|
|
#endif
|
|
#if CLIP_FAR
|
|
plane_index_far,
|
|
#endif
|
|
plane_count
|
|
};
|
|
|
|
// Types.
|
|
typedef ScePspFVector4 plane_type;
|
|
typedef plane_type frustum_t[plane_count];
|
|
|
|
// Transformed frustum.
|
|
static ScePspFMatrix4 projection_view_matrix __attribute__((aligned(16)));
|
|
static frustum_t projection_view_frustum __attribute__((aligned(16)));
|
|
static frustum_t clipping_frustum __attribute__((aligned(16)));
|
|
/*
|
|
shpuld's magical clipping adventures:
|
|
|
|
wide frustum explained, PSP hardware cull happens when any vert goes past the 0-4095 virtual coordinate space (VCS)
|
|
the viewport is centered in the middle of the VCS, so verts that go enough pixels past any of the screen edges to reach
|
|
the edge of the VCS get culled completely. this is why we need some kind of frustum clipping. however clipping to view
|
|
frustum is very wasteful, as most polys clipped to it would not get rejected by HW cull, only a tiny minority reach the edge of VCS.
|
|
|
|
for this reason, we have a wider frustum to better approximate (not calculated precisely) if polys get actually close to the edges.
|
|
now we could just use wide frustum only in clipping, check if clipping is required with the wide one, as well as clip with the wide one.
|
|
however this turned out to be slower, as a lot of the polygons that are completely out of regular frustum get through and get rendered,
|
|
and in addition polygons that clip the wider frustum might be completely out of view too so it's wasteful to clip them at all.
|
|
|
|
the currently fastest system uses wide frustum to check if a poly should proceed to clipping, if not then it gets drawn fast, then
|
|
polygons that do require clipping are then clipped using the accurate view frustum, this allows for vast majority of them to be rejected
|
|
when they fall completely outside the view. as a result the amount of actually clipped polygons ends up being extremely low.
|
|
this is fast.
|
|
*/
|
|
static ScePspFMatrix4 wide_projection_view_matrix __attribute__((aligned(16)));
|
|
static frustum_t wide_projection_view_frustum __attribute__((aligned(16)));
|
|
static frustum_t wide_clipping_frustum __attribute__((aligned(16)));
|
|
|
|
// The temporary working buffers.
|
|
static const std::size_t max_clipped_vertices = 32;
|
|
static glvert_t work_buffer[2][max_clipped_vertices] __attribute__((aligned(16)));
|
|
|
|
static inline void calculate_frustum(const ScePspFMatrix4& clip, frustum_t* frustum)
|
|
{
|
|
__asm__ (
|
|
".set push\n" // save assembler option
|
|
".set noreorder\n" // suppress reordering
|
|
#if CLIP_NEAR_FAR
|
|
"lv.q C000, 0(%6)\n" // C000 = clip->x
|
|
"lv.q C010, 16(%6)\n" // C010 = clip->y
|
|
"lv.q C020, 32(%6)\n" // C020 = clip->z
|
|
"lv.q C030, 48(%6)\n" // C030 = clip->w
|
|
#else
|
|
"lv.q C000, 0(%4)\n" // C000 = clip->x
|
|
"lv.q C010, 16(%4)\n" // C010 = clip->y
|
|
"lv.q C020, 32(%4)\n" // C020 = clip->z
|
|
"lv.q C030, 48(%4)\n" // C030 = clip->w
|
|
#endif
|
|
/* Extract the BOTTOM plane */
|
|
"vadd.s S100, S003, S001\n" // S100 = clip->x.w + clip->x.y
|
|
"vadd.s S101, S013, S011\n" // S101 = clip->y.w + clip->y.y
|
|
"vadd.s S102, S023, S021\n" // S102 = clip->z.w + clip->z.y
|
|
"vadd.s S103, S033, S031\n" // S103 = clip->w.w + clip->w.y
|
|
"vdot.q S110, C100, C100\n" // S110 = S100*S100 + S101*S101 + S102*S102 + S103*S103
|
|
"vzero.s S111\n" // S111 = 0
|
|
"vcmp.s EZ, S110\n" // CC[0] = ( S110 == 0.0f )
|
|
"vrsq.s S110, S110\n" // S110 = 1.0 / sqrt( S110 )
|
|
"vcmovt.s S110, S111, 0\n" // if ( CC[0] ) S110 = S111
|
|
"vscl.q C100[-1:1,-1:1,-1:1,-1:1], C100, S110\n" // C100 = C100 * S110
|
|
"sv.q C100, %0\n" // Store plane from register
|
|
/* Extract the LEFT plane */
|
|
"vadd.s S100, S003, S000\n" // S100 = clip->x.w + clip->x.x
|
|
"vadd.s S101, S013, S010\n" // S101 = clip->y.w + clip->y.x
|
|
"vadd.s S102, S023, S020\n" // S102 = clip->z.w + clip->z.x
|
|
"vadd.s S103, S033, S030\n" // S103 = clip->w.w + clip->w.x
|
|
"vdot.q S110, C100, C100\n" // S110 = S100*S100 + S101*S101 + S102*S102 + S103*S103
|
|
"vzero.s S111\n" // S111 = 0
|
|
"vcmp.s EZ, S110\n" // CC[0] = ( S110 == 0.0f )
|
|
"vrsq.s S110, S110\n" // S110 = 1.0 / sqrt( S110 )
|
|
"vcmovt.s S110, S111, 0\n" // if ( CC[0] ) S110 = S111
|
|
"vscl.q C100[-1:1,-1:1,-1:1,-1:1], C100, S110\n" // C100 = C100 * S110
|
|
"sv.q C100, %1\n" // Store plane from register
|
|
/* Extract the RIGHT plane */
|
|
"vsub.s S100, S003, S000\n" // S100 = clip->x.w - clip->x.x
|
|
"vsub.s S101, S013, S010\n" // S101 = clip->y.w - clip->y.x
|
|
"vsub.s S102, S023, S020\n" // S102 = clip->z.w - clip->z.x
|
|
"vsub.s S103, S033, S030\n" // S103 = clip->w.w - clip->w.x
|
|
"vdot.q S110, C100, C100\n" // S110 = S100*S100 + S101*S101 + S102*S102 + S103*S103
|
|
"vzero.s S111\n" // S111 = 0
|
|
"vcmp.s EZ, S110\n" // CC[0] = ( S110 == 0.0f )
|
|
"vrsq.s S110, S110\n" // S110 = 1.0 / sqrt( S110 )
|
|
"vcmovt.s S110, S111, 0\n" // if ( CC[0] ) S110 = S111
|
|
"vscl.q C100[-1:1,-1:1,-1:1,-1:1], C100, S110\n" // C100 = C100 * S110
|
|
"sv.q C100, %2\n" // Store plane from register
|
|
/* Extract the TOP plane */
|
|
"vsub.s S100, S003, S001\n" // S100 = clip->x.w - clip->x.y
|
|
"vsub.s S101, S013, S011\n" // S101 = clip->y.w - clip->y.y
|
|
"vsub.s S102, S023, S021\n" // S102 = clip->z.w - clip->z.y
|
|
"vsub.s S103, S033, S031\n" // S103 = clip->w.w - clip->w.y
|
|
"vdot.q S110, C100, C100\n" // S110 = S100*S100 + S101*S101 + S102*S102 + S103*S103
|
|
"vzero.s S111\n" // S111 = 0
|
|
"vcmp.s EZ, S110\n" // CC[0] = ( S110 == 0.0f )
|
|
"vrsq.s S110, S110\n" // S110 = 1.0 / sqrt( S110 )
|
|
"vcmovt.s S110, S111, 0\n" // if ( CC[0] ) S110 = S111
|
|
"vscl.q C100[-1:1,-1:1,-1:1,-1:1], C100, S110\n" // C100 = C100 * S110
|
|
"sv.q C100, %3\n" // Store plane from register
|
|
#if CLIP_NEAR_FAR
|
|
/* Extract the NEAR plane */
|
|
"vadd.s S100, S003, S002\n" // S100 = clip->x.w + clip->x.z
|
|
"vadd.s S101, S013, S012\n" // S101 = clip->y.w + clip->y.z
|
|
"vadd.s S102, S023, S022\n" // S102 = clip->z.w + clip->z.z
|
|
"vadd.s S103, S033, S032\n" // S103 = clip->w.w + clip->w.z
|
|
"vdot.q S110, C100, C100\n" // S110 = S100*S100 + S101*S101 + S102*S102 + S103*S103
|
|
"vzero.s S111\n" // S111 = 0
|
|
"vcmp.s EZ, S110\n" // CC[0] = ( S110 == 0.0f )
|
|
"vrsq.s S110, S110\n" // S110 = 1.0 / sqrt( S110 )
|
|
"vcmovt.s S110, S111, 0\n" // if ( CC[0] ) S110 = S111
|
|
"vscl.q C100[-1:1,-1:1,-1:1,-1:1], C100, S110\n" // C100 = C100 * S110
|
|
"sv.q C100, %4\n" // Store plane from register
|
|
/* Extract the FAR plane */
|
|
"vsub.s S100, S003, S002\n" // S100 = clip->x.w - clip->x.z
|
|
"vsub.s S101, S013, S012\n" // S101 = clip->y.w - clip->y.z
|
|
"vsub.s S102, S023, S022\n" // S102 = clip->z.w - clip->z.z
|
|
"vsub.s S103, S033, S032\n" // S103 = clip->w.w - clip->w.z
|
|
"vdot.q S110, C100, C100\n" // S110 = S100*S100 + S101*S101 + S102*S102 + S103*S103
|
|
"vzero.s S111\n" // S111 = 0
|
|
"vcmp.s EZ, S110\n" // CC[0] = ( S110 == 0.0f )
|
|
"vrsq.s S110, S110\n" // S110 = 1.0 / sqrt( S110 )
|
|
"vcmovt.s S110, S111, 0\n" // if ( CC[0] ) S110 = S111
|
|
"vscl.q C100[-1:1,-1:1,-1:1,-1:1], C100, S110\n" // C100 = C100 * S110
|
|
"sv.q C100, %5\n" // Store plane from register
|
|
#endif
|
|
".set pop\n" // Restore assembler option
|
|
: "=m"( ( *frustum )[plane_index_bottom] ),
|
|
"=m"( ( *frustum )[plane_index_left] ),
|
|
"=m"( ( *frustum )[plane_index_right] ),
|
|
#if CLIP_NEAR_FAR
|
|
"=m"( ( *frustum )[plane_index_top] ),
|
|
"=m"( ( *frustum )[plane_index_near] ),
|
|
"=m"( ( *frustum )[plane_index_far] )
|
|
#else
|
|
"=m"( ( *frustum )[plane_index_top] )
|
|
#endif
|
|
: "r"( &clip )
|
|
);
|
|
}
|
|
|
|
void begin_frame(float regularfov, float wideclippingfov, float screenaspect)
|
|
{
|
|
// Get the projection matrix.
|
|
sceGumMatrixMode(GU_PROJECTION);
|
|
sceGumLoadIdentity();
|
|
sceGumPerspective(regularfov + 1.0f, screenaspect, 6, 4096); // add + 1.0f to reduce the 1px lines at the edge of viewport when polys get clipped
|
|
sceGumUpdateMatrix();
|
|
|
|
ScePspFMatrix4 proj;
|
|
sceGumStoreMatrix(&proj);
|
|
|
|
sceGumLoadIdentity();
|
|
sceGumPerspective(wideclippingfov, screenaspect, 6, 4096);
|
|
sceGumUpdateMatrix();
|
|
|
|
ScePspFMatrix4 wide_proj;
|
|
sceGumStoreMatrix(&wide_proj);
|
|
|
|
// Get the view matrix.
|
|
sceGumMatrixMode(GU_VIEW);
|
|
ScePspFMatrix4 view;
|
|
sceGumStoreMatrix(&view);
|
|
|
|
// Restore matrix mode.
|
|
sceGumMatrixMode(GU_MODEL);
|
|
|
|
// Combine the two matrices (multiply projection by view).
|
|
gumMultMatrix(&projection_view_matrix, &proj, &view);
|
|
gumMultMatrix(&wide_projection_view_matrix, &wide_proj, &view);
|
|
|
|
// Calculate and cache the clipping frustum.
|
|
calculate_frustum(projection_view_matrix, &projection_view_frustum);
|
|
calculate_frustum(wide_projection_view_matrix, &wide_projection_view_frustum);
|
|
|
|
__asm__ volatile (
|
|
"ulv.q C700, %4\n" // Load plane into register
|
|
"ulv.q C710, %5\n" // Load plane into register
|
|
"ulv.q C720, %6\n" // Load plane into register
|
|
"ulv.q C730, %7\n" // Load plane into register
|
|
"sv.q C700, %0\n" // Store plane from register
|
|
"sv.q C710, %1\n" // Store plane from register
|
|
"sv.q C720, %2\n" // Store plane from register
|
|
"sv.q C730, %3\n" // Store plane from register
|
|
: "=m"( clipping_frustum[plane_index_bottom] ),
|
|
"=m"( clipping_frustum[plane_index_left] ),
|
|
"=m"( clipping_frustum[plane_index_right] ),
|
|
"=m"( clipping_frustum[plane_index_top] )
|
|
: "m"( projection_view_frustum[plane_index_bottom] ),
|
|
"m"( projection_view_frustum[plane_index_left] ),
|
|
"m"( projection_view_frustum[plane_index_right] ),
|
|
"m"( projection_view_frustum[plane_index_top] )
|
|
);
|
|
|
|
__asm__ volatile (
|
|
"ulv.q C500, %4\n" // Load plane into register
|
|
"ulv.q C510, %5\n" // Load plane into register
|
|
"ulv.q C520, %6\n" // Load plane into register
|
|
"ulv.q C530, %7\n" // Load plane into register
|
|
"sv.q C500, %0\n" // Store plane from register
|
|
"sv.q C510, %1\n" // Store plane from register
|
|
"sv.q C520, %2\n" // Store plane from register
|
|
"sv.q C530, %3\n" // Store plane from register
|
|
: "=m"( wide_clipping_frustum[plane_index_bottom] ),
|
|
"=m"( wide_clipping_frustum[plane_index_left] ),
|
|
"=m"( wide_clipping_frustum[plane_index_right] ),
|
|
"=m"( wide_clipping_frustum[plane_index_top] )
|
|
: "m"( wide_projection_view_frustum[plane_index_bottom] ),
|
|
"m"( wide_projection_view_frustum[plane_index_left] ),
|
|
"m"( wide_projection_view_frustum[plane_index_right] ),
|
|
"m"( wide_projection_view_frustum[plane_index_top] )
|
|
);
|
|
}
|
|
|
|
void begin_brush_model()
|
|
{
|
|
// Get the model matrix.
|
|
ScePspFMatrix4 model_matrix;
|
|
sceGumStoreMatrix(&model_matrix);
|
|
|
|
// Combine the matrices (multiply projection-view by model).
|
|
ScePspFMatrix4 projection_view_model_matrix;
|
|
gumMultMatrix(&projection_view_model_matrix, &projection_view_matrix, &model_matrix);
|
|
|
|
// Calculate the clipping frustum.
|
|
calculate_frustum(projection_view_model_matrix, &clipping_frustum);
|
|
|
|
__asm__ volatile (
|
|
"ulv.q C700, %0\n" // Load plane into register
|
|
"ulv.q C710, %1\n" // Load plane into register
|
|
"ulv.q C720, %2\n" // Load plane into register
|
|
"ulv.q C730, %3\n" // Load plane into register
|
|
:: "m"(clipping_frustum[plane_index_bottom]),
|
|
"m"(clipping_frustum[plane_index_left]),
|
|
"m"(clipping_frustum[plane_index_right]),
|
|
"m"(clipping_frustum[plane_index_top])
|
|
);
|
|
|
|
// Combine the matrices (multiply projection-view by model).
|
|
ScePspFMatrix4 wide_projection_view_model_matrix;
|
|
gumMultMatrix(&wide_projection_view_model_matrix, &wide_projection_view_matrix, &model_matrix);
|
|
|
|
// Calculate the clipping frustum.
|
|
calculate_frustum(wide_projection_view_model_matrix, &wide_clipping_frustum);
|
|
|
|
__asm__ volatile (
|
|
"ulv.q C500, %0\n" // Load plane into register
|
|
"ulv.q C510, %1\n" // Load plane into register
|
|
"ulv.q C520, %2\n" // Load plane into register
|
|
"ulv.q C530, %3\n" // Load plane into register
|
|
:: "m"(wide_clipping_frustum[plane_index_bottom]),
|
|
"m"(wide_clipping_frustum[plane_index_left]),
|
|
"m"(wide_clipping_frustum[plane_index_right]),
|
|
"m"(wide_clipping_frustum[plane_index_top])
|
|
);
|
|
}
|
|
|
|
void end_brush_model()
|
|
{
|
|
// Restore the clipping frustum.
|
|
__asm__ volatile (
|
|
"ulv.q C700, %4\n" // Load plane into register
|
|
"ulv.q C710, %5\n" // Load plane into register
|
|
"ulv.q C720, %6\n" // Load plane into register
|
|
"ulv.q C730, %7\n" // Load plane into register
|
|
"sv.q C700, %0\n" // Store plane from register
|
|
"sv.q C710, %1\n" // Store plane from register
|
|
"sv.q C720, %2\n" // Store plane from register
|
|
"sv.q C730, %3\n" // Store plane from register
|
|
: "=m"( clipping_frustum[plane_index_bottom] ),
|
|
"=m"( clipping_frustum[plane_index_left] ),
|
|
"=m"( clipping_frustum[plane_index_right] ),
|
|
"=m"( clipping_frustum[plane_index_top] )
|
|
: "m"( projection_view_frustum[plane_index_bottom] ),
|
|
"m"( projection_view_frustum[plane_index_left] ),
|
|
"m"( projection_view_frustum[plane_index_right] ),
|
|
"m"( projection_view_frustum[plane_index_top] )
|
|
);
|
|
|
|
__asm__ volatile (
|
|
"ulv.q C500, %4\n" // Load plane into register
|
|
"ulv.q C510, %5\n" // Load plane into register
|
|
"ulv.q C520, %6\n" // Load plane into register
|
|
"ulv.q C530, %7\n" // Load plane into register
|
|
"sv.q C500, %0\n" // Store plane from register
|
|
"sv.q C510, %1\n" // Store plane from register
|
|
"sv.q C520, %2\n" // Store plane from register
|
|
"sv.q C530, %3\n" // Store plane from register
|
|
: "=m"( wide_clipping_frustum[plane_index_bottom] ),
|
|
"=m"( wide_clipping_frustum[plane_index_left] ),
|
|
"=m"( wide_clipping_frustum[plane_index_right] ),
|
|
"=m"( wide_clipping_frustum[plane_index_top] )
|
|
: "m"( wide_projection_view_frustum[plane_index_bottom] ),
|
|
"m"( wide_projection_view_frustum[plane_index_left] ),
|
|
"m"( wide_projection_view_frustum[plane_index_right] ),
|
|
"m"( wide_projection_view_frustum[plane_index_top] )
|
|
);
|
|
}
|
|
|
|
bool is_clipping_required(const struct glvert_s* vertices, std::size_t vertex_count)
|
|
{
|
|
int res;
|
|
__asm__ (
|
|
".set push\n" // save assembler option
|
|
".set noreorder\n" // suppress reordering
|
|
"move $8, %1\n" // $8 = &v[0]
|
|
"move $9, %2\n" // $9 = vc
|
|
"li $10, 20\n" // $10 = 20( sizeof( gu_vert_t ) )
|
|
"mul $10, $10, $9\n" // $10 = $10 * $9
|
|
"addu $10, $10, $8\n" // $10 = $10 + $8
|
|
"addiu %0, $0, 1\n" // res = 1
|
|
"vzero.q C600\n" // C600 = [0.0f, 0.0f, 0.0f. 0.0f]
|
|
"0:\n" // loop
|
|
"lv.s S610, 8($8)\n" // S610 = v[i].xyz[0]
|
|
"lv.s S611, 12($8)\n" // S611 = v[i].xyz[1]
|
|
"lv.s S612, 16($8)\n" // S612 = v[i].xyz[2]
|
|
"vhtfm4.q C620, M500, C610\n" // C620 = frustrum * v[i].xyz, note: 500 is wide frustum, 700 is regular frustum
|
|
"vcmp.q LT, C620, C600\n" // S620 < 0.0f || S621 < 0.0f || S622 < 0.0f || S623 < 0.0f
|
|
"bvt 4, 1f\n" // if ( CC[4] == 1 ) jump to exit
|
|
"addiu $8, $8, 20\n" // $8 = $8 + 20( sizeof( gu_vert_t ) ) ( delay slot )
|
|
"bne $10, $8, 0b\n" // if ( $10 != $8 ) jump to loop
|
|
"nop\n" // ( delay slot )
|
|
"move %0, $0\n" // res = 0
|
|
"1:\n" // exit
|
|
".set pop\n" // Restore assembler option
|
|
: "=r"(res)
|
|
: "r"(vertices), "r"(vertex_count)
|
|
: "$8", "$9", "$10"
|
|
);
|
|
return (res == 1) ? true : false;
|
|
}
|
|
|
|
// Clips a polygon against a plane.
|
|
// http://hpcc.engin.umich.edu/CFD/users/charlton/Thesis/html/node90.html
|
|
static void clip_to_plane(
|
|
const plane_type& plane,
|
|
const glvert_t* const unclipped_vertices,
|
|
std::size_t const unclipped_vertex_count,
|
|
glvert_t* const clipped_vertices,
|
|
std::size_t* const clipped_vertex_count)
|
|
{
|
|
__asm__ (
|
|
".set push\n" // save assembler option
|
|
".set noreorder\n" // suppress reordering
|
|
"move $8, %1\n" // $8 = uv[0] is S
|
|
"addiu $9, $8, 20\n" // $9 = uv[1] is P
|
|
"move $10, %2\n" // $10 = uvc
|
|
"li $11, 20\n" // $11 = 20( sizeof( gu_vert_t ) )
|
|
"mul $11, $11, $10\n" // $11 = $11 * $10
|
|
"addu $11, $11, $8\n" // $11 = $11 + $8
|
|
"move $12, %3\n" // $12 = &cv[0]
|
|
"move %0, $0\n" // cvc = 0
|
|
"ulv.q C100, %4\n" // Load plane into register
|
|
"vzero.s S110\n" // Set zero for cmp
|
|
"0:\n" // loop
|
|
"ulv.q C000, 0($8)\n" // Load vertex S TEX(8b) into register
|
|
"vzero.p C002\n" // Set the 3th and 4th entry C000 to zero
|
|
"ulv.q C010, 8($8)\n" // Load vertex S XYZ(12b) into register
|
|
"vzero.s S013\n" // Set the 4th entry C010 to zero
|
|
"ulv.q C020, 0($9)\n" // Load vertex P TEX(8b) into register
|
|
"vzero.p C022\n" // Set the 3th and 4th entry C020 to zero
|
|
"ulv.q C030, 8($9)\n" // Load vertex P XYZ(12b) into register
|
|
"vzero.s S033\n" // Set the 4th entry C030 to zero
|
|
"vdot.q S111, C100, C010\n" // S111 = plane * S
|
|
"vdot.q S112, C100, C030\n" // S112 = plane * P
|
|
"vadd.s S111, S111, S103\n" // S111 = S111 + plane->w is S dist
|
|
"vadd.s S112, S112, S103\n" // S112 = S112 + plane->w is P dist
|
|
"vcmp.s LE, S111, S110\n" // (S dist <= 0.0f)
|
|
"bvt 0, 2f\n" // if ( CC[0] == 1 ) jump to 2f
|
|
"nop\n" // ( delay slot )
|
|
"vcmp.s LE, S112, S110\n" // (P dist <= 0.0f)
|
|
"bvt 0, 1f\n" // if ( CC[0] == 1 ) jump to 1f
|
|
"nop\n" // ( delay slot )
|
|
"sv.s S020, 0($12)\n" // cv->uv[0] = C020 TEX U
|
|
"sv.s S021, 4($12)\n" // cv->uv[1] = C021 TEX V
|
|
"sv.s S030, 8($12)\n" // cv->xyz[0] = C030 XYZ X
|
|
"sv.s S031, 12($12)\n" // cv->xyz[1] = C031 XYZ Y
|
|
"sv.s S032, 16($12)\n" // cv->xyz[2] = C032 XYZ Z
|
|
"addiu $12, $12, 20\n" // $12 = $12 + 20( sizeof( gu_vert_t ) )
|
|
"j 3f\n" // jump to next
|
|
"addiu %0, %0, 1\n" // cvc += 1 ( delay slot )
|
|
"1:\n"
|
|
"vsub.s S112, S111, S112\n" // S112 = ( S dist - P dist )
|
|
"vdiv.s S112, S111, S112\n" // S112 = S111 / S112
|
|
"vsub.q C120, C020, C000\n" // C120 = C020(P TEX) - C000(S TEX)
|
|
"vsub.q C130, C030, C010\n" // C130 = C030(P XYZ) - C010(S XYZ)
|
|
"vscl.q C120, C120, S112\n" // C120 = C020 * S112
|
|
"vscl.q C130, C130, S112\n" // C130 = C030 * S112
|
|
"vadd.q C120, C120, C000\n" // C120 = C120 + C000(S TEX)
|
|
"vadd.q C130, C130, C010\n" // C130 = C130 + C010(S XYZ)
|
|
"sv.s S120, 0($12)\n" // cv->uv[0] = S120 TEX U
|
|
"sv.s S121, 4($12)\n" // cv->uv[1] = S121 TEX V
|
|
"sv.s S130, 8($12)\n" // cv->xyz[0] = S130 XYZ X
|
|
"sv.s S131, 12($12)\n" // cv->xyz[1] = S131 XYZ Y
|
|
"sv.s S132, 16($12)\n" // cv->xyz[2] = S132 XYZ Z
|
|
"addiu $12, $12, 20\n" // $12 = $12 + 20( sizeof( gu_vert_t ) )
|
|
"j 3f\n" // jump to next
|
|
"addiu %0, %0, 1\n" // cvc += 1 ( delay slot )
|
|
"2:\n"
|
|
"vcmp.s LE, S112, S110\n" // (P dist <= 0.0f)
|
|
"bvt 0, 3f\n" // if ( CC[0] == 1 ) jump to next
|
|
"nop\n" // ( delay slot )
|
|
"vsub.s S112, S111, S112\n" // S112 = ( S dist - P dist )
|
|
"vdiv.s S112, S111, S112\n" // S112 = S111 / S112
|
|
"vsub.q C120, C020, C000\n" // C120 = C020(P TEX) - C000(S TEX)
|
|
"vsub.q C130, C030, C010\n" // C130 = C030(P XYZ) - C010(S XYZ)
|
|
"vscl.q C120, C120, S112\n" // C120 = C020 * S112
|
|
"vscl.q C130, C130, S112\n" // C130 = C030 * S112
|
|
"vadd.q C120, C120, C000\n" // C120 = C120 + C000(S TEX)
|
|
"vadd.q C130, C130, C010\n" // C130 = C130 + C010(S XYZ)
|
|
"sv.s S120, 0($12)\n" // cv->uv[0] = S120 TEX U
|
|
"sv.s S121, 4($12)\n" // cv->uv[1] = S121 TEX V
|
|
"sv.s S130, 8($12)\n" // cv->xyz[0] = S130 XYZ X
|
|
"sv.s S131, 12($12)\n" // cv->xyz[1] = S131 XYZ Y
|
|
"sv.s S132, 16($12)\n" // cv->xyz[2] = S132 XYZ Z
|
|
"addiu $12, $12, 20\n" // $12 = $12 + 20( sizeof( gu_vert_t ) )
|
|
"addiu %0, %0, 1\n" // cvc += 1
|
|
"sv.s S020, 0($12)\n" // cv->uv[0] = S020 TEX U
|
|
"sv.s S021, 4($12)\n" // cv->uv[1] = S021 TEX V
|
|
"sv.s S030, 8($12)\n" // cv->xyz[0] = S030 XYZ X
|
|
"sv.s S031, 12($12)\n" // cv->xyz[1] = S031 XYZ Y
|
|
"sv.s S032, 16($12)\n" // cv->xyz[2] = S032 XYZ Z
|
|
"addiu $12, $12, 20\n" // $12 = $12 + 20( sizeof( gu_vert_t ) )
|
|
"addiu %0, %0, 1\n" // cvc += 1
|
|
"3:\n" // next
|
|
"addiu $8, $8, 20\n" // $8 = $8 + 20( sizeof( gu_vert_t ) )
|
|
"addiu $9, $8, 20\n" // $9 = $8 + 20( sizeof( gu_vert_t ) )
|
|
"bne $9, $11, 4f\n" // if ( $11 != $9 ) jump to next
|
|
"nop\n"
|
|
"move $9, %1\n" // $9 = &uv[0] set P
|
|
"4:\n"
|
|
"bne $11, $8, 0b\n" // if ( $11 != $8 ) jump to loop
|
|
"nop\n" // ( delay slot )
|
|
".set pop\n" // Restore assembler option
|
|
: "+r"( *clipped_vertex_count )
|
|
: "r"( unclipped_vertices ), "r"( unclipped_vertex_count ), "r"( clipped_vertices ), "m"( plane )
|
|
: "$8", "$9", "$10", "$11", "$12"
|
|
);
|
|
}
|
|
|
|
// Clips a polygon against the frustum.
|
|
void clip(
|
|
const struct glvert_s* unclipped_vertices,
|
|
std::size_t unclipped_vertex_count,
|
|
const struct glvert_s** clipped_vertices,
|
|
std::size_t* clipped_vertex_count)
|
|
{
|
|
// No vertices to clip?
|
|
if (!unclipped_vertex_count)
|
|
{
|
|
// Error.
|
|
Sys_Error("Calling clip with zero vertices");
|
|
}
|
|
|
|
// Set up constants.
|
|
const plane_type* const last_plane = &clipping_frustum[plane_count];
|
|
|
|
// Set up the work buffer pointers.
|
|
const glvert_t* src = unclipped_vertices;
|
|
glvert_t* dst = work_buffer[0];
|
|
std::size_t vertex_count = unclipped_vertex_count;
|
|
|
|
// For each frustum plane...
|
|
for (const plane_type* plane = &clipping_frustum[0]; plane != last_plane; ++plane)
|
|
{
|
|
// Clip the poly against this frustum plane.
|
|
clip_to_plane(*plane, src, vertex_count, dst, &vertex_count);
|
|
|
|
// No vertices left to clip?
|
|
if (!vertex_count)
|
|
{
|
|
// Quit early.
|
|
*clipped_vertex_count = 0;
|
|
return;
|
|
}
|
|
|
|
// Use the next pair of buffers.
|
|
src = dst;
|
|
if (dst == work_buffer[0])
|
|
{
|
|
dst = work_buffer[1];
|
|
}
|
|
else
|
|
{
|
|
dst = work_buffer[0];
|
|
}
|
|
}
|
|
|
|
// Fill in the return data.
|
|
*clipped_vertices = src;
|
|
*clipped_vertex_count = vertex_count;
|
|
}
|
|
}
|
|
} |