Skip to content

Commit d820f7e

Browse files
committed
Migrate Ripple effect to Graphics Example
See lcaron/SWT-OldSchoolEffect#3 or https://github.com/lcaron/SWT-OldSchoolEffect for all SWT examples
1 parent 98062b7 commit d820f7e

File tree

4 files changed

+201
-0
lines changed

4 files changed

+201
-0
lines changed

examples/org.eclipse.swt.examples/src/examples_graphics.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,3 +188,5 @@ SpiralDescription=Miscellaneous tab that presents a spiral consisting of the num
188188
StarfieldDescription=This is a miscellaneous demonstration that uses the drawPoint() operation to simulate a moving starfield.
189189
StarPolygonDescription=This tab draws a polygon and shows the effects of setting different fill rules: SWT.FILL_WINDING or SWT.FILL_EVEN_ODD
190190
AntialiasingTextDesc=This tab demonstrates antialiasing for text. Antialiasing is used for smoothing jagged edges in graphics. This tab allows the user to see the effects of different antialiasing values.
191+
Ripple=Ripple
192+
RippleDescription=This is a miscellaneous demonstration that uses a displacement map to simulate water ripples on an image. Move the mouse over the image to disturb the water.

examples/org.eclipse.swt.examples/src/org/eclipse/swt/examples/graphics/GraphicsExample.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,7 @@ GraphicsTab[] createTabs() {
470470
new LineJoinTab(this),
471471
new RegionClippingTab(this),
472472
new StarfieldTab(this),
473+
new RippleTab(this),
473474
new CustomAlphaTab(this),
474475
new TextAntialiasTab(this),
475476
new GraphicAntialiasTab(this),
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2026 Laurent Caron and others.
3+
*
4+
* This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Public License 2.0
6+
* which accompanies this distribution, and is available at
7+
* https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*
11+
* Contributors:
12+
* Neil Wallis (http://www.neilwallis.com/java/water.html) - Original Version
13+
* Laurent Caron (laurent.caron at gmail dot com) - Conversion to SWT
14+
* IBM Corporation - adaptation to GraphicsExample
15+
*******************************************************************************/
16+
17+
package org.eclipse.swt.examples.graphics;
18+
19+
import org.eclipse.swt.graphics.GC;
20+
import org.eclipse.swt.graphics.Image;
21+
import org.eclipse.swt.graphics.ImageData;
22+
import org.eclipse.swt.graphics.Rectangle;
23+
import org.eclipse.swt.widgets.Composite;
24+
25+
/**
26+
* This tab displays a ripple effect on an image.
27+
*/
28+
public class RippleTab extends AnimatedGraphicsTab {
29+
30+
private Image sourceImage;
31+
private ImageData offImageData;
32+
private int width, height;
33+
private int hwidth, hheight;
34+
private int riprad;
35+
private int size;
36+
private short[] ripplemap;
37+
private int[] ripple;
38+
private int[] texture;
39+
private int oldind;
40+
private int newind;
41+
private Image outputImage;
42+
43+
public RippleTab(GraphicsExample example) {
44+
super(example);
45+
}
46+
47+
@Override
48+
public String getCategory() {
49+
return GraphicsExample.getResourceString("Misc"); //$NON-NLS-1$
50+
}
51+
52+
@Override
53+
public String getText() {
54+
return GraphicsExample.getResourceString("Ripple"); //$NON-NLS-1$
55+
}
56+
57+
@Override
58+
public String getDescription() {
59+
return GraphicsExample.getResourceString("RippleDescription"); //$NON-NLS-1$
60+
}
61+
62+
@Override
63+
public int getInitialAnimationTime() {
64+
return 30;
65+
}
66+
67+
@Override
68+
public void createControlPanel(Composite parent) {
69+
super.createControlPanel(parent);
70+
// Add mouse listener to the canvas to disturb the water
71+
example.canvas.addMouseMoveListener(e -> {
72+
if (example.getTab() == RippleTab.this) {
73+
Rectangle rect = example.canvas.getClientArea();
74+
disturb(e.x, e.y, rect.width, rect.height);
75+
}
76+
});
77+
}
78+
79+
@Override
80+
public void dispose() {
81+
if (sourceImage != null) {
82+
sourceImage.dispose();
83+
sourceImage = null;
84+
}
85+
if (outputImage != null) {
86+
outputImage.dispose();
87+
outputImage = null;
88+
}
89+
}
90+
91+
@Override
92+
public void next(int width, int height) {
93+
if (texture == null) return;
94+
if (Math.random() > 0.98) {
95+
disturb((int)(Math.random() * width), (int)(Math.random() * height), width, height);
96+
}
97+
newframe();
98+
}
99+
100+
@Override
101+
public void paint(GC gc, int width, int height) {
102+
if (!example.checkAdvancedGraphics()) return;
103+
104+
if (sourceImage == null) {
105+
sourceImage = example.loadImage(gc.getDevice(), "ocean.jpg");
106+
if (sourceImage == null) return;
107+
108+
ImageData imgData = sourceImage.getImageData();
109+
this.width = imgData.width;
110+
this.height = imgData.height;
111+
hwidth = this.width >> 1;
112+
hheight = this.height >> 1;
113+
riprad = 3;
114+
115+
size = this.width * (this.height + 2) * 2;
116+
ripplemap = new short[size];
117+
ripple = new int[this.width * this.height];
118+
texture = new int[this.width * this.height];
119+
oldind = this.width;
120+
newind = this.width * (this.height + 3);
121+
122+
imgData.getPixels(0, 0, this.width * this.height, texture, 0);
123+
offImageData = new ImageData(this.width, this.height, imgData.depth, imgData.palette);
124+
}
125+
126+
offImageData.setPixels(0, 0, this.width * this.height, ripple, 0);
127+
128+
if (outputImage != null) outputImage.dispose();
129+
outputImage = new Image(gc.getDevice(), offImageData);
130+
131+
int x = (width - this.width) / 2;
132+
int y = (height - this.height) / 2;
133+
gc.drawImage(outputImage, x, y);
134+
}
135+
136+
private void newframe() {
137+
int i, a, b;
138+
// Toggle maps each frame
139+
i = oldind;
140+
oldind = newind;
141+
newind = i;
142+
143+
i = 0;
144+
int mapind = oldind;
145+
for (int y = 0; y < height; y++) {
146+
for (int x = 0; x < width; x++) {
147+
short data = (short) (ripplemap[mapind - width] + ripplemap[mapind + width] + ripplemap[mapind - 1] + ripplemap[mapind + 1] >> 1);
148+
data -= ripplemap[newind + i];
149+
data -= data >> 5;
150+
ripplemap[newind + i] = data;
151+
152+
// where data=0 then still, where data>0 then wave
153+
data = (short) (1024 - data);
154+
155+
// offsets
156+
a = (x - hwidth) * data / 1024 + hwidth;
157+
b = (y - hheight) * data / 1024 + hheight;
158+
159+
// bounds check
160+
if (a >= width) {
161+
a = width - 1;
162+
}
163+
if (a < 0) {
164+
a = 0;
165+
}
166+
if (b >= height) {
167+
b = height - 1;
168+
}
169+
if (b < 0) {
170+
b = 0;
171+
}
172+
173+
ripple[i] = texture[a + b * width];
174+
mapind++;
175+
i++;
176+
}
177+
}
178+
}
179+
180+
private void disturb(int dx, int dy, int canvasWidth, int canvasHeight) {
181+
if (texture == null) return;
182+
183+
// Adjust dx, dy based on center alignment in paint()
184+
int xOffset = (canvasWidth - width) / 2;
185+
int yOffset = (canvasHeight - height) / 2;
186+
187+
int x = dx - xOffset;
188+
int y = dy - yOffset;
189+
190+
for (int j = y - riprad; j < y + riprad; j++) {
191+
for (int k = x - riprad; k < x + riprad; k++) {
192+
if (j >= 0 && j < height && k >= 0 && k < width) {
193+
ripplemap[oldind + j * width + k] += 512;
194+
}
195+
}
196+
}
197+
}
198+
}
25.2 KB
Loading

0 commit comments

Comments
 (0)