parent
							
								
									7024fb4402
								
							
						
					
					
						commit
						ec64ad21fc
					
				@ -0,0 +1,34 @@ | 
				
			||||
package mightypork.gamecore.backend; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
import mightypork.gamecore.render.RenderModule; | 
				
			||||
import mightypork.utils.eventbus.BusAccess; | 
				
			||||
import mightypork.utils.eventbus.clients.RootBusNode; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Application backend interface (set of core modules) | 
				
			||||
 *  | 
				
			||||
 * @author MightyPork | 
				
			||||
 */ | 
				
			||||
public abstract class Backend extends RootBusNode { | 
				
			||||
	 | 
				
			||||
	public Backend(BusAccess busAccess) { | 
				
			||||
		super(busAccess); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Initialize backend modules, add them to event bus.<br> | 
				
			||||
	 * Event bus must already be available in the BusAccess. | 
				
			||||
	 */ | 
				
			||||
	public abstract void initialize(); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Get graphics module (renderer) | 
				
			||||
	 *  | 
				
			||||
	 * @return graphics module | 
				
			||||
	 */ | 
				
			||||
	public abstract RenderModule getRenderer(); | 
				
			||||
} | 
				
			||||
@ -0,0 +1,32 @@ | 
				
			||||
package mightypork.gamecore.backend; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
import mightypork.utils.annotations.DefaultImpl; | 
				
			||||
import mightypork.utils.eventbus.BusAccess; | 
				
			||||
import mightypork.utils.eventbus.clients.BusNode; | 
				
			||||
import mightypork.utils.interfaces.Destroyable; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Abstract application backend module. | 
				
			||||
 *  | 
				
			||||
 * @author MightyPork | 
				
			||||
 */ | 
				
			||||
public abstract class BackendModule extends BusNode implements Destroyable { | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Create a module with bus access | 
				
			||||
	 *  | 
				
			||||
	 * @param busAccess | 
				
			||||
	 */ | 
				
