Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added getho_bold.ttf
Binary file not shown.
4 changes: 4 additions & 0 deletions gradleScripts/dependenciesClient.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,14 @@ dependencies {
implementation "org.lwjgl:lwjgl-openal"
implementation "org.lwjgl:lwjgl-opengl"
implementation "org.lwjgl:lwjgl-stb"
implementation "org.lwjgl:lwjgl-freetype"
implementation "org.lwjgl:lwjgl-harfbuzz"
runtimeOnly "org.lwjgl:lwjgl::$lwjglNatives"
runtimeOnly "org.lwjgl:lwjgl-glfw::$lwjglNatives"
runtimeOnly "org.lwjgl:lwjgl-nanovg::$lwjglNatives"
runtimeOnly "org.lwjgl:lwjgl-openal::$lwjglNatives"
runtimeOnly "org.lwjgl:lwjgl-opengl::$lwjglNatives"
runtimeOnly "org.lwjgl:lwjgl-stb::$lwjglNatives"
runtimeOnly "org.lwjgl:lwjgl-freetype::$lwjglNatives"
runtimeOnly "org.lwjgl:lwjgl-harfbuzz::$lwjglNatives"
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.terminalvelocitycabbage.engine.client.renderer.materials.TextureCache;
import com.terminalvelocitycabbage.engine.client.renderer.model.Mesh;
import com.terminalvelocitycabbage.engine.client.renderer.model.Model;
import com.terminalvelocitycabbage.engine.client.ui.Font;
import com.terminalvelocitycabbage.engine.client.window.InputCallbackListener;
import com.terminalvelocitycabbage.engine.client.window.WindowManager;
import com.terminalvelocitycabbage.engine.filesystem.resources.ResourceCategory;
Expand All @@ -32,10 +33,11 @@ public abstract class ClientBase extends MainEntrypoint implements NetworkedSide
private final WindowManager windowManager;
private final Registry<RenderGraph> renderGraphRegistry;

//Scene stuff
//Rendering stuff
protected final Registry<Mesh> meshRegistry;
protected final Registry<Model> modelRegistry;
protected TextureCache textureCache;
protected final Registry<Font> fontRegistry;

//Networking stuff
private final Client client;
Expand All @@ -55,6 +57,7 @@ public ClientBase(String namespace, int ticksPerSecond) {
inputCallbackListener = new InputCallbackListener();
meshRegistry = new Registry<>();
modelRegistry = new Registry<>();
fontRegistry = new Registry<>();
client = new Client();
}

Expand Down Expand Up @@ -92,6 +95,7 @@ public void init() {
eventDispatcher.dispatchEvent(new EntityComponentRegistrationEvent(manager));
eventDispatcher.dispatchEvent(new EntitySystemRegistrationEvent(manager));
eventDispatcher.dispatchEvent(new RoutineRegistrationEvent(routineRegistry));
eventDispatcher.dispatchEvent(new GenerateFontsEvent(fileSystem, fontRegistry));
var configureTexturesEvent = new ConfigureTexturesEvent(fileSystem);
eventDispatcher.dispatchEvent(configureTexturesEvent);
textureCache = new TextureCache(configureTexturesEvent.getTexturesToCompileToAtlas(), configureTexturesEvent.getSingleTextures());
Expand Down Expand Up @@ -216,4 +220,8 @@ public Registry<Model> getModelRegistry() {
public TextureCache getTextureCache() {
return textureCache;
}

public Registry<Font> getFontRegistry() {
return fontRegistry;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ public void init(GLCapabilities capabilities) {

initialized = true;
this.capabilities = capabilities;
graphNodes.forEach((identifier, togglePair) -> {
if (togglePair.getValue1() instanceof RenderNode renderNode) renderNode.init(this);
});
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package com.terminalvelocitycabbage.engine.client.renderer.materials;

import com.terminalvelocitycabbage.engine.client.ui.Font;
import com.terminalvelocitycabbage.engine.debug.Log;
import com.terminalvelocitycabbage.engine.util.ImageUtils;
import com.terminalvelocitycabbage.engine.util.MathUtils;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.util.freetype.FT_Bitmap;
import org.lwjgl.util.freetype.FreeType;

import java.io.File;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;

public class FontAtlas extends Texture {

private final Map<Integer, GlyphInfo> glyphMap = new HashMap<>();

public FontAtlas(Font font, int[] glyphIds) {

//Determine the likely size of atlas (cross the bridge when we get to it if we're wrong)
var atlasSize = MathUtils.findNearestPowerOfTwo((int) Math.ceil(Math.sqrt(font.getFontSize() * font.getFontSize() * glyphIds.length)));
this.width = atlasSize;
this.height = atlasSize;

//Create the buffer for this atlas
ByteBuffer atlasBuffer = ByteBuffer.allocateDirect(this.width * this.height);

int x = 0, y = 0, rowHeight = 0;
try (MemoryStack stack = MemoryStack.stackPush()) {
for (int glyphId : glyphIds) {
// Load glyph into FreeType
FreeType.FT_Load_Glyph(font.getFace(), glyphId, FreeType.FT_LOAD_RENDER);
FT_Bitmap bitmap = font.getFace().glyph().bitmap();

if (x + bitmap.width() >= getWidth()) {
x = 0;
y += rowHeight;
rowHeight = 0;
}

// Copy glyph bitmap into atlas
ByteBuffer bitmapBuffer = bitmap.buffer(bitmap.rows() * bitmap.pitch());
for (int row = 0; row < bitmap.rows(); row++) {
for (int col = 0; col < bitmap.width(); col++) {
atlasBuffer.put((y + row) * getWidth() + (x + col), bitmapBuffer.get(row * bitmap.pitch() + col));
}
}

// Record glyph info
glyphMap.put(glyphId, new GlyphInfo(x, y, bitmap.width(), bitmap.rows(), font.getFace().glyph().advance().x() / 64f));

x += bitmap.width() + 1;
rowHeight = Math.max(rowHeight, bitmap.rows());
}
}

// Upload to OpenGL
Log.info("generateOpenGLTexture");
generateOpenGLTexture(width, height, 4, atlasBuffer);

Log.info("Saving font atlas to file");
ImageUtils.saveRGBAtoPNG(atlasBuffer, width, height, new File("font_atlas.png"));
}

public GlyphInfo getGlyphInfo(int glyphId) {
return glyphMap.get(glyphId);
}

public record GlyphInfo(int x, int y, int width, int height, float xAdvance) { }

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.terminalvelocitycabbage.engine.client.renderer.materials;

import com.terminalvelocitycabbage.engine.client.ClientBase;
import com.terminalvelocitycabbage.engine.debug.Log;
import com.terminalvelocitycabbage.engine.filesystem.resources.Resource;
import com.terminalvelocitycabbage.engine.registry.Identifier;
Expand All @@ -18,22 +19,29 @@ public class TextureCache {

private final Map<Identifier, Resource> singleTextures;
private final Map<Identifier, Texture> generatedTextures;
private final Map<Identifier, Texture> fontAtlasTextures;

public TextureCache(Map<Identifier, Map<Identifier, Resource>> texturesToCompileToAtlas, Map<Identifier, Resource> singleTextures) {
this.generatedTextures = new HashMap<>();
this.texturesToCompileToAtlas = texturesToCompileToAtlas;

this.singleTextures = singleTextures;
this.generatedTextures = new HashMap<>();
this.fontAtlasTextures = new HashMap<>();
}

public void generateAtlas(Identifier atlasIdentifier) {
var textures = texturesToCompileToAtlas.get(atlasIdentifier);
var atlas = new Atlas(textures);
for (Identifier textureId : textures.keySet()) {
Log.info("Generating texture " + textureId + " for atlas " + atlasIdentifier);
this.generatedTextures.put(textureId, atlas);
}
}

public void generateFontAtlas(Identifier fontIdentifier, int[] glyphIds) {
Log.info("Generating font atlas for " + fontIdentifier);
this.fontAtlasTextures.put(fontIdentifier, new FontAtlas(ClientBase.getInstance().getFontRegistry().get(fontIdentifier), glyphIds));
}

/**
* @param texture The identifier for the texture you wish to retrieve from this cache
* @return The requested texture or null (in the future this will return a default texture)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package com.terminalvelocitycabbage.engine.client.ui;

import org.joml.Matrix4f;
import org.joml.Vector3f;

public class ContainerLayout extends Layout {

Anchor anchor;
PlacementDirection placementDirection;
JustifyChildren justifyChildren;

Matrix4f transformationMatrix;

public ContainerLayout(Dimension width, Dimension height, Anchor anchor, PlacementDirection placementDirection, JustifyChildren justifyChildren) {
super(width, height);
this.anchor = anchor;
this.placementDirection = placementDirection;
this.justifyChildren = justifyChildren;
}

public ContainerLayout(Dimension width, Dimension height) {
this(width, height, Anchor.CENTER_CENTER, PlacementDirection.CENTERED, JustifyChildren.CENTER);
}

public ContainerLayout(int width, int height) {
this(new Dimension(width, Unit.PIXELS), new Dimension(height, Unit.PIXELS));
}

@Override
public void setDimensions(int width, int height) {
super.setDimensions(width, height);
this.computedWidth = width;
this.computedHeight = height;
}

public enum Anchor {
TOP_LEFT(1, -1),
TOP_CENTER(1, 0),
TOP_RIGHT(1, 1),
CENTER_LEFT(0, -1),
CENTER_CENTER(0, 0),
CENTER_RIGHT(0, 1),
BOTTOM_LEFT( -1, -1),
BOTTOM_CENTER( -1, 0),
BOTTOM_RIGHT( -1, 1);

public int verticalMultiplier;
public int horizontalMultiplier;

Anchor(int verticalMultiplier, int horizontalMultiplier) {
this.verticalMultiplier = verticalMultiplier;
this.horizontalMultiplier = horizontalMultiplier;
}
}

public enum PlacementDirection {
DOWN_RIGHT(-0.5f, 0.5f),
DOWN(-0.5f, 0),
DOWN_LEFT(-0.5f, -0.5f),
RIGHT(0, 0.5f),
CENTERED(0, 0),
LEFT(0, -0.5f),
UP_RIGHT(0.5f, 0.5f),
UP(0.5f, 0),
UP_LEFT(0.5f, -0.5f);

float xMultiplier;
float yMultiplier;

PlacementDirection(float yOffset, float xOffset) {
this.xMultiplier = xOffset;
this.yMultiplier = yOffset;
}
}

public enum JustifyChildren {
TOP_LEFT(0.5f, -0.5f, PlacementDirection.DOWN_RIGHT),
TOP(0.5f, 0, PlacementDirection.DOWN),
TOP_RIGHT(0.5f, 0.5f, PlacementDirection.DOWN_LEFT),
LEFT(0, -0.5f, PlacementDirection.RIGHT),
CENTER(0, 0, PlacementDirection.CENTERED),
RIGHT(0, 0.5f, PlacementDirection.LEFT),
BOTTOM_LEFT( -0.5f, -0.5f, PlacementDirection.UP_RIGHT),
BOTTOM( -0.5f, 0, PlacementDirection.UP),
BOTTOM_RIGHT( -0.5f, 0.5f, PlacementDirection.UP_LEFT);

public float verticalMultiplier;
public float horizontalMultiplier;
public PlacementDirection placementDirection;

JustifyChildren(float verticalMultiplier, float horizontalMultiplier, PlacementDirection placementDirection) {
this.verticalMultiplier = verticalMultiplier;
this.horizontalMultiplier = horizontalMultiplier;
this.placementDirection = placementDirection;
}
}

@Override
public Matrix4f getTransformationMatrix(ContainerLayout currentContainerLayout, Layout previousElementLayout) {

transformationMatrix = new Matrix4f();

var pixelWidth = width.toPixelDimension(currentContainerLayout, true);
var pixelHeight = height.toPixelDimension(currentContainerLayout, false);

var containerPixelWidth = currentContainerLayout.getComputedWidth();
var containerPixelHeight = currentContainerLayout.getComputedHeight();

//Scale the object by its sizes
transformationMatrix.scale(pixelWidth, pixelHeight, 1);
//If the placement direction is not center, we want to move by half each dimension in the placement directions
//This is so that once we scale it'll already be in the right place
transformationMatrix.translateLocal(
placementDirection.xMultiplier * pixelWidth,
placementDirection.yMultiplier * pixelHeight,
0);

//Move the element to its proper location
var parentTransformationMatrix = currentContainerLayout.getStoredTransformationMatrix();
transformationMatrix.translateLocal(
anchor.horizontalMultiplier * ((float) containerPixelWidth / 2),
anchor.verticalMultiplier * ((float) containerPixelHeight / 2),
0);
//TODO precompute this somehow because it currently results in a one frame delay of proper layout generation
if (parentTransformationMatrix != null) transformationMatrix.translateLocal(parentTransformationMatrix.getTranslation(new Vector3f()));
return transformationMatrix;
}

public PlacementDirection getPlacementDirection() {
return placementDirection;
}

public Anchor getAnchor() {
return anchor;
}

public JustifyChildren getChildJustification() {
return justifyChildren;
}

public Matrix4f getStoredTransformationMatrix() {
return transformationMatrix;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.terminalvelocitycabbage.engine.client.ui;

import com.terminalvelocitycabbage.engine.registry.Identifier;

public final class Element {

private Identifier parent;
private Layout layout;
private Style style;

public Element(Identifier parent, Layout layout, Style style) {
this.parent = parent;
this.layout = layout;
this.style = style;
}

public void setParent(Identifier parent) {
this.parent = parent;
}

public Identifier getParent() {
return parent;
}

public Layout getLayout() {
return layout;
}

public Style getStyle() {
return style;
}

public void reset() {
layout.reset();
}

@Override
public String toString() {
return "Element{" +
"parent=" + parent +
", layout=" + layout.toString() +
", style=" + style.toString() +
'}';
}
}
Loading