parent
ebac276ed2
commit
e940c53dd6
@ -1,144 +0,0 @@ |
||||
package mightypork.gamecore.loading; |
||||
|
||||
|
||||
import mightypork.gamecore.control.interf.Destroyable; |
||||
import mightypork.utils.logging.Log; |
||||
import mightypork.utils.logging.LoggedName; |
||||
|
||||
|
||||
/** |
||||
* Deferred resource abstraction.<br> |
||||
* Resources implementing {@link NullResource} will be treated as fake and not |
||||
* attempted to load. |
||||
* |
||||
* @author MightyPork |
||||
*/ |
||||
@LoggedName(name = "Resource") |
||||
public abstract class BaseDeferredResource implements DeferredResource, Destroyable { |
||||
|
||||
private final String resource; |
||||
private volatile boolean loadFailed = false; |
||||
private volatile boolean loadAttempted = false; |
||||
|
||||
|
||||
/** |
||||
* @param resource resource path / name; this string is later used in |
||||
* loadResource() |
||||
*/ |
||||
public BaseDeferredResource(String resource) { |
||||
this.resource = resource; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public synchronized final void load() |
||||
{ |
||||
if(loadFailed) return; |
||||
|
||||
if (loadAttempted) { |
||||
Log.w("<RES> Already loaded @ load():\n " + this); |
||||
(new IllegalStateException()).printStackTrace(); |
||||
return; |
||||
} |
||||
|
||||
loadAttempted = true; |
||||
|
||||
loadFailed = false; |
||||
|
||||
if (isNull()) return; |
||||
try { |
||||
if (resource == null) { |
||||
throw new NullPointerException("Resource string cannot be null for non-null resource."); |
||||
} |
||||
|
||||
Log.f3("<RES> Loading:\n " + this); |
||||
loadResource(resource); |
||||
Log.f3("<RES> Loaded:\n " + this); |
||||
} catch (final Exception e) { |
||||
loadFailed = true; |
||||
Log.e("<RES> Failed to load:\n " + this, e); |
||||
} |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public synchronized final boolean isLoaded() |
||||
{ |
||||
if (isNull()) return false; |
||||
|
||||
return loadAttempted && !loadFailed; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Check if the resource is loaded; if not, try to do so. |
||||
* |
||||
* @return true if it's loaded now. |
||||
*/ |
||||
public synchronized final boolean ensureLoaded() |
||||
{ |
||||
if (isNull()) return false; |
||||
|
||||
if (isLoaded()) { |
||||
return true; |
||||
} else { |
||||
if(loadFailed) return false; |
||||
|
||||
Log.f3("<RES> (!) First use, not loaded yet - loading directly\n " + this); |
||||
load(); |
||||
} |
||||
|
||||
return isLoaded(); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Load the resource. Called from load() - once only. |
||||
* |
||||
* @param resource the path / name of a resource |
||||
* @throws Exception when some problem prevented the resource from being |
||||
* loaded. |
||||
*/ |
||||
protected abstract void loadResource(String resource) throws Exception; |
||||
|
||||
|
||||
@Override |
||||
public abstract void destroy(); |
||||
|
||||
|
||||
@Override |
||||
public String toString() |
||||
{ |
||||
return Log.str(getClass()) + "(\"" + resource + "\")"; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public int hashCode() |
||||
{ |
||||
final int prime = 31; |
||||
int result = 1; |
||||
result = prime * result + ((resource == null) ? 0 : resource.hashCode()); |
||||
return result; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public boolean equals(Object obj) |
||||
{ |
||||
if (this == obj) return true; |
||||
if (obj == null) return false; |
||||
if (!(obj instanceof BaseDeferredResource)) return false; |
||||
final BaseDeferredResource other = (BaseDeferredResource) obj; |
||||
if (resource == null) { |
||||
if (other.resource != null) return false; |
||||
} else if (!resource.equals(other.resource)) return false; |
||||
return true; |
||||
} |
||||
|
||||
|
||||
private boolean isNull() |
||||
{ |
||||
return this instanceof NullResource; |
||||
} |
||||
} |
@ -0,0 +1,23 @@ |
||||
package mightypork.gamecore.loading; |
||||
|
||||
|
||||
/** |
||||
* Deferred resource |
||||
* |
||||
* @author MightyPork |
||||
*/ |
||||
public interface Deferred { |
||||
|
||||
/** |
||||
* Load the actual resource, if not loaded yet. |
||||
*/ |
||||
void load(); |
||||
|
||||
|
||||
/** |
||||
* Check if resource was successfully loaded. |
||||
* |
||||
* @return true if already loaded |
||||
*/ |
||||
boolean isLoaded(); |
||||
} |
@ -1,23 +1,140 @@ |
||||
package mightypork.gamecore.loading; |
||||
|
||||
|
||||
import mightypork.gamecore.control.interf.Destroyable; |
||||
import mightypork.utils.logging.Log; |
||||
import mightypork.utils.logging.LoggedName; |
||||
|
||||
|
||||
/** |
||||
* Deferred resource |
||||
* Deferred resource abstraction.<br> |
||||
* Resources implementing {@link NullResource} will be treated as fake and not |
||||
* attempted to load. |
||||
* |
||||
* @author MightyPork |
||||
*/ |
||||
public interface DeferredResource { |
||||
@LoggedName(name = "Resource") |
||||
public abstract class DeferredResource implements Deferred, Destroyable { |
||||
|
||||
private final String resource; |
||||
private volatile boolean loadFailed = false; |
||||
private volatile boolean loadAttempted = false; |
||||
|
||||
|
||||
/** |
||||
* Load the actual resource, if not loaded yet. |
||||
* @param resource resource path / name; this string is later used in |
||||
* loadResource() |
||||
*/ |
||||
void load(); |
||||
public DeferredResource(String resource) { |
||||
this.resource = resource; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public synchronized final void load() |
||||
{ |
||||
if (loadFailed) return; |
||||
|
||||
if (loadAttempted) return; |
||||
|
||||
loadAttempted = true; |
||||
|
||||
loadFailed = false; |
||||
|
||||
if (isNull()) return; |
||||
try { |
||||
if (resource == null) { |
||||
throw new NullPointerException("Resource string cannot be null for non-null resource."); |
||||
} |
||||
|
||||
Log.f3("<RES> Loading: " + this); |
||||
loadResource(resource); |
||||
Log.f3("<RES> Loaded: " + this); |
||||
} catch (final Exception e) { |
||||
loadFailed = true; |
||||
Log.e("<RES> Failed to load: " + this, e); |
||||
} |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public synchronized final boolean isLoaded() |
||||
{ |
||||
if (isNull()) return false; |
||||
|
||||
return loadAttempted && !loadFailed; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Check if resource was successfully loaded. |
||||
* Check if the resource is loaded; if not, try to do so. |
||||
* |
||||
* @return true if already loaded |
||||
* @return true if it's loaded now. |
||||
*/ |
||||
boolean isLoaded(); |
||||
public synchronized final boolean ensureLoaded() |
||||
{ |
||||
if (isNull()) return false; |
||||
|
||||
if (isLoaded()) { |
||||
return true; |
||||
} else { |
||||
if (loadFailed) return false; |
||||
|
||||
Log.f3("<RES> (!) Loading on access: " + this); |
||||
load(); |
||||
} |
||||
|
||||
return isLoaded(); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Load the resource. Called from load() - once only. |
||||
* |
||||
* @param resource the path / name of a resource |
||||
* @throws Exception when some problem prevented the resource from being |
||||
* loaded. |
||||
*/ |
||||
protected abstract void loadResource(String resource) throws Exception; |
||||
|
||||
|
||||
@Override |
||||
public abstract void destroy(); |
||||
|
||||
|
||||
@Override |
||||
public String toString() |
||||
{ |
||||
return Log.str(getClass()) + "(\"" + resource + "\")"; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public int hashCode() |
||||
{ |
||||
final int prime = 31; |
||||
int result = 1; |
||||
result = prime * result + ((resource == null) ? 0 : resource.hashCode()); |
||||
return result; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public boolean equals(Object obj) |
||||
{ |
||||
if (this == obj) return true; |
||||
if (obj == null) return false; |
||||
if (!(obj instanceof DeferredResource)) return false; |
||||
final DeferredResource other = (DeferredResource) obj; |
||||
if (resource == null) { |
||||
if (other.resource != null) return false; |
||||
} else if (!resource.equals(other.resource)) return false; |
||||
return true; |
||||
} |
||||
|
||||
|
||||
private boolean isNull() |
||||
{ |
||||
return this instanceof NullResource; |
||||
} |
||||
} |
||||
|
@ -1,134 +0,0 @@ |
||||
package mightypork.gamecore.render.fonts; |
||||
|
||||
|
||||
import static org.lwjgl.opengl.GL11.*; |
||||
|
||||
import java.awt.Font; |
||||
|
||||
import mightypork.gamecore.render.Render; |
||||
import mightypork.gamecore.render.textures.FilterMode; |
||||
import mightypork.utils.math.color.RGB; |
||||
import mightypork.utils.math.coord.Coord; |
||||
|
||||
import org.newdawn.slick.Color; |
||||
import org.newdawn.slick.TrueTypeFont; |
||||
|
||||
|
||||
/** |
||||
* Wrapper for slick font |
||||
* |
||||
* @author MightyPork |
||||
*/ |
||||
public class SlickFont implements GLFont { |
||||
|
||||
private final TrueTypeFont ttf; |
||||
private FilterMode filter; |
||||
private final int fsize; |
||||
|
||||
|
||||
/** |
||||
* A font with ASCII and extra chars |
||||
* |
||||
* @param font font to load |
||||
* @param filtering filtering mode |
||||
* @param extraChars extra chars to load |
||||
*/ |
||||
public SlickFont(Font font, FilterMode filtering, String extraChars) { |
||||
|
||||
this.filter = filtering; |
||||
this.fsize = font.getSize(); |
||||
ttf = new TrueTypeFont(font, true, stripASCII(extraChars)); |
||||
} |
||||
|
||||
|
||||
|
||||
@Override |
||||
public void setFiltering(FilterMode filter) |
||||
{ |
||||
this.filter = filter; |
||||
} |
||||
|
||||
|
||||
private static char[] stripASCII(String chars) |
||||
{ |
||||
if (chars == null) return null; |
||||
|
||||
final StringBuilder sb = new StringBuilder(); |
||||
for (final char c : chars.toCharArray()) { |
||||
if (c <= 255) continue; // already included in default set
|
||||
sb.append(c); |
||||
} |
||||
|
||||
return sb.toString().toCharArray(); |
||||
} |
||||
|
||||
|
||||
private void prepareForRender() |
||||
{ |
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); |
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); |
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter.num); |
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter.num); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Draw in color |
||||
* |
||||
* @param str string to draw |
||||
* @param color text color |
||||
*/ |
||||
@Override |
||||
public void draw(String str, RGB color) |
||||
{ |
||||
Render.pushState(); |
||||
|
||||
prepareForRender(); |
||||
ttf.drawString(0, 0, str, rgbToSlickColor(color)); |
||||
|
||||
Render.popState(); |
||||
} |
||||
|
||||
|
||||
private static Color rgbToSlickColor(RGB rgb) |
||||
{ |
||||
return new Color((float) rgb.r, (float) rgb.g, (float) rgb.b, (float) rgb.a); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public Coord getNeededSpace(String text) |
||||
{ |
||||
return new Coord(getWidth(text), getGlyphHeight()); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public int getGlyphHeight() |
||||
{ |
||||
return ttf.getHeight(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public int getWidth(String text) |
||||
{ |
||||
return ttf.getWidth(text); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public int getSize() |
||||
{ |
||||
return fsize; |
||||
} |
||||
|
||||
|
||||
|
||||
@Override |
||||
public FilterMode getFiltering() |
||||
{ |
||||
return filter; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,430 @@ |
||||
package mightypork.gamecore.render.fonts.impl; |
||||
|
||||
|
||||
import static org.lwjgl.opengl.GL11.*; |
||||
|
||||
import java.awt.Color; |
||||
import java.awt.FontMetrics; |
||||
import java.awt.Graphics2D; |
||||
import java.awt.RenderingHints; |
||||
import java.awt.image.BufferedImage; |
||||
import java.awt.image.DataBuffer; |
||||
import java.awt.image.DataBufferByte; |
||||
import java.awt.image.DataBufferInt; |
||||
import java.nio.ByteBuffer; |
||||
import java.nio.ByteOrder; |
||||
import java.nio.IntBuffer; |
||||
import java.util.ArrayList; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
import mightypork.gamecore.render.fonts.GLFont; |
||||
import mightypork.gamecore.render.textures.FilterMode; |
||||
import mightypork.utils.logging.Log; |
||||
import mightypork.utils.math.color.RGB; |
||||
import mightypork.utils.math.coord.Coord; |
||||
|
||||
import org.lwjgl.BufferUtils; |
||||
import org.lwjgl.util.glu.GLU; |
||||
import org.newdawn.slick.opengl.GLUtils; |
||||
|
||||
|
||||
/** |
||||
* A TrueType font renderer with backing texture. |
||||
* |
||||
* @author James Chambers (Jimmy) |
||||
* @author Jeremy Adams (elias4444) |
||||
* @author Kevin Glass (kevglass) |
||||
* @author Peter Korzuszek (genail) |
||||
* @author David Aaron Muhar (bobjob) |
||||
* @author MightyPork |
||||
*/ |
||||
public class CachedFont implements GLFont { |
||||
|
||||
private class CharTile { |
||||
|
||||
public int width; |
||||
public int height; |
||||
public int texPosX; |
||||
public int texPosY; |
||||
} |
||||
|
||||
/* char bank */ |
||||
private final Map<Character, CharTile> chars = new HashMap<>(255); |
||||
|
||||
/* use antialiasing for rendering */ |
||||
private final boolean antiAlias; |
||||
|
||||
/* loaded font size (requested) */ |
||||
private final int fontSize; |
||||
|
||||
/* actual height of drawn glyphs */ |
||||
private int fontHeight; |
||||
|
||||
/* texture id */ |
||||
private int textureID; |
||||
|
||||
/* texture width */ |
||||
private int textureWidth; |
||||
|
||||
/* texture height */ |
||||
private int textureHeight; |
||||
|
||||
/* AWT font source */ |
||||
private final java.awt.Font font; |
||||
|
||||
private final FilterMode filter; |
||||
|
||||
|
||||
/** |
||||
* Make a font |
||||
* |
||||
* @param font original awt font to load |
||||
* @param antialias use antialiasing when rendering to cache texture |
||||
* @param filter used Gl filter |
||||
* @param chars chars to load |
||||
*/ |
||||
public CachedFont(java.awt.Font font, boolean antialias, FilterMode filter, String chars) { |
||||
this(font, antialias, filter, chars.toCharArray()); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Make a font |
||||
* |
||||
* @param font original awt font to load |
||||
* @param antialias use antialiasing when rendering to cache texture |
||||
* @param filter used Gl filter |
||||
* @param chars chars to load |
||||
*/ |
||||
public CachedFont(java.awt.Font font, boolean antialias, FilterMode filter, char[] chars) { |
||||
GLUtils.checkGLContext(); |
||||
|
||||
this.font = font; |
||||
this.filter = filter; |
||||
this.fontSize = font.getSize(); |
||||
this.antiAlias = antialias; |
||||
|
||||
createSet(chars); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Create a BufferedImage of the given character |
||||
* |
||||
* @param ch the character |
||||
* @return BufferedImage containing the drawn character |
||||
*/ |
||||
private BufferedImage getFontImage(char ch) |
||||
{ |
||||
FontMetrics metrics; |
||||
BufferedImage img; |
||||
Graphics2D g; |
||||
|
||||
// Create a temporary image to extract the character's size
|
||||
img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB); |
||||
|
||||
g = (Graphics2D) img.getGraphics(); |
||||
if (antiAlias == true) g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); |
||||
g.setFont(font); |
||||
|
||||
metrics = g.getFontMetrics(); |
||||
|
||||
final int charwidth = Math.max(1, metrics.charWidth(ch)); |
||||
final int charheight = Math.max(fontSize, metrics.getHeight()); |
||||
|
||||
// Create another image holding the character we are creating
|
||||
final BufferedImage fontImage = new BufferedImage(charwidth, charheight, BufferedImage.TYPE_INT_ARGB); |
||||
|
||||
g = (Graphics2D) fontImage.getGraphics(); |
||||
if (antiAlias == true) g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); |
||||
g.setFont(font); |
||||
g.setColor(Color.WHITE); |
||||
g.drawString(String.valueOf(ch), 0, metrics.getAscent()); |
||||
|
||||
return fontImage; |
||||
} |
||||
|
||||
|
||||
private void createSet(char[] charsToLoad) |
||||
{ |
||||
try { |
||||
class LoadedGlyph { |
||||
|
||||
public char c; |
||||
public BufferedImage image; |
||||
public int width; |
||||
public int height; |
||||
|
||||
|
||||
public LoadedGlyph(char c, BufferedImage image) { |
||||
this.image = image; |
||||
this.c = c; |
||||
this.width = image.getWidth(); |
||||
this.height = image.getHeight(); |
||||
} |
||||
} |
||||
|
||||
final List<LoadedGlyph> glyphs = new ArrayList<>(); |
||||
final List<Character> loaded = new ArrayList<>(); |
||||
for (final char ch : charsToLoad) { |
||||
if (!loaded.contains(ch)) { |
||||
glyphs.add(new LoadedGlyph(ch, getFontImage(ch))); |
||||
loaded.add(ch); |
||||
} |
||||
} |
||||
|
||||
int lineHeight = 0; |
||||
|
||||
int beginX = 0, beginY = 0; |
||||
int canvasW = 128, canvasH = 128; |
||||
|
||||
boolean needsLarger = false; |
||||
|
||||
// find smallest 2^x size for texture
|
||||
while (true) { |
||||
needsLarger = false; |
||||
|
||||
for (final LoadedGlyph glyph : glyphs) { |
||||
if (beginX + glyph.width > canvasW) { |
||||
beginY += lineHeight; |
||||
lineHeight = 0; |
||||
beginX = 0; |
||||
} |
||||
|
||||
if (lineHeight < glyph.height) { |
||||
lineHeight = glyph.height; |
||||
} |
||||
|
||||
if (beginY + lineHeight > canvasH) { |
||||
needsLarger = true; |
||||
break; |
||||
} |
||||
|
||||
// draw.
|
||||
beginX += glyph.width; |
||||
} |
||||
|
||||
if (needsLarger) { |
||||
canvasW *= 2; |
||||
canvasH *= 2; |
||||
beginX = 0; |
||||
beginY = 0; |
||||
lineHeight = 0; |
||||
} else { |
||||
Log.f3(String.format("Generating font texture: %d×%d", canvasW, canvasH)); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
textureWidth = canvasW; |
||||
textureHeight = canvasH; |
||||
|
||||
BufferedImage imag = new BufferedImage(textureWidth, textureHeight, BufferedImage.TYPE_INT_ARGB); |
||||
final Graphics2D g = (Graphics2D) imag.getGraphics(); |
||||
|
||||
g.setColor(new Color(0, 0, 0, 1)); |
||||
g.fillRect(0, 0, textureWidth, textureHeight); |
||||
|
||||
int rowHeight = 0, posX = 0, posY = 0; |
||||
|
||||
for (final LoadedGlyph glyph : glyphs) { |
||||
final CharTile cht = new CharTile(); |
||||
|
||||
cht.width = glyph.width; |
||||
cht.height = glyph.height; |
||||
|
||||
if (posX + cht.width >= textureWidth) { |
||||
posX = 0; |
||||
posY += rowHeight; |
||||
rowHeight = 0; |
||||
} |
||||
|
||||
cht.texPosX = posX; |
||||
cht.texPosY = posY; |
||||
|
||||
if (cht.height > fontHeight) { |
||||
fontHeight = cht.height; |
||||
} |
||||
|
||||
if (cht.height > rowHeight) { |
||||
rowHeight = cht.height; |
||||
} |
||||
|
||||
// Draw it here
|
||||
g.drawImage(glyph.image, posX, posY, null); |
||||
|
||||
posX += cht.width; |
||||
|
||||
chars.put(glyph.c, cht); |
||||
} |
||||
|
||||
textureID = loadImage(imag); |
||||
|
||||
imag = null; |
||||
|
||||
} catch (final Exception e) { |
||||
Log.e("Failed to load font.", e); |
||||
} |
||||
} |
||||
|
||||
|
||||
private int loadImage(BufferedImage bufferedImage) |
||||
{ |
||||
try { |
||||
final short width = (short) bufferedImage.getWidth(); |
||||
final short height = (short) bufferedImage.getHeight(); |
||||
final int bpp = (byte) bufferedImage.getColorModel().getPixelSize(); |
||||
|
||||
ByteBuffer byteBuffer; |
||||
final DataBuffer db = bufferedImage.getData().getDataBuffer(); |
||||
if (db instanceof DataBufferInt) { |
||||
final int intI[] = ((DataBufferInt) (bufferedImage.getData().getDataBuffer())).getData(); |
||||
final byte newI[] = new byte[intI.length * 4]; |
||||
for (int i = 0; i < intI.length; i++) { |
||||
final byte b[] = intToByteArray(intI[i]); |
||||
final int newIndex = i * 4; |
||||
|
||||
newI[newIndex] = b[1]; |
||||
newI[newIndex + 1] = b[2]; |
||||
newI[newIndex + 2] = b[3]; |
||||
newI[newIndex + 3] = b[0]; |
||||
} |
||||
|
||||
byteBuffer = ByteBuffer.allocateDirect(width * height * (bpp / 8)).order(ByteOrder.nativeOrder()).put(newI); |
||||
} else { |
||||
byteBuffer = ByteBuffer.allocateDirect(width * height * (bpp / 8)).order(ByteOrder.nativeOrder()).put(((DataBufferByte) (bufferedImage.getData().getDataBuffer())).getData()); |
||||
} |
||||
|
||||
byteBuffer.flip(); |
||||
|
||||
final int internalFormat = GL_RGBA8, format = GL_RGBA; |
||||
final IntBuffer textureId = BufferUtils.createIntBuffer(1); |
||||
|
||||
glGenTextures(textureId); |
||||
glBindTexture(GL_TEXTURE_2D, textureId.get(0)); |
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); |
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); |
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter.num); |
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
||||
|
||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); |
||||
|
||||
GLU.gluBuild2DMipmaps(GL_TEXTURE_2D, internalFormat, width, height, format, GL_UNSIGNED_BYTE, byteBuffer); |
||||
return textureId.get(0); |
||||
|
||||
} catch (final Exception e) { |
||||
Log.e("Failed to load font.", e); |
||||
} |
||||
|
||||
return -1; |
||||
} |
||||
|
||||
|
||||
private static byte[] intToByteArray(int value) |
||||
{ |
||||
return new byte[] { (byte) (value >>> 24), (byte) (value >>> 16), (byte) (value >>> 8), (byte) value }; |
||||
} |
||||
|
||||
|
||||
private void drawQuad(float xmin, float ymin, float xmax, float ymax, float txmin, float tymin, float txmax, float tymax) |
||||
{ |
||||
final float draw_h = xmax - xmin; |
||||
final float draw_w = ymax - ymin; |
||||
final float txmin01 = txmin / textureWidth; |
||||
final float tymin01 = tymin / textureHeight; |
||||
final float twidth01 = ((txmax - txmin) / textureWidth); |
||||
final float theight01 = ((tymax - tymin) / textureHeight); |
||||
|
||||
glTexCoord2f(txmin01, tymin01); |
||||
glVertex2f(xmin, ymin); |
||||
|
||||
glTexCoord2f(txmin01, tymin01 + theight01); |
||||
glVertex2f(xmin, ymin + draw_w); |
||||
|
||||
glTexCoord2f(txmin01 + twidth01, tymin01 + theight01); |
||||
glVertex2f(xmin + draw_h, ymin + draw_w); |
||||
|
||||
glTexCoord2f(txmin01 + twidth01, tymin01); |
||||
glVertex2f(xmin + draw_h, ymin); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Get size needed to draw given string |
||||
* |
||||
* @param text drawn text |
||||
* @return needed width |
||||
*/ |
||||
@Override |
||||
public int getWidth(String text) |
||||
{ |
||||
int totalwidth = 0; |
||||
CharTile ch = null; |
||||
for (int i = 0; i < text.length(); i++) { |
||||
|
||||
ch = chars.get(text.charAt(i)); |
||||
|
||||
if (ch != null) totalwidth += ch.width; |
||||
} |
||||
return totalwidth; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public int getHeight() |
||||
{ |
||||
return fontHeight; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public int getSize() |
||||
{ |
||||
return fontSize; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void draw(String text, RGB color) |
||||
{ |
||||
GLUtils.checkGLContext(); |
||||
|
||||
glPushAttrib(GL_ENABLE_BIT); |
||||
glEnable(GL_TEXTURE_2D); |
||||
glBindTexture(GL_TEXTURE_2D, textureID); |
||||
glColor4d(color.r, color.g, color.b, color.a); |
||||
glBegin(GL_QUADS); |
||||
|
||||
CharTile chtx = null; |
||||
char charCurrent; |
||||
|
||||
glBegin(GL_QUADS); |
||||
|
||||
int totalwidth = 0; |
||||
for (int i = 0; i < text.length(); i++) { |
||||
charCurrent = text.charAt(i); |
||||
|
||||
chtx = chars.get(charCurrent); |
||||
|
||||
if (chtx != null) { |
||||
drawQuad((totalwidth), 0, (totalwidth + chtx.width), (chtx.height), chtx.texPosX, chtx.texPosY, chtx.texPosX + chtx.width, chtx.texPosY + chtx.height); |
||||
totalwidth += chtx.width; |
||||
} |
||||
} |
||||
|
||||
glEnd(); |
||||
glPopAttrib(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public Coord getNeededSpace(String text) |
||||
{ |
||||
return new Coord(getWidth(text), getHeight()); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,42 @@ |
||||
package mightypork.utils.math.coord; |
||||
|
||||
|
||||
import mightypork.gamecore.gui.constraints.NumberConstraint; |
||||
|
||||
|
||||
public class ConstraintCoordView extends CoordView { |
||||
|
||||
private final NumberConstraint xc; |
||||
private final NumberConstraint yc; |
||||
private final NumberConstraint zc; |
||||
|
||||
|
||||
public ConstraintCoordView(NumberConstraint x, NumberConstraint y, NumberConstraint z) { |
||||
super(null); |
||||
this.xc = x; |
||||
this.yc = y; |
||||
this.zc = z; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public double x() |
||||
{ |
||||
return xc == null ? 0 : xc.getValue(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public double y() |
||||
{ |
||||
return yc == null ? 0 : yc.getValue(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public double z() |
||||
{ |
||||
return zc == null ? 0 : zc.getValue(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,31 @@ |
||||
package mightypork.utils.math.coord; |
||||
|
||||
|
||||
import mightypork.gamecore.gui.constraints.NumberConstraint; |
||||
|
||||
|
||||
/** |
||||
* Coord values provider |
||||
* |
||||
* @author MightyPork |
||||
*/ |
||||
public interface CoordValue { |
||||
|
||||
double x(); |
||||
|
||||
|
||||
double y(); |
||||
|
||||
|
||||
double z(); |
||||
|
||||
|
||||
NumberConstraint xc(); |
||||
|
||||
|
||||
NumberConstraint zc(); |
||||
|
||||
|
||||
NumberConstraint yc(); |
||||
|
||||
} |
@ -0,0 +1,62 @@ |
||||
package mightypork.utils.math.coord; |
||||
|
||||
|
||||
public class CoordView extends Coord { |
||||
|
||||
private CoordValue observed = null; |
||||
|
||||
|
||||
public CoordView(CoordValue coord) { |
||||
observed = coord; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public boolean isView() |
||||
{ |
||||
return true; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public boolean isWritable() |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public Coord view() |
||||
{ |
||||
return this; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public Coord freeze() |
||||
{ |
||||
return this; // no effect
|
||||
} |
||||
|
||||
|
||||
@Override |
||||
public double x() |
||||
{ |
||||
return observed.x(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public double y() |
||||
{ |
||||
return observed.y(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public double z() |
||||
{ |
||||
return observed.z(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,37 @@ |
||||
package mightypork.utils.math.coord; |
||||
|
||||
|
||||
/** |
||||
* Read only rect |
||||
* |
||||
* @author MightyPork |
||||
*/ |
||||
public class RectView extends Rect { |
||||
|
||||
public RectView(Rect observed) { |
||||
super(observed.min.view(), observed.max.view()); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public boolean isWritable() |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public boolean isView() |
||||
{ |
||||
return true; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public Rect freeze() |
||||
{ |
||||
// do nothing
|
||||
return this; |
||||
} |
||||
|
||||
} |
Loading…
Reference in new issue