			||||
	public BackendModule(BusAccess busAccess) { | 
				
			||||
		super(busAccess); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	@DefaultImpl | 
				
			||||
	public void destroy() | 
				
			||||
	{	 | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
} | 
				
			||||
@ -0,0 +1,85 @@ | 
				
			||||
package mightypork.gamecore.backend.lwjgl; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
import java.awt.image.BufferedImage; | 
				
			||||
import java.io.File; | 
				
			||||
import java.io.IOException; | 
				
			||||
import java.nio.ByteBuffer; | 
				
			||||
 | 
				
			||||
import javax.imageio.ImageIO; | 
				
			||||
 | 
				
			||||
import mightypork.gamecore.render.Screenshot; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Screenshot object, can be used to extract image or write to file.<br> | 
				
			||||
 * Screenshot, once taken, can be safely processed in separate thread.<br> | 
				
			||||
 * Based on {@link BufferedImage} and {@link ImageIO}. | 
				
			||||
 *  | 
				
			||||
 * @author Ondřej Hruška (MightyPork) | 
				
			||||
 */ | 
				
			||||
public class AwtScreenshot implements Screenshot { | 
				
			||||
	 | 
				
			||||
	private final int width; | 
				
			||||
	private final int height; | 
				
			||||
	private final int bpp; | 
				
			||||
	private final ByteBuffer bytes; | 
				
			||||
	private BufferedImage image; | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * @param width image width | 
				
			||||
	 * @param height image height | 
				
			||||
	 * @param bpp bits per pixel (typically 4) | 
				
			||||
	 * @param buffer | 
				
			||||
	 */ | 
				
			||||
	public AwtScreenshot(int width, int height, int bpp, ByteBuffer buffer) | 
				
			||||
	{ | 
				
			||||
		this.width = width; | 
				
			||||
		this.height = height; | 
				
			||||
		this.bpp = bpp; | 
				
			||||
		this.bytes = buffer; | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Extract to an image.<br> | 
				
			||||
	 * Subsequent calls will use a cached value. | 
				
			||||
	 *  | 
				
			||||
	 * @return image | 
				
			||||
	 */ | 
				
			||||
	public BufferedImage getImage() | 
				
			||||
	{ | 
				
			||||
		if (image != null) return image; | 
				
			||||
		 | 
				
			||||
		image = new BufferedImage(this.width, this.height, BufferedImage.TYPE_INT_RGB); | 
				
			||||
		 | 
				
			||||
		// convert to a buffered image
 | 
				
			||||
		for (int x = 0; x < this.width; x++) { | 
				
			||||
			for (int y = 0; y < this.height; y++) { | 
				
			||||
				final int i = (x + (this.width * y)) * this.bpp; | 
				
			||||
				final int r = this.bytes.get(i) & 0xFF; | 
				
			||||
				final int g = this.bytes.get(i + 1) & 0xFF; | 
				
			||||
				final int b = this.bytes.get(i + 2) & 0xFF; | 
				
			||||
				image.setRGB(x, this.height - (y + 1), (0xFF << 24) | (r << 16) | (g << 8) | b); | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
		 | 
				
			||||
		return image; | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Save to a file.<br> | 
				
			||||
	 * Cached value is used if any. | 
				
			||||
	 *  | 
				
			||||
	 * @param file target file | 
				
			||||
	 * @throws IOException on error writing to file | 
				
			||||
	 */ | 
				
			||||
	@Override | 
				
			||||
	public void save(File file) throws IOException | 
				
			||||
	{ | 
				
			||||
		file.getParentFile().mkdirs(); | 
				
			||||
		ImageIO.write(getImage(), "PNG", file); | 
				
			||||
	} | 
				
			||||
} | 
				
			||||
@ -0,0 +1,37 @@ | 
				
			||||
package mightypork.gamecore.backend.lwjgl; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
import mightypork.gamecore.backend.Backend; | 
				
			||||
import mightypork.gamecore.render.RenderModule; | 
				
			||||
import mightypork.utils.eventbus.BusAccess; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Game backend using LWJGL | 
				
			||||
 *  | 
				
			||||
 * @author MightyPork | 
				
			||||
 */ | 
				
			||||
public class LwjglBackend extends Backend { | 
				
			||||
	 | 
				
			||||
	public LwjglBackend(BusAccess busAccess) { | 
				
			||||
		super(busAccess); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
 | 
				
			||||
	private LwjglRenderModule renderer; | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void initialize() | 
				
			||||
	{ | 
				
			||||
		addChildClient(renderer = new LwjglRenderModule(this)); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public RenderModule getRenderer() | 
				
			||||
	{ | 
				
			||||
		return renderer; | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
} | 
				
			||||
@ -0,0 +1,641 @@ | 
				
			||||
package mightypork.gamecore.backend.lwjgl; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
import static org.lwjgl.opengl.GL11.*; | 
				
			||||
 | 
				
			||||
import java.nio.ByteBuffer; | 
				
			||||
import java.util.Stack; | 
				
			||||
 | 
				
			||||
import org.lwjgl.BufferUtils; | 
				
			||||
import org.lwjgl.LWJGLException; | 
				
			||||
import org.lwjgl.opengl.Display; | 
				
			||||
import org.lwjgl.opengl.DisplayMode; | 
				
			||||
import org.lwjgl.opengl.GL11; | 
				
			||||
 | 
				
			||||
import mightypork.gamecore.render.Grad; | 
				
			||||
import mightypork.gamecore.render.RenderModule; | 
				
			||||
import mightypork.gamecore.render.Screenshot; | 
				
			||||
import mightypork.gamecore.render.events.DisplayReadyEvent; | 
				
			||||
import mightypork.gamecore.render.events.ViewportChangeEvent; | 
				
			||||
import mightypork.gamecore.resources.textures.ITexture; | 
				
			||||
import mightypork.gamecore.resources.textures.LazyTexture; | 
				
			||||
import mightypork.gamecore.resources.textures.TxQuad; | 
				
			||||
import mightypork.utils.eventbus.BusAccess; | 
				
			||||
import mightypork.utils.logging.Log; | 
				
			||||
import mightypork.utils.math.color.Color; | 
				
			||||
import mightypork.utils.math.color.pal.RGB; | 
				
			||||
import mightypork.utils.math.constraints.rect.Rect; | 
				
			||||
import mightypork.utils.math.constraints.rect.caching.RectDigest; | 
				
			||||
import mightypork.utils.math.constraints.vect.Vect; | 
				
			||||
import mightypork.utils.math.timing.FpsMeter; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * LWJGL rendering module | 
				
			||||
 *  | 
				
			||||
 * @author MightyPork | 
				
			||||
 */ | 
				
			||||
public class LwjglRenderModule extends RenderModule { | 
				
			||||
	 | 
				
			||||
	public LwjglRenderModule(BusAccess busAccess) { | 
				
			||||
		super(busAccess); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	/** Currently binded color */ | 
				
			||||
	private Color activeColor = null; | 
				
			||||
	/** Currently binded color's alpha multiplier */ | 
				
			||||
	private double activeColorAlpha = 1; | 
				
			||||
	/** Stack of pushed colors */ | 
				
			||||
	private Stack<Color> colorPushStack = new Stack<>(); | 
				
			||||
	/** Currently binded texture */ | 
				
			||||
	private ITexture activeTexture; | 
				
			||||
	 | 
				
			||||
	/** Display mode used currently for the window */ | 
				
			||||
	private DisplayMode windowDisplayMode; | 
				
			||||
	/** FPS the user wants */ | 
				
			||||
	private int targetFps; | 
				
			||||
	/** FPS meter used for measuring actual FPS */ | 
				
			||||
	private FpsMeter fpsMeter; | 
				
			||||
	 | 
				
			||||
	/** Flag that at the end of frame, fullscreen should be toggled. */ | 
				
			||||
	private boolean fullscreenToggleRequested; | 
				
			||||
	/** Flag that at the end of frame, fullscreen should be set. */ | 
				
			||||
	private boolean fullscreenSetRequested; | 
				
			||||
	/** State to which fullscreen should be set. */ | 
				
			||||
	private boolean fullscreenSetState; | 
				
			||||
	 | 
				
			||||
	/** Current screen size */ | 
				
			||||
	private static final Vect screenSize = new Vect() { | 
				
			||||
		 | 
				
			||||
		@Override | 
				
			||||
		public double y() | 
				
			||||
		{ | 
				
			||||
			return Display.getHeight(); | 
				
			||||
		} | 
				
			||||
		 | 
				
			||||
		 | 
				
			||||
		@Override | 
				
			||||
		public double x() | 
				
			||||
		{ | 
				
			||||
			return Display.getWidth(); | 
				
			||||
		} | 
				
			||||
	}; | 
				
			||||
	 | 
				
			||||
	/** Current screen rectangle */ | 
				
			||||
	private static final Rect rect = Rect.make(screenSize); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void setColor(Color color) | 
				
			||||
	{ | 
				
			||||
		setColor(color, 1); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void setColor(Color color, double alpha) | 
				
			||||
	{ | 
				
			||||
		if (color == null) color = RGB.WHITE; | 
				
			||||
		 | 
				
			||||
		// color components can change over time - must use equals()
 | 
				
			||||
		if (activeColorAlpha == alpha && color.equals(activeColor)) return; | 
				
			||||
		 | 
				
			||||
		activeColor = color; | 
				
			||||
		activeColorAlpha = alpha; | 
				
			||||
		GL11.glColor4d(color.r(), color.g(), color.b(), alpha * color.a()); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void translate(double x, double y) | 
				
			||||
	{ | 
				
			||||
		glTranslated(x, y, 0); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void translate(double x, double y, double z) | 
				
			||||
	{ | 
				
			||||
		glTranslated(x, y, z); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void translate(Vect offset) | 
				
			||||
	{ | 
				
			||||
		glTranslated(offset.x(), offset.y(), offset.z()); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void translateXY(Vect offset) | 
				
			||||
	{ | 
				
			||||
		glTranslated(offset.x(), offset.y(), 0); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void scale(double x, double y) | 
				
			||||
	{ | 
				
			||||
		glScaled(x, y, 0); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void scale(double x, double y, double z) | 
				
			||||
	{ | 
				
			||||
		glScaled(x, y, z); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void scale(Vect scale) | 
				
			||||
	{ | 
				
			||||
		glScaled(scale.x(), scale.y(), scale.z()); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void scaleXY(double scale) | 
				
			||||
	{ | 
				
			||||
		glScaled(scale, scale, 1); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void scaleX(double scale) | 
				
			||||
	{ | 
				
			||||
		glScaled(scale, 1, 1); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void scaleY(double scale) | 
				
			||||
	{ | 
				
			||||
		glScaled(1, scale, 1); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void scaleZ(double scale) | 
				
			||||
	{ | 
				
			||||
		glScaled(1, 1, scale); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void rotateX(double angle) | 
				
			||||
	{ | 
				
			||||
		rotate(angle, AXIS_X); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void rotateY(double angle) | 
				
			||||
	{ | 
				
			||||
		rotate(angle, AXIS_Y); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void rotateZ(double angle) | 
				
			||||
	{ | 
				
			||||
		rotate(angle, AXIS_Z); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void rotate(double angle, Vect axis) | 
				
			||||
	{ | 
				
			||||
		final Vect vec = axis.norm(1); | 
				
			||||
		glRotated(angle, vec.x(), vec.y(), vec.z()); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void pushState() | 
				
			||||
	{ | 
				
			||||
		GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS); | 
				
			||||
		GL11.glPushClientAttrib(GL11.GL_ALL_CLIENT_ATTRIB_BITS); | 
				
			||||
		GL11.glPushMatrix(); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void popState() | 
				
			||||
	{ | 
				
			||||
		GL11.glPopMatrix(); | 
				
			||||
		GL11.glPopClientAttrib(); | 
				
			||||
		GL11.glPopAttrib(); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void pushGeometry() | 
				
			||||
	{ | 
				
			||||
		GL11.glPushMatrix(); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void popGeometry() | 
				
			||||
	{ | 
				
			||||
		GL11.glPopMatrix(); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void pushColor() | 
				
			||||
	{ | 
				
			||||
		colorPushStack.push(activeColor); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void popColor() | 
				
			||||
	{ | 
				
			||||
		setColor(colorPushStack.pop()); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void quad(Rect rect) | 
				
			||||
	{ | 
				
			||||
		final RectDigest q = rect.digest(); | 
				
			||||
		 | 
				
			||||
		// disable texture
 | 
				
			||||
		if (activeTexture != null) { | 
				
			||||
			activeTexture = null; | 
				
			||||
			glDisable(GL_TEXTURE_2D); | 
				
			||||
		} | 
				
			||||
		 | 
				
			||||
		// quad
 | 
				
			||||
		glBegin(GL_QUADS); | 
				
			||||
		glVertex2d(q.left, q.bottom); | 
				
			||||
		glVertex2d(q.right, q.bottom); | 
				
			||||
		glVertex2d(q.right, q.top); | 
				
			||||
		glVertex2d(q.left, q.top); | 
				
			||||
		glEnd(); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void quad(Rect rect, Color color) | 
				
			||||
	{ | 
				
			||||
		setColor(color); | 
				
			||||
		quad(rect); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void quad(Rect rect, Grad grad) | 
				
			||||
	{ | 
				
			||||
		final RectDigest r = rect.digest(); | 
				
			||||
		 | 
				
			||||
		// disable texture
 | 
				
			||||
		if (activeTexture != null) { | 
				
			||||
			activeTexture = null; | 
				
			||||
			glDisable(GL_TEXTURE_2D); | 
				
			||||
		} | 
				
			||||
		 | 
				
			||||
		// quad
 | 
				
			||||
		glBegin(GL_QUADS); | 
				
			||||
		setColor(grad.leftBottom); | 
				
			||||
		glVertex2d(r.left, r.bottom); | 
				
			||||
		 | 
				
			||||
		setColor(grad.rightBottom); | 
				
			||||
		glVertex2d(r.right, r.bottom); | 
				
			||||
		 | 
				
			||||
		setColor(grad.rightTop); | 
				
			||||
		glVertex2d(r.right, r.top); | 
				
			||||
		 | 
				
			||||
		setColor(grad.leftTop); | 
				
			||||
		glVertex2d(r.left, r.top); | 
				
			||||
		glEnd(); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void quad(Rect rect, TxQuad txquad) | 
				
			||||
	{ | 
				
			||||
		quad(rect, txquad, RGB.WHITE); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void quad(Rect rect, TxQuad txquad, Color color) | 
				
			||||
	{ | 
				
			||||
		// texture is loaded uniquely -> can compare with ==
 | 
				
			||||
		if (activeTexture != txquad.tx) { | 
				
			||||
			glEnable(GL_TEXTURE_2D); | 
				
			||||
			activeTexture = txquad.tx; | 
				
			||||
			activeTexture.bind(); | 
				
			||||
		} | 
				
			||||
		 | 
				
			||||
		glBegin(GL_QUADS); | 
				
			||||
		setColor(color); | 
				
			||||
		 | 
				
			||||
		final RectDigest q = rect.digest(); | 
				
			||||
		final RectDigest u = txquad.uvs.digest(); | 
				
			||||
		 | 
				
			||||
		final double offs = 0.0001;// hack to avoid white stitching
 | 
				
			||||
		 | 
				
			||||
		double tL = u.left + offs, tR = u.right - offs, tT = u.top + offs, tB = u.bottom - offs; | 
				
			||||
		 | 
				
			||||
		// handle flip
 | 
				
			||||
		if (txquad.isFlippedY()) { | 
				
			||||
			final double swap = tT; | 
				
			||||
			tT = tB; | 
				
			||||
			tB = swap; | 
				
			||||
		} | 
				
			||||
		 | 
				
			||||
		if (txquad.isFlippedX()) { | 
				
			||||
			final double swap = tL; | 
				
			||||
			tL = tR; | 
				
			||||
			tR = swap; | 
				
			||||
		} | 
				
			||||
		 | 
				
			||||
		final double w = txquad.tx.getWidth01(); | 
				
			||||
		final double h = txquad.tx.getHeight01(); | 
				
			||||
		 | 
				
			||||
		// quad with texture
 | 
				
			||||
		glTexCoord2d(tL * w, tB * h); | 
				
			||||
		glVertex2d(q.left, q.bottom); | 
				
			||||
		 | 
				
			||||
		glTexCoord2d(tR * w, tB * h); | 
				
			||||
		glVertex2d(q.right, q.bottom); | 
				
			||||
		 | 
				
			||||
		glTexCoord2d(tR * w, tT * h); | 
				
			||||
		glVertex2d(q.right, q.top); | 
				
			||||
		 | 
				
			||||
		glTexCoord2d(tL * w, tT * h); | 
				
			||||
		glVertex2d(q.left, q.top); | 
				
			||||
		 | 
				
			||||
		glEnd(); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void setupProjection(Vect screenSize) | 
				
			||||
	{ | 
				
			||||
		// fix projection for changed size
 | 
				
			||||
		glMatrixMode(GL_PROJECTION); | 
				
			||||
		glLoadIdentity(); | 
				
			||||
		glViewport(0, 0, screenSize.xi(), screenSize.yi()); | 
				
			||||
		glOrtho(0, screenSize.xi(), screenSize.yi(), 0, -1000, 1000); | 
				
			||||
		 | 
				
			||||
		// back to modelview
 | 
				
			||||
		glMatrixMode(GL_MODELVIEW); | 
				
			||||
		 | 
				
			||||
		glLoadIdentity(); | 
				
			||||
		 | 
				
			||||
		glDisable(GL_LIGHTING); | 
				
			||||
		 | 
				
			||||
		glClearDepth(1f); | 
				
			||||
		glEnable(GL_DEPTH_TEST); | 
				
			||||
		glDepthFunc(GL_LEQUAL); | 
				
			||||
		 | 
				
			||||
		glEnable(GL_NORMALIZE); | 
				
			||||
		 | 
				
			||||
		glShadeModel(GL_SMOOTH); | 
				
			||||
		 | 
				
			||||
		glEnable(GL_BLEND); | 
				
			||||
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public LazyTexture getLazyTexture(String path) | 
				
			||||
	{ | 
				
			||||
		return new SlickLazyTexture(path); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void destroy() | 
				
			||||
	{ | 
				
			||||
		Display.destroy(); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void setTargetFps(int fps) | 
				
			||||
	{ | 
				
			||||
		this.targetFps = fps; | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void createDisplay() | 
				
			||||
	{ | 
				
			||||
		if (Display.isCreated()) throw new IllegalStateException("Display already created."); | 
				
			||||
		try { | 
				
			||||
			Display.create(); | 
				
			||||
			 | 
				
			||||
			fpsMeter = new FpsMeter(); | 
				
			||||
			 | 
				
			||||
			if (fullscreenSetRequested && fullscreenSetState) { | 
				
			||||
				doToggleFullscreen(); | 
				
			||||
				Display.update(); | 
				
			||||
				fullscreenSetRequested = false; | 
				
			||||
			} | 
				
			||||
			 | 
				
			||||
			getEventBus().send(new DisplayReadyEvent()); | 
				
			||||
			 | 
				
			||||
		} catch (final Exception e) { | 
				
			||||
			throw new RuntimeException("Could not initialize display.", e); | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void setFullscreen(boolean fs) | 
				
			||||
	{ | 
				
			||||
		fullscreenSetRequested = true; | 
				
			||||
		fullscreenSetState = fs; | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void switchFullscreen() | 
				
			||||
	{ | 
				
			||||
		fullscreenToggleRequested = true; | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public boolean isFullscreen() | 
				
			||||
	{ | 
				
			||||
		return Display.isFullscreen(); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	private void doToggleFullscreen() | 
				
			||||
	{ | 
				
			||||
		doSetFullscreen(!Display.isFullscreen()); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	private void doSetFullscreen(boolean fs) | 
				
			||||
	{ | 
				
			||||
		try { | 
				
			||||
			 | 
				
			||||
			if (Display.isFullscreen() == fs) return; // no work
 | 
				
			||||
				 | 
				
			||||
			if (fs) { | 
				
			||||
				Log.f3("Entering fullscreen."); | 
				
			||||
				// save window resize
 | 
				
			||||
				windowDisplayMode = new DisplayMode(Display.getWidth(), Display.getHeight()); | 
				
			||||
				 | 
				
			||||
				Display.setDisplayMode(Display.getDesktopDisplayMode()); | 
				
			||||
				Display.setFullscreen(true); | 
				
			||||
				Display.update(); | 
				
			||||
			} else { | 
				
			||||
				Log.f3("Leaving fullscreen."); | 
				
			||||
				Display.setDisplayMode(windowDisplayMode); | 
				
			||||
				Display.update(); | 
				
			||||
			} | 
				
			||||
			 | 
				
			||||
			getEventBus().send(new ViewportChangeEvent(getSize())); | 
				
			||||
			 | 
				
			||||
		} catch (final Throwable t) { | 
				
			||||
			Log.e("Failed to change fullscreen mode.", t); | 
				
			||||
			try { | 
				
			||||
				Display.setDisplayMode(windowDisplayMode); | 
				
			||||
				Display.update(); | 
				
			||||
			} catch (final Throwable t1) { | 
				
			||||
				throw new RuntimeException("Failed to revert failed fullscreen toggle.", t1); | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public Screenshot takeScreenshot() | 
				
			||||
	{ | 
				
			||||
		glReadBuffer(GL_FRONT); | 
				
			||||
		final int width = Display.getWidth(); | 
				
			||||
		final int height = Display.getHeight(); | 
				
			||||
		final int bpp = 4; | 
				
			||||
		final ByteBuffer buffer = BufferUtils.createByteBuffer(width * height * bpp); | 
				
			||||
		glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer); | 
				
			||||
		 | 
				
			||||
		final AwtScreenshot sc = new AwtScreenshot(width, height, bpp, buffer); | 
				
			||||
		 | 
				
			||||
		return sc; | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public boolean isCloseRequested() | 
				
			||||
	{ | 
				
			||||
		return Display.isCloseRequested(); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void beginFrame() | 
				
			||||
	{ | 
				
			||||
		// handle resize
 | 
				
			||||
		if (Display.wasResized()) { | 
				
			||||
			getEventBus().send(new ViewportChangeEvent(getSize())); | 
				
			||||
		} | 
				
			||||
		 | 
				
			||||
		if (fullscreenToggleRequested) { | 
				
			||||
			fullscreenToggleRequested = false; | 
				
			||||
			doToggleFullscreen(); | 
				
			||||
		} | 
				
			||||
		 | 
				
			||||
		if (fullscreenSetRequested) { | 
				
			||||
			fullscreenSetRequested = false; | 
				
			||||
			doSetFullscreen(fullscreenSetState); | 
				
			||||
		} | 
				
			||||
		 | 
				
			||||
		glLoadIdentity(); | 
				
			||||
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | 
				
			||||
		fpsMeter.frame(); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void endFrame() | 
				
			||||
	{ | 
				
			||||
		Display.update(false); // don't poll input devices
 | 
				
			||||
		Display.sync(targetFps); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void setSize(int width, int height) | 
				
			||||
	{ | 
				
			||||
		try { | 
				
			||||
			Display.setDisplayMode(windowDisplayMode = new DisplayMode(width, height)); | 
				
			||||
		} catch (LWJGLException e) { | 
				
			||||
			throw new RuntimeException(e); | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void setTitle(String title) | 
				
			||||
	{ | 
				
			||||
		Display.setTitle(title); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void setVSync(boolean vsync) | 
				
			||||
	{ | 
				
			||||
		Display.setVSyncEnabled(vsync); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void setResizable(boolean resizable) | 
				
			||||
	{ | 
				
			||||
		Display.setResizable(resizable); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public Rect getRect() | 
				
			||||
	{ | 
				
			||||
		return rect; | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public long getFps() | 
				
			||||
	{ | 
				
			||||
		return fpsMeter.getFPS(); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public Vect getCenter() | 
				
			||||
	{ | 
				
			||||
		return rect.center(); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public int getWidth() | 
				
			||||
	{ | 
				
			||||
		return Display.getWidth(); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public int getHeight() | 
				
			||||
	{ | 
				
			||||
		return Display.getHeight(); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public Vect getSize() | 
				
			||||
	{ | 
				
			||||
		return screenSize; | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
} | 
				
			||||
@ -0,0 +1,142 @@ | 
				
			||||
package mightypork.gamecore.backend.lwjgl; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
import java.io.IOException; | 
				
			||||
 | 
				
			||||
import mightypork.gamecore.resources.TextureBasedResource; | 
				
			||||
import mightypork.gamecore.resources.textures.*; | 
				
			||||
import mightypork.utils.annotations.Alias; | 
				
			||||
import mightypork.utils.files.FileUtils; | 
				
			||||
import mightypork.utils.logging.Log; | 
				
			||||
import org.lwjgl.opengl.GL11; | 
				
			||||
import org.newdawn.slick.opengl.Texture; | 
				
			||||
import org.newdawn.slick.opengl.TextureLoader; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Deferred texture | 
				
			||||
 *  | 
				
			||||
 * @author Ondřej Hruška (MightyPork) | 
				
			||||
 */ | 
				
			||||
@Alias(name = "Texture") | 
				
			||||
@TextureBasedResource | 
				
			||||
public class SlickLazyTexture extends LazyTexture { | 
				
			||||
	 | 
				
			||||
	private org.newdawn.slick.opengl.Texture backingTexture; | 
				
			||||
	private boolean alpha; | 
				
			||||
	private boolean alphal; | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * @param resourcePath resource path | 
				
			||||
	 */ | 
				
			||||
	public SlickLazyTexture(String resourcePath) { | 
				
			||||
		super(resourcePath); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	protected synchronized void loadResource(String path) | 
				
			||||
	{ | 
				
			||||
		try { | 
				
			||||
			final String ext = FileUtils.getExtension(path).toUpperCase(); | 
				
			||||
			 | 
				
			||||
			final Texture texture = TextureLoader.getTexture(ext, FileUtils.getResource(path), false, filter.num); | 
				
			||||
			 | 
				
			||||
			if (texture == null) { | 
				
			||||
				Log.w("Texture " + path + " could not be loaded."); | 
				
			||||
			} | 
				
			||||
			 | 
				
			||||
			backingTexture = texture; | 
				
			||||
			 | 
				
			||||
		} catch (final IOException e) { | 
				
			||||
			Log.e("Loading of texture " + path + " failed.", e); | 
				
			||||
			throw new RuntimeException("Could not load texture " + path + ".", e); | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public boolean hasAlpha() | 
				
			||||
	{ | 
				
			||||
		if (!ensureLoaded()) return false; | 
				
			||||
		 | 
				
			||||
		if (!alphal) { | 
				
			||||
			alphal = true; | 
				
			||||
			alpha = backingTexture.hasAlpha(); | 
				
			||||
		} | 
				
			||||
		 | 
				
			||||
		return alpha; | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void bind() | 
				
			||||
	{ | 
				
			||||
		if (!ensureLoaded()) return; | 
				
			||||
		 | 
				
			||||
		//GL11.glEnable(GL11.GL_TEXTURE_2D);
 | 
				
			||||
		 | 
				
			||||
		GL11.glBindTexture(GL11.GL_TEXTURE_2D, getTextureID()); | 
				
			||||
		 | 
				
			||||
		GL11.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_MODULATE); | 
				
			||||
		 | 
				
			||||
		GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, wrap.num); | 
				
			||||
		GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, wrap.num); | 
				
			||||
		 | 
				
			||||
		GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, filter.num); | 
				
			||||
		GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, filter.num); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public int getImageHeight() | 
				
			||||
	{ | 
				
			||||
		if (!ensureLoaded()) return 0; | 
				
			||||
		 | 
				
			||||
		return backingTexture.getImageHeight(); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public int getImageWidth() | 
				
			||||
	{ | 
				
			||||
		if (!ensureLoaded()) return 0; | 
				
			||||
		 | 
				
			||||
		return backingTexture.getImageWidth(); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public float getHeight01() | 
				
			||||
	{ | 
				
			||||
		if (!ensureLoaded()) return 0; | 
				
			||||
		 | 
				
			||||
		return backingTexture.getHeight(); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public float getWidth01() | 
				
			||||
	{ | 
				
			||||
		if (!ensureLoaded()) return 0; | 
				
			||||
		 | 
				
			||||
		return backingTexture.getWidth(); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public void destroy() | 
				
			||||
	{ | 
				
			||||
		if (!isLoaded()) return; | 
				
			||||
		 | 
				
			||||
		backingTexture.release(); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	@Override | 
				
			||||
	public int getTextureID() | 
				
			||||
	{ | 
				
			||||
		if (!ensureLoaded()) return -1; | 
				
			||||
		 | 
				
			||||
		return backingTexture.getTextureID(); | 
				
			||||
	} | 
				
			||||
} | 
				
			||||
@ -0,0 +1,85 @@ | 
				
			||||
package mightypork.gamecore.core.modules; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
import mightypork.gamecore.backend.Backend; | 
				
			||||
import mightypork.gamecore.render.RenderModule; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Game base class & static subsystem access | 
				
			||||
 *  | 
				
			||||
 * @author MightyPork | 
				
			||||
 */ | 
				
			||||
public class App { | 
				
			||||
	 | 
				
			||||
	private static App runningInstance; | 
				
			||||
	private static Backend backend; | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	public App() { | 
				
			||||
		if (App.isInitialized()) throw new IllegalStateException("App already initialized"); | 
				
			||||
		 | 
				
			||||
		// store current instance in static field
 | 
				
			||||
		App.runningInstance = this; | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Create app with given backend. | 
				
			||||
	 *  | 
				
			||||
	 * @param backend backend to use | 
				
			||||
	 */ | 
				
			||||
	public void setBackend(Backend backend) | 
				
			||||
	{ | 
				
			||||
		// store used backend in static field
 | 
				
			||||
		App.backend = backend; | 
				
			||||
		 | 
				
			||||
		// initialize the backend
 | 
				
			||||
		App.backend.initialize(); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Throw error if app is not initialized | 
				
			||||
	 */ | 
				
			||||
	protected static void assertInitialized() | 
				
			||||
	{ | 
				
			||||
		if (!App.isInitialized()) throw new IllegalStateException("App is not initialized."); | 
				
			||||
		if (backend == null) throw new IllegalStateException("No backend set!"); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Check whether the app is initialized (backend assigned). | 
				
			||||
	 *  | 
				
			||||
	 * @return is initialized | 
				
			||||
	 */ | 
				
			||||
	public static boolean isInitialized() | 
				
			||||
	{ | 
				
			||||
		return runningInstance != null; | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Get current backend | 
				
			||||
	 *  | 
				
			||||
	 * @return the backend | 
				
			||||
	 */ | 
				
			||||
	public static Backend getBackend() | 
				
			||||
	{ | 
				
			||||
		assertInitialized(); | 
				
			||||
		return backend; | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Get renderer instance from the backend | 
				
			||||
	 *  | 
				
			||||
	 * @return backend | 
				
			||||
	 */ | 
				
			||||
	public static RenderModule gfx() | 
				
			||||
	{ | 
				
			||||
		assertInitialized(); | 
				
			||||
		return backend.getRenderer(); | 
				
			||||
	} | 
				
			||||
} | 
				
			||||
@ -0,0 +1,31 @@ | 
				
			||||
package mightypork.gamecore.render; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
import mightypork.utils.math.color.Color; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Linear gradient (each vertex can have different color) | 
				
			||||
 *  | 
				
			||||
 * @author MightyPork | 
				
			||||
 */ | 
				
			||||
public class Grad { | 
				
			||||
	 | 
				
			||||
	public final Color leftTop, rightTop, rightBottom, leftBottom; | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Create a gradient | 
				
			||||
	 *  | 
				
			||||
	 * @param leftTop left top color | 
				
			||||
	 * @param rightTop right top color | 
				
			||||
	 * @param rightBottom right bottom color | 
				
			||||
	 * @param leftBottom left bottom color | 
				
			||||
	 */ | 
				
			||||
	public Grad(Color leftTop, Color rightTop, Color rightBottom, Color leftBottom) { | 
				
			||||
		this.leftTop = leftTop; | 
				
			||||
		this.rightTop = rightTop; | 
				
			||||
		this.rightBottom = rightBottom; | 
				
			||||
		this.leftBottom = leftBottom; | 
				
			||||
	} | 
				
			||||
} | 
				
			||||
@ -0,0 +1,17 @@ | 
				
			||||
package mightypork.gamecore.render; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
import mightypork.utils.math.color.Color; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Linear horizontal gradient | 
				
			||||
 *  | 
				
			||||
 * @author MightyPork | 
				
			||||
 */ | 
				
			||||
public class GradH extends Grad { | 
				
			||||
	 | 
				
			||||
	public GradH(Color left, Color right) { | 
				
			||||
		super(left, right, right, left); | 
				
			||||
	} | 
				
			||||
} | 
				
			||||
@ -0,0 +1,17 @@ | 
				
			||||
package mightypork.gamecore.render; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
import mightypork.utils.math.color.Color; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Linear vertical gradient | 
				
			||||
 *  | 
				
			||||
 * @author MightyPork | 
				
			||||
 */ | 
				
			||||
public class GradV extends Grad { | 
				
			||||
	 | 
				
			||||
	public GradV(Color top, Color bottom) { | 
				
			||||
		super(top, top, bottom, bottom); | 
				
			||||
	} | 
				
			||||
} | 
				
			||||
@ -0,0 +1,420 @@ | 
				
			||||
package mightypork.gamecore.render; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
import mightypork.gamecore.backend.BackendModule; | 
				
			||||
import mightypork.gamecore.resources.textures.LazyTexture; | 
				
			||||
import mightypork.gamecore.resources.textures.TxQuad; | 
				
			||||
import mightypork.utils.eventbus.BusAccess; | 
				
			||||
import mightypork.utils.math.color.Color; | 
				
			||||
import mightypork.utils.math.constraints.rect.Rect; | 
				
			||||
import mightypork.utils.math.constraints.vect.Vect; | 
				
			||||
import mightypork.utils.math.constraints.vect.VectConst; | 
				
			||||
import mightypork.utils.math.timing.FpsMeter; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Render and display backend module.<br> | 
				
			||||
 * This module takes care of setting and getting screen size and parameters, | 
				
			||||
 * drawing on screen and timing render frames. | 
				
			||||
 *  | 
				
			||||
 * @author MightyPork | 
				
			||||
 */ | 
				
			||||
public abstract class RenderModule extends BackendModule { | 
				
			||||
	 | 
				
			||||
	public RenderModule(BusAccess busAccess) { | 
				
			||||
		super(busAccess); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	protected static final VectConst AXIS_X = Vect.make(1, 0, 0); | 
				
			||||
	protected static final VectConst AXIS_Y = Vect.make(0, 1, 0); | 
				
			||||
	protected static final VectConst AXIS_Z = Vect.make(0, 0, 1); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Set drawing color | 
				
			||||
	 *  | 
				
			||||
	 * @param color color | 
				
			||||
	 */ | 
				
			||||
	public abstract void setColor(Color color); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Set drawing color, adjust alpha | 
				
			||||
	 *  | 
				
			||||
	 * @param color color | 
				
			||||
	 * @param alpha alpha multiplier | 
				
			||||
	 */ | 
				
			||||
	public abstract void setColor(Color color, double alpha); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Translate by x, y | 
				
			||||
	 *  | 
				
			||||
	 * @param x x offset | 
				
			||||
	 * @param y y offset | 
				
			||||
	 */ | 
				
			||||
	public abstract void translate(double x, double y); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Translate by x, y, z | 
				
			||||
	 *  | 
				
			||||
	 * @param x x offset | 
				
			||||
	 * @param y y offset | 
				
			||||
	 * @param z z offset | 
				
			||||
	 */ | 
				
			||||
	public abstract void translate(double x, double y, double z); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Translate by offset vector | 
				
			||||
	 *  | 
				
			||||
	 * @param offset offset coordinate | 
				
			||||
	 */ | 
				
			||||
	public abstract void translate(Vect offset); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Translate by offset vector, ignore Z | 
				
			||||
	 *  | 
				
			||||
	 * @param offset offset coordinate | 
				
			||||
	 */ | 
				
			||||
	public abstract void translateXY(Vect offset); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Set scale for translations and coordinates | 
				
			||||
	 *  | 
				
			||||
	 * @param x x scale | 
				
			||||
	 * @param y y scale | 
				
			||||
	 */ | 
				
			||||
	public abstract void scale(double x, double y); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Set scale for translations and coordinates | 
				
			||||
	 *  | 
				
			||||
	 * @param x x scale | 
				
			||||
	 * @param y y scale | 
				
			||||
	 * @param z z scale | 
				
			||||
	 */ | 
				
			||||
	public abstract void scale(double x, double y, double z); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Set scale for translations and coordinates | 
				
			||||
	 *  | 
				
			||||
	 * @param scale vector | 
				
			||||
	 */ | 
				
			||||
	public abstract void scale(Vect scale); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Set scale for translations and coordinates (same value for X and Y scale) | 
				
			||||
	 *  | 
				
			||||
	 * @param scale scaling factor | 
				
			||||
	 */ | 
				
			||||
	public abstract void scaleXY(double scale); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Set X scale for translations and coordinates | 
				
			||||
	 *  | 
				
			||||
	 * @param scale scaling factor | 
				
			||||
	 */ | 
				
			||||
	public abstract void scaleX(double scale); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Set Y scale for translations and coordinates | 
				
			||||
	 *  | 
				
			||||
	 * @param scale scaling factor | 
				
			||||
	 */ | 
				
			||||
	public abstract void scaleY(double scale); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Set Z scale for translations and coordinates | 
				
			||||
	 *  | 
				
			||||
	 * @param scale scaling factor | 
				
			||||
	 */ | 
				
			||||
	public abstract void scaleZ(double scale); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Rotate coordinate system around X axis | 
				
			||||
	 *  | 
				
			||||
	 * @param angle rotation (in degrees) | 
				
			||||
	 */ | 
				
			||||
	public abstract void rotateX(double angle); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Rotate coordinate system around Y axis | 
				
			||||
	 *  | 
				
			||||
	 * @param angle rotation (in degrees) | 
				
			||||
	 */ | 
				
			||||
	public abstract void rotateY(double angle); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Rotate coordinate system around Z axis | 
				
			||||
	 *  | 
				
			||||
	 * @param angle rotation (in degrees) | 
				
			||||
	 */ | 
				
			||||
	public abstract void rotateZ(double angle); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Rotate coordinate system around given axis | 
				
			||||
	 *  | 
				
			||||
	 * @param angle rotation angle | 
				
			||||
	 * @param axis rotation axis (unit vector) | 
				
			||||
	 */ | 
				
			||||
	public abstract void rotate(double angle, Vect axis); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Store render state on stack<br> | 
				
			||||
	 * This includes pushGeometry and pushColor. | 
				
			||||
	 */ | 
				
			||||
	public abstract void pushState(); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Restore state from stack (must be pushed first)<br> | 
				
			||||
	 * This includes popColor and popGeometry. | 
				
			||||
	 */ | 
				
			||||
	public abstract void popState(); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Store current rotation and translation on stack | 
				
			||||
	 */ | 
				
			||||
	public abstract void pushGeometry(); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Restore rotation and translation from stack | 
				
			||||
	 */ | 
				
			||||
	public abstract void popGeometry(); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Store color on stack (so it can later be restored) | 
				
			||||
	 */ | 
				
			||||
	public abstract void pushColor(); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Restore color from stack (must be pushed first) | 
				
			||||
	 */ | 
				
			||||
	public abstract void popColor(); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Render 2D quad with currently set color | 
				
			||||
	 *  | 
				
			||||
	 * @param rect drawn rect | 
				
			||||
	 */ | 
				
			||||
	public abstract void quad(Rect rect); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Render 2D quad with given color.<br> | 
				
			||||
	 * This may change current drawing color. | 
				
			||||
	 *  | 
				
			||||
	 * @param rect rectangle | 
				
			||||
	 * @param color draw color | 
				
			||||
	 */ | 
				
			||||
	public abstract void quad(Rect rect, Color color); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Render 2D quad with gradient.<br> | 
				
			||||
	 * This may change current drawing color. | 
				
			||||
	 *  | 
				
			||||
	 * @param rect rectangle | 
				
			||||
	 * @param grad gradient | 
				
			||||
	 */ | 
				
			||||
	public abstract void quad(Rect rect, Grad grad); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Render textured quad with current color | 
				
			||||
	 *  | 
				
			||||
	 * @param rect rectangle to draw | 
				
			||||
	 * @param txquad texture quad | 
				
			||||
	 */ | 
				
			||||
	public abstract void quad(Rect rect, TxQuad txquad); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Render textured quad with given color | 
				
			||||
	 *  | 
				
			||||
	 * @param rect rectangle to draw | 
				
			||||
	 * @param txquad texture instance | 
				
			||||
	 * @param color color tint | 
				
			||||
	 */ | 
				
			||||
	public abstract void quad(Rect rect, TxQuad txquad, Color color); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Setup projection for 2D graphics | 
				
			||||
	 *  | 
				
			||||
	 * @param screenSize current viewport size | 
				
			||||
	 */ | 
				
			||||
	public abstract void setupProjection(Vect screenSize); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Get backend-flavoured lazy texture | 
				
			||||
	 *  | 
				
			||||
	 * @param path path to texture | 
				
			||||
	 * @return the lazy texture | 
				
			||||
	 */ | 
				
			||||
	public abstract LazyTexture getLazyTexture(String path); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Set target fps (for syncing in endFrame() call).<br> | 
				
			||||
	 * With vsync enabled, the target fps may not be met. | 
				
			||||
	 *  | 
				
			||||
	 * @param fps requested fps | 
				
			||||
	 */ | 
				
			||||
	public abstract void setTargetFps(int fps); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Create a main window | 
				
			||||
	 */ | 
				
			||||
	public abstract void createDisplay(); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Set fullscreen | 
				
			||||
	 *  | 
				
			||||
	 * @param fs true for fullscreen | 
				
			||||
	 */ | 
				
			||||
	public abstract void setFullscreen(boolean fs); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Request fullscreen toggle (eg. at the end of render frame) | 
				
			||||
	 */ | 
				
			||||
	public abstract void switchFullscreen(); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Get fullscreen state | 
				
			||||
	 *  | 
				
			||||
	 * @return is fullscreen | 
				
			||||
	 */ | 
				
			||||
	public abstract boolean isFullscreen(); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Take screenshot (expensive processing should be done in separate thread | 
				
			||||
	 * when screenshot is saved). | 
				
			||||
	 *  | 
				
			||||
	 * @return screenshot object | 
				
			||||
	 */ | 
				
			||||
	public abstract Screenshot takeScreenshot(); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * FIXME This should be moved to inout module | 
				
			||||
	 *  | 
				
			||||
	 * @return true if close was requested recently (i.e. click on cross) | 
				
			||||
	 */ | 
				
			||||
	public abstract boolean isCloseRequested(); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Start a render frame - clear buffers, prepare rendering context etc. | 
				
			||||
	 */ | 
				
			||||
	public abstract void beginFrame(); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * End a render frame: flip buffers, sync to fps... | 
				
			||||
	 */ | 
				
			||||
	public abstract void endFrame(); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Set display dimensions | 
				
			||||
	 *  | 
				
			||||
	 * @param width display width (pixels) | 
				
			||||
	 * @param height display height (pixels) | 
				
			||||
	 */ | 
				
			||||
	public abstract void setSize(int width, int height); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Set titlebar text | 
				
			||||
	 *  | 
				
			||||
	 * @param title titlebar text | 
				
			||||
	 */ | 
				
			||||
	public abstract void setTitle(String title); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Enable or disable VSync | 
				
			||||
	 *  | 
				
			||||
	 * @param vsync true for vsync enabled | 
				
			||||
	 */ | 
				
			||||
	public abstract void setVSync(boolean vsync); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Set window resizable / fixed | 
				
			||||
	 *  | 
				
			||||
	 * @param resizable true for resizable | 
				
			||||
	 */ | 
				
			||||
	public abstract void setResizable(boolean resizable); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Get screen rect. Should always return the same Vect instance. | 
				
			||||
	 *  | 
				
			||||
	 * @return the rect | 
				
			||||
	 */ | 
				
			||||
	public abstract Rect getRect(); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Get current FPS (eg. measured by a {@link FpsMeter}) | 
				
			||||
	 *  | 
				
			||||
	 * @return current FPS | 
				
			||||
	 */ | 
				
			||||
	public abstract long getFps(); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Get screen center. Should always return the same Vect instance. | 
				
			||||
	 *  | 
				
			||||
	 * @return screen center. | 
				
			||||
	 */ | 
				
			||||
	public abstract Vect getCenter(); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * @return screen width | 
				
			||||
	 */ | 
				
			||||
	public abstract int getWidth(); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * @return screen height | 
				
			||||
	 */ | 
				
			||||
	public abstract int getHeight(); | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Get screen size. Should always return the same Vect instance. | 
				
			||||
	 *  | 
				
			||||
	 * @return size | 
				
			||||
	 */ | 
				
			||||
	public abstract Vect getSize(); | 
				
			||||
} | 
				
			||||
@ -1,81 +1,33 @@ | 
				
			||||
package mightypork.gamecore.render; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
import java.awt.image.BufferedImage; | 
				
			||||
import java.io.File; | 
				
			||||
import java.io.IOException; | 
				
			||||
import java.nio.ByteBuffer; | 
				
			||||
 | 
				
			||||
import javax.imageio.ImageIO; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Screenshot object, can be used to extract image or write to file.<br> | 
				
			||||
 * Screenshot, once taken, can be safely processed in separate thread. | 
				
			||||
 * <p> | 
				
			||||
 * Screenshot object, can be used to save image to file. | 
				
			||||
 * </p> | 
				
			||||
 * <p> | 
				
			||||
 * Screenshot typically takes a byte buffer and converts it to image before | 
				
			||||
 * saving to file. This image can be cached to speed up repeated saving. | 
				
			||||
 * </p> | 
				
			||||
 * <p> | 
				
			||||
 * Once created (passing byte buffer in constructor), the Screenshot should be | 
				
			||||
 * safe to process (call the save() method) in separate thread. | 
				
			||||
 * </p> | 
				
			||||
 *  | 
				
			||||
 * @author Ondřej Hruška (MightyPork) | 
				
			||||
 * @author MightyPork | 
				
			||||
 */ | 
				
			||||
public class Screenshot { | 
				
			||||
	 | 
				
			||||
	private final int width; | 
				
			||||
	private final int height; | 
				
			||||
	private final int bpp; | 
				
			||||
	private final ByteBuffer bytes; | 
				
			||||
	private BufferedImage image; | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * @param width image width | 
				
			||||
	 * @param height image height | 
				
			||||
	 * @param bpp bits per pixel (typically 4) | 
				
			||||
	 * @param buffer | 
				
			||||
	 */ | 
				
			||||
	public Screenshot(int width, int height, int bpp, ByteBuffer buffer) | 
				
			||||
	{ | 
				
			||||
		this.width = width; | 
				
			||||
		this.height = height; | 
				
			||||
		this.bpp = bpp; | 
				
			||||
		this.bytes = buffer; | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Extract to an image.<br> | 
				
			||||
	 * Subsequent calls will use a cached value. | 
				
			||||
	 *  | 
				
			||||
	 * @return image | 
				
			||||
	 */ | 
				
			||||
	public BufferedImage getImage() | 
				
			||||
	{ | 
				
			||||
		if (image != null) return image; | 
				
			||||
		 | 
				
			||||
		image = new BufferedImage(this.width, this.height, BufferedImage.TYPE_INT_RGB); | 
				
			||||
		 | 
				
			||||
		// convert to a buffered image
 | 
				
			||||
		for (int x = 0; x < this.width; x++) { | 
				
			||||
			for (int y = 0; y < this.height; y++) { | 
				
			||||
				final int i = (x + (this.width * y)) * this.bpp; | 
				
			||||
				final int r = this.bytes.get(i) & 0xFF; | 
				
			||||
				final int g = this.bytes.get(i + 1) & 0xFF; | 
				
			||||
				final int b = this.bytes.get(i + 2) & 0xFF; | 
				
			||||
				image.setRGB(x, this.height - (y + 1), (0xFF << 24) | (r << 16) | (g << 8) | b); | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
		 | 
				
			||||
		return image; | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
public interface Screenshot { | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Save to a file.<br> | 
				
			||||
	 * Cached value is used if any. | 
				
			||||
	 * Process byte buffer and write image to a file.<br> | 
				
			||||
	 * Image can be cached for future save. | 
				
			||||
	 *  | 
				
			||||
	 * @param file target file | 
				
			||||
	 * @throws IOException on error writing to file | 
				
			||||
	 */ | 
				
			||||
	public void save(File file) throws IOException | 
				
			||||
	{ | 
				
			||||
		file.getParentFile().mkdirs(); | 
				
			||||
		ImageIO.write(getImage(), "PNG", file); | 
				
			||||
	} | 
				
			||||
	void save(File file) throws IOException; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
					Loading…
					
					
				
		Reference in new issue