This commit is contained in:
parent
4671a295f5
commit
9407c13217
BIN
assets/Fonts/Tuffy_Bold.ttf
Normal file
BIN
assets/Fonts/Tuffy_Bold.ttf
Normal file
Binary file not shown.
@ -1,3 +1,3 @@
|
||||
#maven.buildNumber.plugin properties file
|
||||
#Mon Feb 26 10:41:04 EST 2024
|
||||
buildNumber=22
|
||||
#Wed Feb 28 20:29:21 EST 2024
|
||||
buildNumber=26
|
||||
|
||||
99
docs/src/fonts/Fonts.md
Normal file
99
docs/src/fonts/Fonts.md
Normal file
@ -0,0 +1,99 @@
|
||||
# Fonts
|
||||
|
||||
|
||||
|
||||
|
||||
## High Level Overview
|
||||
The font loading mechanism loads all fonts at engine startup. It leverages java.awt.Font to read font data from ttf files on disk, render them to a bitmap, and then display appropriately.
|
||||
Globals has a font manager that can be leveraged to get fonts based on identification strings.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Major Usage Notes
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Main Classes
|
||||
|
||||
[Font.java](@ref #electrosphere.renderer.ui.font.Font) - Holds all the data about a font: the glyphs and metadata about them, as well as the material containing the actual bitmap
|
||||
|
||||
[FontManager.java](@ref #electrosphere.renderer.ui.font.FontManager) - Keeps track of all fonts loaded into the engine.
|
||||
|
||||
[FontUtils.java](@ref #electrosphere.renderer.ui.font.FontUtils) - Utilities to load fonts from disk
|
||||
|
||||
[BitmapCharacter.java](@ref #electrosphere.renderer.ui.font.bitmapchar.BitmapCharacter) - The main rendering component for text. Renders a single character of text based on a given font, font size, and character.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Code Organization and Best Practices
|
||||
|
||||
#### Startup
|
||||
|
||||
|
||||
#### Usage
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Terminology
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Known Bugs To Fix
|
||||
|
||||
|
||||
|
||||
|
||||
## Future Goals
|
||||
|
||||
- Scan assets/fonts and load all fonts automatically
|
||||
- Ability to specify font for a given label (currently it's always hard-set to "default")
|
||||
@ -57,8 +57,7 @@ import electrosphere.renderer.shader.ShaderOptionMap;
|
||||
import electrosphere.renderer.texture.TextureMap;
|
||||
import electrosphere.renderer.ui.ElementManager;
|
||||
import electrosphere.renderer.ui.elements.ImagePanel;
|
||||
import electrosphere.renderer.ui.font.FontUtils;
|
||||
import electrosphere.renderer.ui.font.RawFontMap;
|
||||
import electrosphere.renderer.ui.font.FontManager;
|
||||
import electrosphere.script.ScriptEngine;
|
||||
import electrosphere.server.ai.AIManager;
|
||||
import electrosphere.server.content.ServerContentManager;
|
||||
@ -231,6 +230,9 @@ public class Globals {
|
||||
public static String particleBillboardModel;
|
||||
|
||||
public static ShaderOptionMap shaderOptionMap;
|
||||
|
||||
//manages all loaded fonts
|
||||
public static FontManager fontManager;
|
||||
|
||||
|
||||
|
||||
@ -435,9 +437,10 @@ public class Globals {
|
||||
materialDefault.set_diffuse("Textures/default_diffuse.png");
|
||||
materialDefault.set_specular("Textures/default_specular.png");
|
||||
//create default lights
|
||||
//create font manager
|
||||
fontManager = new FontManager();
|
||||
fontManager.loadFonts();
|
||||
assetManager.registerModelToSpecificString(RenderUtils.createBitmapCharacter(), AssetDataStrings.BITMAP_CHARACTER_MODEL);
|
||||
RawFontMap fontMap = FileUtils.loadObjectFromAssetPath("Textures/Fonts/myFont2Map.json", RawFontMap.class);
|
||||
FontUtils.setFontDataMap(fontMap);
|
||||
//particle billboard model
|
||||
particleBillboardModel = assetManager.registerModel(RenderUtils.createParticleModel());
|
||||
//black texture for backgrouns
|
||||
|
||||
@ -515,7 +515,21 @@ public class Model {
|
||||
this.textureMap = textureMask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the shader program to use drawing the modal
|
||||
* @param program The shader program
|
||||
*/
|
||||
public void setProgram(ShaderProgram program){
|
||||
this.program = program;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to attempt overwriting the model's meshes with a new material
|
||||
* @param material The material
|
||||
*/
|
||||
public void tryOverwriteMaterial(Material material){
|
||||
for(Mesh mesh : meshes){
|
||||
mesh.setMaterial(material);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -717,7 +717,10 @@ public class RenderUtils {
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates a model to use to show bitmap characters
|
||||
* @return The model
|
||||
*/
|
||||
public static Model createBitmapCharacter(){
|
||||
|
||||
Model rVal = new Model();
|
||||
@ -798,14 +801,6 @@ public class RenderUtils {
|
||||
m.parent = rVal;
|
||||
m.nodeID = AssetDataStrings.ASSET_STRING_BITMAP_FONT_MESH_NAME;
|
||||
|
||||
Material uiMat = new Material();
|
||||
Globals.assetManager.addTexturePathtoQueue("/Textures/Fonts/myfont2.png");
|
||||
uiMat.set_diffuse("/Textures/Fonts/myfont2.png");
|
||||
uiMat.set_specular("/Textures/Fonts/myfont2.png");
|
||||
m.setMaterial(uiMat);
|
||||
rVal.materials = new ArrayList<Material>();
|
||||
rVal.materials.add(uiMat);
|
||||
|
||||
rVal.meshes.add(m);
|
||||
|
||||
return rVal;
|
||||
|
||||
@ -33,7 +33,7 @@ public class Texture {
|
||||
String path = "";
|
||||
|
||||
|
||||
public Texture(){
|
||||
private Texture(){
|
||||
|
||||
}
|
||||
|
||||
@ -41,6 +41,73 @@ public class Texture {
|
||||
this.texturePointer = pointer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an in engine texture object from a java bufferedimage object
|
||||
* @param bufferedImage The java bufferedimage object
|
||||
*/
|
||||
public Texture(BufferedImage bufferedImage){
|
||||
texturePointer = glGenTextures();
|
||||
//bind the new texture
|
||||
glBindTexture(GL_TEXTURE_2D, texturePointer);
|
||||
//how are we gonna wrap the texture??
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
|
||||
//set the border color to black
|
||||
float borderColor[] = { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
|
||||
//set magnification and minification operation sampling strategies
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
//load the image here
|
||||
ByteBuffer data;
|
||||
width = 1;
|
||||
height = 1;
|
||||
BufferedImage image_data = bufferedImage;
|
||||
if (
|
||||
image_data.getType() == BufferedImage.TYPE_3BYTE_BGR ||
|
||||
image_data.getType() == BufferedImage.TYPE_INT_RGB
|
||||
){
|
||||
hasTransparency = false;
|
||||
} else if(
|
||||
image_data.getType() == BufferedImage.TYPE_4BYTE_ABGR ||
|
||||
image_data.getType() == BufferedImage.TYPE_INT_ARGB
|
||||
){
|
||||
hasTransparency = true;
|
||||
}
|
||||
width = image_data.getWidth();
|
||||
height = image_data.getHeight();
|
||||
if(hasTransparency){
|
||||
data = BufferUtils.createByteBuffer(width * height * 4);
|
||||
} else {
|
||||
data = BufferUtils.createByteBuffer(width * height * 3);
|
||||
}
|
||||
for(int y = height - 1; y > -1; y--){
|
||||
for(int x = 0; x < width; x++){
|
||||
Color temp = new Color(image_data.getRGB(x, y), true);
|
||||
|
||||
data.put((byte)temp.getRed());
|
||||
data.put((byte)temp.getGreen());
|
||||
data.put((byte)temp.getBlue());
|
||||
if(hasTransparency){
|
||||
data.put((byte)temp.getAlpha());
|
||||
}
|
||||
}
|
||||
}
|
||||
data.flip();
|
||||
//call if width != height so opengl figures out how to unpack it properly
|
||||
if(width != height){
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
}
|
||||
//buffer the texture information
|
||||
if(hasTransparency){
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||
} else {
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
|
||||
}
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
public Texture(String path){
|
||||
this.path = path;
|
||||
if(!Globals.HEADLESS){
|
||||
|
||||
@ -10,6 +10,7 @@ import electrosphere.renderer.debug.DebugRendering;
|
||||
import electrosphere.renderer.ui.DrawableElement;
|
||||
import electrosphere.renderer.ui.Element;
|
||||
import electrosphere.renderer.ui.events.Event;
|
||||
import electrosphere.renderer.ui.font.Font;
|
||||
import electrosphere.renderer.ui.font.FontUtils;
|
||||
import electrosphere.renderer.ui.font.bitmapchar.BitmapCharacter;
|
||||
|
||||
@ -39,12 +40,15 @@ public class Label implements DrawableElement {
|
||||
List<BitmapCharacter> childrenElements = new LinkedList<BitmapCharacter>();
|
||||
|
||||
static final Vector3f windowDrawDebugColor = new Vector3f(1.0f,1.0f,1.0f);
|
||||
|
||||
Font font;
|
||||
|
||||
public Label(int x, int y, float fontSize){
|
||||
this.positionX = x;
|
||||
this.positionY = y;
|
||||
this.width = 0;
|
||||
this.height = (int)(FontUtils.getFontHeight() * fontSize);
|
||||
this.font = Globals.fontManager.getFont("default");
|
||||
this.height = (int)(font.getFontHeight() * fontSize);
|
||||
this.fontSize = fontSize;
|
||||
}
|
||||
|
||||
@ -53,8 +57,8 @@ public class Label implements DrawableElement {
|
||||
int rollingOffset = 0;
|
||||
for(int i = 0; i < text.length(); i++){
|
||||
char toDraw = text.charAt(i);
|
||||
Vector3f bitMapDimension = FontUtils.getDimensionOfCharacterDiscrete(toDraw);
|
||||
BitmapCharacter newLetter = new BitmapCharacter((int)(rollingOffset * fontSize) + positionX, positionY, (int)(bitMapDimension.x * fontSize), this.height, toDraw);
|
||||
Vector3f bitMapDimension = this.font.getDimensionOfCharacterDiscrete(toDraw);
|
||||
BitmapCharacter newLetter = new BitmapCharacter(this.font,(int)(rollingOffset * fontSize) + positionX, positionY, (int)(bitMapDimension.x * fontSize), this.height, toDraw);
|
||||
rollingOffset += (int)bitMapDimension.x;
|
||||
childrenElements.add(newLetter);
|
||||
}
|
||||
@ -64,7 +68,7 @@ public class Label implements DrawableElement {
|
||||
this.text = text;
|
||||
textPixelWidth = 0;
|
||||
for(int i = 0; i < text.length(); i++){
|
||||
Vector3f bitMapDimension = FontUtils.getDimensionOfCharacterDiscrete(text.charAt(i));
|
||||
Vector3f bitMapDimension = this.font.getDimensionOfCharacterDiscrete(text.charAt(i));
|
||||
textPixelWidth = textPixelWidth + (int)bitMapDimension.x;
|
||||
}
|
||||
generateLetters();
|
||||
|
||||
@ -5,6 +5,7 @@ import java.util.List;
|
||||
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.renderer.ui.DrawableElement;
|
||||
import electrosphere.renderer.ui.Element;
|
||||
import electrosphere.renderer.ui.FocusableElement;
|
||||
@ -15,6 +16,7 @@ import electrosphere.renderer.ui.events.FocusEvent;
|
||||
import electrosphere.renderer.ui.events.MenuEvent;
|
||||
import electrosphere.renderer.ui.events.ValueChangeEvent;
|
||||
import electrosphere.renderer.ui.events.MenuEvent.MenuEventType;
|
||||
import electrosphere.renderer.ui.font.Font;
|
||||
import electrosphere.renderer.ui.font.FontUtils;
|
||||
import electrosphere.renderer.ui.font.bitmapchar.BitmapCharacter;
|
||||
|
||||
@ -46,12 +48,15 @@ public class StringCarousel implements DrawableElement, MenuEventElement, Focusa
|
||||
float fontSize = 1.0f;
|
||||
|
||||
List<BitmapCharacter> childrenElements = new LinkedList<BitmapCharacter>();
|
||||
|
||||
Font font;
|
||||
|
||||
public StringCarousel(int x, int y, float fontSize){
|
||||
this.positionX = x;
|
||||
this.positionY = y;
|
||||
this.width = 0;
|
||||
this.height = (int)(FontUtils.getFontHeight() * fontSize);
|
||||
this.font = Globals.fontManager.getFont("default");
|
||||
this.height = (int)(font.getFontHeight() * fontSize);
|
||||
this.fontSize = fontSize;
|
||||
}
|
||||
|
||||
@ -82,8 +87,8 @@ public class StringCarousel implements DrawableElement, MenuEventElement, Focusa
|
||||
int rollingOffset = 0;
|
||||
for(int i = 0; i < textCurrent.length(); i++){
|
||||
char toDraw = textCurrent.charAt(i);
|
||||
Vector3f bitMapDimension = FontUtils.getDimensionOfCharacterDiscrete(toDraw);
|
||||
BitmapCharacter newLetter = new BitmapCharacter((int)(rollingOffset * fontSize) + positionX, positionY, (int)(bitMapDimension.x * fontSize), this.height, toDraw);
|
||||
Vector3f bitMapDimension = this.font.getDimensionOfCharacterDiscrete(toDraw);
|
||||
BitmapCharacter newLetter = new BitmapCharacter(this.font,(int)(rollingOffset * fontSize) + positionX, positionY, (int)(bitMapDimension.x * fontSize), this.height, toDraw);
|
||||
rollingOffset += (int)bitMapDimension.x;
|
||||
childrenElements.add(newLetter);
|
||||
}
|
||||
@ -93,7 +98,7 @@ public class StringCarousel implements DrawableElement, MenuEventElement, Focusa
|
||||
this.textCurrent = text;
|
||||
textPixelWidth = 0;
|
||||
for(int i = 0; i < text.length(); i++){
|
||||
Vector3f bitMapDimension = FontUtils.getDimensionOfCharacterDiscrete(text.charAt(i));
|
||||
Vector3f bitMapDimension = this.font.getDimensionOfCharacterDiscrete(text.charAt(i));
|
||||
textPixelWidth = textPixelWidth + (int)bitMapDimension.x;
|
||||
}
|
||||
generateLetters();
|
||||
|
||||
@ -14,6 +14,7 @@ import electrosphere.renderer.ui.KeyEventElement;
|
||||
import electrosphere.renderer.ui.events.Event;
|
||||
import electrosphere.renderer.ui.events.FocusEvent;
|
||||
import electrosphere.renderer.ui.events.KeyboardEvent;
|
||||
import electrosphere.renderer.ui.font.Font;
|
||||
import electrosphere.renderer.ui.font.FontUtils;
|
||||
import electrosphere.renderer.ui.font.bitmapchar.BitmapCharacter;
|
||||
|
||||
@ -54,12 +55,15 @@ public class TextInput implements DrawableElement, FocusableElement, KeyEventEle
|
||||
float fontSize = 1.0f;
|
||||
|
||||
List<BitmapCharacter> childrenElements = new LinkedList<BitmapCharacter>();
|
||||
|
||||
Font font;
|
||||
|
||||
public TextInput(int x, int y, float fontSize){
|
||||
this.positionX = x;
|
||||
this.positionY = y;
|
||||
this.width = 0;
|
||||
this.height = (int)(FontUtils.getFontHeight() * fontSize);
|
||||
this.font = Globals.fontManager.getFont("default");
|
||||
this.height = (int)(this.font.getFontHeight() * fontSize);
|
||||
this.fontSize = fontSize;
|
||||
this.color = new Vector3f(1,1,1);
|
||||
}
|
||||
@ -69,8 +73,8 @@ public class TextInput implements DrawableElement, FocusableElement, KeyEventEle
|
||||
int rollingOffset = 0;
|
||||
for(int i = 0; i < text.length(); i++){
|
||||
char toDraw = text.charAt(i);
|
||||
Vector3f bitMapDimension = FontUtils.getDimensionOfCharacterDiscrete(toDraw);
|
||||
BitmapCharacter newLetter = new BitmapCharacter((int)(rollingOffset * fontSize) + positionX, positionY, (int)(bitMapDimension.x * fontSize), this.height, toDraw);
|
||||
Vector3f bitMapDimension = this.font.getDimensionOfCharacterDiscrete(toDraw);
|
||||
BitmapCharacter newLetter = new BitmapCharacter(this.font,(int)(rollingOffset * fontSize) + positionX, positionY, (int)(bitMapDimension.x * fontSize), this.height, toDraw);
|
||||
newLetter.setColor(color);
|
||||
rollingOffset += (int)bitMapDimension.x;
|
||||
childrenElements.add(newLetter);
|
||||
@ -81,7 +85,7 @@ public class TextInput implements DrawableElement, FocusableElement, KeyEventEle
|
||||
this.text = text;
|
||||
textPixelWidth = 0;
|
||||
for(int i = 0; i < text.length(); i++){
|
||||
Vector3f bitMapDimension = FontUtils.getDimensionOfCharacterDiscrete(text.charAt(i));
|
||||
Vector3f bitMapDimension = this.font.getDimensionOfCharacterDiscrete(text.charAt(i));
|
||||
textPixelWidth = textPixelWidth + (int)bitMapDimension.x;
|
||||
}
|
||||
generateLetters();
|
||||
|
||||
143
src/main/java/electrosphere/renderer/ui/font/Font.java
Normal file
143
src/main/java/electrosphere/renderer/ui/font/Font.java
Normal file
@ -0,0 +1,143 @@
|
||||
package electrosphere.renderer.ui.font;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import electrosphere.renderer.Material;
|
||||
|
||||
/**
|
||||
* A font
|
||||
*/
|
||||
public class Font {
|
||||
|
||||
//the font image
|
||||
Material fontMaterial;
|
||||
//the list of glyphs for the font
|
||||
public List<Glyph> glyphs;
|
||||
//dimensions of the font image
|
||||
public int imageWidth;
|
||||
public int imageHeight;
|
||||
|
||||
//the map of character->position in the image
|
||||
HashMap<Character,Vector3f> positionMap = new HashMap<Character,Vector3f>();
|
||||
//the map of character->dimension of the character in pixels
|
||||
HashMap<Character,Vector3f> dimensionMap = new HashMap<Character,Vector3f>();
|
||||
|
||||
/**
|
||||
* Creates the font object
|
||||
* @param fontMaterial
|
||||
* @param glyphs
|
||||
* @param imageWidth
|
||||
* @param imageHeight
|
||||
*/
|
||||
protected Font(
|
||||
Material fontMaterial,
|
||||
List<Glyph> glyphs,
|
||||
int imageWidth,
|
||||
int imageHeight
|
||||
){
|
||||
this.fontMaterial = fontMaterial;
|
||||
this.glyphs = glyphs;
|
||||
this.imageHeight = imageHeight;
|
||||
this.imageWidth = imageWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data about a single glyph in the font
|
||||
*/
|
||||
public static class Glyph {
|
||||
|
||||
public String symbol;
|
||||
public int startX;
|
||||
public int startY;
|
||||
public int width;
|
||||
public int height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the position of a given character
|
||||
* @param character The character
|
||||
* @return the position
|
||||
*/
|
||||
public Vector3f getPositionOfCharacter(char character){
|
||||
Vector3f position;
|
||||
if((position = positionMap.get(character))!=null){
|
||||
position = new Vector3f(position);
|
||||
position.x = position.x / imageWidth;
|
||||
position.y = position.y / imageHeight;
|
||||
} else {
|
||||
position = new Vector3f();
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the dimensions of a given character
|
||||
* @param character the character
|
||||
* @return the dimensions
|
||||
*/
|
||||
public Vector3f getDimensionOfCharacter(char character){
|
||||
Vector3f dimension;
|
||||
if((dimension = dimensionMap.get(character))!=null){
|
||||
dimension = new Vector3f(dimension);
|
||||
dimension.x = dimension.x / imageWidth;
|
||||
dimension.y = dimension.y / imageHeight;
|
||||
} else {
|
||||
dimension = new Vector3f(0.5f,0.5f,0f);
|
||||
}
|
||||
return dimension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the dimensions of a given character in discrete pixels
|
||||
* @param character The character
|
||||
* @return the dimensions in pixels
|
||||
*/
|
||||
public Vector3f getDimensionOfCharacterDiscrete(char character){
|
||||
Vector3f dimension;
|
||||
if((dimension = dimensionMap.get(character))!=null){
|
||||
dimension = new Vector3f(dimension);
|
||||
} else {
|
||||
dimension = new Vector3f(12,14,0f);
|
||||
}
|
||||
return dimension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the height of the font
|
||||
* @return the height
|
||||
*/
|
||||
public int getFontHeight(){
|
||||
return imageHeight;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Processes the glyphs into structures that will contain instantly lookup-able data
|
||||
*/
|
||||
protected void process(){
|
||||
for(Glyph glyph : glyphs){
|
||||
char charVal = glyph.symbol.charAt(0);
|
||||
Vector3f position = new Vector3f(glyph.startX,glyph.startY,0);
|
||||
positionMap.put(charVal,position);
|
||||
}
|
||||
//fill dimension map
|
||||
dimensionMap.clear();
|
||||
for(Glyph glyph : glyphs){
|
||||
char charVal = glyph.symbol.charAt(0);
|
||||
Vector3f dimension = new Vector3f(glyph.width,glyph.height,0);
|
||||
dimensionMap.put(charVal,dimension);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the material for the font
|
||||
* @return The material
|
||||
*/
|
||||
public Material getMaterial(){
|
||||
return fontMaterial;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
package electrosphere.renderer.ui.font;
|
||||
|
||||
import java.awt.FontFormatException;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import electrosphere.logger.LoggerInterface;
|
||||
import electrosphere.renderer.Material;
|
||||
import electrosphere.util.FileUtils;
|
||||
|
||||
/**
|
||||
* Manages all fonts loaded into the engine
|
||||
*/
|
||||
public class FontManager {
|
||||
|
||||
//the default font
|
||||
Font defaultFont;
|
||||
|
||||
//maps names of fonts to font objects
|
||||
Map<String,Font> fontMap = new HashMap<String,Font>();
|
||||
|
||||
|
||||
/**
|
||||
* Gets a font based on an identifying string
|
||||
* @param identifier the identifying string
|
||||
* @return The font if it exists or null
|
||||
*/
|
||||
public Font getFont(String identifier){
|
||||
return fontMap.get(identifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads fonts at engine startup during the init graphics resource phase
|
||||
*/
|
||||
public void loadFonts(){
|
||||
java.awt.Font font = null;
|
||||
try {
|
||||
font = java.awt.Font.createFont(java.awt.Font.TRUETYPE_FONT, FileUtils.getAssetFileAsStream("Fonts/Tuffy_Bold.ttf"));
|
||||
font = font.deriveFont(24f);
|
||||
} catch (FontFormatException e) {
|
||||
LoggerInterface.loggerEngine.ERROR("Failed to load a font!", e);
|
||||
} catch (IOException e) {
|
||||
LoggerInterface.loggerEngine.ERROR("Failed to load a font!", e);
|
||||
}
|
||||
if(font==null){
|
||||
font = new java.awt.Font(java.awt.Font.MONOSPACED, java.awt.Font.PLAIN, 16);
|
||||
}
|
||||
if(font!=null){
|
||||
defaultFont = FontUtils.loadFont(font, false);
|
||||
fontMap.put("default",defaultFont);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,87 +1,162 @@
|
||||
package electrosphere.renderer.ui.font;
|
||||
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.entity.Entity;
|
||||
import electrosphere.entity.EntityDataStrings;
|
||||
import electrosphere.entity.EntityUtils;
|
||||
import electrosphere.renderer.Model;
|
||||
import electrosphere.renderer.ModelUtils;
|
||||
import electrosphere.renderer.actor.ActorUtils;
|
||||
import electrosphere.renderer.ui.font.RawFontMap.Glyph;
|
||||
import java.util.HashMap;
|
||||
import org.joml.Vector3f;
|
||||
import org.joml.Vector3i;
|
||||
import electrosphere.renderer.Material;
|
||||
import electrosphere.renderer.texture.Texture;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author amaterasu
|
||||
* Utilities for loading fonts
|
||||
*/
|
||||
public class FontUtils {
|
||||
|
||||
static RawFontMap rawFontMap;
|
||||
|
||||
static HashMap<Character,Vector3f> positionMap = new HashMap<Character,Vector3f>();
|
||||
static HashMap<Character,Vector3f> dimensionMap = new HashMap<Character,Vector3f>();
|
||||
|
||||
static int width = 10;
|
||||
static int height = 10;
|
||||
|
||||
public static Vector3f getPositionOfCharacter(char character){
|
||||
Vector3f position;
|
||||
if((position = positionMap.get(character))!=null){
|
||||
position = new Vector3f(position);
|
||||
position.x = position.x / rawFontMap.imageWidth;
|
||||
position.y = position.y / rawFontMap.imageHeight;
|
||||
} else {
|
||||
position = new Vector3f();
|
||||
|
||||
|
||||
/**
|
||||
* Renders a single character to a buffered image
|
||||
* @param font The java font object
|
||||
* @param c the character
|
||||
* @param antiAlias whether to antialias the font or not
|
||||
* @return The buffered image with the rendered font
|
||||
*/
|
||||
private static BufferedImage createCharImage(java.awt.Font font, char c, boolean antiAlias) {
|
||||
|
||||
//get the size of the character
|
||||
BufferedImage image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g = image.createGraphics();
|
||||
if(antiAlias){
|
||||
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
}
|
||||
return position;
|
||||
g.setFont(font);
|
||||
FontMetrics metrics = g.getFontMetrics();
|
||||
g.dispose();
|
||||
int charWidth = metrics.charWidth(c);
|
||||
int charHeight = metrics.getHeight();
|
||||
|
||||
//return 0 width characters
|
||||
if (charWidth == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//render character to a properly sized buffered image
|
||||
image = new BufferedImage(charWidth, charHeight, BufferedImage.TYPE_INT_ARGB);
|
||||
g = image.createGraphics();
|
||||
if (antiAlias) {
|
||||
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
}
|
||||
g.setFont(font);
|
||||
g.setPaint(java.awt.Color.WHITE);
|
||||
g.drawString(String.valueOf(c), 0, metrics.getAscent());
|
||||
g.dispose();
|
||||
return image;
|
||||
}
|
||||
|
||||
public static Vector3f getDimensionOfCharacter(char character){
|
||||
Vector3f dimension;
|
||||
if((dimension = dimensionMap.get(character))!=null){
|
||||
dimension = new Vector3f(dimension);
|
||||
dimension.x = dimension.x / rawFontMap.imageWidth;
|
||||
dimension.y = dimension.y / rawFontMap.imageHeight;
|
||||
} else {
|
||||
dimension = new Vector3f(0.5f,0.5f,0f);
|
||||
|
||||
/**
|
||||
* Loads a java font object into an engine font object
|
||||
* @param font The java font object
|
||||
* @param antiAlias if true, antialias, otherwise dont
|
||||
* @return The engine font object
|
||||
*/
|
||||
protected static Font loadFont(java.awt.Font font, boolean antiAlias) {
|
||||
int imageWidth = 0;
|
||||
int imageHeight = 0;
|
||||
|
||||
|
||||
//data for parsing characters out of the font image
|
||||
List<Font.Glyph> glyphs = new LinkedList<Font.Glyph>();
|
||||
|
||||
//iterate through ascii codes
|
||||
for(int i = 32; i < 256; i++){
|
||||
if(i == 127){
|
||||
//skip del character
|
||||
continue;
|
||||
}
|
||||
char c = (char)i;
|
||||
BufferedImage ch = createCharImage(font, c, antiAlias);
|
||||
if(ch == null){
|
||||
//skip characters with no images
|
||||
continue;
|
||||
}
|
||||
|
||||
imageWidth += ch.getWidth();
|
||||
imageHeight = Math.max(imageHeight, ch.getHeight());
|
||||
}
|
||||
return dimension;
|
||||
}
|
||||
|
||||
public static Vector3f getDimensionOfCharacterDiscrete(char character){
|
||||
Vector3f dimension;
|
||||
if((dimension = dimensionMap.get(character))!=null){
|
||||
dimension = new Vector3f(dimension);
|
||||
} else {
|
||||
dimension = new Vector3f(12,14,0f);
|
||||
|
||||
int fontHeight = imageHeight;
|
||||
|
||||
//create font bitmap
|
||||
BufferedImage image = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g = image.createGraphics();
|
||||
|
||||
int x = 0;
|
||||
|
||||
//loop through ascii codes
|
||||
for (int i = 32; i < 256; i++) {
|
||||
if (i == 127) {
|
||||
//skip del character command
|
||||
continue;
|
||||
}
|
||||
char c = (char) i;
|
||||
BufferedImage charImage = createCharImage(font, c, antiAlias);
|
||||
if (charImage == null) {
|
||||
//don't render if the character is blank
|
||||
continue;
|
||||
}
|
||||
|
||||
int charWidth = charImage.getWidth();
|
||||
int charHeight = charImage.getHeight();
|
||||
|
||||
//draw the glyph to the image
|
||||
g.drawImage(charImage, x, 0, null);
|
||||
|
||||
//create glyph and push it into the array
|
||||
Font.Glyph glyph = new Font.Glyph();
|
||||
glyph.height = charHeight;
|
||||
glyph.width = charWidth;
|
||||
glyph.startX = x;
|
||||
glyph.startY = 0;
|
||||
glyph.symbol = (char)i + "";
|
||||
glyphs.add(glyph);
|
||||
|
||||
//increment image
|
||||
x += charWidth;
|
||||
}
|
||||
return dimension;
|
||||
}
|
||||
|
||||
public static int getFontHeight(){
|
||||
return height;
|
||||
}
|
||||
|
||||
public static void setFontDataMap(RawFontMap map){
|
||||
rawFontMap = map;
|
||||
width = map.imageWidth;
|
||||
height = map.imageHeight;
|
||||
//fill position map
|
||||
positionMap.clear();
|
||||
for(Glyph glyph : rawFontMap.glyphs){
|
||||
char charVal = glyph.symbol.charAt(0);
|
||||
Vector3f position = new Vector3f(glyph.startX,glyph.startY,0);
|
||||
positionMap.put(charVal,position);
|
||||
}
|
||||
//fill dimension map
|
||||
dimensionMap.clear();
|
||||
for(Glyph glyph : rawFontMap.glyphs){
|
||||
char charVal = glyph.symbol.charAt(0);
|
||||
Vector3f dimension = new Vector3f(glyph.width,glyph.height,0);
|
||||
dimensionMap.put(charVal,dimension);
|
||||
|
||||
//uncomment if you need to flip the font
|
||||
// AffineTransform transform = AffineTransform.getScaleInstance(1f, -1f);
|
||||
// transform.translate(0, -image.getHeight());
|
||||
// AffineTransformOp operation = new AffineTransformOp(transform, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
|
||||
// image = operation.filter(image, null);
|
||||
|
||||
try {
|
||||
ImageIO.write(image, "png", Files.newOutputStream(new File("C:/users/satellite/Pictures/testimg.png").toPath()));
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
//create material with new font image
|
||||
Material uiMat = new Material();
|
||||
Texture texture = new Texture(image);
|
||||
uiMat.setTexturePointer(texture.getTexturePointer());
|
||||
|
||||
|
||||
//construct final font object and return
|
||||
Font rVal = new Font(uiMat,glyphs,imageWidth,imageHeight);
|
||||
rVal.process();
|
||||
return rVal;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1,27 +0,0 @@
|
||||
package electrosphere.renderer.ui.font;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author amaterasu
|
||||
*/
|
||||
public class RawFontMap {
|
||||
|
||||
public List<Glyph> glyphs;
|
||||
public int imageWidth;
|
||||
public int imageHeight;
|
||||
|
||||
|
||||
public class Glyph {
|
||||
public String symbol;
|
||||
public int startX;
|
||||
public int startY;
|
||||
public int width;
|
||||
public int height;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -2,10 +2,12 @@ package electrosphere.renderer.ui.font.bitmapchar;
|
||||
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.engine.assetmanager.AssetDataStrings;
|
||||
import electrosphere.renderer.Material;
|
||||
import electrosphere.renderer.Model;
|
||||
import electrosphere.renderer.ui.DrawableElement;
|
||||
import electrosphere.renderer.ui.events.Event;
|
||||
import electrosphere.renderer.ui.font.FontUtils;
|
||||
import electrosphere.renderer.ui.font.Font;
|
||||
// import electrosphere.renderer.ui.font.FontUtils;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
/**
|
||||
@ -17,15 +19,18 @@ public class BitmapCharacter implements DrawableElement {
|
||||
String text;
|
||||
|
||||
Vector3f color = new Vector3f(0,0,0);
|
||||
|
||||
Font font;
|
||||
|
||||
|
||||
|
||||
public BitmapCharacter(int posX, int posY, int width, int height, char toDraw){
|
||||
public BitmapCharacter(Font font, int posX, int posY, int width, int height, char toDraw){
|
||||
this.positionX = posX;
|
||||
this.positionY = posY;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.text = "" + toDraw;
|
||||
this.font = font;
|
||||
}
|
||||
|
||||
|
||||
@ -56,13 +61,16 @@ public class BitmapCharacter implements DrawableElement {
|
||||
char toDraw = text.charAt(0);
|
||||
Vector3f characterPosition = new Vector3f(ndcX,ndcY,0);
|
||||
Vector3f characterDimensions = new Vector3f(ndcWidth,ndcHeight,0);
|
||||
Vector3f bitMapPosition = FontUtils.getPositionOfCharacter(toDraw);
|
||||
Vector3f bitMapDimension = FontUtils.getDimensionOfCharacter(toDraw);
|
||||
Vector3f bitMapPosition = this.font.getPositionOfCharacter(toDraw);
|
||||
Vector3f bitMapDimension = this.font.getDimensionOfCharacter(toDraw);
|
||||
// bitMapDimension.y = 1;
|
||||
// System.out.println(bitMapPosition);
|
||||
// System.out.println(bitMapDimension);
|
||||
// System.out.println("\n\n");
|
||||
//load model and try overwriting with font material
|
||||
Model charModel = Globals.assetManager.fetchModel(AssetDataStrings.BITMAP_CHARACTER_MODEL);
|
||||
Material mat = this.font.getMaterial();
|
||||
charModel.tryOverwriteMaterial(mat);
|
||||
if(charModel != null && toDraw != ' '){
|
||||
charModel.pushUniformToMesh(AssetDataStrings.ASSET_STRING_BITMAP_FONT_MESH_NAME, "mPosition", characterPosition);
|
||||
charModel.pushUniformToMesh(AssetDataStrings.ASSET_STRING_BITMAP_FONT_MESH_NAME, "mDimension", characterDimensions);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user