blob: 246ec2f13833c18aade255e467a1515b00510522 [file] [log] [blame]
// SwiftShader Software Renderer
//
// Copyright(c) 2005-2012 TransGaming Inc.
//
// All rights reserved. No part of this software may be copied, distributed, transmitted,
// transcribed, stored in a retrieval system, translated into any human or computer
// language by any means, or disclosed to third parties without the explicit written
// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
// or implied, including but not limited to any patent rights, are granted to you.
//
#include "Clipper.hpp"
#include "Polygon.hpp"
#include "Renderer.hpp"
#include "Debug.hpp"
#include <malloc.h>
namespace sw
{
Clipper::Clipper()
{
}
Clipper::~Clipper()
{
}
bool Clipper::clip(Polygon &polygon, int clipFlagsOr, const DrawCall &draw)
{
DrawData &data = *draw.data;
polygon.b = 0;
if(clipFlagsOr & 0x0000003F)
{
if(clipFlagsOr & CLIP_NEAR) clipNear(polygon);
if(polygon.n >= 3) {
if(clipFlagsOr & CLIP_FAR) clipFar(polygon);
if(polygon.n >= 3) {
if(clipFlagsOr & CLIP_LEFT) clipLeft(polygon, data);
if(polygon.n >= 3) {
if(clipFlagsOr & CLIP_RIGHT) clipRight(polygon, data);
if(polygon.n >= 3) {
if(clipFlagsOr & CLIP_TOP) clipTop(polygon, data);
if(polygon.n >= 3) {
if(clipFlagsOr & CLIP_BOTTOM) clipBottom(polygon, data);
}}}}}
}
if(clipFlagsOr & 0x00003F00)
{
if(polygon.n >= 3) {
if(draw.clipFlags & CLIP_PLANE0) clipPlane(polygon, data.clipPlane[0]);
if(polygon.n >= 3) {
if(draw.clipFlags & CLIP_PLANE1) clipPlane(polygon, data.clipPlane[1]);
if(polygon.n >= 3) {
if(draw.clipFlags & CLIP_PLANE2) clipPlane(polygon, data.clipPlane[2]);
if(polygon.n >= 3) {
if(draw.clipFlags & CLIP_PLANE3) clipPlane(polygon, data.clipPlane[3]);
if(polygon.n >= 3) {
if(draw.clipFlags & CLIP_PLANE4) clipPlane(polygon, data.clipPlane[4]);
if(polygon.n >= 3) {
if(draw.clipFlags & CLIP_PLANE5) clipPlane(polygon, data.clipPlane[5]);
}}}}}}
}
return polygon.n >= 3;
}
void Clipper::clipNear(Polygon &polygon)
{
if(polygon.n == 0) return;
const float4 **V = polygon.P[polygon.i];
const float4 **T = polygon.P[polygon.i + 1];
int t = 0;
for(int i = 0; i < polygon.n; i++)
{
int j = i == polygon.n - 1 ? 0 : i + 1;
float di = V[i]->z;
float dj = V[j]->z;
if(di >= 0)
{
T[t++] = V[i];
if(dj < 0)
{
clipEdge(polygon.B[polygon.b], *V[i], *V[j], di, dj);
polygon.B[polygon.b].z = 0;
T[t++] = &polygon.B[polygon.b++];
}
}
else
{
if(dj > 0)
{
clipEdge(polygon.B[polygon.b], *V[j], *V[i], dj, di);
polygon.B[polygon.b].z = 0;
T[t++] = &polygon.B[polygon.b++];
}
}
}
polygon.n = t;
polygon.i += 1;
}
void Clipper::clipFar(Polygon &polygon)
{
if(polygon.n == 0) return;
const float4 **V = polygon.P[polygon.i];
const float4 **T = polygon.P[polygon.i + 1];
int t = 0;
for(int i = 0; i < polygon.n; i++)
{
int j = i == polygon.n - 1 ? 0 : i + 1;
float di = V[i]->w - V[i]->z;
float dj = V[j]->w - V[j]->z;
if(di >= 0)
{
T[t++] = V[i];
if(dj < 0)
{
clipEdge(polygon.B[polygon.b], *V[i], *V[j], di, dj);
polygon.B[polygon.b].z = polygon.B[polygon.b].w;
T[t++] = &polygon.B[polygon.b++];
}
}
else
{
if(dj > 0)
{
clipEdge(polygon.B[polygon.b], *V[j], *V[i], dj, di);
polygon.B[polygon.b].z = polygon.B[polygon.b].w;
T[t++] = &polygon.B[polygon.b++];
}
}
}
polygon.n = t;
polygon.i += 1;
}
void Clipper::clipLeft(Polygon &polygon, const DrawData &data)
{
if(polygon.n == 0) return;
const float4 **V = polygon.P[polygon.i];
const float4 **T = polygon.P[polygon.i + 1];
int t = 0;
for(int i = 0; i < polygon.n; i++)
{
int j = i == polygon.n - 1 ? 0 : i + 1;
float di = V[i]->w + (V[i]->x + data.halfPixelX[0] * V[i]->w);
float dj = V[j]->w + (V[j]->x + data.halfPixelX[0] * V[j]->w);
if(di >= 0)
{
T[t++] = V[i];
if(dj < 0)
{
clipEdge(polygon.B[polygon.b], *V[i], *V[j], di, dj);
// polygon.B[polygon.b].x = -polygon.B[polygon.b].w;
T[t++] = &polygon.B[polygon.b++];
}
}
else
{
if(dj > 0)
{
clipEdge(polygon.B[polygon.b], *V[j], *V[i], dj, di);
// polygon.B[polygon.b].x = -polygon.B[polygon.b].w;
T[t++] = &polygon.B[polygon.b++];
}
}
}
polygon.n = t;
polygon.i += 1;
}
void Clipper::clipRight(Polygon &polygon, const DrawData &data)
{
if(polygon.n == 0) return;
const float4 **V = polygon.P[polygon.i];
const float4 **T = polygon.P[polygon.i + 1];
int t = 0;
for(int i = 0; i < polygon.n; i++)
{
int j = i == polygon.n - 1 ? 0 : i + 1;
float di = V[i]->w - (V[i]->x + data.halfPixelX[0] * V[i]->w);
float dj = V[j]->w - (V[j]->x + data.halfPixelX[0] * V[j]->w);
if(di >= 0)
{
T[t++] = V[i];
if(dj < 0)
{
clipEdge(polygon.B[polygon.b], *V[i], *V[j], di, dj);
// polygon.B[polygon.b].x = polygon.B[polygon.b].w;
T[t++] = &polygon.B[polygon.b++];
}
}
else
{
if(dj > 0)
{
clipEdge(polygon.B[polygon.b], *V[j], *V[i], dj, di);
// polygon.B[polygon.b].x = polygon.B[polygon.b].w;
T[t++] = &polygon.B[polygon.b++];
}
}
}
polygon.n = t;
polygon.i += 1;
}
void Clipper::clipTop(Polygon &polygon, const DrawData &data)
{
if(polygon.n == 0) return;
const float4 **V = polygon.P[polygon.i];
const float4 **T = polygon.P[polygon.i + 1];
int t = 0;
for(int i = 0; i < polygon.n; i++)
{
int j = i == polygon.n - 1 ? 0 : i + 1;
float di = V[i]->w - (V[i]->y + data.halfPixelY[0] * V[i]->w);
float dj = V[j]->w - (V[j]->y + data.halfPixelY[0] * V[j]->w);
if(di >= 0)
{
T[t++] = V[i];
if(dj < 0)
{
clipEdge(polygon.B[polygon.b], *V[i], *V[j], di, dj);
// polygon.B[polygon.b].y = polygon.B[polygon.b].w;
T[t++] = &polygon.B[polygon.b++];
}
}
else
{
if(dj > 0)
{
clipEdge(polygon.B[polygon.b], *V[j], *V[i], dj, di);
// polygon.B[polygon.b].y = polygon.B[polygon.b].w;
T[t++] = &polygon.B[polygon.b++];
}
}
}
polygon.n = t;
polygon.i += 1;
}
void Clipper::clipBottom(Polygon &polygon, const DrawData &data)
{
if(polygon.n == 0) return;
const float4 **V = polygon.P[polygon.i];
const float4 **T = polygon.P[polygon.i + 1];
int t = 0;
for(int i = 0; i < polygon.n; i++)
{
int j = i == polygon.n - 1 ? 0 : i + 1;
float di = V[i]->w + (V[i]->y + data.halfPixelY[0] * V[i]->w);
float dj = V[j]->w + (V[j]->y + data.halfPixelY[0] * V[j]->w);
if(di >= 0)
{
T[t++] = V[i];
if(dj < 0)
{
clipEdge(polygon.B[polygon.b], *V[i], *V[j], di, dj);
// polygon.B[polygon.b].y = -polygon.B[polygon.b].w;
T[t++] = &polygon.B[polygon.b++];
}
}
else
{
if(dj > 0)
{
clipEdge(polygon.B[polygon.b], *V[j], *V[i], dj, di);
// polygon.B[polygon.b].y = -polygon.B[polygon.b].w;
T[t++] = &polygon.B[polygon.b++];
}
}
}
polygon.n = t;
polygon.i += 1;
}
void Clipper::clipPlane(Polygon &polygon, const Plane &p)
{
if(polygon.n == 0) return;
const float4 **V = polygon.P[polygon.i];
const float4 **T = polygon.P[polygon.i + 1];
int t = 0;
for(int i = 0; i < polygon.n; i++)
{
int j = i == polygon.n - 1 ? 0 : i + 1;
float di = p.A * V[i]->x + p.B * V[i]->y + p.C * V[i]->z + p.D * V[i]->w;
float dj = p.A * V[j]->x + p.B * V[j]->y + p.C * V[j]->z + p.D * V[j]->w;
if(di >= 0)
{
T[t++] = V[i];
if(dj < 0)
{
clipEdge(polygon.B[polygon.b], *V[i], *V[j], di, dj);
T[t++] = &polygon.B[polygon.b++];
}
}
else
{
if(dj > 0)
{
clipEdge(polygon.B[polygon.b], *V[j], *V[i], dj, di);
T[t++] = &polygon.B[polygon.b++];
}
}
}
polygon.n = t;
polygon.i += 1;
}
inline void Clipper::clipEdge(float4 &Vo, const float4 &Vi, const float4 &Vj, float di, float dj) const
{
float D = 1.0f / (dj - di);
Vo.x = (dj * Vi.x - di * Vj.x) * D;
Vo.y = (dj * Vi.y - di * Vj.y) * D;
Vo.z = (dj * Vi.z - di * Vj.z) * D;
Vo.w = (dj * Vi.w - di * Vj.w) * D;
}
}