rectClipper.cpp
Engine/source/util/rectClipper.cpp
Detailed Description
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "util/rectClipper.h" 25 26namespace { 27 28inline void 29swap(F32& in_one, F32& in_two) 30{ 31 F32 temp = in_one; 32 in_one = in_two; 33 in_two = temp; 34} 35 36} 37 38bool 39RectClipper::clipLine(const Point2I& in_rStart, 40 const Point2I& in_rEnd, 41 Point2I& out_rStart, 42 Point2I& out_rEnd) const 43{ 44 // Check for trivial rejection 45 if ((in_rStart.x < m_clipRect.point.x && in_rEnd.x < m_clipRect.point.x) || 46 (in_rStart.x >= m_clipRect.point.x + m_clipRect.extent.x && 47 in_rEnd.x >= m_clipRect.point.x + m_clipRect.extent.x)) 48 return false; 49 if ((in_rStart.y < m_clipRect.point.y && in_rEnd.y < m_clipRect.point.y) || 50 (in_rStart.y >= m_clipRect.point.y + m_clipRect.extent.y && 51 in_rEnd.y >= m_clipRect.point.y + m_clipRect.extent.y)) 52 return false; 53 54 F32 x1 = F32(in_rStart.x); 55 F32 y1 = F32(in_rStart.y); 56 F32 x2 = F32(in_rEnd.x); 57 F32 y2 = F32(in_rEnd.y); 58 59 // I'm using essentially what's in the Phoenix libs, Liang-Biarsky based, but 60 // converted to FP math for greater precision on the back end... 61 // 62 bool flipped = false; 63 if (x1 > x2) 64 { 65 swap(x1, x2); 66 swap(y1, y2); 67 flipped = !flipped; 68 } 69 70 F32 dx = x2 - x1; 71 F32 dy = y2 - y1; 72 73 // Clip x coord 74 F32 t; 75 if (x1 < F32(m_clipRect.point.x)) 76 { 77 t = (F32(m_clipRect.point.x) - x1) / F32(dx); 78 x1 = F32(m_clipRect.point.x); 79 y1 += t * dy; 80 dx = x2 - x1; 81 dy = y2 - y1; 82 } 83 if (x2 >= F32(m_clipRect.point.x + m_clipRect.extent.x)) 84 { 85 t = (F32(m_clipRect.point.x + m_clipRect.extent.x - 1) - x1) / F32(dx); 86 x2 = F32(m_clipRect.point.x + m_clipRect.extent.x - 1); 87 y2 = y1 + (t * dy); 88 dx = x2 - x1; 89 dy = y2 - y1; 90 } 91 92 // Recheck trivial rejection condition... 93 if((y1 > F32(m_clipRect.point.y + m_clipRect.extent.y - 1) && 94 y2 > F32(m_clipRect.point.y + m_clipRect.extent.y - 1)) || 95 (y1 < F32(m_clipRect.point.y) && y2 < F32(m_clipRect.point.y))) 96 return false; 97 98 if (y1 > y2) 99 { 100 swap(x1, x2); 101 swap(y1, y2); 102 flipped = !flipped; 103 } 104 105 if (y1 < F32(m_clipRect.point.y)) 106 { 107 t = (F32(m_clipRect.point.y) - y1) / F32(dy); 108 y1 = F32(m_clipRect.point.y); 109 x1 += t * dx; 110 dx = x2 - x1; 111 dy = y2 - y1; 112 } 113 if (y2 > F32(m_clipRect.point.y + m_clipRect.extent.y - 1)) 114 { 115 t = (F32(m_clipRect.point.y + m_clipRect.extent.y - 1) - y1) / F32(dy); 116 y2 = F32(m_clipRect.point.y + m_clipRect.extent.y - 1); 117 x2 = x1 + (t * dx); 118 } 119 120 if (flipped == true) 121 { 122 out_rEnd.x = S32(x1 + 0.5f); 123 out_rEnd.y = S32(y1 + 0.5f); 124 out_rStart.x = S32(x2 + 0.5f); 125 out_rStart.y = S32(y2 + 0.5f); 126 } 127 else 128 { 129 out_rStart.x = S32(x1 + 0.5f); 130 out_rStart.y = S32(y1 + 0.5f); 131 out_rEnd.x = S32(x2 + 0.5f); 132 out_rEnd.y = S32(y2 + 0.5f); 133 } 134 135 return true; 136} 137 138 139bool 140RectClipper::clipRect(const RectI& in_rRect, 141 RectI& out_rRect) const 142{ 143 AssertFatal(in_rRect.isValidRect(), "Inappropriate min/max coords for rectangle"); 144 145 if (in_rRect.point.x + in_rRect.extent.x - 1 < m_clipRect.point.x || 146 in_rRect.point.x > m_clipRect.point.x + m_clipRect.extent.x - 1) 147 return false; 148 if (in_rRect.point.y + in_rRect.extent.y - 1 < m_clipRect.point.y || 149 in_rRect.point.y > m_clipRect.point.y + m_clipRect.extent.y - 1) 150 return false; 151 152 if (in_rRect.point.x < m_clipRect.point.x) out_rRect.point.x = m_clipRect.point.x; 153 else out_rRect.point.x = in_rRect.point.x; 154 155 if (in_rRect.point.y < m_clipRect.point.y) out_rRect.point.y = m_clipRect.point.y; 156 else out_rRect.point.y = in_rRect.point.y; 157 158 Point2I bottomR; 159 bottomR.x = getMin(in_rRect.point.x + in_rRect.extent.x - 1, 160 m_clipRect.point.x + m_clipRect.extent.x - 1); 161 bottomR.y = getMin(in_rRect.point.y + in_rRect.extent.y - 1, 162 m_clipRect.point.y + m_clipRect.extent.y - 1); 163 164 out_rRect.extent.x = bottomR.x - out_rRect.point.x + 1; 165 out_rRect.extent.x = bottomR.y - out_rRect.point.y + 1; 166 167 return true; 168} 169