/*****************************************************
* "JawaBump" v1.0
* Written by Jawed Karim
* http://www.jawed.com/bump/
*
* You may use and distribute this source code freely.
* If you decide to use it, please give credit to the
* original author of this source code.
* Always leave this disclaimer intact.
*****************************************************/
import java.applet.Applet;
import java.awt.image.*;
import java.awt.*;
import java.awt.event.*;
public class bump extends Applet implements MouseMotionListener
{
//normal vector
private float normalVectors[][];
// image pixel array
private int imgcolors[][];
// double buffer
int buffer[];
private int Width, Height;
// mouse coords
private int mouseX = 0, mouseY = 0;
public void init ()
{
// mouse handling
addMouseMotionListener (this);
// load images
String imageName = getParameter ("image");
String bumpName = getParameter ("bumpmap");
if (imageName == null || bumpName == null)
{
showStatus ("ERROR: need parameters 'image' and 'bumpmap'!");
}
Image img = getImage (getDocumentBase (), imageName);
Image map = getImage (getDocumentBase (), bumpName);
MediaTracker imageTracker = new MediaTracker (this);
imageTracker.addImage (img, 0);
imageTracker.addImage (map, 0);
try {
imageTracker.waitForAll ();
}
catch (InterruptedException e) {
System.err.println("interrupted waiting for images!");
}
Width = img.getWidth (this);
Height = img.getHeight (this);
// normal vectors
normalVectors = new float[Width * Height][3];
// precalculate normal vectors
FindNormalVectors (map, normalVectors);
// color array
imgcolors = new int[Width * Height][3];
// fill color array
ImageToRGBArray (img, imgcolors);
// allocate doublebuffer
buffer = new int[Width * Height];
// release images
img.flush ();
map.flush ();
}
public void update (Graphics g)
{
paint (g);
}
public void paint (Graphics g)
{
int x, y;
float intensity;
int newR, newG, newB;
int oldR, oldG, oldB;
for (x = 0; x < Width; x++)
{
for (y = 0; y < Height; y++)
{
intensity = BumpIntensity (mouseX, mouseY, x, y);
// brighten slightly (ambient)
intensity += 0.18;
if (intensity > 1.0)
intensity = (float)1.0;
oldR = imgcolors[y * Width + x][0];
oldG = imgcolors[y * Width + x][1];
oldB = imgcolors[y * Width + x][2];
newR = (int)(intensity * oldR);
newG = (int)(intensity * oldG);
newB = (int)(intensity * oldB);
// Color c = new Color (newR, newG, newB);
// g.setColor (c);
// g.drawLine (x, y, x, y);
buffer[y * Width + x] = (255 << 24) | (newR << 16) | (newG << 8) | newB;
}
}
Image blitthis = createImage (new MemoryImageSource (Width, Height, buffer, 0, Width));
g.drawImage (blitthis, 0, 0, this);
blitthis.flush ();
}
void ImageToRGBArray (Image image, int RGBarray[][])
{
// Store RGB values into array
int imageWidth = image.getWidth (this);
int imageHeight = image.getHeight (this);
int[] pixelarray = new int [imageWidth * imageHeight];
PixelGrabber pg = new PixelGrabber (image, 0, 0, imageWidth, imageHeight, pixelarray, 0, imageWidth);
try {
pg.grabPixels ();
}
catch (InterruptedException e) {
System.err.println("interrupted waiting for pixels!");
}
for (int x = 0; x < Width; x++)
{
for (int y = 0; y < Height; y++)
{
Color c = GetPixelColor (pixelarray, x, y);
RGBarray[y * imageWidth + x][0] = (int)c.getRed ();
RGBarray[y * imageWidth + x][1] = (int)c.getGreen ();
RGBarray[y * imageWidth + x][2] = (int)c.getBlue ();
}
}
}
Color GetPixelColor (int[] arr, int x, int y)
{
int pixel = arr [y * Width + x];
int alpha = (pixel >> 24) & 0xff;
int red = (pixel >> 16) & 0xff;
int green = (pixel >> 8) & 0xff;
int blue = (pixel ) & 0xff;
return (new Color (red, green, blue));
}
float BumpIntensity (int lightX, int lightY, int pixelX, int pixelY)
{
float Nx, Ny, Nz;
// get normal vector of map
Nx = normalVectors[pixelY * Width + pixelX][0];
Ny = normalVectors[pixelY * Width + pixelX][1];
Nz = normalVectors[pixelY * Width + pixelX][2];
// make vector from pixel to light
float lightvX = (float)(lightX - pixelX);
float lightvY = (float)(lightY - pixelY);
float lightvZ = (float)(30.0f - 0.0f);
// normalize
float length = (float)Math.sqrt (lightvX*lightvX + lightvY*lightvY + lightvZ*lightvZ);
lightvX /= length;
lightvY /= length;
lightvZ /= length;
// take dot product
float intensity = (Nx * lightvX + Ny * lightvY + Nz * lightvZ);
if (intensity < 0.0f)
intensity = 0.0f;
return intensity;
}
// fills up the array with normal vectors of the image
void FindNormalVectors (Image imagemap, float nv[][])
{
PixelGrabber pg;
int[] pixelarray;
int imageWidth = imagemap.getWidth (this);
int imageHeight = imagemap.getHeight (this);
// get pixels into pixelarray
int[] pixelarraymap = new int [imageWidth * imageHeight];
pg = new PixelGrabber (imagemap, 0, 0, imageWidth, imageHeight, pixelarraymap, 0, imageWidth);
try {
pg.grabPixels ();
}
catch (InterruptedException e) {
System.err.println("interrupted waiting for pixels!");
}
for (int x = 1; x < Width - 1; x++)
{
for (int y = 1; y < Height - 1; y++)
{
Color X0 = GetPixelColor (pixelarraymap, x + 1, y);
Color X1 = GetPixelColor (pixelarraymap, x - 1, y);
Color Y0 = GetPixelColor (pixelarraymap, x, y + 1);
Color Y1 = GetPixelColor (pixelarraymap, x, y - 1);
float Xd = (X0.getRed() - X1.getRed())
+ (X0.getGreen() - X1.getGreen())
+ (X0.getBlue() - X1.getBlue());
float Yd = (Y0.getRed() - Y1.getRed())
+ (Y0.getGreen() - Y1.getGreen())
+ (Y0.getBlue() - Y1.getBlue());
// maximum for Xd, Yd is: (MAX - 0) + (MAX - 0) + (MAX - 0) = 3 * MAX
Xd /= (float)(3 * 255);
Yd /= (float)(3 * 255);
float Nx = Xd;
float Ny = Yd;
float Nz = (float)(1 - Math.sqrt ((Xd * Xd) + (Yd * Yd)));
if (Nz < 0.0f)
Nz = 0.0f;
nv[y * imageWidth + x][0] = Nx;
nv[y * imageWidth + x][1] = Ny;
nv[y * imageWidth + x][2] = Nz;
}
}
}
public void mouseDragged (MouseEvent e) {}
public void mouseMoved (MouseEvent e)
{
mouseX = e.getX();
mouseY = e.getY();
showStatus ("JawaBump, Copyright (c) 1999 Jawed Karim, WWW.JAWED.COM");
repaint ();
}
}