Change build scripts
[jvcard.git] / src / com / googlecode / lanterna / graphics / DefaultShapeRenderer.java
1 /*
2 * This file is part of lanterna (http://code.google.com/p/lanterna/).
3 *
4 * lanterna is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Copyright (C) 2010-2015 Martin
18 */
19 package com.googlecode.lanterna.graphics;
20
21 import com.googlecode.lanterna.TerminalPosition;
22 import com.googlecode.lanterna.TerminalSize;
23 import com.googlecode.lanterna.TextCharacter;
24
25 import java.util.Arrays;
26 import java.util.Comparator;
27
28 /**
29 * Default implementation of ShapeRenderer. This class (and the interface) is mostly here to make the code cleaner in
30 * {@code AbstractTextGraphics}.
31 * @author Martin
32 */
33 class DefaultShapeRenderer implements ShapeRenderer {
34 interface Callback {
35 void onPoint(int column, int row, TextCharacter character);
36 }
37
38 private final Callback callback;
39
40 DefaultShapeRenderer(Callback callback) {
41 this.callback = callback;
42 }
43
44 @Override
45 public void drawLine(TerminalPosition p1, TerminalPosition p2, TextCharacter character) {
46 //http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
47 //Implementation from Graphics Programming Black Book by Michael Abrash
48 //Available at http://www.gamedev.net/page/resources/_/technical/graphics-programming-and-theory/graphics-programming-black-book-r1698
49 if(p1.getRow() > p2.getRow()) {
50 TerminalPosition temp = p1;
51 p1 = p2;
52 p2 = temp;
53 }
54 int deltaX = p2.getColumn() - p1.getColumn();
55 int deltaY = p2.getRow() - p1.getRow();
56 if(deltaX > 0) {
57 if(deltaX > deltaY) {
58 drawLine0(p1, deltaX, deltaY, true, character);
59 }
60 else {
61 drawLine1(p1, deltaX, deltaY, true, character);
62 }
63 }
64 else {
65 deltaX = Math.abs(deltaX);
66 if(deltaX > deltaY) {
67 drawLine0(p1, deltaX, deltaY, false, character);
68 }
69 else {
70 drawLine1(p1, deltaX, deltaY, false, character);
71 }
72 }
73 }
74
75 private void drawLine0(TerminalPosition start, int deltaX, int deltaY, boolean leftToRight, TextCharacter character) {
76 int x = start.getColumn();
77 int y = start.getRow();
78 int deltaYx2 = deltaY * 2;
79 int deltaYx2MinusDeltaXx2 = deltaYx2 - (deltaX * 2);
80 int errorTerm = deltaYx2 - deltaX;
81 callback.onPoint(x, y, character);
82 while(deltaX-- > 0) {
83 if(errorTerm >= 0) {
84 y++;
85 errorTerm += deltaYx2MinusDeltaXx2;
86 }
87 else {
88 errorTerm += deltaYx2;
89 }
90 x += leftToRight ? 1 : -1;
91 callback.onPoint(x, y, character);
92 }
93 }
94
95 private void drawLine1(TerminalPosition start, int deltaX, int deltaY, boolean leftToRight, TextCharacter character) {
96 int x = start.getColumn();
97 int y = start.getRow();
98 int deltaXx2 = deltaX * 2;
99 int deltaXx2MinusDeltaYx2 = deltaXx2 - (deltaY * 2);
100 int errorTerm = deltaXx2 - deltaY;
101 callback.onPoint(x, y, character);
102 while(deltaY-- > 0) {
103 if(errorTerm >= 0) {
104 x += leftToRight ? 1 : -1;
105 errorTerm += deltaXx2MinusDeltaYx2;
106 }
107 else {
108 errorTerm += deltaXx2;
109 }
110 y++;
111 callback.onPoint(x, y, character);
112 }
113 }
114
115 @Override
116 public void drawTriangle(TerminalPosition p1, TerminalPosition p2, TerminalPosition p3, TextCharacter character) {
117 drawLine(p1, p2, character);
118 drawLine(p2, p3, character);
119 drawLine(p3, p1, character);
120 }
121
122 @Override
123 public void drawRectangle(TerminalPosition topLeft, TerminalSize size, TextCharacter character) {
124 TerminalPosition topRight = topLeft.withRelativeColumn(size.getColumns() - 1);
125 TerminalPosition bottomRight = topRight.withRelativeRow(size.getRows() - 1);
126 TerminalPosition bottomLeft = topLeft.withRelativeRow(size.getRows() - 1);
127 drawLine(topLeft, topRight, character);
128 drawLine(topRight, bottomRight, character);
129 drawLine(bottomRight, bottomLeft, character);
130 drawLine(bottomLeft, topLeft, character);
131 }
132
133 @Override
134 public void fillTriangle(TerminalPosition p1, TerminalPosition p2, TerminalPosition p3, TextCharacter character) {
135 //I've used the algorithm described here:
136 //http://www-users.mat.uni.torun.pl/~wrona/3d_tutor/tri_fillers.html
137 TerminalPosition[] points = new TerminalPosition[]{p1, p2, p3};
138 Arrays.sort(points, new Comparator<TerminalPosition>() {
139 @Override
140 public int compare(TerminalPosition o1, TerminalPosition o2) {
141 return (o1.getRow() < o2.getRow()) ? -1 : ((o1.getRow() == o2.getRow()) ? 0 : 1);
142 }
143 });
144
145 float dx1, dx2, dx3;
146 if (points[1].getRow() - points[0].getRow() > 0) {
147 dx1 = (float)(points[1].getColumn() - points[0].getColumn()) / (float)(points[1].getRow() - points[0].getRow());
148 }
149 else {
150 dx1 = 0;
151 }
152 if (points[2].getRow() - points[0].getRow() > 0) {
153 dx2 = (float)(points[2].getColumn() - points[0].getColumn()) / (float)(points[2].getRow() - points[0].getRow());
154 }
155 else {
156 dx2 = 0;
157 }
158 if (points[2].getRow() - points[1].getRow() > 0) {
159 dx3 = (float)(points[2].getColumn() - points[1].getColumn()) / (float)(points[2].getRow() - points[1].getRow());
160 }
161 else {
162 dx3 = 0;
163 }
164
165 float startX, startY, endX;
166 startX = endX = points[0].getColumn();
167 startY = points[0].getRow();
168 if (dx1 > dx2) {
169 for (; startY <= points[1].getRow(); startY++, startX += dx2, endX += dx1) {
170 drawLine(new TerminalPosition((int)startX, (int)startY), new TerminalPosition((int)endX, (int)startY), character);
171 }
172 endX = points[1].getColumn();
173 for (; startY <= points[2].getRow(); startY++, startX += dx2, endX += dx3) {
174 drawLine(new TerminalPosition((int)startX, (int)startY), new TerminalPosition((int)endX, (int)startY), character);
175 }
176 } else {
177 for (; startY <= points[1].getRow(); startY++, startX += dx1, endX += dx2) {
178 drawLine(new TerminalPosition((int)startX, (int)startY), new TerminalPosition((int)endX, (int)startY), character);
179 }
180 startX = points[1].getColumn();
181 startY = points[1].getRow();
182 for (; startY <= points[2].getRow(); startY++, startX += dx3, endX += dx2) {
183 drawLine(new TerminalPosition((int)startX, (int)startY), new TerminalPosition((int)endX, (int)startY), character);
184 }
185 }
186 }
187
188 @Override
189 public void fillRectangle(TerminalPosition topLeft, TerminalSize size, TextCharacter character) {
190 for(int y = 0; y < size.getRows(); y++) {
191 for(int x = 0; x < size.getColumns(); x++) {
192 callback.onPoint(topLeft.getColumn() + x, topLeft.getRow() + y, character);
193 }
194 }
195 }
196 }