Spaced snake-like trails
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
SpacedTrail/src/sig/engine/Panel.java

1037 lines
36 KiB

package sig.engine;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.ColorModel;
import java.awt.image.MemoryImageSource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.GraphicsEnvironment;
import java.awt.GraphicsConfiguration;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.event.MouseInputListener;
import java.awt.event.KeyListener;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import sig.JavaProjectTemplate;
public class Panel extends JPanel implements Runnable,KeyListener {
JFrame window;
static JavaProjectTemplate gameInstance;
public int pixel[];
final int CIRCLE_PRECISION=32;
final int OUTLINE_COL=Color.BRIGHT_WHITE.getColor();
private Thread thread;
private Image imageBuffer;
private MemoryImageSource mImageProducer;
private ColorModel cm;
int scanLine=0;
int nextScanLine=0;
double x_offset=0;
double y_offset=0;
int frameCount=0;
long lastSecond=0;
boolean resizing=false;
long lastUpdate=System.nanoTime();
final long TARGET_FRAMETIME = 8333333l;
public double nanaX = 0;
public double nanaY = 0;
public int button = 0;
private MouseScrollValue scrollWheel=null;
public static final int UPDATE_LOOP_FRAMERATE = 244;
public static final long UPDATE_LOOP_NANOTIME = (long)((1d/UPDATE_LOOP_FRAMERATE)*1000000000l);
public static final double UPDATE_MULT = 1d / UPDATE_LOOP_FRAMERATE;
public static RenderingHints RENDERHINTS = new RenderingHints(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
static long lastReportedTime = System.currentTimeMillis();
public static long TIME = 0;
public static long scaleTime;
public static Panel p;
public static JFrame f;
public static void InitializeEngine(JavaProjectTemplate instance){
System.setProperty("sun.java2d.transaccel", "True");
System.setProperty("sun.java2d.d3d", "True");
System.setProperty("sun.java2d.ddforcevram", "True");
System.setProperty("sun.java2d.xrender", "True");
gameInstance=instance;
RENDERHINTS.put(RenderingHints.KEY_COLOR_RENDERING,RenderingHints.VALUE_COLOR_RENDER_SPEED);
RENDERHINTS.put(RenderingHints.KEY_DITHERING,RenderingHints.VALUE_DITHER_DISABLE);
RENDERHINTS.put(RenderingHints.KEY_FRACTIONALMETRICS,RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
RENDERHINTS.put(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_SPEED);
f = new JFrame(JavaProjectTemplate.PROGRAM_NAME);
f.setResizable(false);
f.setSize(JavaProjectTemplate.WINDOW_WIDTH,JavaProjectTemplate.WINDOW_HEIGHT);
p = new Panel(f);
JavaProjectTemplate.game=p;
p.init();
f.add(p);
f.addKeyListener(p);
f.setLocation((int) ((Toolkit.getDefaultToolkit().getScreenSize().getWidth() - f.getWidth()) / 2),
(int) ((Toolkit.getDefaultToolkit().getScreenSize().getHeight() - f.getHeight()) / 2));
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
p.render();
long lastGameTime = System.nanoTime();
long dt = 0;
while (true) {
dt += System.nanoTime() - lastGameTime;
lastGameTime = System.nanoTime();
while (dt >= UPDATE_LOOP_NANOTIME) {
gameInstance.updateGame(UPDATE_LOOP_NANOTIME/1000000000d);
Mouse.pressMap.clear();
Mouse.releaseMap.clear();
Key.KEYS_PRESS.clear();
Key.KEYS_RELEASE.clear();
dt -= UPDATE_LOOP_NANOTIME;
TIME += UPDATE_LOOP_NANOTIME;
}
gameUpdateLoopStabilizer(dt); //This is hackish. Removing this slows down the game by about 30%. The timer runs slower. ???
}
}
private static void gameUpdateLoopStabilizer(long dt) {
if (dt < UPDATE_LOOP_NANOTIME) {
lastReportedTime = System.currentTimeMillis();
} else {
if (System.currentTimeMillis() - lastReportedTime > 5000) {
System.out.println("WARNING! Game is lagging behind! Frames Behind: " + (dt / UPDATE_LOOP_NANOTIME));
lastReportedTime = System.currentTimeMillis();
}
}
try {
Thread.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public Panel(JFrame f) {
super(true);
this.window=f;
thread = new Thread(this, "MyPanel Thread");
this.addMouseListener(new MouseInputListener(){
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
Mouse.clickMap.put(e.getButton(),true);
Mouse.pressMap.put(e.getButton(),true);
}
@Override
public void mouseReleased(MouseEvent e) {
Mouse.clickMap.put(e.getButton(),false);
Mouse.releaseMap.put(e.getButton(),true);
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
@Override
public void mouseDragged(MouseEvent e) {
}
@Override
public void mouseMoved(MouseEvent e) {
}
});
this.addMouseMotionListener(new MouseMotionListener(){
@Override
public void mouseDragged(MouseEvent e) {
Mouse.x=e.getX();
Mouse.y=e.getY();
Mouse.mousePosition.set(e.getX(),e.getY());
}
@Override
public void mouseMoved(MouseEvent e) {
Mouse.x=e.getX();
Mouse.y=e.getY();
Mouse.mousePosition.set(e.getX(),e.getY());
}
});
this.addMouseWheelListener(new MouseWheelListener(){
//-1 is UP, 1 is DOWN
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
scrollWheel=MouseScrollValue.getValue(e.getWheelRotation());
}
});
}
/**
* Get Best Color model available for current screen.
* @return color model
*/
protected static ColorModel getCompatibleColorModel(){
GraphicsConfiguration gfx_config = GraphicsEnvironment.
getLocalGraphicsEnvironment().getDefaultScreenDevice().
getDefaultConfiguration();
return gfx_config.getColorModel();
}
/**
* Call it after been visible and after resizes.
*/
public void init(){
cm = getCompatibleColorModel();
int screenSize = JavaProjectTemplate.WINDOW_WIDTH * JavaProjectTemplate.WINDOW_HEIGHT;
if(pixel == null || pixel.length < screenSize){
pixel = new int[screenSize];
}
mImageProducer = new MemoryImageSource(JavaProjectTemplate.WINDOW_WIDTH, JavaProjectTemplate.WINDOW_HEIGHT, cm, pixel,0, JavaProjectTemplate.WINDOW_WIDTH);
mImageProducer.setAnimated(true);
mImageProducer.setFullBufferUpdates(true);
imageBuffer = Toolkit.getDefaultToolkit().createImage(mImageProducer);
if(thread.isInterrupted() || !thread.isAlive()){
thread.start();
}
}
@Override
public void paintComponent(Graphics g) {
//super.paintComponent(g);
// perform draws on pixels
long startTime = System.currentTimeMillis();
g.drawImage(this.imageBuffer,0,0,JavaProjectTemplate.WINDOW_WIDTH,JavaProjectTemplate.WINDOW_HEIGHT,0,0,JavaProjectTemplate.WINDOW_WIDTH,JavaProjectTemplate.WINDOW_HEIGHT,this);
scaleTime=System.currentTimeMillis()-startTime;
}
/**
* Overrides ImageObserver.imageUpdate.
* Always return true, assuming that imageBuffer is ready to go when called
*/
@Override
public boolean imageUpdate(Image image, int a, int b, int c, int d, int e) {
return true;
}
/**
* Do your draws in here !!
* pixel is your canvas!
*/
public /* abstract */ void render(){
gameInstance.drawGame();
}
public void FillCircle(double center_x,double center_y,double r,Color col) {
int counter=0;
List<Point<Integer>> points = new ArrayList<Point<Integer>>();
for (double theta=0;theta<Math.PI*2;theta+=((Math.PI*2)/CIRCLE_PRECISION)) {
//System.out.println("Loop "+counter+++". Theta:"+theta);
//System.out.println("X:"+(Math.sin(theta)*r+center_x)+" Y:"+(Math.cos(theta)*r+center_y));
points.add(new Point<Integer>((int)(Math.round(Math.sin(theta)*r+center_x)),(int)(Math.round(Math.cos(theta)*r+center_y))));
}
FillPolygon(0,0,col,points);
}
public void FillOval(double center_x,double center_y,double w,double h,Color col) {
int counter=0;
List<Point<Integer>> points = new ArrayList<Point<Integer>>();
double r = Math.max(w,h);
double ratio = Math.min(w,h)/r;
for (double theta=0;theta<Math.PI*2;theta+=((Math.PI*2)/CIRCLE_PRECISION)) {
//System.out.println("Loop "+counter+++". Theta:"+theta);
//System.out.println("X:"+(Math.sin(theta)*r+center_x)+" Y:"+(Math.cos(theta)*r+center_y));
Point<Integer> newP = new Point<Integer>((int)(Math.round(Math.sin(theta)*r)),(int)(Math.round(Math.cos(theta)*r)));
if (w<h) {
newP.x=(int)Math.round(newP.x*ratio);
} else {
newP.y=(int)Math.round(newP.y*ratio);
}
newP.x+=(int)center_x;
newP.y+=(int)center_y;
points.add(newP);
}
FillPolygon(0,0,col,points);
}
public void FillPolygon(double x_offset,double y_offset,Color col,List<Point<Integer>>points) {
Edge[] edges = new Edge[points.size()];
List<Edge> edges_sorted = new ArrayList<Edge>();
for (int i=0;i<points.size();i++) {
edges[i] = new Edge(points.get(i),points.get((i+1)%points.size()));
if (!Double.isInfinite(edges[i].inverse_slope)) {
if (edges_sorted.size()==0) {
edges_sorted.add(edges[i]);
} else {
boolean inserted=false;
for (int j=0;j<edges_sorted.size();j++) {
Edge e2 = edges_sorted.get(j);
if (e2.min_y>=edges[i].min_y) {
edges_sorted.add(j,edges[i]);
inserted=true;
break;
}
}
if (!inserted) {
edges_sorted.add(edges[i]);
}
}
}
}
//System.out.println(edges_sorted);
List<Edge> active_edges = new ArrayList<Edge>();
scanLine = edges_sorted.get(0).min_y-1;
nextScanLine = scanLine+1;
do {
for (int i=0;i<active_edges.size();i+=2) {
if (i>=active_edges.size()-1) break;
Edge e1 = active_edges.get(i);
Edge e2 = active_edges.get(i+1);
//System.out.println("Drawing from "+((int)Math.round(e1.x_of_min_y))+" to "+e2.x_of_min_y+" on line "+scanLine);
for (int x=(int)Math.round(e1.x_of_min_y);x<=e2.x_of_min_y;x++) {
if (x<0||x>JavaProjectTemplate.WINDOW_WIDTH) continue;
int index = (scanLine+(int)y_offset)*getWidth()+x+(int)x_offset;
if (index<pixel.length&&index>=0) {
Draw(index,col.getColor());
}
}
}
List<Edge> new_active_edges = new ArrayList<Edge>();
for (int i=0;i<active_edges.size();i++) {
Edge e = active_edges.get(i);
if (e.max_y==scanLine+1) {
active_edges.remove(i--);
} else {
e.x_of_min_y+=e.inverse_slope;
}
}
scanLine++;
for (int i=0;i<active_edges.size();i++) {
Edge e = active_edges.get(i);
boolean inserted=false;
for (int j=0;j<new_active_edges.size();j++) {
Edge e2 = new_active_edges.get(j);
if (e2.x_of_min_y>e.x_of_min_y) {
new_active_edges.add(j,e);
inserted=true;
break;
}
}
if (!inserted) {
new_active_edges.add(e);
}
}
active_edges=new_active_edges;
GetNextScanLineEdges(edges_sorted, active_edges);
}
while (active_edges.size()>0);
}
private void GetNextScanLineEdges(List<Edge> edges_sorted, List<Edge> active_edges) {
if (scanLine==nextScanLine) {
for (int i=0;i<edges_sorted.size();i++) {
Edge e = edges_sorted.get(i);
if (e.min_y==scanLine) {
e = edges_sorted.remove(i--);
boolean inserted=false;
for (int j=0;j<active_edges.size();j++) {
if (e.x_of_min_y<active_edges.get(j).x_of_min_y) {
active_edges.add(j,e);
inserted=true;
break;
}
}
if (!inserted) {
active_edges.add(e);
}
} else
if (e.min_y>scanLine) {
nextScanLine=e.min_y;
break;
}
}
}
}
public void Draw(int x, int y, Color col) {
if (x<0||y<0||x>=JavaProjectTemplate.WINDOW_WIDTH||y>=JavaProjectTemplate.WINDOW_HEIGHT) return;
Draw(y*JavaProjectTemplate.WINDOW_WIDTH+x,col.getColor());
}
void Draw(int index, int col) {
if (((col>>>24)&0xff)==0) return;
if (((col>>>24)&0xff)!=255) {
pixel[index]=ColorLerpNoAlpha(new Color(pixel[index]),new Color(col),((col>>>24)&0xff)/255f).getColor();
} else {
pixel[index]=col;
}
}
@Override
public void run() {
while (true) {
// request a JPanel re-drawing
render();
mImageProducer.newPixels();
if (f!=null) {
Graphics2D g2 = (Graphics2D)f.getGraphics();
if (g2!=null) {
g2.setRenderingHints(RENDERHINTS);
try {
repaint();
} finally {
g2.dispose();
}
}
}
updateFPSCounter();
//System.out.println("Repaint "+frameCount++);
waitForNextFrame();
}
}
private void waitForNextFrame() {
long newTime = System.nanoTime();
if (newTime-lastUpdate<TARGET_FRAMETIME) {
long timeRemaining=TARGET_FRAMETIME-(newTime-lastUpdate);
long millis = timeRemaining/1000000l;
int nanos = (int)(timeRemaining-millis*1000000l);
//System.out.println(timeRemaining+"/"+millis+" Nanos:"+nanos);
try {
Thread.sleep(millis,nanos);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
lastUpdate=newTime;
}
private void updateFPSCounter() {
if (window!=null&&System.currentTimeMillis()-lastSecond>=1000) {
window.setTitle(JavaProjectTemplate.PROGRAM_NAME+" - FPS: "+(frameCount));
frameCount=0;
lastSecond=System.currentTimeMillis();
}
frameCount++;
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
if (!Key.isHeld(e.getKeyCode())) {
Key.setKeyHeld(e.getKeyCode(), true);
Key.KEYS_PRESS.put(e.getKeyCode(),true);
}
//System.out.println("Key List: "+KEYS);
}
@Override
public void keyReleased(KeyEvent e) {
Key.setKeyHeld(e.getKeyCode(), false);
Key.KEYS_RELEASE.put(e.getKeyCode(),true);
//System.out.println("Key List: "+KEYS);
}
public void Draw_Text(double x, double y, java.lang.String s, Font f){
Draw_Text(x,y,new String(s),f);
}
public void Draw_Text_Ext(double x, double y, java.lang.String s, Font f, Color col){
Draw_Text_Ext(x,y,new String(s),f,col);
}
private void Draw_Text(double x, double y, String s, Font f) {
Draw_Text_Ext(x,y,s,f,Color.BLACK);
}
private void Draw_Text_Ext(double x, double y, String s, Font f, Color col) {
java.lang.String finalS = s.toString();
int charCount=0;
int yOffset=0;
int xOffset=0;
Color currentCol = col;
for (int i=0;i<finalS.length();i++) {
if (finalS.charAt(i)=='\n') {
xOffset+=(charCount+1)*f.getGlyphWidth();
yOffset+=f.getGlyphHeight();
charCount=0;
} else {
Draw_Sprite_Partial_Ext(x+i*f.getGlyphWidth()-xOffset, y+yOffset, f.getCharInfo(finalS.charAt(i)).getX(), f.getCharInfo(finalS.charAt(i)).getY(), f.getCharInfo(finalS.charAt(i)).getWidth(), f.getCharInfo(finalS.charAt(i)).getHeight(), f.getSprite(), 0,currentCol,Transform.NONE);
charCount++;
}
}
}
public void Draw_Line(int x1,int y1,int x2,int y2,Color col) {
int x,y,dx,dy,dx1,dy1,px,py,xe,ye;
dx=x2-x1;dy=y2-y1;
dx1=Math.abs(dx);dy1=Math.abs(dy);
px=2*dy1-dx1;py=2*dx1-dy1;
if (dy1<=dx1) {
if (dx>=0) {
x=x1;y=y1;xe=x2-1;
} else {
x=x2-1;y=y2-1;xe=x1;
}
while (x<xe) {
x=x+1;
if (px<0) {
px=px+2*dy1;
} else {
if ((dx<0&&dy<0)||(dx>0&&dy>0)) {
y=y+1;
} else {
y=y-1;
}
px=px+2*(dy1-dx1);
}
Draw(y*JavaProjectTemplate.WINDOW_WIDTH+x,col.getColor());
}
} else {
if (dy>=0) {
x=x1;y=y1;ye=y2-1;
} else {
x=x2-1;y=y2-1;ye=y1;
}
Draw(y*JavaProjectTemplate.WINDOW_WIDTH+x,col.getColor());
while (y<ye) {
y=y+1;
if (py<=0) {
py=py+2*dx1;
} else {
if ((dx<0&&dy<0)||(dx>0&&dy>0)) {
x=x+1;
} else {
x=x-1;
}
py=py+2*(dx1-dy1);
}
Draw(y*JavaProjectTemplate.WINDOW_WIDTH+x,col.getColor());
}
}
}
public void Fill_Rect(double x,double y,double w,double h,Color col) {
for (int xx=0;xx<w;xx++) {
for (int yy=0;yy<h;yy++) {
if (x+xx>=0&&y+yy>=0&&x+xx<JavaProjectTemplate.WINDOW_WIDTH&&y+yy<JavaProjectTemplate.WINDOW_HEIGHT) {
int index = ((int)y+yy)*JavaProjectTemplate.WINDOW_WIDTH+(int)x+xx;
Draw(index,col.getColor());
}
}
}
}
public void Draw_Sprite(double x, double y, Sprite sprite){
Draw_Sprite_Partial(x,y,0,0,sprite.getWidth(),sprite.getHeight(),sprite,0,Color.WHITE,Transform.NONE);
}
public void Draw_Animated_Sprite(double x, double y, AnimatedSprite sprite, double frameIndex){
Rectangle frameRectangle=sprite.getFrame((int)frameIndex);
Draw_Sprite_Partial(x,y,frameRectangle.getX(),frameRectangle.getY(),frameRectangle.getWidth(),frameRectangle.getHeight(),sprite,frameIndex,Color.WHITE,Transform.NONE);
}
public void Draw_Sprite(double x, double y, Sprite sprite, Color col){
Draw_Sprite_Partial(x,y,0,0,sprite.getWidth(),sprite.getHeight(),sprite,0,col,Transform.NONE);
}
public void Draw_Sprite(double x, double y, Sprite sprite, Transform transform){
Draw_Sprite_Partial(x,y,0,0,sprite.getWidth(),sprite.getHeight(),sprite,0,Color.WHITE,transform);
}
public void Draw_Animated_Sprite(double x, double y, AnimatedSprite sprite, double frameIndex, Color col, Transform transform){
Rectangle frameRectangle=sprite.getFrame((int)frameIndex);
Draw_Sprite_Partial(x,y,frameRectangle.getX(),frameRectangle.getY(),frameRectangle.getWidth(),frameRectangle.getHeight(),sprite,frameIndex,col,transform);
}
public void Draw_Sprite_Partial(double x, double y, double xOffset, double yOffset, double w, double h, Sprite sprite, double frame_index, Color col, Transform transform){
Draw_Sprite_Partial_Ext(x,y,xOffset,yOffset,w,h,sprite,frame_index, col,transform);
}
public void Draw_Sprite_Partial_Ext(double x, double y, double xOffset, double yOffset, double w, double h, Sprite sprite, Color col, Transform transform){
Draw_Sprite_Partial_Ext(x, y, xOffset, yOffset, w, h, sprite, 0, col, transform);
}
public void Draw_Animated_Sprite_Partial_Ext(double x, double y, double xOffset, double yOffset, double w, double h, AnimatedSprite sprite, double frameIndex, Color col, Transform transform){
Rectangle frameRectangle=sprite.getFrame((int)frameIndex);
Draw_Sprite_Partial_Ext(x, y, frameRectangle.getX(), frameRectangle.getY(), frameRectangle.getWidth(), frameRectangle.getHeight(), sprite, 0, col, transform);
}
public void Draw_Sprite_Partial_Ext(double x, double y, double xOffset, double yOffset, double w, double h, Sprite sprite, double frame_index, Color col, Transform transform){
boolean horizontal = transform==Transform.HORIZONTAL||transform==Transform.HORIZ_VERTIC;
boolean vertical = transform==Transform.VERTICAL||transform==Transform.HORIZ_VERTIC;
for(int X=(int)xOffset;X<(int)(w+xOffset);X++){
for(int Y=(int)yOffset;Y<(int)(h+yOffset);Y++){
if (X+x-xOffset<0||Y+y-yOffset<0||X-xOffset+x>=JavaProjectTemplate.WINDOW_WIDTH||Y-yOffset+y>=JavaProjectTemplate.WINDOW_HEIGHT) {
continue;
} else {
int index =
((vertical?
sprite.getHeight()-(Y-(int)yOffset):
(Y-(int)yOffset))
+(int)y)*JavaProjectTemplate.WINDOW_WIDTH+
(horizontal?
sprite.getWidth()-(X-(int)xOffset):
(X-(int)xOffset))
+(int)x;
if (((sprite.getImg().getRGB(X,Y)>>>24)&0xFF)==0||index<0||index>=pixel.length) {
continue;
} else {
if (col==Color.WHITE) {
Draw(index,sprite.getImg().getRGB(X,Y));
} else {
Color img = new Color(sprite.getImg().getRGB(X,Y));
Draw(index,new Color(
(int)Math.min(255.0f,Math.max(0,(float)img.r * col.r / 255.0f)),
(int)Math.min(255.0f,Math.max(0,(float)img.g * col.g / 255.0f)),
(int)Math.min(255.0f,Math.max(0,(float)img.b * col.b / 255.0f)),
(int)Math.min(255.0f,Math.max(0,(float)img.a * col.a / 255.0f))).getColor()
);
}
}
}
}
}
}
public void Draw_Rect(double x,double y, double w, double h, Color col) {
Draw_Line((int)x, (int)y, (int)x+(int)w, (int)y, col);
Draw_Line((int)x+(int)w, (int)y, (int)x+(int)w, (int)y+(int)h, col);
Draw_Line((int)x+(int)w, (int)y+(int)h, (int)x, (int)y+(int)h, col);
Draw_Line((int)x, (int)y+(int)h, (int)x, (int)y, col);
}
public void Draw_Triangle(double x1, double y1, double x2, double y2, double x3, double y3, Color col) {
Draw_Line((int)x1, (int)y1, (int)x2, (int)y2, col);
Draw_Line((int)x2, (int)y2, (int)x3, (int)y3, col);
Draw_Line((int)x3, (int)y3, (int)x1, (int)y1, col);
}
private void drawline(int sx,int ex,int ny,Color col){
for (int i = sx; i <= ex; i++) Draw(i, ny, col);
}
public void Fill_Triangle(double x1, double y1, double x2, double y2, double x3, double y3, Color col){
int t1x, t2x, y, minx, maxx, t1xp, t2xp;
boolean changed1 = false;
boolean changed2 = false;
int signx1, signx2, dx1, dy1, dx2, dy2;
int e1, e2;
// Sort vertices
int temp;
if (y1 > y2) {temp=(int)y1;y1=y2;y2=temp;temp=(int)x1;x1=x2;x2=temp;}
if (y1 > y3) {temp=(int)y1;y1=y3;y3=temp;temp=(int)x1;x1=x3;x3=temp;}
if (y2 > y3) {temp=(int)y2;y2=y3;y3=temp;temp=(int)x2;x2=x3;x3=temp;}
t1x = t2x = (int)x1; y = (int)y1; // Starting points
dx1 = (int)(x2 - x1);
if (dx1 < 0) { dx1 = -dx1; signx1 = -1; }
else signx1 = 1;
dy1 = (int)(y2 - y1);
dx2 = (int)(x3 - x1);
if (dx2 < 0) { dx2 = -dx2; signx2 = -1; }
else signx2 = 1;
dy2 = (int)(y3 - y1);
if (dy1 > dx1) {temp=dx1;dx1=dy1;dy1=temp;changed1 = true; }
if (dy2 > dx2) {temp=dx2;dx2=dy2;dy2=temp;changed2 = true; }
e2 = (int)(dx2 >> 1);
// Flat top, just process the second half
boolean firstHalfDone=false;
if (y1 == y2) firstHalfDone=true;
if (!firstHalfDone) {
e1 = (int)(dx1 >> 1);
for (int i = 0; i < dx1;) {
t1xp = 0; t2xp = 0;
if (t1x < t2x) { minx = t1x; maxx = t2x; }
else { minx = t2x; maxx = t1x; }
// process first line until y value is about to change
next0:
while (i < dx1) {
i++;
e1 += dy1;
while (e1 >= dx1) {
e1 -= dx1;
if (changed1) t1xp = signx1;//t1x += signx1;
else {
break next0;
}
}
if (changed1) break;
else t1x += signx1;
}
// Move line
next1:
// process second line until y value is about to change
while (true) {
e2 += dy2;
while (e2 >= dx2) {
e2 -= dx2;
if (changed2) t2xp = signx2;//t2x += signx2;
else {
break next1;
}
}
if (changed2) break;
else t2x += signx2;
}
if (minx > t1x) minx = t1x;
if (minx > t2x) minx = t2x;
if (maxx < t1x) maxx = t1x;
if (maxx < t2x) maxx = t2x;
drawline(minx, maxx, y, col); // Draw line from min to max points found on the y
// Now increase y
if (!changed1) t1x += signx1;
t1x += t1xp;
if (!changed2) t2x += signx2;
t2x += t2xp;
y += 1;
if (y == y2) break;
}
}
// Second half
dx1 = (int)(x3 - x2); if (dx1 < 0) { dx1 = -dx1; signx1 = -1; }
else signx1 = 1;
dy1 = (int)(y3 - y2);
t1x = (int)x2;
if (dy1 > dx1) { // swap values
temp=dy1;dx1=dy1;dy1=temp;
changed1 = true;
}
else changed1 = false;
e1 = (int)(dx1 >> 1);
for (int i = 0; i <= dx1; i++) {
t1xp = 0; t2xp = 0;
if (t1x < t2x) { minx = t1x; maxx = t2x; }
else { minx = t2x; maxx = t1x; }
// process first line until y value is about to change
next3:
while (i < dx1) {
e1 += dy1;
while (e1 >= dx1) {
e1 -= dx1;
if (changed1) { t1xp = signx1; break; }//t1x += signx1;
else break next3;
}
if (changed1) break;
else t1x += signx1;
if (i < dx1) i++;
}
next4:
// process second line until y value is about to change
while (t2x != x3) {
e2 += dy2;
while (e2 >= dx2) {
e2 -= dx2;
if (changed2) t2xp = signx2;
else break next4;
}
if (changed2) break;
else t2x += signx2;
}
if (minx > t1x) minx = t1x;
if (minx > t2x) minx = t2x;
if (maxx < t1x) maxx = t1x;
if (maxx < t2x) maxx = t2x;
drawline(minx, maxx, y,col);
if (!changed1) t1x += signx1;
t1x += t1xp;
if (!changed2) t2x += signx2;
t2x += t2xp;
y += 1;
if (y > y3) return;
}
}
public void FillTexturedTriangle(List<Point<Double>>vPoints,List<Point<Double>>vTex,List<Color>vColour,Sprite sprTex){
try {
vColour=new ArrayList<Color>(vColour);
Point<Double> p1 = vPoints.get(0).clone();
Point<Double> p2 = vPoints.get(1).clone();
Point<Double> p3 = vPoints.get(2).clone();
Double tempP;
Color tempC;
if (p2.y < p1.y){tempP=(double)p1.y;p1.y=p2.y;p2.y=tempP;tempP=(double)p1.x;p1.x=p2.x;p2.x=tempP;tempP=vTex.get(0).x;vTex.get(0).x=vTex.get(1).x;vTex.get(1).x=tempP;vTex.get(0).y=vTex.get(1).y;vTex.get(1).y=tempP;tempC=vColour.get(0);vColour.set(0,vColour.get(1));vColour.set(1,tempC);}
if (p3.y < p1.y){tempP=(double)p1.y;p1.y=p3.y;p3.y=tempP;tempP=(double)p1.x;p1.x=p3.x;p3.x=tempP;tempP=vTex.get(0).x;vTex.get(0).x=vTex.get(2).x;vTex.get(2).x=tempP;vTex.get(0).y=vTex.get(2).y;vTex.get(2).y=tempP;tempC=vColour.get(0);vColour.set(0,vColour.get(2));vColour.set(2,tempC);}
if (p3.y < p2.y){tempP=(double)p2.y;p2.y=p3.y;p3.y=tempP;tempP=(double)p2.x;p2.x=p3.x;p3.x=tempP;tempP=vTex.get(1).x;vTex.get(1).x=vTex.get(2).x;vTex.get(2).x=tempP;vTex.get(1).y=vTex.get(2).y;vTex.get(2).y=tempP;tempC=vColour.get(1);vColour.set(1,vColour.get(2));vColour.set(2,tempC);}
Point<Integer> dPos1 = new Point<Integer>((int)(p2.x-p1.x),(int)(p2.y-p1.y));
Point<Integer> dTex1 = new Point<Integer>((int)(vTex.get(1).x-vTex.get(0).x),(int)(vTex.get(1).y-vTex.get(0).y));
int dcr1 = vColour.get(1).r - vColour.get(0).r;
int dcg1 = vColour.get(1).g - vColour.get(0).g;
int dcb1 = vColour.get(1).b - vColour.get(0).b;
int dca1 = vColour.get(1).a - vColour.get(0).a;
Point<Integer> dPos2 = new Point<Integer>((int)(p3.x-p1.x),(int)(p3.y-p1.y));
Point<Integer> dTex2 = new Point<Integer>((int)(vTex.get(2).x-vTex.get(0).x),(int)(vTex.get(2).y-vTex.get(0).y));
int dcr2 = vColour.get(2).r - vColour.get(0).r;
int dcg2 = vColour.get(2).g - vColour.get(0).g;
int dcb2 = vColour.get(2).b - vColour.get(0).b;
int dca2 = vColour.get(2).a - vColour.get(0).a;
float dax_step = 0, dbx_step = 0, dcr1_step = 0, dcr2_step = 0, dcg1_step = 0, dcg2_step = 0, dcb1_step = 0, dcb2_step = 0, dca1_step = 0, dca2_step = 0;
Point<Float> vTex1Step=null, vTex2Step=null;
if (dPos1.y!=0)
{
dax_step = dPos1.x / (float)Math.abs(dPos1.y);
vTex1Step = new Point<Float>(dTex1.x / (float)Math.abs(dPos1.y),dTex1.y / (float)Math.abs(dPos1.y));
dcr1_step = dcr1 / (float)Math.abs(dPos1.y);
dcg1_step = dcg1 / (float)Math.abs(dPos1.y);
dcb1_step = dcb1 / (float)Math.abs(dPos1.y);
dca1_step = dca1 / (float)Math.abs(dPos1.y);
}
if (dPos2.y!=0)
{
dbx_step = dPos2.x / (float)Math.abs(dPos2.y);
vTex2Step = new Point<Float>(dTex2.x / (float)Math.abs(dPos2.y),dTex2.y / (float)Math.abs(dPos2.y));
dcr2_step = dcr2 / (float)Math.abs(dPos2.y);
dcg2_step = dcg2 / (float)Math.abs(dPos2.y);
dcb2_step = dcb2 / (float)Math.abs(dPos2.y);
dca2_step = dca2 / (float)Math.abs(dPos2.y);
}
Point<Double> vStart;
Point<Double> vEnd;
int vStartIdx;
for (int pass = 0; pass < 2; pass++)
{
if (pass == 0)
{
vStart = p1; vEnd = p2; vStartIdx = 0;
}
else
{
dPos1 = new Point<Integer>((int)(p3.x-p2.x),(int)(p3.y-p2.y));
dTex1 = new Point<Integer>((int)(vTex.get(2).x-vTex.get(1).x),(int)(vTex.get(2).y-vTex.get(1).y));
dcr1 = vColour.get(2).r - vColour.get(1).r;
dcg1 = vColour.get(2).g - vColour.get(1).g;
dcb1 = vColour.get(2).b - vColour.get(1).b;
dca1 = vColour.get(2).a - vColour.get(1).a;
dcr1_step = 0; dcg1_step = 0; dcb1_step = 0; dca1_step = 0;
if (dPos2.y!=0) dbx_step = dPos2.x / (float)Math.abs(dPos2.y);
if (dPos1.y!=0)
{
dax_step = dPos1.x / (float)Math.abs(dPos1.y);
vTex1Step = new Point<Float>(dTex1.x/(float)Math.abs(dPos1.y),dTex1.y/(float)Math.abs(dPos1.y));
dcr1_step = dcr1 / (float)Math.abs(dPos1.y);
dcg1_step = dcg1 / (float)Math.abs(dPos1.y);
dcb1_step = dcb1 / (float)Math.abs(dPos1.y);
dca1_step = dca1 / (float)Math.abs(dPos1.y);
}
vStart = p2; vEnd = p3; vStartIdx = 1;
}
if (dPos1.y!=0)
{
for (int i = (int)Math.floor(vStart.y); i <= vEnd.y; i++)
{
int ax = (int)(vStart.x + (float)(i - vStart.y) * dax_step);
int bx = (int)(p1.x + (float)(i - p1.y) * dbx_step);
Point<Float> tex_s = new Point<Float>((float)(vTex.get(vStartIdx).x + (float)(i - vStart.y) * vTex1Step.x),(float)(vTex.get(vStartIdx).y + (float)(i - vStart.y) * vTex1Step.y));
Point<Float> tex_e = new Point<Float>((float)(vTex.get(0).x + (float)(i - p1.y) * vTex2Step.x),(float)(vTex.get(0).y + (float)(i - p1.y) * vTex2Step.y));
Color col_s= new Color(vColour.get(vStartIdx).r + (int)((float)(i - vStart.y) * dcr1_step), vColour.get(vStartIdx).g + (int)((float)(i - vStart.y) * dcg1_step),
vColour.get(vStartIdx).b + (int)((float)(i - vStart.y) * dcb1_step), vColour.get(vStartIdx).a + (int)((float)(i - vStart.y) * dca1_step));
Color col_e= new Color(vColour.get(0).r + (int)((float)(i - p1.y) * dcr2_step), vColour.get(0).g + (int)((float)(i - p1.y) * dcg2_step),
vColour.get(0).b + (int)((float)(i - p1.y) * dcb2_step), vColour.get(0).a + (int)((float)(i - p1.y) * dca2_step));
int temp;
Point<Float> tempF;
if (ax > bx) {temp=ax;ax=bx;bx=temp;tempF=tex_s.clone();tex_s=tex_e.clone();tex_e=tempF;tempC=col_s.clone();col_s=col_e.clone();col_e=tempC;}
float tstep = 1.0f / ((float)(bx - ax));
float t = 0.0f;
for (int j = ax; j < bx; j++)
{
Color pixel = ColorLerp(col_s, col_e, t);
if (sprTex != null) {
Point<Float> lerpComponents = new Point<Float>(
tex_s.x*(1.0f-t)+tex_e.x*t,
tex_s.y*(1.0f-t)+tex_e.y*t
);
Color c=new Color(sprTex.getImg().getRGB((int)Math.min(lerpComponents.x*sprTex.width,sprTex.width-1),(int)Math.min(lerpComponents.y*sprTex.height,sprTex.height-1)));
pixel.r = (int)Math.min(255.0f,Math.max(0,(float)pixel.r * c.r / 255.0f));
pixel.g = (int)Math.min(255.0f,Math.max(0,(float)pixel.g * c.g / 255.0f));
pixel.b = (int)Math.min(255.0f,Math.max(0,(float)pixel.b * c.b / 255.0f));
pixel.a = (int)Math.min(255.0f,Math.max(0,(float)pixel.a * c.a / 255.0f));
}
Draw(j, i, pixel);
t += tstep;
}
}
}
}
} catch (CloneNotSupportedException e) {}
}
public void Draw_Circle(int x, int y, int radius, Color col) {
Draw_Circle(x,y,radius,col,(byte)0xFF);
}
//The mask indicates which pie slices to draw, each bit of the mask represents 1/8th of a pie slice. By default all pie slices are drawn.
public void Draw_Circle(int x, int y, int radius, Color col, byte mask) {
if (radius < 0 || x < -radius || y < -radius || x - JavaProjectTemplate.WINDOW_WIDTH > radius || y - JavaProjectTemplate.WINDOW_HEIGHT > radius)
return;
if (radius > 0)
{
int x0 = 0;
int y0 = radius;
int d = 3 - 2 * radius;
while (y0 >= x0) // only formulate 1/8 of circle
{
// Draw even octants
if ((mask & 0x01)!=0) Draw(x + x0, y - y0, col);// Q6 - upper right right
if ((mask & 0x04)!=0) Draw(x + y0, y + x0, col);// Q4 - lower lower right
if ((mask & 0x10)!=0) Draw(x - x0, y + y0, col);// Q2 - lower left left
if ((mask & 0x40)!=0) Draw(x - y0, y - x0, col);// Q0 - upper upper left
if (x0 != 0 && x0 != y0)
{
if ((mask & 0x02)!=0) Draw(x + y0, y - x0, col);// Q7 - upper upper right
if ((mask & 0x08)!=0) Draw(x + x0, y + y0, col);// Q5 - lower right right
if ((mask & 0x20)!=0) Draw(x - y0, y + x0, col);// Q3 - lower lower left
if ((mask & 0x80)!=0) Draw(x - x0, y - y0, col);// Q1 - upper left left
}
if (d < 0)
d += 4 * x0++ + 6;
else
d += 4 * (x0++ - y0--) + 10;
}
}
else
Draw(x, y, col);
}
public void Fill_Circle(int x, int y, int radius, Color col) {
if (radius < 0 || x < -radius || y < -radius || x - JavaProjectTemplate.WINDOW_WIDTH > radius || y - JavaProjectTemplate.WINDOW_HEIGHT > radius)
return;
if (radius > 0)
{
int x0 = 0;
int y0 = radius;
int d = 3 - 2 * radius;
while (y0 >= x0)
{
drawline(x - y0, x + y0, y - x0, col);
if (x0 > 0) drawline(x - y0, x + y0, y + x0, col);
if (d < 0)
d += 4 * x0++ + 6;
else
{
if (x0 != y0)
{
drawline(x - x0, x + x0, y - y0, col);
drawline(x - x0, x + x0, y + y0, col);
}
d += 4 * (x0++ - y0--) + 10;
}
}
}
else
Draw(x, y, col);
}
public void FillTexturedPolygon(List<Point<Double>>vPoints,List<Point<Double>>vTex,List<Color>vColour,Sprite sprTex,PolygonStructure structure) {
try {
if (vPoints.size() < 3 || vTex.size() < 3 || vColour.size() < 3)
return;
if (structure == PolygonStructure.LIST)
{
for (int tri = 0; tri < vPoints.size() / 3; tri++)
{
List<Point<Double>> vP = new ArrayList<Point<Double>>(List.of(vPoints.get(tri * 3 + 0), vPoints.get(tri * 3 + 1), vPoints.get(tri * 3 + 2)));
List<Point<Double>> vT = new ArrayList<Point<Double>>(List.of(vTex.get(tri * 3 + 0), vTex.get(tri * 3 + 1), vTex.get(tri * 3 + 2)));
List<Color> vC = new ArrayList<Color>(List.of(vColour.get(tri * 3 + 0), vColour.get(tri * 3 + 1), vColour.get(tri * 3 + 2)));
FillTexturedTriangle(vP, vT, vC, sprTex);
}
return;
}
if (structure == PolygonStructure.STRIP)
{
for (int tri = 2; tri < vPoints.size(); tri++)
{
List<Point<Double>> vP = new ArrayList<Point<Double>>(List.of(vPoints.get(tri - 2), vPoints.get(tri - 1), vPoints.get(tri)));
List<Point<Double>> vT = new ArrayList<Point<Double>>(List.of(vTex.get(tri - 2), vTex.get(tri - 1), vTex.get(tri)));
List<Color> vC = new ArrayList<Color>(List.of(vColour.get(tri - 2), vColour.get(tri - 1), vColour.get(tri)));
FillTexturedTriangle(vP, vT, vC, sprTex);
}
return;
}
if (structure == PolygonStructure.FAN)
{
for (int tri = 2; tri < vPoints.size(); tri++)
{
List<Point<Double>> vP;
vP = new ArrayList<Point<Double>>(List.of(vPoints.get(0).clone(), vPoints.get(tri - 1).clone(), vPoints.get(tri).clone()));
List<Point<Double>> vT = new ArrayList<Point<Double>>(List.of(vTex.get(0).clone(), vTex.get(tri - 1).clone(), vTex.get(tri).clone()));
List<Color> vC = new ArrayList<Color>(List.of(vColour.get(0).clone(), vColour.get(tri - 1).clone(), vColour.get(tri).clone()));
FillTexturedTriangle(vP, vT, vC, sprTex);
}
return;
}
} catch (CloneNotSupportedException e) {}
}
Color ColorLerp(Color c1, Color c2, float t)
{ return new Color((int)((c2.r * t) + c1.r * (1.0f - t)),(int)((c2.g * t) + c1.g * (1.0f - t)),(int)((c2.b * t) + c1.b * (1.0f - t)),(int)((c2.a * t) + c1.a * (1.0f - t))); }
Color ColorLerpNoAlpha(Color c1, Color c2, float t)
{ return new Color((int)((c2.r * t) + c1.r * (1.0f - t)),(int)((c2.g * t) + c1.g * (1.0f - t)),(int)((c2.b * t) + c1.b * (1.0f - t))); }
public void Clear(Color col){
for (int y=0;y<JavaProjectTemplate.WINDOW_HEIGHT;y++) {
for (int x=0;x<JavaProjectTemplate.WINDOW_WIDTH;x++) {
Draw(y*JavaProjectTemplate.WINDOW_WIDTH+x,col.getColor());
}
}
}
}