diff --git a/examples/org.eclipse.swt.examples/src/examples_graphics.properties b/examples/org.eclipse.swt.examples/src/examples_graphics.properties index 01daf8ae790..7165e3f9939 100644 --- a/examples/org.eclipse.swt.examples/src/examples_graphics.properties +++ b/examples/org.eclipse.swt.examples/src/examples_graphics.properties @@ -211,3 +211,18 @@ MoireDescription=This is a miscellaneous demonstration of an animated moir\u00e9 RasterBars=Raster Bars RasterBarsDescription=This is a miscellaneous demonstration of animated raster bars sweeping across the screen following sine wave patterns. + +Explosion=Explosion +ExplosionDescription=This is a miscellaneous demonstration of an animated explosion effect using a particle system and fire propagation algorithm. + +Mandelbrot=Mandelbrot +MandelbrotDescription=This is a miscellaneous demonstration of an animated Mandelbrot fractal with a continuously zooming view into the fractal boundary. + +ShadeBobs=Shade Bobs +ShadeBobsDescription=This is a miscellaneous demonstration of an animated shade bobs effect where a heated bob shape moves along a precomputed path, leaving a fading heat trail. + +Twister=Twister +TwisterDescription=This is a miscellaneous demonstration of an animated twister effect using precomputed sine tables and a torsion deformation on a checkered pattern. + +Wave=Wave +WaveDescription=This is a miscellaneous demonstration of an animated wave effect with multiple motion patterns cycling through four different wave algorithms. diff --git a/examples/org.eclipse.swt.examples/src/org/eclipse/swt/examples/graphics/ExplosionTab.java b/examples/org.eclipse.swt.examples/src/org/eclipse/swt/examples/graphics/ExplosionTab.java new file mode 100644 index 00000000000..0f21951f6af --- /dev/null +++ b/examples/org.eclipse.swt.examples/src/org/eclipse/swt/examples/graphics/ExplosionTab.java @@ -0,0 +1,213 @@ +/******************************************************************************* + * Copyright (c) 2018 Laurent Caron and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * W.P. van Paassen - Original Version + * Laurent Caron (laurent.caron at gmail dot com) - Conversion to SWT + * IBM Corporation - adaptation to GraphicsExample + *******************************************************************************/ + +package org.eclipse.swt.examples.graphics; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.PaletteData; +import org.eclipse.swt.graphics.RGB; + +/** + * This tab displays an animated explosion effect using a particle system + * and fire propagation algorithm. + */ +public class ExplosionTab extends AnimatedGraphicsTab { + + private static final int NUMBER_OF_PARTICLES = 500; + + private ImageData imageData; + private Image outputImage; + private int[] fire; + private Particle[] particles; + private RGB[] colors; + private int lastWidth; + private int lastHeight; + + private static class Particle { + int xpos, ypos, xdir, ydir; + int colorindex; + boolean dead; + } + + public ExplosionTab(GraphicsExample example) { + super(example); + } + + @Override + public String getCategory() { + return GraphicsExample.getResourceString("Misc"); //$NON-NLS-1$ + } + + @Override + public String getText() { + return GraphicsExample.getResourceString("Explosion"); //$NON-NLS-1$ + } + + @Override + public String getDescription() { + return GraphicsExample.getResourceString("ExplosionDescription"); //$NON-NLS-1$ + } + + @Override + public int getInitialAnimationTime() { + return 10; + } + + @Override + public void dispose() { + if (outputImage != null) { + outputImage.dispose(); + outputImage = null; + } + } + + @Override + public void next(int width, int height) { + if (fire == null) { + return; + } + if (width != lastWidth || height != lastHeight) { + init(width, height); + } + + // Move and draw particles into fire array + int nbDead = 0; + for (int i = 0; i < NUMBER_OF_PARTICLES; i++) { + if (!particles[i].dead) { + particles[i].xpos += particles[i].xdir; + particles[i].ypos += particles[i].ydir; + + if (particles[i].ypos >= height - 3 || particles[i].colorindex == 0 + || particles[i].xpos <= 1 || particles[i].xpos >= width - 3) { + particles[i].dead = true; + continue; + } + + particles[i].ydir++; + particles[i].colorindex--; + + final int temp = particles[i].ypos * width + particles[i].xpos; + fire[temp] = particles[i].colorindex; + fire[temp - 1] = particles[i].colorindex; + fire[temp + width] = particles[i].colorindex; + fire[temp - width] = particles[i].colorindex; + fire[temp + 1] = particles[i].colorindex; + } else { + nbDead++; + } + } + + // Create fire effect + for (int i = 1; i < height - 2; i++) { + final int index = (i - 1) * width; + for (int j = 1; j < width - 2; j++) { + int buf = index + j; + int temp = fire[buf]; + temp += fire[buf + 1]; + temp += fire[buf - 1]; + buf += width; + temp += fire[buf - 1]; + temp += fire[buf + 1]; + buf += width; + temp += fire[buf]; + temp += fire[buf + 1]; + temp += fire[buf - 1]; + temp >>= 3; + if (temp > 4) { + temp -= 4; + } else { + temp = 0; + } + fire[buf - width] = temp; + } + } + + // Draw fire array to image from bottom to top + int pixel = width * height - 1; + for (int i = height - 1; i >= 0; --i) { + final int temp = i * width; + for (int j = width - 1; j >= 0; --j) { + imageData.setPixel(pixel % width, pixel / width, fire[temp + j]); + pixel--; + } + } + + if (nbDead == NUMBER_OF_PARTICLES) { + initParticles(width, height); + } + } + + @Override + public void paint(GC gc, int width, int height) { + if (fire == null) { + init(width, height); + } + + gc.setBackground(gc.getDevice().getSystemColor(SWT.COLOR_BLACK)); + gc.fillRectangle(0, 0, width, height); + + if (imageData == null) { + return; + } + + if (outputImage != null) { + outputImage.dispose(); + } + outputImage = new Image(gc.getDevice(), imageData); + gc.drawImage(outputImage, 0, 0); + } + + private void init(int width, int height) { + lastWidth = width; + lastHeight = height; + + fire = new int[width * height]; + particles = new Particle[NUMBER_OF_PARTICLES]; + + colors = new RGB[256]; + for (int i = 0; i < 32; ++i) { + colors[i] = new RGB(0, 0, i << 1); + colors[i + 32] = new RGB(i << 3, 0, 64 - (i << 1)); + colors[i + 64] = new RGB(255, i << 3, 0); + colors[i + 96] = new RGB(255, 255, i << 2); + colors[i + 128] = new RGB(255, 255, 64 + (i << 2)); + colors[i + 160] = new RGB(255, 255, 128 + (i << 2)); + colors[i + 192] = new RGB(255, 255, 192 + i); + colors[i + 224] = new RGB(255, 255, 224 + i); + } + + imageData = new ImageData(width, height, 8, new PaletteData(colors)); + + for (int i = 0; i < NUMBER_OF_PARTICLES; i++) { + particles[i] = new Particle(); + } + initParticles(width, height); + } + + private void initParticles(int width, int height) { + for (int i = 0; i < NUMBER_OF_PARTICLES; i++) { + particles[i].xpos = (width >> 1) - 20 + (int) (40.0 * Math.random()); + particles[i].ypos = (height >> 1) - 20 + (int) (40.0 * Math.random()); + particles[i].xdir = -10 + (int) (20.0 * Math.random()); + particles[i].ydir = -17 + (int) (19.0 * Math.random()); + particles[i].colorindex = 255; + particles[i].dead = false; + } + } +} diff --git a/examples/org.eclipse.swt.examples/src/org/eclipse/swt/examples/graphics/GraphicsExample.java b/examples/org.eclipse.swt.examples/src/org/eclipse/swt/examples/graphics/GraphicsExample.java index ee7cdcaf974..c0dea636616 100644 --- a/examples/org.eclipse.swt.examples/src/org/eclipse/swt/examples/graphics/GraphicsExample.java +++ b/examples/org.eclipse.swt.examples/src/org/eclipse/swt/examples/graphics/GraphicsExample.java @@ -486,6 +486,11 @@ GraphicsTab[] createTabs() { new FireTab(this), new MoireTab(this), new RasterBarsTab(this), + new ExplosionTab(this), + new MandelbrotTab(this), + new ShadeBobsTab(this), + new TwisterTab(this), + new WaveTab(this), }; } diff --git a/examples/org.eclipse.swt.examples/src/org/eclipse/swt/examples/graphics/MandelbrotTab.java b/examples/org.eclipse.swt.examples/src/org/eclipse/swt/examples/graphics/MandelbrotTab.java new file mode 100644 index 00000000000..59f806a64b8 --- /dev/null +++ b/examples/org.eclipse.swt.examples/src/org/eclipse/swt/examples/graphics/MandelbrotTab.java @@ -0,0 +1,133 @@ +/******************************************************************************* + * Copyright (c) 2019 Laurent Caron and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Calogiuri Enzo Antonio (Insolit Dust) - Original Version + * Laurent Caron (laurent.caron at gmail dot com) - Conversion to SWT + * IBM Corporation - adaptation to GraphicsExample + *******************************************************************************/ + +package org.eclipse.swt.examples.graphics; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.PaletteData; + +/** + * This tab displays an animated Mandelbrot fractal with a continuously + * zooming view into the fractal boundary. + */ +public class MandelbrotTab extends AnimatedGraphicsTab { + + private static final int MAX_ITER = 570; + + private ImageData imageData; + private Image outputImage; + private double zoom = 150; + private double moveX = -0.5; + private double moveY = 0.0; + private double zoomSpeed = 1.02; + private int lastWidth; + private int lastHeight; + + public MandelbrotTab(GraphicsExample example) { + super(example); + } + + @Override + public String getCategory() { + return GraphicsExample.getResourceString("Misc"); //$NON-NLS-1$ + } + + @Override + public String getText() { + return GraphicsExample.getResourceString("Mandelbrot"); //$NON-NLS-1$ + } + + @Override + public String getDescription() { + return GraphicsExample.getResourceString("MandelbrotDescription"); //$NON-NLS-1$ + } + + @Override + public int getInitialAnimationTime() { + return 50; + } + + @Override + public void dispose() { + if (outputImage != null) { + outputImage.dispose(); + outputImage = null; + } + } + + @Override + public void next(int width, int height) { + if (imageData == null) { + return; + } + if (width != lastWidth || height != lastHeight) { + init(width, height); + } + + zoom *= zoomSpeed; + drawMandelbrot(width, height); + } + + @Override + public void paint(GC gc, int width, int height) { + if (imageData == null) { + init(width, height); + } + + gc.setBackground(gc.getDevice().getSystemColor(SWT.COLOR_BLACK)); + gc.fillRectangle(0, 0, width, height); + + if (imageData == null) { + return; + } + + if (outputImage != null) { + outputImage.dispose(); + } + outputImage = new Image(gc.getDevice(), imageData); + gc.drawImage(outputImage, 0, 0); + } + + private void init(int width, int height) { + lastWidth = width; + lastHeight = height; + zoom = 150; + imageData = new ImageData(width, height, 24, new PaletteData(0xFF0000, 0xFF00, 0xFF)); + } + + private void drawMandelbrot(int width, int height) { + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + double zx = 0; + double zy = 0; + final double cX = (x - width / 2.0) / zoom + moveX; + final double cY = (y - height / 2.0) / zoom + moveY; + double tmp; + int iter = MAX_ITER; + while (zx * zx + zy * zy < 4 && iter > 0) { + tmp = zx * zx - zy * zy + cX; + zy = 2.0 * zx * zy + cY; + zx = tmp; + iter--; + } + imageData.setPixel(x, y, iter | iter << 8); + } + } + } +} diff --git a/examples/org.eclipse.swt.examples/src/org/eclipse/swt/examples/graphics/ShadeBobsTab.java b/examples/org.eclipse.swt.examples/src/org/eclipse/swt/examples/graphics/ShadeBobsTab.java new file mode 100644 index 00000000000..4421f526796 --- /dev/null +++ b/examples/org.eclipse.swt.examples/src/org/eclipse/swt/examples/graphics/ShadeBobsTab.java @@ -0,0 +1,207 @@ +/******************************************************************************* + * Copyright (c) 2018 Laurent Caron and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * W.P. van Paassen and Byron Ellacott - Original Version + * Laurent Caron (laurent.caron at gmail dot com) - Conversion to SWT + * IBM Corporation - adaptation to GraphicsExample + *******************************************************************************/ + +package org.eclipse.swt.examples.graphics; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.PaletteData; +import org.eclipse.swt.graphics.RGB; + +/** + * This tab displays an animated shade bobs effect where a heated bob shape + * moves along a precomputed path, leaving a fading heat trail. + */ +public class ShadeBobsTab extends AnimatedGraphicsTab { + + private static final int[][] HEAT = { + { 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 0, 0, 0 }, + { 0, 0, 1, 1, 2, 2, 2, 3, 3, 2, 2, 2, 1, 1, 0, 0 }, + { 0, 0, 1, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 1, 0, 0 }, + { 0, 1, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 1, 0 }, + { 0, 1, 2, 2, 3, 3, 3, 4, 4, 3, 3, 3, 2, 2, 1, 0 }, + { 1, 1, 2, 3, 3, 3, 4, 4, 4, 4, 3, 3, 3, 2, 1, 1 }, + { 1, 1, 2, 3, 3, 3, 4, 4, 4, 4, 3, 3, 3, 2, 1, 1 }, + { 0, 1, 2, 2, 3, 3, 3, 4, 4, 3, 3, 3, 2, 2, 1, 0 }, + { 0, 1, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 1, 0 }, + { 0, 0, 1, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 1, 0, 0 }, + { 0, 0, 1, 1, 2, 2, 2, 3, 3, 2, 2, 2, 1, 1, 0, 0 }, + { 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0 }, + }; + + private ImageData imageData; + private Image outputImage; + private int[] xpath; + private int[] ypath; + private int[] pathpath; + private int trail; + private int lastWidth; + private int lastHeight; + + public ShadeBobsTab(GraphicsExample example) { + super(example); + } + + @Override + public String getCategory() { + return GraphicsExample.getResourceString("Misc"); //$NON-NLS-1$ + } + + @Override + public String getText() { + return GraphicsExample.getResourceString("ShadeBobs"); //$NON-NLS-1$ + } + + @Override + public String getDescription() { + return GraphicsExample.getResourceString("ShadeBobsDescription"); //$NON-NLS-1$ + } + + @Override + public int getInitialAnimationTime() { + return 10; + } + + @Override + public void dispose() { + if (outputImage != null) { + outputImage.dispose(); + outputImage = null; + } + } + + @Override + public void next(int width, int height) { + if (xpath == null) { + return; + } + if (width != lastWidth || height != lastHeight) { + init(width, height); + } + + // Remove heat from tail + if (trail >= 500) { + int tmp = trail - 500; + int remx = getBobXLocation(tmp); + int remy = getBobYLocation(tmp); + for (int i = 0; i < 16; i++) { + int base = (remy + i) * width + remx; + for (int j = 0; j < 16; j++) { + int px = (base + j) % width; + int py = (base + j) / width; + if (py >= 0 && py < height) { + int val = imageData.getPixel(px, py); + val -= HEAT[i][j] * 8; + if (val < 0) { + val = 0; + } + imageData.setPixel(px, py, val); + } + } + } + } + + // Add heat at new head + int drawx = getBobXLocation(trail); + int drawy = getBobYLocation(trail); + for (int i = 0; i < 16; i++) { + int base = (drawy + i) * width + drawx; + for (int j = 0; j < 16; j++) { + int px = (base + j) % width; + int py = (base + j) / width; + if (py >= 0 && py < height) { + int val = imageData.getPixel(px, py); + val += HEAT[i][j] * 8; + if (val > 255) { + val = 255; + } + imageData.setPixel(px, py, val); + } + } + } + trail++; + } + + @Override + public void paint(GC gc, int width, int height) { + if (xpath == null) { + init(width, height); + } + + gc.setBackground(gc.getDevice().getSystemColor(SWT.COLOR_BLACK)); + gc.fillRectangle(0, 0, width, height); + + if (imageData == null) { + return; + } + + if (outputImage != null) { + outputImage.dispose(); + } + outputImage = new Image(gc.getDevice(), imageData); + gc.drawImage(outputImage, 0, 0); + } + + private void init(int width, int height) { + lastWidth = width; + lastHeight = height; + trail = 0; + + xpath = new int[512]; + ypath = new int[512]; + pathpath = new int[1024]; + + final int hw = width - 150; + final int hh = height - 180; + final int aw = 67; + final int ah = 82; + + for (int i = 0; i < 512; i++) { + final double rad = i * 0.703125 * 0.0174532; + xpath[i] = (int) (Math.sin(rad * 2) * hw / 2 + hw / 2 + aw); + ypath[i] = (int) (Math.sin(rad) * hh / 2 + hh / 2 + ah); + } + + for (int i = 0; i < 1024; i++) { + final double rad = i * 0.3515625 * 0.0174532; + pathpath[i] = (int) (Math.sin(rad) * 15); + } + + final RGB[] colors = new RGB[256]; + for (int i = 0; i < 64; ++i) { + colors[i] = new RGB(0, 0, i << 1); + colors[i + 64] = new RGB(i << 1, 0, 128 - (i << 1)); + colors[i + 128] = new RGB(128 + (i << 1), 0, 128 - (i << 1)); + colors[i + 192] = new RGB(255, i << 2, i << 2); + } + + imageData = new ImageData(width, height, 8, new PaletteData(colors)); + } + + private int getBobXLocation(int index) { + return xpath[index & 511] + pathpath[index & 1023]; + } + + private int getBobYLocation(int index) { + return ypath[index & 511] + pathpath[index & 1023]; + } +} diff --git a/examples/org.eclipse.swt.examples/src/org/eclipse/swt/examples/graphics/TwisterTab.java b/examples/org.eclipse.swt.examples/src/org/eclipse/swt/examples/graphics/TwisterTab.java new file mode 100644 index 00000000000..d58bc009d4b --- /dev/null +++ b/examples/org.eclipse.swt.examples/src/org/eclipse/swt/examples/graphics/TwisterTab.java @@ -0,0 +1,187 @@ +/******************************************************************************* + * Copyright (c) 2019 Laurent Caron and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Calogiuri Enzo Antonio (Insolit Dust) - Original Version + * Laurent Caron (laurent.caron at gmail dot com) - Conversion to SWT + * IBM Corporation - adaptation to GraphicsExample + *******************************************************************************/ + +package org.eclipse.swt.examples.graphics; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.PaletteData; + +/** + * This tab displays an animated twister effect using precomputed sine tables + * and a torsion deformation on a checkered pattern. + */ +public class TwisterTab extends AnimatedGraphicsTab { + + private static final int SIN_TABLE_SIZE = 256; + + private ImageData imageData; + private Image outputImage; + private final int[] guim1 = new int[SIN_TABLE_SIZE]; + private final int[] guim2 = new int[SIN_TABLE_SIZE]; + private final int[] guim3 = new int[SIN_TABLE_SIZE]; + private final float[] pas = new float[SIN_TABLE_SIZE]; + private int[] palette; + private int roll; + private boolean initialized; + private int lastWidth; + private int lastHeight; + + public TwisterTab(GraphicsExample example) { + super(example); + } + + @Override + public String getCategory() { + return GraphicsExample.getResourceString("Misc"); //$NON-NLS-1$ + } + + @Override + public String getText() { + return GraphicsExample.getResourceString("Twister"); //$NON-NLS-1$ + } + + @Override + public String getDescription() { + return GraphicsExample.getResourceString("TwisterDescription"); //$NON-NLS-1$ + } + + @Override + public int getInitialAnimationTime() { + return 50; + } + + @Override + public void dispose() { + if (outputImage != null) { + outputImage.dispose(); + outputImage = null; + } + } + + @Override + public void next(int width, int height) { + if (!initialized) { + return; + } + if (width != lastWidth || height != lastHeight) { + init(width, height); + } + imageData = new ImageData(width, height, 24, new PaletteData(0xFF0000, 0xFF00, 0xFF)); + doTwister(width, height); + } + + @Override + public void paint(GC gc, int width, int height) { + if (!initialized) { + init(width, height); + } + + gc.setBackground(gc.getDevice().getSystemColor(SWT.COLOR_BLACK)); + gc.fillRectangle(0, 0, width, height); + + if (imageData == null) { + return; + } + + if (outputImage != null) { + outputImage.dispose(); + } + outputImage = new Image(gc.getDevice(), imageData); + gc.drawImage(outputImage, 0, 0); + } + + private void init(int width, int height) { + lastWidth = width; + lastHeight = height; + roll = 0; + createColors(); + initSinTables(width); + initialized = true; + } + + private void createColors() { + palette = new int[256]; + for (int i = 0; i < 256; i++) { + palette[i] = (i << 16) | (i / 2 << 8) | (i / 4); + } + } + + private void initSinTables(int width) { + for (int i = 0; i < SIN_TABLE_SIZE; i++) { + int min = width; + int numMin = 0; + final int[] tmp = new int[4]; + + for (int k = 0; k < 4; k++) { + tmp[k] = width / 2 + - (int) ((width / 2 - 20) * Math.cos(k * Math.PI / 2 + i * (3 * Math.PI / SIN_TABLE_SIZE))); + if (tmp[k] < min) { + min = tmp[k]; + numMin = k; + } + } + + guim1[i] = tmp[numMin]; + guim2[i] = tmp[(numMin + 1) & 3]; + guim3[i] = tmp[(numMin + 2) & 3]; + + pas[i] = (float) (1.2 * Math.sin(i * 14f * Math.PI / SIN_TABLE_SIZE) + * Math.cos(i * 2f * Math.PI / SIN_TABLE_SIZE)); + } + } + + private void doTwister(int width, int height) { + roll = (roll + 1) % (SIN_TABLE_SIZE - 1); + + for (int j = 0; j < height; j++) { + int wouaf = (int) (roll + j * pas[roll]); + wouaf &= SIN_TABLE_SIZE - 1; + + final int tmp1 = guim1[wouaf]; + final int tmp2 = guim2[wouaf]; + final int tmp3 = guim3[wouaf]; + + zoom(tmp1, tmp2 - tmp1, j, width, height); + zoom(tmp2, tmp3 - tmp2, j, width, height); + } + } + + private void zoom(int begin, int size, int row, int width, int height) { + if (size == 0 || row >= height) { + return; + } + int screenIndex = begin + row * width; + final int j = row & 63; + final float rap = 64.0f / size; + + for (float k = 0f; k < 64f; k += rap) { + final int i = (int) k; + int color = (i ^ j) << 2; + if ((color & 64) == 0) { + color ^= 64; + } + int posX = screenIndex % width; + int posY = screenIndex / width; + if (posX >= 0 && posX < width && posY >= 0 && posY < height) { + imageData.setPixel(posX, posY, palette[color]); + } + screenIndex++; + } + } +} diff --git a/examples/org.eclipse.swt.examples/src/org/eclipse/swt/examples/graphics/WaveTab.java b/examples/org.eclipse.swt.examples/src/org/eclipse/swt/examples/graphics/WaveTab.java new file mode 100644 index 00000000000..438704d405c --- /dev/null +++ b/examples/org.eclipse.swt.examples/src/org/eclipse/swt/examples/graphics/WaveTab.java @@ -0,0 +1,190 @@ +/******************************************************************************* + * Copyright (c) 2018 Laurent Caron and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Laurent Caron (laurent.caron at gmail dot com) - Conversion to SWT + * IBM Corporation - adaptation to GraphicsExample + *******************************************************************************/ + +package org.eclipse.swt.examples.graphics; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; + +/** + * This tab displays an animated wave effect with multiple motion patterns. + * The effect cycles through four different wave algorithms automatically. + */ +public class WaveTab extends AnimatedGraphicsTab { + + private static final double STEP = 0.07; + private static final int COLS = 30; + private static final int LINES = 20; + + private Image offscreenImage; + private int[][] xPos; + private int[][] yPos; + private double position; + private int kind; + private int patternWidth; + private int patternHeight; + private int centerX; + private int centerY; + private int lastWidth; + private int lastHeight; + private int frameCount; + + public WaveTab(GraphicsExample example) { + super(example); + } + + @Override + public String getCategory() { + return GraphicsExample.getResourceString("Misc"); //$NON-NLS-1$ + } + + @Override + public String getText() { + return GraphicsExample.getResourceString("Wave"); //$NON-NLS-1$ + } + + @Override + public String getDescription() { + return GraphicsExample.getResourceString("WaveDescription"); //$NON-NLS-1$ + } + + @Override + public int getInitialAnimationTime() { + return 10; + } + + @Override + public void dispose() { + if (offscreenImage != null) { + offscreenImage.dispose(); + offscreenImage = null; + } + } + + @Override + public void next(int width, int height) { + if (xPos == null) { + return; + } + if (width != lastWidth || height != lastHeight) { + init(width, height); + } + + // Auto-cycle through effects + frameCount++; + if (frameCount % 300 == 0) { + kind = (kind + 1) % 4; + } + + computePositions(width, height); + } + + @Override + public void paint(GC gc, int width, int height) { + if (xPos == null) { + init(width, height); + } + + gc.setBackground(gc.getDevice().getSystemColor(SWT.COLOR_BLACK)); + gc.fillRectangle(0, 0, width, height); + + if (offscreenImage != null) { + offscreenImage.dispose(); + } + offscreenImage = new Image(gc.getDevice(), width, height); + GC imageGC = new GC(offscreenImage); + imageGC.setBackground(gc.getDevice().getSystemColor(SWT.COLOR_BLACK)); + imageGC.fillRectangle(0, 0, width, height); + + Color white = new Color(255, 255, 255); + imageGC.setForeground(white); + + for (int i = 0; i < COLS; ++i) { + for (int j = 0; j < LINES; ++j) { + int px = xPos[i][j]; + int py = yPos[i][j]; + if (px >= 0 && px < width - 1 && py >= 0 && py < height - 1) { + imageGC.drawPoint(px, py); + imageGC.drawPoint(px + 1, py); + imageGC.drawPoint(px, py + 1); + imageGC.drawPoint(px + 1, py + 1); + } + } + } + + imageGC.dispose(); + gc.drawImage(offscreenImage, 0, 0); + } + + private void init(int width, int height) { + lastWidth = width; + lastHeight = height; + position = 0.0; + kind = 0; + frameCount = 0; + xPos = new int[COLS][LINES]; + yPos = new int[COLS][LINES]; + + patternWidth = (int) (0.5 * (width - (COLS - 1) * 15)) - 3; + patternHeight = (int) (0.5 * (height - (LINES - 1) * 15)) - 3; + centerX = (int) (0.5 * width); + centerY = (int) (0.5 * height); + } + + private void computePositions(int width, int height) { + position += STEP; + + for (int i = 0; i < COLS; ++i) { + for (int j = 0; j < LINES; ++j) { + switch (kind) { + case 0: + xPos[i][j] = (int) (patternWidth + 15 * i + + 10.0 * Math.cos(position * (1.0 + 0.01 * i + 0.015 * j))); + yPos[i][j] = (int) (patternHeight + 15 * j + - 10.0 * Math.sin(position * (1.0 + 0.0123 * j + 0.012 * i))); + break; + case 1: + xPos[i][j] = (int) (patternWidth + 15 * i + + 20.0 * Math.sin(position * (1.0 + 0.0059 * j + 0.00639 * i)) + * Math.cos(position + 0.3 * i + 0.3 * j)); + yPos[i][j] = (int) (patternHeight + 15 * j + - 20.0 * Math.cos(position * (1.0 - 0.073 * j + 0.00849 * i)) + * Math.sin(position + 0.23 * j + 0.389 * i)); + break; + case 2: + xPos[i][j] = (int) (centerX + 14.0 * i * Math.cos(0.01 * (40.0 - i) * position + j)); + yPos[i][j] = (int) (centerY - 14.0 * i * Math.sin(0.01 * (40.0 - i) * position + j)); + break; + case 3: + double d1 = 1.0; + int k = 0; + if (i >= 2 && i < 5) { d1 = -1.0; k = 1; } + else if (i >= 5 && i < 8) { d1 = 1.0; k = 2; } + else if (i >= 8 && i < 12) { d1 = -1.0; k = 3; } + else if (i >= 12 && i < 17) { d1 = 1.0; k = 4; } + else if (i >= 17 && i < 23) { d1 = -1.0; k = 5; } + else if (i >= 23 && i < 31) { d1 = 1.0; k = 6; } + xPos[i][j] = (int) (centerX + + 20.0 * (k + 4) * Math.cos(0.1 * position * d1 + j + 0.786 * i)); + yPos[i][j] = (int) (centerY + - 20.0 * (k + 4) * Math.sin(0.1 * position * d1 + j + 0.786 * i)); + break; + } + } + } + } +}