Commit | Line | Data |
---|---|---|
a3b510ab NR |
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 | } |