Skip to content

Commit 86235a8

Browse files
authored
Merge pull request #127 from 110Percent/main
Add double-buffering to GridWorld view
2 parents 6286ced + 7de31bc commit 86235a8

File tree

3 files changed

+98
-54
lines changed

3 files changed

+98
-54
lines changed

examples/blocks-world/BlocksEnv/WorldModel.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import java.util.List;
88
import java.util.Stack;
99
import java.util.logging.Logger;
10+
import javax.swing.SwingUtilities;
1011

1112
public class WorldModel extends GridWorldModel {
1213

@@ -91,7 +92,9 @@ boolean move(String a, String b, List<String> adds, List<String> dels) throws Ex
9192
}
9293
modelToGrid();
9394
if (view != null)
94-
view.update();
95+
SwingUtilities.invokeLater(() -> {
96+
view.update();
97+
});
9598

9699
return true;
97100
}
@@ -155,16 +158,16 @@ static WorldModel world4() throws Exception {
155158
void modelToGrid() {
156159
for (int i=0; i<GWidth; i++) {
157160
for (int j=0; j<GHeight-1; j++) {
158-
model.data[i][j] = 0;
161+
model.set(0, i, j);
159162
model.names[i][j] = "";
160163
}
161-
model.data[i][GHeight-1] = TABLE;
164+
model.set(TABLE, i, GHeight-1);
162165
model.names[i][GHeight-1] = "table";
163166
}
164167
int i=0;
165168
for (Stack<String> s : stackList) {
166169
for (int j=1; j<s.size(); j++) {
167-
model.data[i*2+1][GHeight-j-1] = BLOCK;
170+
model.set(BLOCK, i*2+1, GHeight-j-1);
168171
model.names[i*2+1][GHeight-j-1] = s.get(j);
169172
}
170173
i++;

jason-interpreter/src/main/java/jason/environment/grid/GridWorldModel.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package jason.environment.grid;
22

3+
import javax.swing.*;
34
import java.util.Random;
45

56

@@ -110,7 +111,10 @@ public int countObjects(int obj) {
110111

111112
public void set(int value, int x, int y) {
112113
data[x][y] = value;
113-
if (view != null) view.update(x,y);
114+
if (view != null) {
115+
final int ux = x, uy = y;
116+
SwingUtilities.invokeLater(() -> view.update(ux, uy));
117+
}
114118
}
115119

116120
public void add(int value, Location l) {
@@ -119,7 +123,10 @@ public void add(int value, Location l) {
119123

120124
public void add(int value, int x, int y) {
121125
data[x][y] |= value;
122-
if (view != null) view.update(x,y);
126+
if (view != null) {
127+
final int ux = x, uy = y;
128+
SwingUtilities.invokeLater(() -> view.update(ux, uy));
129+
}
123130
}
124131

125132
public void addWall(int x1, int y1, int x2, int y2) {
@@ -130,13 +137,16 @@ public void addWall(int x1, int y1, int x2, int y2) {
130137
}
131138
}
132139

133-
public void remove(int value, Location l) {
140+
public void remove(int value, Location l) {
134141
remove(value, l.x, l.y);
135142
}
136143

137144
public void remove(int value, int x, int y) {
138145
data[x][y] &= ~value;
139-
if (view != null) view.update(x,y);
146+
if (view != null) {
147+
final int ux = x, uy = y;
148+
SwingUtilities.invokeLater(() -> view.update(ux, uy));
149+
}
140150
}
141151

142152
public void removeAll(int value) {

jason-interpreter/src/main/java/jason/environment/grid/GridWorldView.java

Lines changed: 77 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
package jason.environment.grid;
22

3-
import java.awt.BorderLayout;
4-
import java.awt.Canvas;
5-
import java.awt.Color;
6-
import java.awt.Font;
7-
import java.awt.FontMetrics;
8-
import java.awt.Graphics;
3+
import java.awt.*;
4+
import java.awt.image.BufferedImage;
95

10-
import javax.swing.JFrame;
6+
import javax.swing.*;
117

128
/**
139
* View component for a GirdWorldModel.
@@ -23,6 +19,8 @@ public class GridWorldView extends JFrame {
2319

2420
protected GridCanvas drawArea;
2521
protected GridWorldModel model;
22+
protected BufferedImage backBuffer;
23+
private Graphics2D backG;
2624

2725
protected Font defaultFont = new Font("Arial", Font.BOLD, 10);
2826

@@ -46,20 +44,25 @@ public void repaint() {
4644
cellSizeW = drawArea.getWidth() / model.getWidth();
4745
cellSizeH = drawArea.getHeight() / model.getHeight();
4846
super.repaint();
49-
drawArea.repaint();
5047
}
5148

5249
/** updates all the frame */
5350
public void update() {
51+
ensureBackBuffer();
5452
repaint();
5553
}
5654

5755
/** updates only one position of the grid */
5856
public void update(int x, int y) {
59-
Graphics g = drawArea.getGraphics();
60-
if (g == null) return;
61-
drawEmpty(g, x, y);
62-
draw(g, x, y);
57+
if (!SwingUtilities.isEventDispatchThread()) {
58+
// Only the event dispatch thread can update the GUI
59+
SwingUtilities.invokeLater(this::update);
60+
return;
61+
}
62+
63+
ensureBackBuffer();
64+
renderAllToBackBuffer();
65+
drawArea.repaint();
6366
}
6467

6568
public void drawObstacle(Graphics g, int x, int y) {
@@ -100,25 +103,7 @@ public void draw(Graphics g, int x, int y, int object) {
100103
//drawString(g,x,y,defaultFont,String.valueOf(object));
101104
}
102105

103-
private static int limit = (int)Math.pow(2,14);
104-
105-
private void draw(Graphics g, int x, int y) {
106-
if ((model.data[x][y] & GridWorldModel.OBSTACLE) != 0) {
107-
drawObstacle(g, x, y);
108-
}
109-
110-
int vl = GridWorldModel.OBSTACLE*2; // the next object after OBSTACLE
111-
while (vl < limit) {
112-
if ((model.data[x][y] & vl) != 0) {
113-
draw(g, x, y, vl);
114-
}
115-
vl *= 2;
116-
}
117-
118-
if ((model.data[x][y] & GridWorldModel.AGENT) != 0) {
119-
drawAgent(drawArea.getGraphics(), x, y, Color.blue, model.getAgAtPos(x, y));
120-
}
121-
}
106+
private static final int limit = (int)Math.pow(2,14);
122107

123108
public Canvas getCanvas() {
124109
return drawArea;
@@ -130,27 +115,73 @@ public GridWorldModel getModel() {
130115

131116
class GridCanvas extends Canvas {
132117

133-
private static final long serialVersionUID = 1L;
118+
private static final long serialVersionUID = 2L;
119+
120+
@Override
121+
public void update(Graphics g) {
122+
paint(g);
123+
}
134124

135125
public void paint(Graphics g) {
136-
cellSizeW = drawArea.getWidth() / model.getWidth();
137-
cellSizeH = drawArea.getHeight() / model.getHeight();
138-
int mwidth = model.getWidth();
139-
int mheight = model.getHeight();
140-
141-
g.setColor(Color.lightGray);
142-
for (int l = 1; l <= mheight; l++) {
143-
g.drawLine(0, l * cellSizeH, mwidth * cellSizeW, l * cellSizeH);
126+
ensureBackBuffer();
127+
g.drawImage(backBuffer, 0, 0, this);
128+
Toolkit.getDefaultToolkit().sync();
129+
}
130+
}
131+
132+
private void ensureBackBuffer() {
133+
int w = Math.max(1, drawArea.getWidth());
134+
int h = Math.max(1, drawArea.getHeight());
135+
if (backBuffer == null || backBuffer.getWidth() != w || backBuffer.getHeight() != h) {
136+
if (backG != null) {
137+
backG.dispose();
144138
}
145-
for (int c = 1; c <= mwidth; c++) {
146-
g.drawLine(c * cellSizeW, 0, c * cellSizeW, mheight * cellSizeH);
139+
backBuffer = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
140+
backG = backBuffer.createGraphics();
141+
backG.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
142+
}
143+
renderAllToBackBuffer();
144+
}
145+
146+
private void renderAllToBackBuffer() {
147+
cellSizeW = Math.max(1, backBuffer.getWidth() / model.getWidth());
148+
cellSizeH = Math.max(1, backBuffer.getHeight() / model.getHeight());
149+
150+
backG.setColor(Color.white);
151+
backG.fillRect(0, 0, backBuffer.getWidth(), backBuffer.getHeight());
152+
153+
backG.setColor(Color.lightGray);
154+
for (int l = 1; l <= backBuffer.getHeight(); l++) {
155+
backG.drawLine(0, l * cellSizeH, model.getWidth() * cellSizeW, l * cellSizeH);
156+
}
157+
for (int c = 1; c <= backBuffer.getWidth(); c++) {
158+
backG.drawLine(c * cellSizeW, 0, c * cellSizeW, model.getHeight() * cellSizeH);
159+
}
160+
161+
for (int x = 0; x < model.getWidth(); x++) {
162+
for (int y = 0; y < model.getHeight(); y++) {
163+
renderCell(backG, x, y);
147164
}
165+
}
166+
}
167+
168+
private void renderCell(Graphics2D g, int x, int y) {
169+
drawEmpty(g, x, y);
148170

149-
for (int x = 0; x < mwidth; x++) {
150-
for (int y = 0; y < mheight; y++) {
151-
draw(g,x,y);
152-
}
171+
if ((model.data[x][y] & GridWorldModel.OBSTACLE) != 0) {
172+
drawObstacle(g, x, y);
173+
}
174+
175+
int vl = GridWorldModel.OBSTACLE*2; // the next object after OBSTACLE
176+
while (vl < limit) {
177+
if ((model.data[x][y] & vl) != 0) {
178+
draw(g, x, y, vl);
153179
}
180+
vl *= 2;
181+
}
182+
183+
if ((model.data[x][y] & GridWorldModel.AGENT) != 0) {
184+
drawAgent(g, x, y, Color.blue, model.getAgAtPos(x, y));
154185
}
155186
}
156187
}

0 commit comments

Comments
 (0)