2 * This file is part of lanterna (http://code.google.com/p/lanterna/).
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.
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.
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/>.
17 * Copyright (C) 2010-2015 Martin
19 package com
.googlecode
.lanterna
.graphics
;
21 import com
.googlecode
.lanterna
.TerminalPosition
;
22 import com
.googlecode
.lanterna
.TerminalSize
;
23 import com
.googlecode
.lanterna
.TextCharacter
;
25 import java
.util
.Arrays
;
26 import java
.util
.Comparator
;
29 * Default implementation of ShapeRenderer. This class (and the interface) is mostly here to make the code cleaner in
30 * {@code AbstractTextGraphics}.
33 class DefaultShapeRenderer
implements ShapeRenderer
{
35 void onPoint(int column
, int row
, TextCharacter character
);
38 private final Callback callback
;
40 DefaultShapeRenderer(Callback callback
) {
41 this.callback
= callback
;
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
;
54 int deltaX
= p2
.getColumn() - p1
.getColumn();
55 int deltaY
= p2
.getRow() - p1
.getRow();
58 drawLine0(p1
, deltaX
, deltaY
, true, character
);
61 drawLine1(p1
, deltaX
, deltaY
, true, character
);
65 deltaX
= Math
.abs(deltaX
);
67 drawLine0(p1
, deltaX
, deltaY
, false, character
);
70 drawLine1(p1
, deltaX
, deltaY
, false, character
);
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
);
85 errorTerm
+= deltaYx2MinusDeltaXx2
;
88 errorTerm
+= deltaYx2
;
90 x
+= leftToRight ?
1 : -1;
91 callback
.onPoint(x
, y
, character
);
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) {
104 x
+= leftToRight ?
1 : -1;
105 errorTerm
+= deltaXx2MinusDeltaYx2
;
108 errorTerm
+= deltaXx2
;
111 callback
.onPoint(x
, y
, character
);
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
);
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
);
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
>() {
140 public int compare(TerminalPosition o1
, TerminalPosition o2
) {
141 return (o1
.getRow() < o2
.getRow()) ?
-1 : ((o1
.getRow() == o2
.getRow()) ?
0 : 1);
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());
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());
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());
165 float startX
, startY
, endX
;
166 startX
= endX
= points
[0].getColumn();
167 startY
= points
[0].getRow();
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
);
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
);
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
);
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
);
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
);