diff --git a/src/main/java/engine/animation/skeleton/Bone.java b/src/main/java/engine/animation/skeleton/Bone.java new file mode 100644 index 00000000..a51adcb1 --- /dev/null +++ b/src/main/java/engine/animation/skeleton/Bone.java @@ -0,0 +1,147 @@ +package engine.animation.skeleton; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import math.Matrix4; + +public class Bone { + + private final String name; + private Bone parent; + private final List children; + private Matrix4 localTransform; + private Matrix4 globalTransform; + private Matrix4 inverseBindPose; + private boolean transformDirty = true; + private float weight; + private int index; + + public Bone(String name) { + if (name == null) { + throw new IllegalArgumentException("Name cannot be null."); + } + this.name = name; + this.children = new ArrayList<>(); + this.localTransform = new Matrix4().identity(); + this.globalTransform = new Matrix4().identity(); + this.weight = 1.0f; + } + + public void updateGlobalTransform() { + if (!transformDirty) return; + globalTransform = + (parent != null) ? parent.globalTransform.multiply(localTransform) : localTransform; + transformDirty = false; + } + + public void updateChildrenTransforms() { + for (Bone child : children) { + child.markDirty(); + child.updateGlobalTransform(); + child.updateChildrenTransforms(); + } + } + + public void markDirty() { + transformDirty = true; + } + + public void addChild(Bone child) { + if (child == null) { + throw new IllegalArgumentException("Child bone cannot be null."); + } + if (isAncestorOf(child)) { + throw new IllegalArgumentException("Cannot add a child that would create a cycle."); + } + if (child.getParent() != null) { + child.getParent().removeChild(child); + } + children.add(child); + child.setParent(this); + } + + private boolean isAncestorOf(Bone bone) { + Bone current = this; + while (current != null) { + if (current == bone) { + return true; + } + current = current.getParent(); + } + return false; + } + + public void removeChild(Bone child) { + if (children.remove(child)) { + child.setParent(null); + } + } + + private void setParent(Bone parent) { + if (this.parent == parent) return; + this.parent = parent; + } + + public String getName() { + return name; + } + + public Bone getParent() { + return parent; + } + + public List getChildren() { + return Collections.unmodifiableList(children); + } + + public Matrix4 getLocalTransform() { + return new Matrix4(localTransform); + } + + public void setLocalTransform(Matrix4 localTransform) { + if (localTransform == null) { + throw new IllegalArgumentException("LocalTransform cannot be null."); + } + this.localTransform = localTransform; + markDirty(); + } + + public Matrix4 getGlobalTransform() { + return new Matrix4(globalTransform); + } + + public Matrix4 getInverseBindPose() { + return new Matrix4(inverseBindPose); + } + + public void setInverseBindPose(Matrix4 bindPose) { + this.inverseBindPose = bindPose.invert(); + } + + public float getWeight() { + return weight; + } + + public void setWeight(float weight) { + if (weight < 0.0f || weight > 1.0f) { + throw new IllegalArgumentException("Weight must be between 0.0 and 1.0."); + } + this.weight = weight; + } + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } + + public void printHierarchy(int depth) { + System.out.println(" ".repeat(depth) + name); + for (Bone child : children) { + child.printHierarchy(depth + 1); + } + } +} diff --git a/src/main/java/engine/animation/skeleton/Skeleton.java b/src/main/java/engine/animation/skeleton/Skeleton.java new file mode 100644 index 00000000..1a443e48 --- /dev/null +++ b/src/main/java/engine/animation/skeleton/Skeleton.java @@ -0,0 +1,64 @@ +package engine.animation.skeleton; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class Skeleton { + + private Bone rootBone; + + private final Map allBones; + + public Skeleton(Bone rootBone) { + this.rootBone = rootBone; + this.allBones = new HashMap<>(); + collectBones(rootBone); + } + + private void collectBones(Bone bone) { + allBones.put(bone.getName(), bone); + for (Bone child : bone.getChildren()) { + collectBones(child); + } + } + + public Bone getBone(String name) { + return allBones.get(name); + } + + public void update() { + if (rootBone != null) { + rootBone.updateGlobalTransform(); + } + } + + public Bone getRootBone() { + return rootBone; + } + + public void setRootBone(Bone rootBone) { + this.rootBone = rootBone; + allBones.clear(); + collectBones(rootBone); + } + + public List getAllBones() { + return new ArrayList<>(allBones.values()); + } + + public void printHierarchy() { + printHierarchy(rootBone, 0); + } + + private void printHierarchy(Bone bone, int level) { + for (int i = 0; i < level; i++) { + System.out.print(" "); + } + System.out.println(bone.getName()); + for (Bone child : bone.getChildren()) { + printHierarchy(child, level + 1); + } + } +} diff --git a/src/main/java/engine/application/BasicApplication.java b/src/main/java/engine/application/BasicApplication.java index aa70cff2..51cf5128 100644 --- a/src/main/java/engine/application/BasicApplication.java +++ b/src/main/java/engine/application/BasicApplication.java @@ -2,6 +2,7 @@ import engine.Timer; import engine.components.FlyByCameraControl; +import engine.components.SmoothFlyByCameraControl; import engine.debug.DebugInfoUpdater; import engine.debug.DebugOverlay; import engine.debug.FpsGraph; @@ -9,6 +10,7 @@ import engine.input.Input; import engine.input.Key; import engine.processing.ProcessingApplication; +import engine.resources.Font; import engine.scene.Scene; import engine.scene.SceneNode; import engine.scene.camera.PerspectiveCamera; @@ -86,7 +88,7 @@ private void setupDefaultCamera() { PerspectiveCamera defaultCamera = new PerspectiveCamera(); activeScene.setActiveCamera(defaultCamera); SceneNode cameraNode = new SceneNode("DefaultCamera"); - cameraNode.addComponent(new FlyByCameraControl(input, defaultCamera)); + cameraNode.addComponent(new SmoothFlyByCameraControl(input, defaultCamera)); activeScene.addNode(cameraNode); } @@ -148,6 +150,7 @@ private void renderUi(Graphics g) { private void renderDebugUi(Graphics g) { if (!displayInfo) return; + g.setFont(new Font("Lucida Sans", 12, Font.PLAIN)); debugOverlay.render(g); fpsGraph.render(g); } diff --git a/src/main/java/engine/components/CrossLineReticle.java b/src/main/java/engine/components/CrossLineReticle.java new file mode 100644 index 00000000..0f293793 --- /dev/null +++ b/src/main/java/engine/components/CrossLineReticle.java @@ -0,0 +1,121 @@ +/** + * The CrossLineReticle class represents a visual reticle consisting of cross lines rendered on a + * plane. It is designed to be part of a 3D scene and implements the {@link RenderableComponent} + * interface for rendering capabilities. + * + *

The reticle is created as a textured plane using a {@link Mesh3D} and is configurable with + * parameters like radius, thickness, and color. The texture is generated dynamically. + */ +package engine.components; + +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; + +import engine.resources.FilterMode; +import engine.resources.Texture; +import engine.resources.TextureManager; +import math.Color; +import math.Mathf; +import mesh.Mesh3D; +import mesh.creator.primitives.PlaneCreatorUV; +import mesh.modifier.RotateXModifier; +import workspace.ui.Graphics; + +public class CrossLineReticle extends AbstractComponent implements RenderableComponent { + + /** The radius of the reticle, defining its size. */ + private int radius; + + /** The thickness of the cross lines. */ + private int thickness; + + /** The color of the cross lines. */ + private Color color; + + /** The mesh used to represent the plane of the reticle. */ + private Mesh3D mesh; + + /** The texture used for rendering the reticle. */ + private Texture texture; + + /** Creates a default CrossLineReticle with a radius of 9, thickness of 2, and white color. */ + public CrossLineReticle() { + this(9, 2, Color.WHITE); + } + + /** + * Creates a CrossLineReticle with the specified radius, thickness, and color. + * + * @param radius The radius of the reticle. + * @param thickness The thickness of the cross lines. + * @param color The color of the cross lines. + */ + public CrossLineReticle(int radius, int thickness, Color color) { + this.radius = radius; + this.color = color; + this.thickness = thickness; + this.mesh = new PlaneCreatorUV(radius).create(); + this.mesh.apply(new RotateXModifier(-Mathf.HALF_PI)); + this.texture = createTexture(); + } + + /** + * Renders the reticle onto the provided {@link Graphics} context. + * + * @param g The graphics context used for rendering. + */ + @Override + public void render(Graphics g) { + float centerX = g.getWidth() / 2.0f; + float centerY = g.getHeight() / 2.0f; + g.pushMatrix(); + g.translate(centerX, centerY); + g.bindTexture(texture, 0); + g.fillFaces(mesh); + g.unbindTexture(0); + g.popMatrix(); + } + + /** + * Creates a {@link Texture} for the reticle using a dynamically generated {@link BufferedImage}. + * + * @return The generated texture. + */ + private Texture createTexture() { + BufferedImage image = createTextureImage(); + Texture texture = TextureManager.getInstance().createTexture(image); + texture.setFilterMode(FilterMode.POINT); + return texture; + } + + /** + * Generates a {@link BufferedImage} containing the cross lines of the reticle. + * + * @return The generated image. + */ + private BufferedImage createTextureImage() { + int size = radius + radius; + BufferedImage image = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2d = (Graphics2D) image.getGraphics(); + g2d.setColor(new java.awt.Color(this.color.getRGBA())); + g2d.fillRect(radius - (thickness / 2), 0, thickness, size); + g2d.fillRect(0, radius - (thickness / 2), size, thickness); + return image; + } + + /** + * Called during each update cycle. This reticle does not require updates. + * + * @param tpf The time per frame in seconds. + */ + @Override + public void onUpdate(float tpf) {} + + /** Called when the component is attached to a {@link engine.SceneNode}. */ + @Override + public void onAttach() {} + + /** Called when the component is detached from a {@link engine.SceneNode}. */ + @Override + public void onDetach() {} +} diff --git a/src/main/java/engine/demos/landmass/NoiseMapDisplay.java b/src/main/java/engine/demos/landmass/NoiseMapDisplay.java index bf0b2a23..aaa70bbe 100644 --- a/src/main/java/engine/demos/landmass/NoiseMapDisplay.java +++ b/src/main/java/engine/demos/landmass/NoiseMapDisplay.java @@ -73,7 +73,8 @@ private void createPlaneMesh() { */ public void setPixels(int[] pixels) { texture.setPixels(pixels); - Material material = new Material.Builder().setDiffuseTexture(texture).build(); + Material material = new Material(); + material.setDiffuseTexture(texture); planeGeometry = new Geometry(planeMesh, material); } diff --git a/src/main/java/engine/demos/landmass/ProceduralLandmassDemo.java b/src/main/java/engine/demos/landmass/ProceduralLandmassDemo.java index ee8fd3ac..efe549a0 100644 --- a/src/main/java/engine/demos/landmass/ProceduralLandmassDemo.java +++ b/src/main/java/engine/demos/landmass/ProceduralLandmassDemo.java @@ -11,7 +11,9 @@ import engine.scene.SceneNode; import engine.scene.camera.PerspectiveCamera; import engine.scene.light.DirectionalLight; +import engine.ui.LoadingScreen; import math.Color; +import math.Vector3f; import mesh.Mesh3D; import mesh.modifier.CenterAtModifier; import mesh.modifier.ScaleModifier; @@ -42,10 +44,15 @@ public enum DrawMode { // Configuration fields private int levelOfDetail = 0; // Level of detail for the terrain mesh (0 - 6) - private int chunkSize = 240; // TODO Note that the size has to fit LOD - private int chunkScale = 3; + // private int chunkSize = 960; // TODO Note that the size has to fit LOD + private int chunkSize = 480; + private int chunkScale = 4; private DrawMode drawMode = DrawMode.COLOR_MAP; private Scene scene; + // private EndlessTerrain endlessTerrain; + + private LoadingScreen loadingScreen; + private RoundReticle roundReticle; public static void main(String[] args) { ProceduralLandmassDemo application = new ProceduralLandmassDemo(); @@ -57,10 +64,22 @@ public static void main(String[] args) { /** Initializes the demo scene, including terrain generation, lighting, and UI components. */ @Override public void onInitialize() { - setupScene(); setupUI(); - createTerrain(); + setupScene(); createCamera(); + runTerrainCreation(); + // endlessTerrain = new EndlessTerrain(scene, chunkSize * chunkScale); + } + + private void runTerrainCreation() { + new Thread( + new Runnable() { + @Override + public void run() { + createTerrain(); + } + }) + .start(); } /** Sets up the base scene with a background color and directional lighting. */ @@ -76,8 +95,15 @@ private void setupScene() { /** Sets up the UI elements, such as the round reticle. */ private void setupUI() { SceneNode reticleNode = new SceneNode(); - reticleNode.addComponent(new RoundReticle()); + roundReticle = new RoundReticle(); + roundReticle.setActive(false); + reticleNode.addComponent(roundReticle); rootUI.addChild(reticleNode); + + SceneNode loadingScreenNode = new SceneNode(); + loadingScreen = new LoadingScreen(); + loadingScreenNode.addComponent(loadingScreen); + rootUI.addChild(loadingScreenNode); } /** Creates the terrain based on the selected draw mode and level of detail. */ @@ -98,7 +124,8 @@ private void createTerrain() { // Create a texture from the display and apply it to the terrain material Texture2D texture = display.getTexture(); - Material mapMaterial = new Material.Builder().setDiffuseTexture(texture).build(); + Material mapMaterial = new Material(); + mapMaterial.setDiffuseTexture(texture); // Generate the terrain mesh, apply transformations, and create a geometry node Mesh3D terrainMesh = new TerrainMeshLOD(noiseMap, levelOfDetail).getMesh(); @@ -114,13 +141,18 @@ private void createTerrain() { SceneNode chunkDisplayNode = new SceneNode(); chunkDisplayNode.addComponent(new ChunkBoxDisplay(chunkSize * chunkScale)); scene.addNode(chunkDisplayNode); + + roundReticle.setActive(true); + loadingScreen.hide(); } /** Sets up the camera with smooth fly-by controls. */ private void createCamera() { PerspectiveCamera camera = new PerspectiveCamera(); + camera.getTransform().setPosition(0, -chunkSize / 2f * chunkScale, 0); + SmoothFlyByCameraControl cameraControl = new SmoothFlyByCameraControl(input, camera); - cameraControl.setMoveSpeed(70); + cameraControl.setMoveSpeed(200); SceneNode cameraNode = new SceneNode(); cameraNode.addComponent(cameraControl); @@ -131,7 +163,9 @@ private void createCamera() { /** Update logic (currently empty). */ @Override public void onUpdate(float tpf) { - // No update logic for this demo + Vector3f viewerPosition = activeScene.getActiveCamera().getTransform().getPosition(); + // endlessTerrain.setViewerPosition(viewerPosition); + // endlessTerrain.update(); } /** Render logic (currently empty). */ diff --git a/src/main/java/engine/processing/ProcessingFontManager.java b/src/main/java/engine/processing/ProcessingFontManager.java new file mode 100644 index 00000000..a461c9ba --- /dev/null +++ b/src/main/java/engine/processing/ProcessingFontManager.java @@ -0,0 +1,93 @@ +package engine.processing; + +import java.util.HashMap; +import java.util.Map; + +import engine.resources.Font; +import processing.core.PApplet; +import processing.core.PFont; + +/** + * A class to manage fonts in Processing by caching and loading fonts on demand. It supports + * different font styles such as plain, bold, and italic. + */ +public class ProcessingFontManager { + + /** Cache for fonts to avoid redundant font loading */ + private Map fontCache = new HashMap<>(); + + /** The PApplet instance used for creating fonts */ + private PApplet p; + + /** + * Constructor to initialize the font manager with a PApplet instance. + * + * @param p the PApplet instance used for creating fonts + */ + public ProcessingFontManager(PApplet p) { + this.p = p; + } + + private void loadFont(int size, boolean smooth) { + try { + // Load the font from a custom folder + String filePath = + "monogram/ttf/monogram-extended.ttf"; // Relative path to your custom font folder + String fontPath = + ProcessingTextureLoader.class.getClassLoader().getResource("fonts/" + filePath).getPath(); + + PFont font = p.createFont(fontPath, size); + fontCache.put(new Font("monogram-extended", size, Font.PLAIN), font); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * Loads a font based on the provided Font object. If the font is already cached, it returns the + * cached version. Otherwise, it creates a new font and stores it in the cache. Font smoothing is + * enabled by default. + * + * @param font the Font object to load + * @return the corresponding PFont object + */ + public PFont loadFont(Font font) { + if (!fontCache.containsKey(font)) { + // Enable smoothing by default + boolean smooth = true; + // Create the PFont and add it to the cache + if (font.getName().startsWith("monogram")) { + loadFont(font.getSize(), smooth); + } else { + PFont pFont = p.createFont(getFontName(font), font.getSize(), smooth); + fontCache.put(font, pFont); + } + } + return fontCache.get(font); + } + + /** + * Constructs the font name string, appending the appropriate style based on the Font object's + * style (PLAIN, BOLD, or ITALIC). + * + * @param font the Font object + * @return the constructed font name string with the style + */ + private String getFontName(Font font) { + String style = ""; + switch (font.getStyle()) { + case Font.BOLD: + style = " Bold"; + break; + case Font.ITALIC: + style = " Italic"; + break; + case Font.PLAIN: + style = ""; + break; + default: + throw new IllegalArgumentException("Unexpected value: " + font.getStyle()); + } + return font.getName() + style; + } +} diff --git a/src/main/java/engine/render/Material.java b/src/main/java/engine/render/Material.java index 17a1e5d5..78727c4a 100644 --- a/src/main/java/engine/render/Material.java +++ b/src/main/java/engine/render/Material.java @@ -13,8 +13,7 @@ * reflects off the object's surface. * *

This class includes predefined materials for common use cases (e.g., default white, black, or - * other colors) and supports the creation of custom materials with specific properties through the - * use of {@link Builder}. + * other colors) and supports the creation of custom materials with specific properties. * *

The material properties can control effects like reflectivity, surface roughness, and color, * enabling diverse visual representations for 3D meshes in a rendering engine. @@ -51,149 +50,75 @@ public class Material { /** Water material with a reflective blue appearance. */ public static final Material WATER_MATERIAL = MaterialFactory.createWater(); + /** Indicates whether this material should use lighting effects during rendering. */ private boolean useLighting; + /** + * The name of the material, used to identify and reference the material in rendering pipelines + * and material libraries. + * + *

This name is often defined in material definition files (e.g., MTL files for OBJ models) and + * is used to associate textures and shading properties with specific parts of a 3D model. Having + * a descriptive name can help streamline asset management and debugging within a rendering + * engine. + */ + private String name; + /** Base color for the material. */ - private final Color color; + private Color color; - /** Ambient light coefficient (R, G, B). */ - private final float[] ambient; + /** Ambient light coefficient (R, G, B), controlling the material's reaction to ambient light. */ + private float[] ambient; - /** Diffuse light coefficient (R, G, B). */ - private final float[] diffuse; + /** Diffuse light coefficient (R, G, B), controlling how the material reflects diffuse light. */ + private float[] diffuse; - /** Specular light coefficient (R, G, B). */ - private final float[] specular; + /** + * Specular light coefficient (R, G, B), controlling the shininess and reflections on the surface. + */ + private float[] specular; - /** Shininess factor for specular highlights. */ - private final float shininess; + /** + * Shininess factor for specular highlights, controlling the size and intensity of reflections. + */ + private float shininess; /** The diffuse texture map (map_Kd) of the material. */ private Texture diffuseTexture; + /** The opacity texture map (map_d) of the material */ + private Texture opacityMap; + + /** Default constructor that initializes the material with a base white color. */ + public Material() { + this(Color.WHITE); + } + /** * Constructor to set the base color of the material. * * @param color The base color of the material. + * @throws IllegalArgumentException If the color is null. */ public Material(Color color) { - this(new Builder().setColor(color)); - } - - private Material(Builder builder) { - this.useLighting = builder.useLighting; - this.color = builder.color; - this.ambient = builder.ambient; - this.diffuse = builder.diffuse; - this.specular = builder.specular; - this.shininess = builder.shininess; - this.diffuseTexture = builder.diffuseTexture; - } - - /** - * Builder class to facilitate the creation of custom materials with specific lighting, shader and - * texture properties. - */ - public static class Builder { - - private boolean useLighting = true; - - private Color color = new Color(1, 1, 1); // Default color is white - - private float[] ambient = new float[] {0.2f, 0.2f, 0.2f}; - - private float[] diffuse = new float[] {1.0f, 1.0f, 1.0f}; - - private float[] specular = new float[] {1.0f, 1.0f, 1.0f}; - - private float shininess = 10.0f; - - private Texture diffuseTexture = null; - - /** - * Sets the base color of the material. - * - * @param color The desired base color. - * @return The builder instance for chaining. - */ - public Builder setColor(Color color) { - this.color = color; - return this; - } - - /** - * Sets the ambient light coefficient of the material. - * - * @param ambient The desired ambient light coefficient (R, G, B). - * @return The builder instance for chaining. - */ - public Builder setAmbient(float[] ambient) { - this.ambient = ambient; - return this; - } - - /** - * Sets the diffuse light coefficient of the material. - * - * @param diffuse The desired diffuse light coefficient (R, G, B). - * @return The builder instance for chaining. - */ - public Builder setDiffuse(float[] diffuse) { - this.diffuse = diffuse; - return this; - } - - /** - * Sets the specular light coefficient of the material. - * - * @param specular The desired specular light coefficient (R, G, B). - * @return The builder instance for chaining. - */ - public Builder setSpecular(float[] specular) { - this.specular = specular; - return this; - } - - /** - * Sets the shininess value of the material. - * - * @param shininess The shininess factor for specular highlights. - * @return The builder instance for chaining. - */ - public Builder setShininess(float shininess) { - this.shininess = shininess; - return this; - } - - public Builder setUseLighting(boolean useLighting) { - this.useLighting = useLighting; - return this; - } - - /** - * Sets the diffuse texture of the material. - * - * @param diffuseTexture The diffuse texture, can be null. - * @return The builder instance for chaining - */ - public Builder setDiffuseTexture(Texture diffuseTexture) { - this.diffuseTexture = diffuseTexture; - return this; - } - - /** - * Builds and returns the Material instance with the set properties. - * - * @return A new instance of {@link Material}. - */ - public Material build() { - return new Material(this); + if (color == null) { + throw new IllegalArgumentException("Color cannot be null."); } + this.color = color; + this.name = ""; + this.useLighting = true; + this.ambient = new float[] {0.2f, 0.2f, 0.2f}; + this.diffuse = new float[] {1.0f, 1.0f, 1.0f}; + this.specular = new float[] {1.0f, 1.0f, 1.0f}; + this.shininess = 10.0f; } /** * Applies this material's properties to the provided rendering context. * + *

This method sets the material's color, lighting properties, and binds any associated + * textures to the rendering context. + * * @param g The {@link Graphics} instance to apply this material to. */ public void apply(Graphics g) { @@ -208,16 +133,55 @@ public void apply(Graphics g) { * Releases this material's properties from the rendering context, useful for cleaning up shaders * or material-specific settings. * + *

This method unbinds textures and resets any material properties set during the rendering + * process to ensure the rendering context is restored to a neutral state. + * * @param g The {@link Graphics} instance from which this material will be unbound. */ public void release(Graphics g) { // Logic for releasing or resetting rendering context goes here } + /** + * Checks whether lighting effects are enabled for this material. + * + * @return {@code true} if lighting is used; {@code false} otherwise. + */ public boolean isUseLighting() { return useLighting; } + /** + * Sets whether this material should use lighting effects during rendering. + * + * @param useLighting {@code true} to enable lighting; {@code false} to disable. + */ + public void setUseLighting(boolean useLighting) { + this.useLighting = useLighting; + } + + /** + * Returns the name of the material. + * + * @return The name of the material as a String. + */ + public String getName() { + return name; + } + + /** + * Sets the name of the material. + * + * @param name The new name of the material. + * @throws IllegalArgumentException If the name is null. + */ + public void setName(String name) { + if (name == null) { + throw new IllegalArgumentException("Material name cannot be null."); + } + this.name = name; + } + /** * Retrieves the base color of the material. * @@ -227,6 +191,19 @@ public Color getColor() { return color; } + /** + * Sets the base color of the material. + * + * @param color The new base color to set. + * @throws IllegalArgumentException If color is null. + */ + public void setColor(Color color) { + if (color == null) { + throw new IllegalArgumentException("Color cannot be null."); + } + this.color = color; + } + /** * Retrieves the ambient light coefficient of the material. * @@ -236,6 +213,15 @@ public float[] getAmbient() { return ambient; } + /** + * Sets the ambient light coefficient of the material. + * + * @param ambient An array representing the new ambient light coefficient (R, G, B). + */ + public void setAmbient(float[] ambient) { + this.ambient = ambient; + } + /** * Retrieves the diffuse light coefficient of the material. * @@ -245,6 +231,15 @@ public float[] getDiffuse() { return diffuse; } + /** + * Sets the diffuse light coefficient of the material. + * + * @param diffuse An array representing the new diffuse light coefficient (R, G, B). + */ + public void setDiffuse(float[] diffuse) { + this.diffuse = diffuse; + } + /** * Retrieves the specular light coefficient of the material. * @@ -254,6 +249,15 @@ public float[] getSpecular() { return specular; } + /** + * Sets the specular light coefficient of the material. + * + * @param specular An array representing the new specular light coefficient (R, G, B). + */ + public void setSpecular(float[] specular) { + this.specular = specular; + } + /** * Retrieves the shininess factor of the material. * @@ -264,18 +268,47 @@ public float getShininess() { } /** - * Returns the diffuse texture map (map_Kd) of the material. + * Sets the shininess factor of the material. * - *

The diffuse texture is a 2D image used to define the base color and pattern of the surface, - * simulating the appearance of the material under diffuse lighting. This texture is typically - * applied using UV mapping to wrap the image onto the geometry of a 3D model. - * - *

In the context of material definition files (e.g., MTL for OBJ models), this corresponds to - * the `map_Kd` property, which specifies the file path to the texture image. + * @param shininess The new shininess factor to set. + */ + public void setShininess(float shininess) { + this.shininess = shininess; + } + + /** + * Returns the diffuse texture map (map_Kd) of the material. * * @return The diffuse texture map as {@link Texture}. */ public Texture getDiffuseTexture() { return diffuseTexture; } + + /** + * Sets the diffuse texture map (map_Kd) of the material. + * + * @param diffuseTexture The new diffuse texture map to set. + */ + public void setDiffuseTexture(Texture diffuseTexture) { + this.diffuseTexture = diffuseTexture; + } + + /** + * Returns the opacity texture map (map_d) of the material. + * + * @return The opacity texture map as {@link Texture}. + */ + public Texture getOpacityMap() { + return opacityMap; + } + + /** + * Sets the opacity texture map (map_d) of the material. + * + * @param opacityMap The new opacity texture map to set. + */ + public void setOpacityMap(Texture opacityMap) { + this.opacityMap = opacityMap; + } } diff --git a/src/main/java/engine/render/MaterialFactory.java b/src/main/java/engine/render/MaterialFactory.java index 24dd29ee..cce0403d 100644 --- a/src/main/java/engine/render/MaterialFactory.java +++ b/src/main/java/engine/render/MaterialFactory.java @@ -3,7 +3,7 @@ import math.Color; /** - * Factory class for creating predefined Material instances using a builder pattern. + * Factory class for creating predefined Material instances. * *

This class provides various predefined material configurations, such as metallic silver, * golden metallic, clear glass, stone grey, and water effects. Each material can be created through @@ -28,13 +28,13 @@ public class MaterialFactory { * @return A {@link Material} instance configured as metallic silver. */ public static Material createMetallicSilver() { - return new Material.Builder() - .setColor(new Color(0.75f, 0.75f, 0.75f)) - .setAmbient(new float[] {0.2f, 0.2f, 0.2f}) - .setDiffuse(new float[] {1.0f, 1.0f, 1.0f}) - .setSpecular(new float[] {1.0f, 1.0f, 1.0f}) - .setShininess(50.0f) - .build(); + Material material = new Material(); + material.setColor(new Color(0.75f, 0.75f, 0.75f)); + material.setAmbient(new float[] {0.2f, 0.2f, 0.2f}); + material.setDiffuse(new float[] {1.0f, 1.0f, 1.0f}); + material.setSpecular(new float[] {1.0f, 1.0f, 1.0f}); + material.setShininess(50.0f); + return material; } /** @@ -45,13 +45,13 @@ public static Material createMetallicSilver() { * @return A {@link Material} instance configured as golden metallic. */ public static Material createGoldenMetallic() { - return new Material.Builder() - .setColor(new Color(1.0f, 0.84f, 0.0f)) - .setAmbient(new float[] {0.3f, 0.3f, 0.3f}) - .setDiffuse(new float[] {1.0f, 0.84f, 0.0f}) - .setSpecular(new float[] {1.0f, 1.0f, 0.5f}) - .setShininess(100.0f) - .build(); + Material material = new Material(); + material.setColor(new Color(1.0f, 0.84f, 0.0f)); + material.setAmbient(new float[] {0.3f, 0.3f, 0.3f}); + material.setDiffuse(new float[] {1.0f, 0.84f, 0.0f}); + material.setSpecular(new float[] {1.0f, 1.0f, 0.5f}); + material.setShininess(100.0f); + return material; } /** @@ -62,13 +62,13 @@ public static Material createGoldenMetallic() { * @return A {@link Material} instance configured as clear glass. */ public static Material createGlassClear() { - return new Material.Builder() - .setColor(new Color(0.7f, 0.9f, 1.0f)) - .setAmbient(new float[] {0.3f, 0.3f, 0.3f}) - .setDiffuse(new float[] {0.8f, 0.8f, 0.8f}) - .setSpecular(new float[] {1.0f, 1.0f, 1.0f}) - .setShininess(5.0f) - .build(); + Material material = new Material(); + material.setColor(new Color(0.7f, 0.9f, 1.0f)); + material.setAmbient(new float[] {0.3f, 0.3f, 0.3f}); + material.setDiffuse(new float[] {0.8f, 0.8f, 0.8f}); + material.setSpecular(new float[] {1.0f, 1.0f, 1.0f}); + material.setShininess(5.0f); + return material; } /** @@ -80,13 +80,13 @@ public static Material createGlassClear() { * @return A {@link Material} instance configured as stone grey. */ public static Material createStoneGrey() { - return new Material.Builder() - .setColor(new Color(0.5f, 0.5f, 0.5f)) - .setAmbient(new float[] {0.4f, 0.4f, 0.4f}) - .setDiffuse(new float[] {0.6f, 0.6f, 0.6f}) - .setSpecular(new float[] {0.2f, 0.2f, 0.2f}) - .setShininess(10.0f) - .build(); + Material material = new Material(); + material.setColor(new Color(0.5f, 0.5f, 0.5f)); + material.setAmbient(new float[] {0.4f, 0.4f, 0.4f}); + material.setDiffuse(new float[] {0.6f, 0.6f, 0.6f}); + material.setSpecular(new float[] {0.2f, 0.2f, 0.2f}); + material.setShininess(10.0f); + return material; } /** @@ -98,12 +98,12 @@ public static Material createStoneGrey() { * @return A {@link Material} instance configured as water. */ public static Material createWater() { - return new Material.Builder() - .setColor(new Color(0.0f, 0.5f, 1.0f)) - .setAmbient(new float[] {0.1f, 0.3f, 0.5f}) - .setDiffuse(new float[] {0.3f, 0.5f, 0.7f}) - .setSpecular(new float[] {0.2f, 0.2f, 0.6f}) - .setShininess(2.0f) - .build(); + Material material = new Material(); + material.setColor(new Color(0.0f, 0.5f, 1.0f)); + material.setAmbient(new float[] {0.1f, 0.3f, 0.5f}); + material.setDiffuse(new float[] {0.3f, 0.5f, 0.7f}); + material.setSpecular(new float[] {0.2f, 0.2f, 0.6f}); + material.setShininess(2.0f); + return material; } } diff --git a/src/main/java/engine/resources/Font.java b/src/main/java/engine/resources/Font.java new file mode 100644 index 00000000..41c7b4a7 --- /dev/null +++ b/src/main/java/engine/resources/Font.java @@ -0,0 +1,108 @@ +package engine.resources; + +import java.util.Objects; + +/** + * Represents a font, including its name, size, and style. + * + *

The {@link Font} class encapsulates the characteristics of a font that can be used for text + * rendering. It includes properties for the font's name, size, and style (plain, bold, or italic). + * The font is immutable, meaning its properties cannot be modified after instantiation. + * + *

Font objects are typically used to define the appearance of text in a rendering context, where + * the font's name specifies the typeface, the size defines the text size, and the style determines + * whether the text is rendered in plain, bold, or italic form. + * + *

Font style constants are provided for ease of use: + * + *

    + *
  • {@link #PLAIN} - Represents a normal, unstyled font. + *
  • {@link #BOLD} - Represents a bold font style. + *
  • {@link #ITALIC} - Represents an italic font style. + *
+ */ +public class Font { + + // Font style constants + public static final int PLAIN = 0; + public static final int BOLD = 1; + public static final int ITALIC = 2; + + private final String name; + private final int size; + private final int style; + + /** + * Constructs a {@link Font} object with the specified name, size, and style. + * + *

This constructor allows you to create a font with a specific typeface, size, and style. If + * you need a plain font, you can use the {@link #PLAIN} constant; for bold or italic fonts, use + * the {@link #BOLD} or {@link #ITALIC} constants, respectively. + * + * @param name The name of the font (e.g., "Arial", "Times New Roman"). + * @param size The size of the font in points. + * @param style The style of the font, which can be one of the following: {@link #PLAIN}, {@link + * #BOLD}, or {@link #ITALIC}. + */ + public Font(String name, int size, int style) { + this.name = name; + this.size = size; + this.style = style; + } + + /** + * Retrieves the name of the font. + * + * @return The name of the font (e.g., "Arial"). + */ + public String getName() { + return name; + } + + /** + * Retrieves the size of the font. + * + * @return The size of the font in points. + */ + public int getSize() { + return size; + } + + /** + * Retrieves the style of the font. + * + * @return The style of the font, which can be one of the following: {@link #PLAIN}, {@link + * #BOLD}, or {@link #ITALIC}. + */ + public int getStyle() { + return style; + } + + /** + * Computes a hash code for this {@link Font} object based on its name, size, and style. + * + * @return The hash code for this font. + */ + @Override + public int hashCode() { + return Objects.hash(name, size, style); + } + + /** + * Compares this {@link Font} object to another object for equality. + * + *

This method returns {@code true} if the specified object is a {@link Font} and has the same + * name, size, and style as this font. Otherwise, it returns {@code false}. + * + * @param obj The object to compare this font to. + * @return {@code true} if the object is equal to this font, {@code false} otherwise. + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + Font other = (Font) obj; + return Objects.equals(name, other.name) && size == other.size && style == other.style; + } +} diff --git a/src/main/java/mesh/creator/primitives/PlaneCreator.java b/src/main/java/mesh/creator/primitives/PlaneCreator.java index 7ecdf2ca..78d38449 100644 --- a/src/main/java/mesh/creator/primitives/PlaneCreator.java +++ b/src/main/java/mesh/creator/primitives/PlaneCreator.java @@ -6,59 +6,58 @@ public class PlaneCreator implements IMeshCreator { - private float radius; - - private Mesh3D mesh; - - public PlaneCreator() { - this(1); - } - - public PlaneCreator(float radius) { - this.radius = radius; - } - - @Override - public Mesh3D create() { - initializeMesh(); - createVertices(); - createFace(); - return mesh; - } - - private void initializeMesh() { - mesh = new Mesh3D(); - } - - private void createVertices() { - addVertex(+radius, 0, -radius); - addVertex(+radius, 0, +radius); - addVertex(-radius, 0, +radius); - addVertex(-radius, 0, -radius); - } - - private void addVertex(float x, float y, float z) { - mesh.addVertex(x, y, z); - } - - private void createFace() { - mesh.add(new Face3D(0, 1, 2, 3)); - } - - public float getRadius() { - return radius; - } - - public void setRadius(float radius) { - this.radius = radius; - } - - public float getSize() { - return radius * 2; - } - - public void setSize(float size) { - setRadius(size * 0.5f); - } - + private float radius; + + private Mesh3D mesh; + + public PlaneCreator() { + this(1); + } + + public PlaneCreator(float radius) { + this.radius = radius; + } + + @Override + public Mesh3D create() { + initializeMesh(); + createVertices(); + createFace(); + return mesh; + } + + private void initializeMesh() { + mesh = new Mesh3D(); + } + + private void createVertices() { + addVertex(+radius, 0, -radius); + addVertex(+radius, 0, +radius); + addVertex(-radius, 0, +radius); + addVertex(-radius, 0, -radius); + } + + private void addVertex(float x, float y, float z) { + mesh.addVertex(x, y, z); + } + + private void createFace() { + mesh.add(new Face3D(0, 1, 2, 3)); + } + + public float getRadius() { + return radius; + } + + public void setRadius(float radius) { + this.radius = radius; + } + + public float getSize() { + return radius * 2; + } + + public void setSize(float size) { + setRadius(size * 0.5f); + } } diff --git a/src/main/java/mesh/creator/primitives/PlaneCreatorUV.java b/src/main/java/mesh/creator/primitives/PlaneCreatorUV.java new file mode 100644 index 00000000..5bad06dd --- /dev/null +++ b/src/main/java/mesh/creator/primitives/PlaneCreatorUV.java @@ -0,0 +1,138 @@ +package mesh.creator.primitives; + +import mesh.Face3D; +import mesh.Mesh3D; +import mesh.creator.IMeshCreator; + +/** + * A class for creating a 2D plane mesh centered at the origin. The plane lies on the XZ plane and + * is defined by its radius. + * + *

This creator is UV-ready and generates UV coordinates for the plane, mapping it to a texture + * space ranging from (0, 0) to (1, 1). + */ +public class PlaneCreatorUV implements IMeshCreator { + + /** The radius of the plane. Defines half the width and length of the plane. */ + private float radius; + + /** The mesh object that stores the geometry of the plane. */ + private Mesh3D mesh; + + /** Constructs a PlaneCreator with a default radius of 1. */ + public PlaneCreatorUV() { + this(1); + } + + /** + * Constructs a PlaneCreator with the specified radius. + * + * @param radius the radius of the plane + */ + public PlaneCreatorUV(float radius) { + this.radius = radius; + } + + /** + * Creates the mesh for the plane. + * + *

The resulting mesh includes vertices, a face, and UV coordinates for texture mapping. + * + * @return the generated {@link Mesh3D} object representing the plane + */ + @Override + public Mesh3D create() { + initializeMesh(); + createVertices(); + createUvCoordinates(); + createFace(); + return mesh; + } + + /** Initializes the mesh object to store the geometry. */ + private void initializeMesh() { + mesh = new Mesh3D(); + } + + /** + * Creates the vertices for the plane. The vertices are arranged in a clockwise order on the XZ + * plane. + */ + private void createVertices() { + addVertex(+radius, 0, -radius); // Top-right corner + addVertex(+radius, 0, +radius); // Bottom-right corner + addVertex(-radius, 0, +radius); // Bottom-left corner + addVertex(-radius, 0, -radius); // Top-left corner + } + + /** + * Creates UV coordinates for the plane's vertices. The UV coordinates map the plane to a texture + * space from (0, 0) to (1, 1). + * + *

Note: The `v` values are flipped because the Processing backend uses a texture coordinate + * system where `v = 0` is at the top and `v = 1` is at the bottom. + */ + private void createUvCoordinates() { + mesh.addUvCoordinate(1, 1); // Top-right + mesh.addUvCoordinate(1, 0); // Bottom-right + mesh.addUvCoordinate(0, 0); // Bottom-left + mesh.addUvCoordinate(0, 1); // Top-left + } + + /** + * Adds a vertex to the mesh. + * + * @param x the X coordinate of the vertex + * @param y the Y coordinate of the vertex + * @param z the Z coordinate of the vertex + */ + private void addVertex(float x, float y, float z) { + mesh.addVertex(x, y, z); + } + + /** + * Creates a single face for the plane. The face uses the vertices and UV coordinates in a + * clockwise order. + */ + private void createFace() { + int[] vertexIndices = new int[] {0, 1, 2, 3}; + int[] uvIndices = new int[] {0, 1, 2, 3}; + mesh.add(new Face3D(vertexIndices, uvIndices)); + } + + /** + * Returns the radius of the plane. + * + * @return the radius of the plane + */ + public float getRadius() { + return radius; + } + + /** + * Sets the radius of the plane. + * + * @param radius the new radius of the plane + */ + public void setRadius(float radius) { + this.radius = radius; + } + + /** + * Returns the size (width or length) of the plane. The size is twice the radius. + * + * @return the size of the plane + */ + public float getSize() { + return radius * 2; + } + + /** + * Sets the size (width or length) of the plane. The radius is set to half the size. + * + * @param size the new size of the plane + */ + public void setSize(float size) { + setRadius(size * 0.5f); + } +} diff --git a/src/main/java/workspace/GraphicsPImpl.java b/src/main/java/workspace/GraphicsPImpl.java index 30698d59..e206a7bf 100644 --- a/src/main/java/workspace/GraphicsPImpl.java +++ b/src/main/java/workspace/GraphicsPImpl.java @@ -4,10 +4,12 @@ import engine.processing.LightGizmoRenderer; import engine.processing.LightRendererImpl; +import engine.processing.ProcessingFontManager; import engine.processing.ProcessingTexture; import engine.processing.VBOProcessing; import engine.render.Material; import engine.resources.FilterMode; +import engine.resources.Font; import engine.resources.Image; import engine.resources.Texture; import engine.resources.TextureWrapMode; @@ -21,6 +23,7 @@ import mesh.Face3D; import mesh.Mesh3D; import processing.core.PApplet; +import processing.core.PFont; import processing.core.PGraphics; import processing.core.PImage; import processing.opengl.PGraphicsOpenGL; @@ -53,20 +56,11 @@ public class GraphicsPImpl implements Graphics { private ProcessingTexture texture; - @Override - public void setAmbientColor(math.Color ambientColor) { - this.ambientColor = ambientColor; - } + private Font font; - @Override - public math.Color getAmbientColor() { - return ambientColor; - } + private PFont pFont; - @Override - public void setWireframeMode(boolean wireframeMode) { - this.wireframeMode = wireframeMode; - } + private ProcessingFontManager fontManager; public GraphicsPImpl(PApplet p) { this.g = p.g; @@ -79,10 +73,27 @@ public GraphicsPImpl(PApplet p) { lightGizmoRenderer = new LightGizmoRenderer(p); lightGizmoRenderer.setGraphics(this); + fontManager = new ProcessingFontManager(p); + color = Color.BLACK; ambientColor = math.Color.WHITE; } + @Override + public void setAmbientColor(math.Color ambientColor) { + this.ambientColor = ambientColor; + } + + @Override + public math.Color getAmbientColor() { + return ambientColor; + } + + @Override + public void setWireframeMode(boolean wireframeMode) { + this.wireframeMode = wireframeMode; + } + @Override public void fillFaces(Mesh3D mesh) { faceCount += mesh.faces.size(); @@ -91,11 +102,11 @@ public void fillFaces(Mesh3D mesh) { g.noFill(); stroke(); // renderer.drawFaces(mesh); - drawMeshFaces(mesh); + drawMeshFaces(mesh, true); } else { g.noStroke(); fill(); - drawMeshFaces(mesh); + drawMeshFaces(mesh, true); } } @@ -103,7 +114,7 @@ public void fillFaces(Mesh3D mesh) { public void drawFaces(Mesh3D mesh) { g.noFill(); stroke(); - drawMeshFaces(mesh); + drawMeshFaces(mesh, false); } @Override @@ -115,7 +126,7 @@ public void draw(VBO vbo) { vboProcessing.draw(g); } - @Override + @Override // TODO remove or fix public void renderInstances(Mesh3D mesh, List instanceTransforms) { if (mesh.getFaces().isEmpty() || mesh.getVertices().isEmpty()) { return; @@ -126,7 +137,7 @@ public void renderInstances(Mesh3D mesh, List instanceTransforms) { for (Matrix4f transform : instanceTransforms) { g.pushMatrix(); applyTransform(transform); - drawMeshFaces(mesh); + drawMeshFaces(mesh, true); g.popMatrix(); } } @@ -153,6 +164,16 @@ private void applyTransform(Matrix4f transform) { matrix[15]); } + @Override + public void setFont(Font font) { + if (font == null) { + this.font = new Font("Lucida Sans", 12, Font.PLAIN); + } else { + this.font = font; + } + g.textFont(fontManager.loadFont(this.font)); + } + /** * Applies the specified texture to the current rendering context with the appropriate sampling * mode. @@ -235,7 +256,7 @@ private int getSamplingMode(FilterMode filterMode) { } } - private void drawMeshFaces(Mesh3D mesh) { + private void drawMeshFaces(Mesh3D mesh, boolean texture) { for (Face3D f : mesh.getFaces()) { if (f.indices.length == 3) { g.beginShape(PApplet.TRIANGLES); @@ -245,7 +266,7 @@ private void drawMeshFaces(Mesh3D mesh) { g.beginShape(PApplet.POLYGON); } - applyTexture(); + if (texture) applyTexture(); int[] indices = f.indices; for (int i = 0; i < indices.length; i++) { diff --git a/src/main/java/workspace/ui/Graphics2D.java b/src/main/java/workspace/ui/Graphics2D.java index 029d2bfc..0c3d86f3 100644 --- a/src/main/java/workspace/ui/Graphics2D.java +++ b/src/main/java/workspace/ui/Graphics2D.java @@ -1,5 +1,6 @@ package workspace.ui; +import engine.resources.Font; import engine.resources.Image; /** @@ -226,6 +227,19 @@ public interface Graphics2D { */ void text(String text, float x, float y); + /** + * Sets the current font used for text rendering operations. + * + *

This method changes the font that will be applied to subsequent text rendering commands. The + * provided {@link Font} object determines the style, weight, and size of the text that will be + * drawn on the rendering surface. + * + *

Passing a {@code null} value will reset the font to the default system font. + * + * @param font The {@link Font} to set. If {@code null}, the default font will be used. + */ + void setFont(Font font); + /** * Clears the rendering context with the specified color. * diff --git a/src/main/resources/fonts/monogram/bitmap/monogram-bitfontmaker.json b/src/main/resources/fonts/monogram/bitmap/monogram-bitfontmaker.json new file mode 100644 index 00000000..a1b7b65c --- /dev/null +++ b/src/main/resources/fonts/monogram/bitmap/monogram-bitfontmaker.json @@ -0,0 +1 @@ +{"33":[0,0,0,0,0,16,16,16,16,16,0,16,0,0,0,0],"34":[0,0,0,0,0,40,40,40,0,0,0,0,0,0,0,0],"35":[0,0,0,0,0,0,40,124,40,40,124,40,0,0,0,0],"36":[0,0,0,0,0,16,120,20,56,80,60,16,0,0,0,0],"37":[0,0,0,0,0,68,68,32,16,8,68,68,0,0,0,0],"38":[0,0,0,0,0,24,36,36,120,36,36,88,0,0,0,0],"39":[0,0,0,0,0,16,16,16,0,0,0,0,0,0,0,0],"40":[0,0,0,0,0,32,16,16,16,16,16,32,0,0,0,0],"41":[0,0,0,0,0,8,16,16,16,16,16,8,0,0,0,0],"42":[0,0,0,0,0,0,16,84,56,84,16,0,0,0,0,0],"43":[0,0,0,0,0,0,16,16,124,16,16,0,0,0,0,0],"44":[0,0,0,0,0,0,0,0,0,0,16,16,8,0,0,0],"45":[0,0,0,0,0,0,0,0,124,0,0,0,0,0,0,0],"46":[0,0,0,0,0,0,0,0,0,0,16,16,0,0,0,0],"47":[0,0,0,0,0,64,64,32,16,8,4,4,0,0,0,0],"48":[0,0,0,0,0,56,68,100,84,76,68,56,0,0,0,0],"49":[0,0,0,0,0,16,24,16,16,16,16,124,0,0,0,0],"50":[0,0,0,0,0,56,68,64,32,16,8,124,0,0,0,0],"51":[0,0,0,0,0,56,68,64,48,64,68,56,0,0,0,0],"52":[0,0,0,0,0,72,72,68,124,64,64,64,0,0,0,0],"53":[0,0,0,0,0,124,4,60,64,64,68,56,0,0,0,0],"54":[0,0,0,0,0,56,4,4,60,68,68,56,0,0,0,0],"55":[0,0,0,0,0,124,64,64,32,16,16,16,0,0,0,0],"56":[0,0,0,0,0,56,68,68,56,68,68,56,0,0,0,0],"57":[0,0,0,0,0,56,68,68,120,64,68,56,0,0,0,0],"58":[0,0,0,0,0,0,16,16,0,0,16,16,0,0,0,0],"59":[0,0,0,0,0,0,16,16,0,0,16,16,8,0,0,0],"60":[0,0,0,0,0,0,96,24,4,24,96,0,0,0,0,0],"61":[0,0,0,0,0,0,0,124,0,124,0,0,0,0,0,0],"62":[0,0,0,0,0,0,12,48,64,48,12,0,0,0,0,0],"63":[0,0,0,0,0,56,68,64,32,16,0,16,0,0,0,0],"64":[0,0,0,0,0,56,100,84,84,100,4,56,0,0,0,0],"65":[0,0,0,0,0,56,68,68,68,124,68,68,0,0,0,0],"66":[0,0,0,0,0,60,68,68,60,68,68,60,0,0,0,0],"67":[0,0,0,0,0,56,68,4,4,4,68,56,0,0,0,0],"68":[0,0,0,0,0,60,68,68,68,68,68,60,0,0,0,0],"69":[0,0,0,0,0,124,4,4,60,4,4,124,0,0,0,0],"70":[0,0,0,0,0,124,4,4,60,4,4,4,0,0,0,0],"71":[0,0,0,0,0,56,68,4,116,68,68,56,0,0,0,0],"72":[0,0,0,0,0,68,68,68,124,68,68,68,0,0,0,0],"73":[0,0,0,0,0,124,16,16,16,16,16,124,0,0,0,0],"74":[0,0,0,0,0,64,64,64,64,68,68,56,0,0,0,0],"75":[0,0,0,0,0,68,36,20,12,20,36,68,0,0,0,0],"76":[0,0,0,0,0,4,4,4,4,4,4,124,0,0,0,0],"77":[0,0,0,0,0,68,108,84,68,68,68,68,0,0,0,0],"78":[0,0,0,0,0,68,68,76,84,100,68,68,0,0,0,0],"79":[0,0,0,0,0,56,68,68,68,68,68,56,0,0,0,0],"80":[0,0,0,0,0,60,68,68,60,4,4,4,0,0,0,0],"81":[0,0,0,0,0,56,68,68,68,68,68,56,96,0,0,0],"82":[0,0,0,0,0,60,68,68,60,68,68,68,0,0,0,0],"83":[0,0,0,0,0,56,68,4,56,64,68,56,0,0,0,0],"84":[0,0,0,0,0,124,16,16,16,16,16,16,0,0,0,0],"85":[0,0,0,0,0,68,68,68,68,68,68,56,0,0,0,0],"86":[0,0,0,0,0,68,68,68,68,40,40,16,0,0,0,0],"87":[0,0,0,0,0,68,68,68,68,84,108,68,0,0,0,0],"88":[0,0,0,0,0,68,68,40,16,40,68,68,0,0,0,0],"89":[0,0,0,0,0,68,68,40,16,16,16,16,0,0,0,0],"90":[0,0,0,0,0,124,64,32,16,8,4,124,0,0,0,0],"91":[0,0,0,0,0,48,16,16,16,16,16,48,0,0,0,0],"92":[0,0,0,0,0,4,4,8,16,32,64,64,0,0,0,0],"93":[0,0,0,0,0,24,16,16,16,16,16,24,0,0,0,0],"94":[0,0,0,0,0,16,40,68,0,0,0,0,0,0,0,0],"95":[0,0,0,0,0,0,0,0,0,0,0,124,0,0,0,0],"96":[0,0,0,0,0,8,16,0,0,0,0,0,0,0,0,0],"97":[0,0,0,0,0,0,0,120,68,68,68,120,0,0,0,0],"98":[0,0,0,0,0,4,4,60,68,68,68,60,0,0,0,0],"99":[0,0,0,0,0,0,0,56,68,4,68,56,0,0,0,0],"100":[0,0,0,0,0,64,64,120,68,68,68,120,0,0,0,0],"101":[0,0,0,0,0,0,0,56,68,124,4,56,0,0,0,0],"102":[0,0,0,0,0,48,72,8,60,8,8,8,0,0,0,0],"103":[0,0,0,0,0,0,0,120,68,68,68,120,64,56,0,0],"104":[0,0,0,0,0,4,4,60,68,68,68,68,0,0,0,0],"105":[0,0,0,0,0,16,0,24,16,16,16,124,0,0,0,0],"106":[0,0,0,0,0,64,0,96,64,64,64,64,68,56,0,0],"107":[0,0,0,0,0,4,4,68,36,28,36,68,0,0,0,0],"108":[0,0,0,0,0,12,8,8,8,8,8,112,0,0,0,0],"109":[0,0,0,0,0,0,0,60,84,84,84,84,0,0,0,0],"110":[0,0,0,0,0,0,0,60,68,68,68,68,0,0,0,0],"111":[0,0,0,0,0,0,0,56,68,68,68,56,0,0,0,0],"112":[0,0,0,0,0,0,0,60,68,68,68,60,4,4,0,0],"113":[0,0,0,0,0,0,0,120,68,68,68,120,64,64,0,0],"114":[0,0,0,0,0,0,0,52,76,4,4,4,0,0,0,0],"115":[0,0,0,0,0,0,0,120,4,56,64,60,0,0,0,0],"116":[0,0,0,0,0,8,8,60,8,8,8,112,0,0,0,0],"117":[0,0,0,0,0,0,0,68,68,68,68,120,0,0,0,0],"118":[0,0,0,0,0,0,0,68,68,68,40,16,0,0,0,0],"119":[0,0,0,0,0,0,0,68,68,84,84,40,0,0,0,0],"120":[0,0,0,0,0,0,0,68,40,16,40,68,0,0,0,0],"121":[0,0,0,0,0,0,0,68,68,68,68,120,64,56,0,0],"122":[0,0,0,0,0,0,0,124,32,16,8,124,0,0,0,0],"123":[0,0,0,0,0,32,16,16,8,16,16,32,0,0,0,0],"124":[0,0,0,0,0,16,16,16,16,16,16,16,0,0,0,0],"125":[0,0,0,0,0,8,16,16,32,16,16,8,0,0,0,0],"126":[0,0,0,0,0,0,0,72,52,0,0,0,0,0,0,0],"161":[0,0,0,0,0,16,0,16,16,16,16,16,0,0,0,0],"162":[0,0,0,0,0,16,56,84,20,84,56,16,0,0,0,0],"163":[0,0,0,0,0,48,72,8,60,8,8,124,0,0,0,0],"164":[0,0,0,0,0,0,68,56,40,56,68,0,0,0,0,0],"165":[0,0,0,0,0,68,40,16,124,16,124,16,0,0,0,0],"166":[0,0,0,0,0,16,16,16,0,16,16,16,0,0,0,0],"167":[0,0,0,0,0,120,4,56,68,56,64,60,0,0,0,0],"168":[0,0,0,0,0,40,0,0,0,0,0,0,0,0,0,0],"169":[0,0,0,0,0,56,108,84,116,84,108,56,0,0,0,0],"170":[0,0,0,0,0,56,36,36,36,56,0,0,0,0,0,0],"171":[0,0,0,0,0,0,0,72,36,72,0,0,0,0,0,0],"172":[0,0,0,0,0,0,0,0,124,64,0,0,0,0,0,0],"174":[0,0,0,0,0,56,100,84,84,100,84,56,0,0,0,0],"175":[0,0,0,0,0,0,0,0,124,0,0,0,0,0,0,0],"176":[0,0,0,0,0,24,36,36,24,0,0,0,0,0,0,0],"177":[0,0,0,0,0,16,16,124,16,16,0,124,0,0,0,0],"178":[0,0,0,0,0,12,16,8,4,28,0,0,0,0,0,0],"179":[0,0,0,0,0,12,16,8,16,12,0,0,0,0,0,0],"180":[0,0,0,0,32,16,0,0,0,0,0,0,0,0,0,0],"181":[0,0,0,0,0,0,0,68,68,68,68,60,4,4,0,0],"182":[0,0,0,0,0,120,92,92,92,88,80,80,0,0,0,0],"183":[0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0],"184":[0,0,0,0,0,0,0,0,0,0,0,16,32,24,0,0],"185":[0,0,0,0,0,8,12,8,8,28,0,0,0,0,0,0],"186":[0,0,0,0,0,24,36,36,36,24,0,0,0,0,0,0],"187":[0,0,0,0,0,0,0,36,72,36,0,0,0,0,0,0],"188":[0,0,0,0,0,4,36,20,8,84,112,64,0,0,0,0],"189":[0,0,0,0,0,4,36,20,56,68,32,112,0,0,0,0],"190":[0,0,0,0,0,28,88,60,16,88,116,64,0,0,0,0],"191":[0,0,0,0,0,16,0,16,8,4,68,56,0,0,0,0],"192":[0,0,8,16,0,56,68,68,124,68,68,68,0,0,0,0],"193":[0,0,32,16,0,56,68,68,124,68,68,68,0,0,0,0],"194":[0,0,16,40,0,56,68,68,124,68,68,68,0,0,0,0],"195":[0,0,88,36,0,56,68,68,124,68,68,68,0,0,0,0],"196":[0,0,0,40,0,56,68,68,124,68,68,68,0,0,0,0],"197":[0,0,16,40,16,56,68,68,124,68,68,68,0,0,0,0],"198":[0,0,0,0,0,120,20,20,124,20,20,116,0,0,0,0],"199":[0,0,0,0,0,56,68,4,4,4,68,56,32,24,0,0],"200":[0,0,8,16,0,124,4,4,60,4,4,124,0,0,0,0],"201":[0,0,32,16,0,124,4,4,60,4,4,124,0,0,0,0],"202":[0,0,16,40,0,124,4,4,60,4,4,124,0,0,0,0],"203":[0,0,0,40,0,124,4,4,60,4,4,124,0,0,0,0],"204":[0,0,8,16,0,124,16,16,16,16,16,124,0,0,0,0],"205":[0,0,32,16,0,124,16,16,16,16,16,124,0,0,0,0],"206":[0,0,16,40,0,124,16,16,16,16,16,124,0,0,0,0],"207":[0,0,0,40,0,124,16,16,16,16,16,124,0,0,0,0],"208":[0,0,0,0,0,60,68,68,78,68,68,60,0,0,0,0],"209":[0,0,88,36,0,68,68,76,84,100,68,68,0,0,0,0],"210":[0,0,8,16,0,56,68,68,68,68,68,56,0,0,0,0],"211":[0,0,32,16,0,56,68,68,68,68,68,56,0,0,0,0],"212":[0,0,16,40,0,56,68,68,68,68,68,56,0,0,0,0],"213":[0,0,88,36,0,56,68,68,68,68,68,56,0,0,0,0],"214":[0,0,0,40,0,56,68,68,68,68,68,56,0,0,0,0],"215":[0,0,0,0,0,0,0,0,40,16,40,0,0,0,0,0],"216":[0,0,0,0,0,88,36,100,84,76,72,52,0,0,0,0],"217":[0,0,8,16,0,68,68,68,68,68,68,56,0,0,0,0],"218":[0,0,32,16,0,68,68,68,68,68,68,56,0,0,0,0],"219":[0,0,16,40,0,68,68,68,68,68,68,56,0,0,0,0],"220":[0,0,0,40,0,68,68,68,68,68,68,56,0,0,0,0],"221":[0,0,32,16,0,68,68,40,16,16,16,16,0,0,0,0],"222":[0,0,0,0,0,4,60,68,68,68,60,4,0,0,0,0],"223":[0,0,0,0,0,24,36,36,52,68,68,52,0,0,0,0],"224":[0,0,0,0,8,16,0,120,68,68,68,120,0,0,0,0],"225":[0,0,0,0,32,16,0,120,68,68,68,120,0,0,0,0],"226":[0,0,0,0,16,40,0,120,68,68,68,120,0,0,0,0],"227":[0,0,0,0,88,36,0,120,68,68,68,120,0,0,0,0],"228":[0,0,0,0,0,40,0,120,68,68,68,120,0,0,0,0],"229":[0,0,0,16,40,16,0,120,68,68,68,120,0,0,0,0],"230":[0,0,0,0,0,0,0,56,84,116,20,120,0,0,0,0],"231":[0,0,0,0,0,0,0,56,68,4,68,56,32,24,0,0],"232":[0,0,0,0,8,16,0,56,68,124,4,56,0,0,0,0],"233":[0,0,0,0,32,16,0,56,68,124,4,56,0,0,0,0],"234":[0,0,0,0,16,40,0,56,68,124,4,56,0,0,0,0],"235":[0,0,0,0,0,40,0,56,68,124,4,56,0,0,0,0],"236":[0,0,0,0,8,16,0,24,16,16,16,124,0,0,0,0],"237":[0,0,0,0,32,16,0,24,16,16,16,124,0,0,0,0],"238":[0,0,0,0,16,40,0,24,16,16,16,124,0,0,0,0],"239":[0,0,0,0,0,40,0,24,16,16,16,124,0,0,0,0],"240":[0,0,0,0,56,192,96,120,68,68,68,56,0,0,0,0],"241":[0,0,0,0,88,36,0,60,68,68,68,68,0,0,0,0],"242":[0,0,0,0,8,16,0,56,68,68,68,56,0,0,0,0],"243":[0,0,0,0,32,16,0,56,68,68,68,56,0,0,0,0],"244":[0,0,0,0,16,40,0,56,68,68,68,56,0,0,0,0],"245":[0,0,0,0,88,36,0,56,68,68,68,56,0,0,0,0],"246":[0,0,0,0,0,40,0,56,68,68,68,56,0,0,0,0],"247":[0,0,0,0,0,0,0,16,0,124,0,16,0,0,0,0],"248":[0,0,0,0,0,0,0,88,36,84,72,52,0,0,0,0],"249":[0,0,0,0,8,16,0,68,68,68,68,120,0,0,0,0],"250":[0,0,0,0,32,16,0,68,68,68,68,120,0,0,0,0],"251":[0,0,0,0,16,40,0,68,68,68,68,120,0,0,0,0],"252":[0,0,0,0,0,40,0,68,68,68,68,120,0,0,0,0],"253":[0,0,0,0,32,16,0,68,68,68,68,120,64,56,0,0],"254":[0,0,0,0,0,4,4,60,68,68,68,60,4,4,0,0],"255":[0,0,0,0,0,40,0,68,68,68,68,120,64,56,0,0],"256":[0,0,0,56,0,56,68,68,124,68,68,68,0,0,0,0],"257":[0,0,0,0,0,56,0,120,68,68,68,120,0,0,0,0],"258":[0,0,40,16,0,56,68,68,124,68,68,68,0,0,0,0],"259":[0,0,0,0,40,16,0,120,68,68,68,120,0,0,0,0],"260":[0,0,0,0,0,56,68,68,124,68,68,68,32,64,0,0],"261":[0,0,0,0,0,0,0,120,68,68,68,120,16,96,0,0],"262":[0,0,32,16,0,56,68,4,4,4,68,56,0,0,0,0],"263":[0,0,0,0,32,16,0,56,68,4,68,56,0,0,0,0],"264":[0,0,16,40,0,56,68,4,4,4,68,56,0,0,0,0],"265":[0,0,0,0,16,40,0,56,68,4,68,56,0,0,0,0],"266":[0,0,0,16,0,56,68,4,4,4,68,56,0,0,0,0],"267":[0,0,0,0,0,16,0,56,68,4,68,56,0,0,0,0],"268":[0,0,40,16,0,56,68,4,4,4,68,56,0,0,0,0],"269":[0,0,0,0,40,16,0,56,68,4,68,56,0,0,0,0],"270":[0,0,40,16,0,60,68,68,68,68,68,60,0,0,0,0],"271":[0,0,0,0,320,320,64,120,68,68,68,120,0,0,0,0],"272":[0,0,0,0,0,60,68,68,78,68,68,60,0,0,0,0],"273":[0,0,0,0,64,240,64,120,68,68,68,120,0,0,0,0],"274":[0,0,0,56,0,124,4,4,28,4,4,124,0,0,0,0],"275":[0,0,0,0,0,56,0,56,68,124,4,56,0,0,0,0],"276":[0,0,40,16,0,124,4,4,28,4,4,124,0,0,0,0],"277":[0,0,0,0,40,16,0,56,68,124,4,56,0,0,0,0],"278":[0,0,0,16,0,124,4,4,28,4,4,124,0,0,0,0],"279":[0,0,0,0,0,16,0,56,68,124,4,56,0,0,0,0],"280":[0,0,0,0,0,124,4,4,28,4,4,124,16,96,0,0],"281":[0,0,0,0,0,0,0,56,68,124,4,120,16,96,0,0],"282":[0,0,0,56,0,124,4,4,28,4,4,124,0,0,0,0],"283":[0,0,0,0,0,40,0,56,68,124,4,56,0,0,0,0],"284":[0,0,16,40,0,56,68,4,116,68,68,56,0,0,0,0],"285":[0,0,0,0,16,40,0,120,68,68,68,120,64,56,0,0],"286":[0,0,40,16,0,56,68,4,116,68,68,56,0,0,0,0],"287":[0,0,0,0,40,16,0,120,68,68,68,120,64,56,0,0],"288":[0,0,0,16,0,56,68,4,116,68,68,56,0,0,0,0],"289":[0,0,0,0,0,16,0,120,68,68,68,120,64,56,0,0],"290":[0,0,0,0,0,56,68,4,116,68,68,56,32,24,0,0],"291":[0,0,0,0,32,16,0,120,68,68,68,120,64,56,0,0],"292":[0,0,16,40,0,68,68,68,124,68,68,68,0,0,0,0],"293":[0,0,0,0,32,84,4,60,68,68,68,68,0,0,0,0],"294":[0,0,0,0,0,68,254,68,124,68,68,68,0,0,0,0],"295":[0,0,0,0,0,4,14,4,60,68,68,68,0,0,0,0],"296":[0,0,88,36,0,124,16,16,16,16,16,124,0,0,0,0],"297":[0,0,0,0,88,36,0,24,16,16,16,124,0,0,0,0],"298":[0,0,0,56,0,124,16,16,16,16,16,124,0,0,0,0],"299":[0,0,0,0,0,56,0,24,16,16,16,124,0,0,0,0],"300":[0,0,40,16,0,124,16,16,16,16,16,124,0,0,0,0],"301":[0,0,0,0,40,16,0,24,16,16,16,124,0,0,0,0],"302":[0,0,0,0,0,124,16,16,16,16,16,124,16,96,0,0],"303":[0,0,0,0,0,16,0,24,16,16,16,124,16,96,0,0],"304":[0,0,88,36,0,124,16,16,16,16,16,124,0,0,0,0],"305":[0,0,0,0,0,0,0,24,16,16,16,124,0,0,0,0],"306":[0,0,0,0,0,92,72,72,72,72,72,60,0,0,0,0],"307":[0,0,0,0,0,72,0,108,72,72,72,124,64,56,0,0],"308":[0,0,16,40,0,64,64,64,64,68,68,56,0,0,0,0],"309":[0,0,0,0,64,160,0,96,64,64,64,64,68,56,0,0],"310":[0,0,0,0,0,68,36,20,12,20,36,68,16,16,0,0],"311":[0,0,0,0,0,4,4,68,36,28,36,68,16,16,0,0],"312":[0,0,0,0,0,0,0,68,36,28,36,68,0,0,0,0],"313":[0,0,32,16,0,4,4,4,4,4,4,124,0,0,0,0],"314":[0,0,32,16,0,124,16,16,16,16,16,124,0,0,0,0],"315":[0,0,0,0,0,4,4,4,4,4,4,124,32,24,0,0],"316":[0,0,0,0,0,124,16,16,16,16,16,124,32,24,0,0],"317":[0,0,0,0,0,68,68,36,4,4,4,124,0,0,0,0],"318":[0,0,0,0,0,76,72,40,8,8,8,112,0,0,0,0],"319":[0,0,0,0,0,4,4,4,36,4,4,124,0,0,0,0],"320":[0,0,0,0,0,12,8,8,40,8,8,112,0,0,0,0],"321":[0,0,0,0,0,4,4,4,12,6,4,124,0,0,0,0],"322":[0,0,0,0,0,12,8,8,24,12,8,112,0,0,0,0],"323":[0,0,32,16,0,68,68,76,84,100,68,68,0,0,0,0],"324":[0,0,0,0,32,16,0,60,68,68,68,68,0,0,0,0],"325":[0,0,0,0,0,68,68,76,84,100,68,68,16,12,0,0],"326":[0,0,0,0,0,0,0,60,68,68,68,68,16,12,0,0],"327":[0,0,40,16,0,68,68,76,84,100,68,68,0,0,0,0],"328":[0,0,0,0,40,16,0,60,68,68,68,68,0,0,0,0],"329":[0,0,0,0,0,2,2,60,68,68,68,68,0,0,0,0],"330":[0,0,0,0,0,68,68,76,84,100,68,68,64,48,0,0],"331":[0,0,0,0,0,0,0,60,68,68,68,68,64,48,0,0],"332":[0,0,0,56,0,56,68,68,68,68,68,56,0,0,0,0],"333":[0,0,0,0,0,56,0,56,68,68,68,56,0,0,0,0],"334":[0,0,40,16,0,56,68,68,68,68,68,56,0,0,0,0],"335":[0,0,0,0,40,16,0,56,68,68,68,56,0,0,0,0],"336":[0,0,80,40,0,56,68,68,68,68,68,56,0,0,0,0],"337":[0,0,0,0,80,40,0,56,68,68,68,56,0,0,0,0],"338":[0,0,0,0,0,120,20,20,116,20,20,120,0,0,0,0],"339":[0,0,0,0,0,0,0,56,84,116,20,56,0,0,0,0],"340":[0,0,32,16,0,60,68,68,60,68,68,68,0,0,0,0],"341":[0,0,0,0,32,16,0,52,76,4,4,4,0,0,0,0],"342":[0,0,0,0,0,60,68,68,60,68,68,68,16,12,0,0],"343":[0,0,0,0,0,0,0,52,76,4,4,4,16,12,0,0],"344":[0,0,40,16,0,60,68,68,60,68,68,68,0,0,0,0],"345":[0,0,0,0,40,16,0,52,76,4,4,4,0,0,0,0],"346":[0,0,32,16,0,56,68,4,56,64,68,56,0,0,0,0],"347":[0,0,0,0,32,16,0,120,4,56,64,60,0,0,0,0],"348":[0,0,16,40,0,56,68,4,56,64,68,56,0,0,0,0],"349":[0,0,0,0,16,40,0,120,4,56,64,60,0,0,0,0],"350":[0,0,0,0,0,56,68,4,56,64,68,56,16,12,0,0],"351":[0,0,0,0,0,0,0,120,4,56,64,60,16,12,0,0],"352":[0,0,40,16,0,56,68,4,56,64,68,56,0,0,0,0],"353":[0,0,0,0,40,16,0,120,4,56,64,60,0,0,0,0],"354":[0,0,0,0,0,124,16,16,16,16,16,16,16,12,0,0],"355":[0,0,0,0,0,8,8,60,8,8,8,112,32,24,0,0],"356":[0,0,40,16,0,124,16,16,16,16,16,16,0,0,0,0],"357":[0,0,0,0,32,40,8,60,8,8,8,112,0,0,0,0],"358":[0,0,0,0,0,124,16,56,16,16,16,16,0,0,0,0],"359":[0,0,0,0,0,8,60,8,60,8,8,112,0,0,0,0],"360":[0,0,88,36,0,68,68,68,68,68,68,56,0,0,0,0],"361":[0,0,0,0,88,36,0,68,68,68,68,120,0,0,0,0],"362":[0,0,0,56,0,68,68,68,68,68,68,56,0,0,0,0],"363":[0,0,0,0,0,56,0,68,68,68,68,120,0,0,0,0],"364":[0,0,40,16,0,68,68,68,68,68,68,56,0,0,0,0],"365":[0,0,0,0,40,16,0,68,68,68,68,120,0,0,0,0],"366":[0,16,40,16,0,68,68,68,68,68,68,56,0,0,0,0],"367":[0,0,0,16,40,16,0,68,68,68,68,120,0,0,0,0],"368":[0,0,80,40,0,68,68,68,68,68,68,56,0,0,0,0],"369":[0,0,0,0,80,40,0,68,68,68,68,120,0,0,0,0],"370":[0,0,0,0,0,68,68,68,68,68,68,56,16,96,0,0],"371":[0,0,0,0,0,0,0,68,68,68,68,120,16,96,0,0],"372":[0,0,16,40,0,68,68,68,68,84,108,68,0,0,0,0],"373":[0,0,0,0,16,40,0,68,68,84,84,40,0,0,0,0],"374":[0,0,16,40,0,68,68,40,16,16,16,16,0,0,0,0],"375":[0,0,0,0,16,40,0,68,68,68,68,120,64,56,0,0],"376":[0,0,0,40,0,68,68,40,16,16,16,16,0,0,0,0],"377":[0,0,32,16,0,124,64,32,16,8,4,124,0,0,0,0],"378":[0,0,0,0,32,16,0,124,32,16,8,124,0,0,0,0],"379":[0,0,0,16,0,124,64,32,16,8,4,124,0,0,0,0],"380":[0,0,0,0,0,16,0,124,32,16,8,124,0,0,0,0],"381":[0,0,40,16,0,124,64,32,16,8,4,124,0,0,0,0],"382":[0,0,0,0,40,16,0,124,32,16,8,124,0,0,0,0],"1025":[0,0,0,40,0,124,4,4,60,4,4,124,0,0,0,0],"1040":[0,0,0,0,0,56,68,68,68,124,68,68,0,0,0,0],"1041":[0,0,0,0,0,124,4,4,60,68,68,60,0,0,0,0],"1042":[0,0,0,0,0,60,68,68,60,68,68,60,0,0,0,0],"1043":[0,0,0,0,0,124,4,4,4,4,4,4,0,0,0,0],"1044":[0,0,0,0,0,48,40,40,40,40,40,124,68,0,0,0],"1045":[0,0,0,0,0,124,4,4,60,4,4,124,0,0,0,0],"1046":[0,0,0,0,0,84,84,84,56,84,84,84,0,0,0,0],"1047":[0,0,0,0,0,56,68,64,56,64,68,56,0,0,0,0],"1048":[0,0,0,0,0,68,68,100,84,76,68,68,0,0,0,0],"1049":[0,0,0,40,16,68,68,100,84,76,68,68,0,0,0,0],"1050":[0,0,0,0,0,100,20,20,12,20,36,68,0,0,0,0],"1051":[0,0,0,0,0,120,72,72,72,72,72,68,0,0,0,0],"1052":[0,0,0,0,0,68,108,84,68,68,68,68,0,0,0,0],"1053":[0,0,0,0,0,68,68,68,124,68,68,68,0,0,0,0],"1054":[0,0,0,0,0,56,68,68,68,68,68,56,0,0,0,0],"1055":[0,0,0,0,0,124,68,68,68,68,68,68,0,0,0,0],"1056":[0,0,0,0,0,60,68,68,60,4,4,4,0,0,0,0],"1057":[0,0,0,0,0,56,68,4,4,4,68,56,0,0,0,0],"1058":[0,0,0,0,0,124,16,16,16,16,16,16,0,0,0,0],"1059":[0,0,0,0,0,68,68,68,68,120,64,56,0,0,0,0],"1060":[0,0,0,0,0,16,56,84,84,84,56,16,0,0,0,0],"1061":[0,0,0,0,0,68,68,40,16,40,68,68,0,0,0,0],"1062":[0,0,0,0,0,0,36,36,36,36,36,124,64,0,0,0],"1063":[0,0,0,0,0,68,68,68,120,64,64,64,0,0,0,0],"1064":[0,0,0,0,0,84,84,84,84,84,84,124,0,0,0,0],"1065":[0,0,0,0,0,84,84,84,84,84,84,124,64,0,0,0],"1066":[0,0,0,0,0,0,12,8,56,72,72,56,0,0,0,0],"1067":[0,0,0,0,0,0,68,68,76,84,84,76,0,0,0,0],"1068":[0,0,0,0,0,0,4,4,60,68,68,60,0,0,0,0],"1069":[0,0,0,0,0,56,68,64,112,64,68,56,0,0,0,0],"1070":[0,0,0,0,0,36,84,84,92,84,84,36,0,0,0,0],"1071":[0,0,0,0,0,0,120,68,68,120,68,68,0,0,0,0],"1072":[0,0,0,0,0,0,0,56,64,120,68,120,0,0,0,0],"1073":[0,0,0,0,0,120,4,52,76,68,68,56,0,0,0,0],"1074":[0,0,0,0,0,0,0,60,68,60,68,60,0,0,0,0],"1075":[0,0,0,0,0,0,0,124,4,4,4,4,0,0,0,0],"1076":[0,0,0,0,0,0,0,48,40,40,40,124,68,0,0,0],"1077":[0,0,0,0,0,0,0,56,68,124,4,56,0,0,0,0],"1078":[0,0,0,0,0,0,0,84,56,16,56,84,0,0,0,0],"1079":[0,0,0,0,0,0,0,24,36,16,36,24,0,0,0,0],"1080":[0,0,0,0,0,0,0,68,100,84,76,68,0,0,0,0],"1081":[0,0,0,0,0,40,16,68,100,84,76,68,0,0,0,0],"1082":[0,0,0,0,0,0,0,68,36,28,36,68,0,0,0,0],"1083":[0,0,0,0,0,0,0,120,72,72,72,68,0,0,0,0],"1084":[0,0,0,0,0,0,0,68,108,84,68,68,0,0,0,0],"1085":[0,0,0,0,0,0,0,68,68,124,68,68,0,0,0,0],"1086":[0,0,0,0,0,0,0,56,68,68,68,56,0,0,0,0],"1087":[0,0,0,0,0,0,0,124,68,68,68,68,0,0,0,0],"1088":[0,0,0,0,0,0,0,52,76,68,68,60,4,4,0,0],"1089":[0,0,0,0,0,0,0,56,68,4,68,56,0,0,0,0],"1090":[0,0,0,0,0,0,0,124,16,16,16,16,0,0,0,0],"1091":[0,0,0,0,0,0,0,68,68,68,68,120,64,56,0,0],"1092":[0,0,0,0,0,16,16,56,84,84,84,56,16,16,0,0],"1093":[0,0,0,0,0,0,0,68,40,16,40,68,0,0,0,0],"1094":[0,0,0,0,0,0,0,36,36,36,36,124,64,0,0,0],"1095":[0,0,0,0,0,0,0,68,68,68,120,64,0,0,0,0],"1096":[0,0,0,0,0,0,0,84,84,84,84,124,0,0,0,0],"1097":[0,0,0,0,0,0,0,84,84,84,84,124,64,0,0,0],"1098":[0,0,0,0,0,0,0,12,8,56,72,56,0,0,0,0],"1099":[0,0,0,0,0,0,0,68,68,76,84,76,0,0,0,0],"1100":[0,0,0,0,0,0,0,4,4,60,68,60,0,0,0,0],"1101":[0,0,0,0,0,0,0,56,68,112,68,56,0,0,0,0],"1102":[0,0,0,0,0,0,0,36,84,92,84,36,0,0,0,0],"1103":[0,0,0,0,0,0,0,120,68,68,120,68,0,0,0,0],"1105":[0,0,0,0,0,40,0,56,68,124,4,56,0,0,0,0],"8212":[0,0,0,0,0,0,0,0,124,0,0,0,0,0,0,0],"8217":[0,0,0,0,0,32,16,0,0,0,0,0,0,0,0,0],"8230":[0,0,0,0,0,0,0,0,0,0,84,84,0,0,0,0],"8364":[0,0,0,0,0,48,72,28,8,28,72,48,0,0,0,0],"8592":[0,0,0,0,0,0,0,16,120,124,120,16,0,0,0,0],"8593":[0,0,0,0,0,0,0,16,56,124,56,56,0,0,0,0],"8594":[0,0,0,0,0,0,0,16,60,124,60,16,0,0,0,0],"8595":[0,0,0,0,0,0,0,56,56,124,56,16,0,0,0,0],"name":"monogramextended","copy":"ViniciusMenezio","letterspace":"64","basefont_size":"512","basefont_left":"62","basefont_top":"0","basefont":"Arial","basefont2":"","monospace":true,"monospacewidth":"6"} \ No newline at end of file diff --git a/src/main/resources/fonts/monogram/bitmap/monogram-bitmap.json b/src/main/resources/fonts/monogram/bitmap/monogram-bitmap.json new file mode 100644 index 00000000..45949df0 --- /dev/null +++ b/src/main/resources/fonts/monogram/bitmap/monogram-bitmap.json @@ -0,0 +1,392 @@ +{ +"0":[0,0,0,14,17,25,21,19,17,14,0,0], +"1":[0,0,0,4,6,4,4,4,4,31,0,0], +"2":[0,0,0,14,17,16,8,4,2,31,0,0], +"3":[0,0,0,14,17,16,12,16,17,14,0,0], +"4":[0,0,0,18,18,17,31,16,16,16,0,0], +"5":[0,0,0,31,1,15,16,16,17,14,0,0], +"6":[0,0,0,14,1,1,15,17,17,14,0,0], +"7":[0,0,0,31,16,16,8,4,4,4,0,0], +"8":[0,0,0,14,17,17,14,17,17,14,0,0], +"9":[0,0,0,14,17,17,30,16,17,14,0,0], +"!":[0,0,0,4,4,4,4,4,0,4,0,0], +"\"":[0,0,0,10,10,10,0,0,0,0,0,0], +"#":[0,0,0,0,10,31,10,10,31,10,0,0], +"$":[0,0,0,4,30,5,14,20,15,4,0,0], +"%":[0,0,0,17,17,8,4,2,17,17,0,0], +"&":[0,0,0,6,9,9,30,9,9,22,0,0], +"'":[0,0,0,4,4,4,0,0,0,0,0,0], +"(":[0,0,0,8,4,4,4,4,4,8,0,0], +")":[0,0,0,2,4,4,4,4,4,2,0,0], +"*":[0,0,0,0,4,21,14,21,4,0,0,0], +"+":[0,0,0,0,4,4,31,4,4,0,0,0], +",":[0,0,0,0,0,0,0,0,4,4,2,0], +"-":[0,0,0,0,0,0,31,0,0,0,0,0], +".":[0,0,0,0,0,0,0,0,4,4,0,0], +"/":[0,0,0,16,16,8,4,2,1,1,0,0], +":":[0,0,0,0,4,4,0,0,4,4,0,0], +";":[0,0,0,0,4,4,0,0,4,4,2,0], +"<":[0,0,0,0,24,6,1,6,24,0,0,0], +"=":[0,0,0,0,0,31,0,31,0,0,0,0], +">":[0,0,0,0,3,12,16,12,3,0,0,0], +"?":[0,0,0,14,17,16,8,4,0,4,0,0], +"@":[0,0,0,14,25,21,21,25,1,14,0,0], +"A":[0,0,0,14,17,17,17,31,17,17,0,0], +"B":[0,0,0,15,17,17,15,17,17,15,0,0], +"C":[0,0,0,14,17,1,1,1,17,14,0,0], +"D":[0,0,0,15,17,17,17,17,17,15,0,0], +"E":[0,0,0,31,1,1,15,1,1,31,0,0], +"F":[0,0,0,31,1,1,15,1,1,1,0,0], +"G":[0,0,0,14,17,1,29,17,17,14,0,0], +"H":[0,0,0,17,17,17,31,17,17,17,0,0], +"I":[0,0,0,31,4,4,4,4,4,31,0,0], +"J":[0,0,0,16,16,16,16,17,17,14,0,0], +"K":[0,0,0,17,9,5,3,5,9,17,0,0], +"L":[0,0,0,1,1,1,1,1,1,31,0,0], +"M":[0,0,0,17,27,21,17,17,17,17,0,0], +"N":[0,0,0,17,17,19,21,25,17,17,0,0], +"O":[0,0,0,14,17,17,17,17,17,14,0,0], +"P":[0,0,0,15,17,17,15,1,1,1,0,0], +"Q":[0,0,0,14,17,17,17,17,17,14,24,0], +"R":[0,0,0,15,17,17,15,17,17,17,0,0], +"S":[0,0,0,14,17,1,14,16,17,14,0,0], +"T":[0,0,0,31,4,4,4,4,4,4,0,0], +"U":[0,0,0,17,17,17,17,17,17,14,0,0], +"V":[0,0,0,17,17,17,17,10,10,4,0,0], +"W":[0,0,0,17,17,17,17,21,27,17,0,0], +"X":[0,0,0,17,17,10,4,10,17,17,0,0], +"Y":[0,0,0,17,17,10,4,4,4,4,0,0], +"Z":[0,0,0,31,16,8,4,2,1,31,0,0], +"[":[0,0,0,12,4,4,4,4,4,12,0,0], +"\\":[0,0,0,1,1,2,4,8,16,16,0,0], +"]":[0,0,0,6,4,4,4,4,4,6,0,0], +"^":[0,0,0,4,10,17,0,0,0,0,0,0], +"_":[0,0,0,0,0,0,0,0,0,31,0,0], +"`":[0,0,0,2,4,0,0,0,0,0,0,0], +"a":[0,0,0,0,0,30,17,17,17,30,0,0], +"b":[0,0,0,1,1,15,17,17,17,15,0,0], +"c":[0,0,0,0,0,14,17,1,17,14,0,0], +"d":[0,0,0,16,16,30,17,17,17,30,0,0], +"e":[0,0,0,0,0,14,17,31,1,14,0,0], +"f":[0,0,0,12,18,2,15,2,2,2,0,0], +"g":[0,0,0,0,0,30,17,17,17,30,16,14], +"h":[0,0,0,1,1,15,17,17,17,17,0,0], +"i":[0,0,0,4,0,6,4,4,4,31,0,0], +"j":[0,0,0,16,0,24,16,16,16,16,17,14], +"k":[0,0,0,1,1,17,9,7,9,17,0,0], +"l":[0,0,0,3,2,2,2,2,2,28,0,0], +"m":[0,0,0,0,0,15,21,21,21,21,0,0], +"n":[0,0,0,0,0,15,17,17,17,17,0,0], +"o":[0,0,0,0,0,14,17,17,17,14,0,0], +"p":[0,0,0,0,0,15,17,17,17,15,1,1], +"q":[0,0,0,0,0,30,17,17,17,30,16,16], +"r":[0,0,0,0,0,13,19,1,1,1,0,0], +"s":[0,0,0,0,0,30,1,14,16,15,0,0], +"t":[0,0,0,2,2,15,2,2,2,28,0,0], +"u":[0,0,0,0,0,17,17,17,17,30,0,0], +"v":[0,0,0,0,0,17,17,17,10,4,0,0], +"w":[0,0,0,0,0,17,17,21,21,10,0,0], +"x":[0,0,0,0,0,17,10,4,10,17,0,0], +"y":[0,0,0,0,0,17,17,17,17,30,16,14], +"z":[0,0,0,0,0,31,8,4,2,31,0,0], +"{":[0,0,0,8,4,4,2,4,4,8,0,0], +"|":[0,0,0,4,4,4,4,4,4,4,0,0], +"}":[0,0,0,2,4,4,8,4,4,2,0,0], +"~":[0,0,0,0,0,18,13,0,0,0,0,0], +"¡":[0,0,0,4,0,4,4,4,4,4,0,0], +"¢":[0,0,0,4,14,21,5,21,14,4,0,0], +"£":[0,0,0,12,18,2,15,2,2,31,0,0], +"¤":[0,0,0,0,17,14,10,14,17,0,0,0], +"¥":[0,0,0,17,10,4,31,4,31,4,0,0], +"¦":[0,0,0,4,4,4,0,4,4,4,0,0], +"§":[0,0,0,30,1,14,17,14,16,15,0,0], +"¨":[0,0,0,10,0,0,0,0,0,0,0,0], +"©":[0,0,0,14,27,21,29,21,27,14,0,0], +"ª":[0,0,0,14,9,9,9,14,0,0,0,0], +"«":[0,0,0,0,0,18,9,18,0,0,0,0], +"¬":[0,0,0,0,0,0,31,16,0,0,0,0], +"®":[0,0,0,14,25,21,21,25,21,14,0,0], +"¯":[0,0,0,0,0,0,31,0,0,0,0,0], +"°":[0,0,0,6,9,9,6,0,0,0,0,0], +"±":[0,0,0,4,4,31,4,4,0,31,0,0], +"²":[0,0,0,3,4,2,1,7,0,0,0,0], +"³":[0,0,0,3,4,2,4,3,0,0,0,0], +"´":[0,0,8,4,0,0,0,0,0,0,0,0], +"µ":[0,0,0,0,0,17,17,17,17,15,1,1], +"¶":[0,0,0,30,23,23,23,22,20,20,0,0], +"·":[0,0,0,4,0,0,0,0,0,0,0,0], +"¸":[0,0,0,0,0,0,0,0,0,4,8,6], +"¹":[0,0,0,2,3,2,2,7,0,0,0,0], +"º":[0,0,0,6,9,9,9,6,0,0,0,0], +"»":[0,0,0,0,0,9,18,9,0,0,0,0], +"¼":[0,0,0,1,9,5,2,21,28,16,0,0], +"½":[0,0,0,1,9,5,14,17,8,28,0,0], +"¾":[0,0,0,7,22,15,4,22,29,16,0,0], +"¿":[0,0,0,4,0,4,2,1,17,14,0,0], +"À":[2,4,0,14,17,17,31,17,17,17,0,0], +"Á":[8,4,0,14,17,17,31,17,17,17,0,0], +"Â":[4,10,0,14,17,17,31,17,17,17,0,0], +"Ã":[22,9,0,14,17,17,31,17,17,17,0,0], +"Ä":[0,10,0,14,17,17,31,17,17,17,0,0], +"Å":[4,10,4,14,17,17,31,17,17,17,0,0], +"Æ":[0,0,0,30,5,5,31,5,5,29,0,0], +"Ç":[0,0,0,14,17,1,1,1,17,14,8,6], +"È":[2,4,0,31,1,1,15,1,1,31,0,0], +"É":[8,4,0,31,1,1,15,1,1,31,0,0], +"Ê":[4,10,0,31,1,1,15,1,1,31,0,0], +"Ë":[0,10,0,31,1,1,15,1,1,31,0,0], +"Ì":[2,4,0,31,4,4,4,4,4,31,0,0], +"Í":[8,4,0,31,4,4,4,4,4,31,0,0], +"Î":[4,10,0,31,4,4,4,4,4,31,0,0], +"Ï":[0,10,0,31,4,4,4,4,4,31,0,0], +"Ð":[0,0,0,15,17,17,19,17,17,15,0,0], +"Ñ":[22,9,0,17,17,19,21,25,17,17,0,0], +"Ò":[2,4,0,14,17,17,17,17,17,14,0,0], +"Ó":[8,4,0,14,17,17,17,17,17,14,0,0], +"Ô":[4,10,0,14,17,17,17,17,17,14,0,0], +"Õ":[22,9,0,14,17,17,17,17,17,14,0,0], +"Ö":[0,10,0,14,17,17,17,17,17,14,0,0], +"×":[0,0,0,0,0,0,10,4,10,0,0,0], +"Ø":[0,0,0,22,9,25,21,19,18,13,0,0], +"Ù":[2,4,0,17,17,17,17,17,17,14,0,0], +"Ú":[8,4,0,17,17,17,17,17,17,14,0,0], +"Û":[4,10,0,17,17,17,17,17,17,14,0,0], +"Ü":[0,10,0,17,17,17,17,17,17,14,0,0], +"Ý":[8,4,0,17,17,10,4,4,4,4,0,0], +"Þ":[0,0,0,1,15,17,17,17,15,1,0,0], +"ß":[0,0,0,6,9,9,13,17,17,13,0,0], +"à":[0,0,2,4,0,30,17,17,17,30,0,0], +"á":[0,0,8,4,0,30,17,17,17,30,0,0], +"â":[0,0,4,10,0,30,17,17,17,30,0,0], +"ã":[0,0,22,9,0,30,17,17,17,30,0,0], +"ä":[0,0,0,10,0,30,17,17,17,30,0,0], +"å":[0,4,10,4,0,30,17,17,17,30,0,0], +"æ":[0,0,0,0,0,14,21,29,5,30,0,0], +"ç":[0,0,0,0,0,14,17,1,17,14,8,6], +"è":[0,0,2,4,0,14,17,31,1,14,0,0], +"é":[0,0,8,4,0,14,17,31,1,14,0,0], +"ê":[0,0,4,10,0,14,17,31,1,14,0,0], +"ë":[0,0,0,10,0,14,17,31,1,14,0,0], +"ì":[0,0,2,4,0,6,4,4,4,31,0,0], +"í":[0,0,8,4,0,6,4,4,4,31,0,0], +"î":[0,0,4,10,0,6,4,4,4,31,0,0], +"ï":[0,0,0,10,0,6,4,4,4,31,0,0], +"ð":[0,0,14,48,24,30,17,17,17,14,0,0], +"ñ":[0,0,22,9,0,15,17,17,17,17,0,0], +"ò":[0,0,2,4,0,14,17,17,17,14,0,0], +"ó":[0,0,8,4,0,14,17,17,17,14,0,0], +"ô":[0,0,4,10,0,14,17,17,17,14,0,0], +"õ":[0,0,22,9,0,14,17,17,17,14,0,0], +"ö":[0,0,0,10,0,14,17,17,17,14,0,0], +"÷":[0,0,0,0,0,4,0,31,0,4,0,0], +"ø":[0,0,0,0,0,22,9,21,18,13,0,0], +"ù":[0,0,2,4,0,17,17,17,17,30,0,0], +"ú":[0,0,8,4,0,17,17,17,17,30,0,0], +"û":[0,0,4,10,0,17,17,17,17,30,0,0], +"ü":[0,0,0,10,0,17,17,17,17,30,0,0], +"ý":[0,0,8,4,0,17,17,17,17,30,16,14], +"þ":[0,0,0,1,1,15,17,17,17,15,1,1], +"ÿ":[0,0,0,10,0,17,17,17,17,30,16,14], +"Ā":[0,14,0,14,17,17,31,17,17,17,0,0], +"ā":[0,0,0,14,0,30,17,17,17,30,0,0], +"Ă":[10,4,0,14,17,17,31,17,17,17,0,0], +"ă":[0,0,10,4,0,30,17,17,17,30,0,0], +"Ą":[0,0,0,14,17,17,31,17,17,17,8,16], +"ą":[0,0,0,0,0,30,17,17,17,30,4,24], +"Ć":[8,4,0,14,17,1,1,1,17,14,0,0], +"ć":[0,0,8,4,0,14,17,1,17,14,0,0], +"Ĉ":[4,10,0,14,17,1,1,1,17,14,0,0], +"ĉ":[0,0,4,10,0,14,17,1,17,14,0,0], +"Ċ":[0,4,0,14,17,1,1,1,17,14,0,0], +"ċ":[0,0,0,4,0,14,17,1,17,14,0,0], +"Č":[10,4,0,14,17,1,1,1,17,14,0,0], +"č":[0,0,10,4,0,14,17,1,17,14,0,0], +"Ď":[10,4,0,15,17,17,17,17,17,15,0,0], +"ď":[0,0,80,80,16,30,17,17,17,30,0,0], +"Đ":[0,0,0,15,17,17,19,17,17,15,0,0], +"đ":[0,0,16,60,16,30,17,17,17,30,0,0], +"Ē":[0,14,0,31,1,1,7,1,1,31,0,0], +"ē":[0,0,0,14,0,14,17,31,1,14,0,0], +"Ĕ":[10,4,0,31,1,1,7,1,1,31,0,0], +"ĕ":[0,0,10,4,0,14,17,31,1,14,0,0], +"Ė":[0,4,0,31,1,1,7,1,1,31,0,0], +"ė":[0,0,0,4,0,14,17,31,1,14,0,0], +"Ę":[0,0,0,31,1,1,7,1,1,31,4,24], +"ę":[0,0,0,0,0,14,17,31,1,30,4,24], +"Ě":[0,14,0,31,1,1,7,1,1,31,0,0], +"ě":[0,0,0,10,0,14,17,31,1,14,0,0], +"Ĝ":[4,10,0,14,17,1,29,17,17,14,0,0], +"ĝ":[0,0,4,10,0,30,17,17,17,30,16,14], +"Ğ":[10,4,0,14,17,1,29,17,17,14,0,0], +"ğ":[0,0,10,4,0,30,17,17,17,30,16,14], +"Ġ":[0,4,0,14,17,1,29,17,17,14,0,0], +"ġ":[0,0,0,4,0,30,17,17,17,30,16,14], +"Ģ":[0,0,0,14,17,1,29,17,17,14,8,6], +"ģ":[0,0,8,4,0,30,17,17,17,30,16,14], +"Ĥ":[4,10,0,17,17,17,31,17,17,17,0,0], +"ĥ":[0,0,8,21,1,15,17,17,17,17,0,0], +"Ħ":[0,0,0,17,63,17,31,17,17,17,0,0], +"ħ":[0,0,0,1,3,1,15,17,17,17,0,0], +"Ĩ":[22,9,0,31,4,4,4,4,4,31,0,0], +"ĩ":[0,0,22,9,0,6,4,4,4,31,0,0], +"Ī":[0,14,0,31,4,4,4,4,4,31,0,0], +"ī":[0,0,0,14,0,6,4,4,4,31,0,0], +"Ĭ":[10,4,0,31,4,4,4,4,4,31,0,0], +"ĭ":[0,0,10,4,0,6,4,4,4,31,0,0], +"Į":[0,0,0,31,4,4,4,4,4,31,4,24], +"į":[0,0,0,4,0,6,4,4,4,31,4,24], +"İ":[22,9,0,31,4,4,4,4,4,31,0,0], +"ı":[0,0,0,0,0,6,4,4,4,31,0,0], +"IJ":[0,0,0,23,18,18,18,18,18,15,0,0], +"ij":[0,0,0,18,0,27,18,18,18,31,16,14], +"Ĵ":[4,10,0,16,16,16,16,17,17,14,0,0], +"ĵ":[0,0,16,40,0,24,16,16,16,16,17,14], +"Ķ":[0,0,0,17,9,5,3,5,9,17,4,4], +"ķ":[0,0,0,1,1,17,9,7,9,17,4,4], +"ĸ":[0,0,0,0,0,17,9,7,9,17,0,0], +"Ĺ":[8,4,0,1,1,1,1,1,1,31,0,0], +"ĺ":[8,4,0,31,4,4,4,4,4,31,0,0], +"Ļ":[0,0,0,1,1,1,1,1,1,31,8,6], +"ļ":[0,0,0,31,4,4,4,4,4,31,8,6], +"Ľ":[0,0,0,17,17,9,1,1,1,31,0,0], +"ľ":[0,0,0,19,18,10,2,2,2,28,0,0], +"Ŀ":[0,0,0,1,1,1,9,1,1,31,0,0], +"ŀ":[0,0,0,3,2,2,10,2,2,28,0,0], +"Ł":[0,0,0,1,1,1,3,1,1,31,0,0], +"ł":[0,0,0,3,2,2,6,3,2,28,0,0], +"Ń":[8,4,0,17,17,19,21,25,17,17,0,0], +"ń":[0,0,8,4,0,15,17,17,17,17,0,0], +"Ņ":[0,0,0,17,17,19,21,25,17,17,4,3], +"ņ":[0,0,0,0,0,15,17,17,17,17,4,3], +"Ň":[10,4,0,17,17,19,21,25,17,17,0,0], +"ň":[0,0,10,4,0,15,17,17,17,17,0,0], +"ʼn":[0,0,0,0,0,15,17,17,17,17,0,0], +"Ŋ":[0,0,0,17,17,19,21,25,17,17,16,12], +"ŋ":[0,0,0,0,0,15,17,17,17,17,16,12], +"Ō":[0,14,0,14,17,17,17,17,17,14,0,0], +"ō":[0,0,0,14,0,14,17,17,17,14,0,0], +"Ŏ":[10,4,0,14,17,17,17,17,17,14,0,0], +"ŏ":[0,0,10,4,0,14,17,17,17,14,0,0], +"Ő":[20,10,0,14,17,17,17,17,17,14,0,0], +"ő":[0,0,20,10,0,14,17,17,17,14,0,0], +"Œ":[0,0,0,30,5,5,29,5,5,30,0,0], +"œ":[0,0,0,0,0,14,21,29,5,14,0,0], +"Ŕ":[8,4,0,15,17,17,15,17,17,17,0,0], +"ŕ":[0,0,8,4,0,13,19,1,1,1,0,0], +"Ŗ":[0,0,0,15,17,17,15,17,17,17,4,3], +"ŗ":[0,0,0,0,0,13,19,1,1,1,4,3], +"Ř":[10,4,0,15,17,17,15,17,17,17,0,0], +"ř":[0,0,10,4,0,13,19,1,1,1,0,0], +"Ś":[8,4,0,14,17,1,14,16,17,14,0,0], +"ś":[0,0,8,4,0,30,1,14,16,15,0,0], +"Ŝ":[4,10,0,14,17,1,14,16,17,14,0,0], +"ŝ":[0,0,4,10,0,30,1,14,16,15,0,0], +"Ş":[0,0,0,14,17,1,14,16,17,14,4,3], +"ş":[0,0,0,0,0,30,1,14,16,15,4,3], +"Š":[10,4,0,14,17,1,14,16,17,14,0,0], +"š":[0,0,10,4,0,30,1,14,16,15,0,0], +"Ţ":[0,0,0,31,4,4,4,4,4,4,4,3], +"ţ":[0,0,0,2,2,15,2,2,2,28,8,6], +"Ť":[10,4,0,31,4,4,4,4,4,4,0,0], +"ť":[0,0,8,10,2,15,2,2,2,28,0,0], +"Ŧ":[0,0,0,31,4,14,4,4,4,4,0,0], +"ŧ":[0,0,0,2,15,2,15,2,2,28,0,0], +"Ũ":[22,9,0,17,17,17,17,17,17,14,0,0], +"ũ":[0,0,22,9,0,17,17,17,17,30,0,0], +"Ū":[0,14,0,17,17,17,17,17,17,14,0,0], +"ū":[0,0,0,14,0,17,17,17,17,30,0,0], +"Ŭ":[10,4,0,17,17,17,17,17,17,14,0,0], +"ŭ":[0,0,10,4,0,17,17,17,17,30,0,0], +"Ů":[10,4,0,17,17,17,17,17,17,14,0,0], +"ů":[0,4,10,4,0,17,17,17,17,30,0,0], +"Ű":[20,10,0,17,17,17,17,17,17,14,0,0], +"ű":[0,0,20,10,0,17,17,17,17,30,0,0], +"Ų":[0,0,0,17,17,17,17,17,17,14,4,24], +"ų":[0,0,0,0,0,17,17,17,17,30,4,24], +"Ŵ":[4,10,0,17,17,17,17,21,27,17,0,0], +"ŵ":[0,0,4,10,0,17,17,21,21,10,0,0], +"Ŷ":[4,10,0,17,17,10,4,4,4,4,0,0], +"ŷ":[0,0,4,10,0,17,17,17,17,30,16,14], +"Ÿ":[0,10,0,17,17,10,4,4,4,4,0,0], +"Ź":[8,4,0,31,16,8,4,2,1,31,0,0], +"ź":[0,0,8,4,0,31,8,4,2,31,0,0], +"Ż":[0,4,0,31,16,8,4,2,1,31,0,0], +"ż":[0,0,0,4,0,31,8,4,2,31,0,0], +"Ž":[10,4,0,31,16,8,4,2,1,31,0,0], +"ž":[0,0,10,4,0,31,8,4,2,31,0,0], +"Ё":[0,10,0,31,1,1,15,1,1,31,0,0], +"А":[0,0,0,14,17,17,17,31,17,17,0,0], +"Б":[0,0,0,31,1,1,15,17,17,15,0,0], +"В":[0,0,0,15,17,17,15,17,17,15,0,0], +"Г":[0,0,0,31,1,1,1,1,1,1,0,0], +"Д":[0,0,0,12,10,10,10,10,10,31,17,0], +"Е":[0,0,0,31,1,1,15,1,1,31,0,0], +"Ж":[0,0,0,21,21,21,14,21,21,21,0,0], +"З":[0,0,0,14,17,16,14,16,17,14,0,0], +"И":[0,0,0,17,17,25,21,19,17,17,0,0], +"Й":[0,10,4,17,17,25,21,19,17,17,0,0], +"К":[0,0,0,25,5,5,3,5,9,17,0,0], +"Л":[0,0,0,30,18,18,18,18,18,17,0,0], +"М":[0,0,0,17,27,21,17,17,17,17,0,0], +"Н":[0,0,0,17,17,17,31,17,17,17,0,0], +"О":[0,0,0,14,17,17,17,17,17,14,0,0], +"П":[0,0,0,31,17,17,17,17,17,17,0,0], +"Р":[0,0,0,15,17,17,15,1,1,1,0,0], +"С":[0,0,0,14,17,1,1,1,17,14,0,0], +"Т":[0,0,0,31,4,4,4,4,4,4,0,0], +"У":[0,0,0,17,17,17,17,30,16,14,0,0], +"Ф":[0,0,0,4,14,21,21,21,14,4,0,0], +"Х":[0,0,0,17,17,10,4,10,17,17,0,0], +"Ц":[0,0,0,0,9,9,9,9,9,31,16,0], +"Ч":[0,0,0,17,17,17,30,16,16,16,0,0], +"Ш":[0,0,0,21,21,21,21,21,21,31,0,0], +"Щ":[0,0,0,21,21,21,21,21,21,31,16,0], +"Ъ":[0,0,0,0,3,2,14,18,18,14,0,0], +"Ы":[0,0,0,0,17,17,19,21,21,19,0,0], +"Ь":[0,0,0,0,1,1,15,17,17,15,0,0], +"Э":[0,0,0,14,17,16,28,16,17,14,0,0], +"Ю":[0,0,0,9,21,21,23,21,21,9,0,0], +"Я":[0,0,0,0,30,17,17,30,17,17,0,0], +"а":[0,0,0,0,0,14,16,30,17,30,0,0], +"б":[0,0,0,30,1,13,19,17,17,14,0,0], +"в":[0,0,0,0,0,15,17,15,17,15,0,0], +"г":[0,0,0,0,0,31,1,1,1,1,0,0], +"д":[0,0,0,0,0,12,10,10,10,31,17,0], +"е":[0,0,0,0,0,14,17,31,1,14,0,0], +"ж":[0,0,0,0,0,21,14,4,14,21,0,0], +"з":[0,0,0,0,0,6,9,4,9,6,0,0], +"и":[0,0,0,0,0,17,25,21,19,17,0,0], +"й":[0,0,0,10,4,17,25,21,19,17,0,0], +"к":[0,0,0,0,0,17,9,7,9,17,0,0], +"л":[0,0,0,0,0,30,18,18,18,17,0,0], +"м":[0,0,0,0,0,17,27,21,17,17,0,0], +"н":[0,0,0,0,0,17,17,31,17,17,0,0], +"о":[0,0,0,0,0,14,17,17,17,14,0,0], +"п":[0,0,0,0,0,31,17,17,17,17,0,0], +"р":[0,0,0,0,0,13,19,17,17,15,1,1], +"с":[0,0,0,0,0,14,17,1,17,14,0,0], +"т":[0,0,0,0,0,31,4,4,4,4,0,0], +"у":[0,0,0,0,0,17,17,17,17,30,16,14], +"ф":[0,0,0,4,4,14,21,21,21,14,4,4], +"х":[0,0,0,0,0,17,10,4,10,17,0,0], +"ц":[0,0,0,0,0,9,9,9,9,31,16,0], +"ч":[0,0,0,0,0,17,17,17,30,16,0,0], +"ш":[0,0,0,0,0,21,21,21,21,31,0,0], +"щ":[0,0,0,0,0,21,21,21,21,31,16,0], +"ъ":[0,0,0,0,0,3,2,14,18,14,0,0], +"ы":[0,0,0,0,0,17,17,19,21,19,0,0], +"ь":[0,0,0,0,0,1,1,15,17,15,0,0], +"э":[0,0,0,0,0,14,17,28,17,14,0,0], +"ю":[0,0,0,0,0,9,21,23,21,9,0,0], +"я":[0,0,0,0,0,30,17,17,30,17,0,0], +"ё":[0,0,0,10,0,14,17,31,1,14,0,0], +"—":[0,0,0,0,0,0,31,0,0,0,0,0], +"’":[0,0,0,8,4,0,0,0,0,0,0,0], +"…":[0,0,0,0,0,0,0,0,21,21,0,0], +"€":[0,0,0,12,18,7,2,7,18,12,0,0], +"←":[0,0,0,0,0,4,30,31,30,4,0,0], +"↑":[0,0,0,0,0,4,14,31,14,14,0,0], +"→":[0,0,0,0,0,4,15,31,15,4,0,0], +"↓":[0,0,0,0,0,14,14,31,14,4,0,0], +" ":[0,0,0,0,0,0,0,0,0,0,0,0] +} \ No newline at end of file diff --git a/src/main/resources/fonts/monogram/bitmap/monogram-bitmap.png b/src/main/resources/fonts/monogram/bitmap/monogram-bitmap.png new file mode 100644 index 00000000..d9a99d47 Binary files /dev/null and b/src/main/resources/fonts/monogram/bitmap/monogram-bitmap.png differ diff --git a/src/main/resources/fonts/monogram/bitmap/monogram-italic-bitmap.png b/src/main/resources/fonts/monogram/bitmap/monogram-italic-bitmap.png new file mode 100644 index 00000000..8cdadacc Binary files /dev/null and b/src/main/resources/fonts/monogram/bitmap/monogram-italic-bitmap.png differ diff --git a/src/main/resources/fonts/monogram/credits.txt b/src/main/resources/fonts/monogram/credits.txt new file mode 100644 index 00000000..1c053aa9 --- /dev/null +++ b/src/main/resources/fonts/monogram/credits.txt @@ -0,0 +1,15 @@ +# CREDITS + +Monogram is a free and Creative Commons Zero pixel font, +made by Vinícius Menézio (@vmenezio). + +https://datagoblin.itch.io/monogram + + +# SPECIAL THANKS + +thanks to Ateş Göral (@atesgoral) for creating the bitmap font converter: +https://codepen.io/atesgoral/details/RwGOvPZ + +thanks to Éric Araujo (@merwok_) for the inital port of monogram to PICO-8: +https://itch.io/post/2625522 \ No newline at end of file diff --git a/src/main/resources/fonts/monogram/pico-8/monogram.p8 b/src/main/resources/fonts/monogram/pico-8/monogram.p8 new file mode 100644 index 00000000..426bfece --- /dev/null +++ b/src/main/resources/fonts/monogram/pico-8/monogram.p8 @@ -0,0 +1,184 @@ +pico-8 cartridge // http://www.pico-8.com +version 41 +__lua__ +-- monogram - A FREE FONT +-- BY vinicius menezio +-- datagoblin.itch.io/monogram +-- +-- (COPY SNIPPET IN TAB 1) +-- +-- SPECIAL THANKS TO merwok FOR +-- THE INITIAL PORT TO pico-8! + +function _init() + cls() + rect(2,2,125,125,1) + spr(1,56,56,2,2) + + -- load the font... + load_monogram() + -- ... then print whatever! + print("MONOGRAM\fc.P8",32,24,8) + print("A FREE FONT!",30,96,6) +end + +function _update() end +-->8 +-- load_monogram + +-- COPY SNIPPET BELOW +-- INTO YOUR OWN CART: + +function load_monogram() + -- enable custom fonts + poke(0x5f58,0x81) + + -- add font to memory + poke(0x5600,unpack(split"6,6,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,31,31,31,31,31,31,0,0,0,31,31,31,0,0,0,0,0,31,27,31,0,0,0,0,0,27,4,27,0,0,0,0,0,27,0,27,0,0,0,0,0,27,27,27,0,0,0,0,8,12,14,12,8,0,0,0,2,6,14,6,2,0,0,15,1,1,1,1,0,0,0,0,0,16,16,16,16,30,0,17,10,4,31,4,31,4,0,0,0,0,14,0,0,0,0,0,0,0,0,0,6,12,0,0,0,0,0,0,12,12,0,0,0,10,10,0,0,0,0,0,4,10,4,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,0,4,0,10,10,0,0,0,0,0,0,0,10,31,10,10,31,10,0,8,62,11,62,104,62,8,0,0,51,24,12,6,51,0,0,6,9,9,30,9,9,22,0,8,4,0,0,0,0,0,0,8,4,4,4,4,4,8,0,2,4,4,4,4,4,2,0,0,4,21,14,21,4,0,0,0,4,4,31,4,4,0,0,0,0,0,0,0,4,4,2,0,0,0,31,0,0,0,0,0,0,0,0,0,4,4,0,16,16,8,4,2,1,1,0,14,17,25,21,19,17,14,0,4,6,4,4,4,4,31,0,14,17,16,8,4,2,31,0,14,17,16,12,16,17,14,0,18,18,17,31,16,16,16,0,31,1,1,15,16,16,15,0,14,1,1,15,17,17,14,0,31,16,16,8,4,4,4,0,14,17,17,14,17,17,14,0,14,17,17,30,16,16,14,0,0,4,4,0,0,4,4,0,0,4,4,0,0,4,4,2,0,24,6,1,6,24,0,0,0,0,31,0,31,0,0,0,0,3,12,16,12,3,0,0,14,17,16,8,4,0,4,0,14,25,21,21,25,1,14,0,0,0,30,17,17,17,30,0,1,1,15,17,17,17,15,0,0,0,14,17,1,17,14,0,16,16,30,17,17,17,30,0,0,0,14,17,31,1,14,0,12,18,2,15,2,2,2,0,0,0,30,17,17,30,16,14,1,1,15,17,17,17,17,0,4,0,6,4,4,4,31,0,16,0,24,16,16,16,17,14,1,1,17,9,7,9,17,0,3,2,2,2,2,2,28,0,0,0,15,21,21,21,21,0,0,0,15,17,17,17,17,0,0,0,14,17,17,17,14,0,0,0,15,17,17,15,1,1,0,0,30,17,17,30,16,16,0,0,13,19,1,1,1,0,0,0,30,1,14,16,15,0,2,2,15,2,2,2,28,0,0,0,17,17,17,17,30,0,0,0,17,17,17,10,4,0,0,0,17,17,21,21,10,0,0,0,17,10,4,10,17,0,0,0,17,17,17,30,16,14,0,0,31,8,4,2,31,0,12,4,4,4,4,4,12,0,1,1,2,4,8,16,16,0,12,8,8,8,8,8,12,0,4,10,17,0,0,0,0,0,0,0,0,0,0,0,31,0,2,4,0,0,0,0,0,0,14,17,17,17,31,17,17,0,15,17,17,15,17,17,15,0,14,17,1,1,1,17,14,0,15,17,17,17,17,17,15,0,31,1,1,15,1,1,31,0,31,1,1,15,1,1,1,0,14,17,1,29,17,17,14,0,17,17,17,31,17,17,17,0,31,4,4,4,4,4,31,0,16,16,16,16,17,17,14,0,17,9,5,3,5,9,17,0,1,1,1,1,1,1,31,0,17,27,21,17,17,17,17,0,17,17,19,21,25,17,17,0,14,17,17,17,17,17,14,0,15,17,17,15,1,1,1,0,14,17,17,17,21,9,22,0,15,17,17,15,17,17,17,0,14,17,1,14,16,17,14,0,31,4,4,4,4,4,4,0,17,17,17,17,17,17,14,0,17,17,17,17,17,10,4,0,17,17,17,17,21,27,17,0,17,17,10,4,10,17,17,0,17,17,10,4,4,4,4,0,31,16,8,4,2,1,31,0,8,4,4,2,4,4,8,0,4,4,4,0,4,4,4,0,4,8,8,16,8,8,4,0,0,0,18,13,0,0,0,0,0,0,0,0,0,0,0,0,31,31,31,31,31,31,31,0,21,10,21,10,21,10,21,0,0,17,31,21,21,14,0,0,14,31,17,27,14,17,14,0,17,4,17,4,17,4,17,0,2,6,30,14,15,12,8,0,0,14,19,19,31,23,14,0,0,27,31,31,14,4,0,0,4,17,14,27,27,14,17,4,0,14,14,0,31,14,10,0,0,4,14,31,21,29,0,0,14,27,25,27,14,17,14,0,0,14,31,21,31,17,14,0,4,12,20,20,4,7,3,0,14,17,21,17,14,17,14,0,0,4,14,27,14,4,0,0,0,0,0,21,0,0,0,0,14,27,19,27,14,17,14,0,0,0,4,31,14,27,0,0,31,17,10,4,10,17,31,0,14,27,17,31,14,17,14,0,0,5,2,0,20,8,0,0,8,21,2,0,8,21,2,0,14,21,27,21,14,17,14,0,31,0,31,0,31,0,31,0,21,21,21,21,21,21,21,0")) +end +__gfx__ +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000002882000028820000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00700700088888800888888000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00077000288888888888888200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00077000888888888888888800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00700700888888888888888800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000888888888888888800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000288888888888888200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000088888888888888000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000008888888888880000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000888888888800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000088888888000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000008888880000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000888800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000088000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +__label__ +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ccc00000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000c0000000000000000000000000000100 +00100000000000000000000000000000888800088800888800088800088880808800088880888800000000cccc00c000c0000000000000000000000000000100 +00100000000000000000000000000000808080800080800080800080800080880080800080808080000000c000c00ccc00000000000000000000000000000100 +00100000000000000000000000000000808080800080800080800080800080800000800080808080000000c000c0c000c0000000000000000000000000000100 +0010000000000000000000000000000080808080008080008080008008888080000080008080808000c000cccc00c000c0000000000000000000000000000100 +0010000000000000000000000000000080808008880080008008880000008080000008888080808000c000c000000ccc00000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000088800000000000000000000000000c00000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000002882000028820000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000088888800888888000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000288888888888888200000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000888888888888888800000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000888888888888888800000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000888888888888888800000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000288888888888888200000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000088888888888888000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000008888888888880000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000888888888800000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000088888888000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000008888880000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000888800000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000660000000000000000000000000000660000000000000006000000600000000000000000000000000100 +00100000000000000000000000000000000000000006006000000000000000000000000006006000000000000006000000600000000000000000000000000100 +00100000000000000000000000000006666000000006000060660006660006660000000006000006660066660066660000600000000000000000000000000100 +00100000000000000000000000000060006000000066660066006060006060006000000066660060006060006006000000600000000000000000000000000100 +00100000000000000000000000000060006000000006000060000066666066666000000006000060006060006006000000600000000000000000000000000100 +00100000000000000000000000000060006000000006000060000060000060000000000006000060006060006006000000000000000000000000000000000100 +00100000000000000000000000000006666000000006000060000006660006660000000006000006660060006000666000600000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +00111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + diff --git a/src/main/resources/fonts/monogram/pico-8/monogram.p8.png b/src/main/resources/fonts/monogram/pico-8/monogram.p8.png new file mode 100644 index 00000000..70f2cf5d Binary files /dev/null and b/src/main/resources/fonts/monogram/pico-8/monogram.p8.png differ diff --git a/src/main/resources/fonts/monogram/ttf/monogram-extended-italic.ttf b/src/main/resources/fonts/monogram/ttf/monogram-extended-italic.ttf new file mode 100644 index 00000000..8c39014e Binary files /dev/null and b/src/main/resources/fonts/monogram/ttf/monogram-extended-italic.ttf differ diff --git a/src/main/resources/fonts/monogram/ttf/monogram-extended.ttf b/src/main/resources/fonts/monogram/ttf/monogram-extended.ttf new file mode 100644 index 00000000..e1debf0f Binary files /dev/null and b/src/main/resources/fonts/monogram/ttf/monogram-extended.ttf differ diff --git a/src/main/resources/fonts/monogram/ttf/monogram.ttf b/src/main/resources/fonts/monogram/ttf/monogram.ttf new file mode 100644 index 00000000..aceaebab Binary files /dev/null and b/src/main/resources/fonts/monogram/ttf/monogram.ttf differ