Skip to content

Surface ​

com.jsmacrosce.jsmacros.client.api.classes.render.components3d.Surface

Since1.6.5

A Draw2D panel rendered in the world. Its element coordinates are surface pixels measured from the top left, with y increasing downwards; surface size is in blocks, and getWidth() and getHeight() report pixel dimensions.

This is a 2D overlay living in three dimensions. It is a Draw2D in its own right, so everything a 2D overlay can hold, addText, addRect,
addLine, addImage, addItem and the rest, works on it unchanged, and the same builders do too. The difference is where the result appears:
a surface is placed at a block position in the world, rotated to face a direction,
and drawn as a flat surface there rather than flat on the screen. The coordinates a script gives its elements are the surface's own pixels, measured from its top left with y growing downwards, and how big a pixel is in blocks is decided by the size and the subdivision count rather than by the element.

A surface is reached through Draw3D, either with addDraw2D for the quick form or through Draw3D.surfaceBuilder() for the full one. A surface on its own draws nothing; it is the 3D overlay holding it that has to be registered.

Three settings decide whether it can be seen. cull makes it depth tested, so terrain draws over it; leaving it off draws the surface over the world instead.
renderBack decides whether the back is drawn at all, and with it off the surface disappears when the camera is behind it. And rotateToPlayer turns the surface to face the camera every frame, which overwrites whatever rotations were set.

Lighting is a fourth. By default everything on a surface is drawn at full brightness, ignoring the world. setWorldLight() samples the world instead,
once per frame at the surface's own position, and setLight(int, int) fixes a level. None of them model a cast shadow.

The size and the subdivision count work together rather than independently. The size is in blocks and the subdivision count says how many of those the smaller side is divided into, and one subdivision is the unit the elements are measured in. So a surface 1 block on a side with a subdivision count of 200 is 200 by 200 surface pixels, and the same surface at minSubdivisions of 1 is a single pixel. getWidth() and getHeight() report those subdivision counts, not the block size.

The two ways of making a surface do not start from the same place.
Draw3D.surfaceBuilder() leaves the count at 1, so a builder with nothing set on it gives a single pixel across its smaller side, while the short Draw3D.addDraw2D forms that take no subdivision count pass 200.

js
const draw = Hud.createDraw3D();  
// a one block panel with room for a label, drawn over the world
const surface = draw.surfaceBuilder()
  .pos(0.5, 64, 0.5)
  .size(1, 1)
  .minSubdivisions(200)
  .cull(false)
  .renderBack(true)
  .buildAndAdd();  
surface.addText("hello", 10, 10, Color.rgb(0xFF, 0xFF, 0xFF), true);  
draw.register();

Available in scripts as RenderElements.Surface.

Nested types ​

Constructors ​

new Surface ​

new Surface(Pos3D pos, Pos3D rotations, Pos2D sizes, int minSubdivisions, boolean renderBack, boolean cull)#
Initializes a surface with world position, rotations, block dimensions, and rendering options. The position and rotation are in world coordinates; the position is the panel's top-left corner, and rotation components are degrees. The three position objects are retained by reference and must be non-null. Subdivisions are clamped to at least 1; initialization computes the pixel scale and clears/runs the inherited initialization behavior, but does not add this surface to a Draw3D overlay.

Parameters:

  • pos: panel's top-left world position, in blocks
  • rotations: rotations about x, y, and z, in degrees
  • sizes: physical width and height, in blocks
  • minSubdivisions: subdivisions across the smaller side, clamped to at least 1
  • renderBack: whether to draw the surface when viewed from its back side
  • cull: whether depth testing against the world is enabled

Fields ​

boundEntity ​

boundEntity: EntityHelper<?>Since1.6.5#
Entity followed by this surface, or null if unbound. While alive, the surface uses the entity's interpolated position plus boundOffset; if the entity is no longer alive, rendering uses pos instead.

boundOffset ​

boundOffset: Pos3DSince1.6.5#
Offset in blocks added to the bound entity's interpolated position at render time. It has no effect when the surface is unbound.

cull ​

cull: booleanSince1.6.5#
Whether the surface is depth tested against the world. When false, it is drawn over the world instead.

pos ​

pos: Pos3DSince1.6.5read-only#
World position in blocks used when this surface is not following a live entity. It is the panel corner; rotateCenter changes the rotation pivot, not the position's meaning.

renderBack ​

renderBack: booleanSince1.6.5#
Whether the surface is drawn when the camera is on its back side. When false, rendering is skipped from that side.

rotateCenter ​

rotateCenter: booleanSince1.6.5#
Whether surface rotations pivot around the center rather than the corner. This also selects the pivot for camera-facing rotation. The field defaults to false; the builder defaults to true.

rotateToPlayer ​

rotateToPlayer: booleanSince1.6.5#
Whether the surface faces the camera during rendering. When enabled, the camera-derived angles overwrite rotations each frame; the pivot is controlled by rotateCenter.

rotations ​

rotations: Pos3DSince1.6.5read-only#
Surface rotations in degrees, applied in y, x, then z order. When rotateToPlayer is enabled, rendering overwrites these values each frame.

zIndexScale ​

zIndexScale: doubleSince1.6.5#
Scales each element's z-index into a rendering offset in blocks. Defaults to 0.001 blocks per z-index unit.

Methods ​

bindToEntity ​

bindToEntity(EntityHelper<?> boundEntity): SurfaceSince1.8.4#
Binds this surface to an entity; while that entity is alive, its interpolated position plus boundOffset determines the render position. Passing null unbinds it.

Parameters:

  • boundEntity: the entity to bind the surface to
Returns: self for chaining.

compareToSame ​

compareToSame(Surface other): intSince1.6.5#
Compares surfaces by position, then rotations, then size. Surfaces matching on all three compare equal; this compares those values, not spatial distance.

Parameters:

  • other: another surface to order this one against
Returns: a negative number, zero, or a positive number as this surface sorts before, equal to, or after other

doesRotateToPlayer ​

doesRotateToPlayer(): booleanSince1.8.4#
Returns: true if the surface is configured to face the camera

equals ​

equals(Object o): boolean#
Tests equality using the exact runtime class and the current position, rotations, and size only. These mutable values determine the result; subdivision and rendering settings are ignored.

Parameters:

  • o: object to compare
Returns: true if o is this surface or has the same runtime class and equal position, rotations, and size; false for null or a different class

getBoundEntity ​

getBoundEntity(): EntityHelper<?>Since1.8.4#
Returns the entity this surface follows, if any.
Returns: the bound entity, or null if none is set

getBoundOffset ​

getBoundOffset(): Pos3DSince1.8.4#
Returns the offset added to the bound entity's interpolated position, in blocks. The returned object is the surface's live offset; mutating it changes the offset.
Returns: the bound-entity offset

getHeight ​

getHeight(): intSince1.6.5#
Returns the surface height in pixels. The smaller side has getMinSubdivisions() pixels; the other side scales with the surface's aspect ratio. The result is truncated to an integer.
Returns: the height in surface pixels

getMinSubdivisions ​

getMinSubdivisions(): intSince1.6.5#
Returns the subdivision count across this surface's smaller side. This is the number of surface pixels across the smaller side, so it is what the element coordinates are measured in on that axis. It is never below 1.
Returns: the subdivision count across the smaller side

getSizes ​

getSizes(): Pos2DSince1.6.5#
Returns this surface's physical width and height in blocks. A copy rather than the surface's own size object, so writing to what this returns does not resize the surface. To change the size, use setSizes(double, double). These are blocks. The number of surface pixels the elements are measured in is getWidth() and getHeight(), which are subdivisions of this.
Returns: the size of this surface, in blocks

getWidth ​

getWidth(): intSince1.6.5#
Returns the surface width in pixels. The smaller side has getMinSubdivisions() pixels; the other side scales with the surface's aspect ratio. The result is truncated to an integer.
Returns: the width in surface pixels

getZIndex ​

getZIndex(): intSince1.6.5#
Surfaces do not use a z-index for ordering; this method always returns 0.
Returns: always 0

hashCode ​

hashCode(): int#
Computes a hash from the surface's current position, rotations, and size; changes to those mutable values can change the result.
Returns: hash code derived from the current position, rotations, and size

init ​

init(): voidSince1.6.5#
Recomputes the pixel scale, clears the elements, and runs the init function if set.

isRotatingCenter ​

isRotatingCenter(): booleanSince1.8.4#
Returns: whether rotations use the surface center as their pivot

render ​

render(GuiGraphics drawContext, int mouseX, int mouseY, float delta): void#
This override does nothing; it does not render the surface or use its arguments.

Parameters:

  • drawContext: graphics context, unused
  • mouseX: mouse x-coordinate, unused
  • mouseY: mouse y-coordinate, unused
  • delta: frame delta, unused

setBoundOffset ​

setBoundOffset(Pos3D boundOffset): SurfaceSince1.8.4#
Sets the entity-following offset by reference, in blocks.

Parameters:

  • boundOffset: offset from the entity's interpolated position
Returns: this surface for chaining
setBoundOffset(double x, double y, double z): SurfaceSince1.8.4#
Sets the offset added to the bound entity's interpolated position, in blocks. Has no effect while the surface is unbound. Replaces the offset object.

Parameters:

  • x: the x offset in blocks
  • y: the y offset in blocks
  • z: the z offset in blocks
Returns: this surface

setFullBrightLight ​

setFullBrightLight(): SurfaceSince2.0.0#
Makes all elements on this surface render at full brightness, ignoring world lighting.
Returns: self for chaining.

setLight ​

setLight(int blockLight, int skyLight): SurfaceSince2.0.0#
Sets fixed block and sky light levels for all elements on this surface.

Parameters:

  • blockLight: block light level, 0-15 (e.g. 15 next to a torch)
  • skyLight: sky light level, 0-15 (e.g. 15 outdoors in daylight)
Returns: self for chaining.

setMinSubdivisions ​

setMinSubdivisions(int minSubdivisions): voidSince1.6.5#
Sets the number of subdivisions across the smaller side of this surface. The count is across the smaller side; the larger side gets however many that works out to. A value of 0 or below is raised to 1, so a surface can be made to have a single pixel but never none. The pixel scale is recomputed after the count is set.

Parameters:

  • minSubdivisions: how many subdivisions the smaller side is divided into

setPos ​

setPos(Pos3D pos): SurfaceSince1.8.4#
Updates this surface's position coordinates from pos.

Parameters:

  • pos: position in world blocks
Returns: this surface for chaining
setPos(BlockPosHelper pos): SurfaceSince1.8.4#
Updates this surface's position coordinates from pos.

Parameters:

  • pos: block position in the world
Returns: this surface for chaining
setPos(double x, double y, double z): SurfaceSince1.6.5#
moves this surface to a point in the world. The coordinates are in blocks and are the panel's top left corner, not its middle, unless rotateCenter is on. The position object is written into rather than replaced, so a reference to pos keeps following the surface. This is ignored for rendering while the surface is bound to a live entity, since then the entity's own position is used instead.
const draw = Hud.createDraw3D();
const surface = draw.surfaceBuilder().pos(0, 64, 0).buildAndAdd();
surface.setPos(10, 70, -4);
draw.register();

Parameters:

  • x: the x coordinate of the surface's corner
  • y: the y coordinate of the surface's corner
  • z: the z coordinate of the surface's corner
Returns: self for chaining.

setRotateCenter ​

setRotateCenter(boolean rotateCenter): SurfaceSince1.8.4#

Parameters:

  • rotateCenter: whether rotations use the surface center rather than its corner as pivot
Returns: self for chaining.

setRotateToPlayer ​

setRotateToPlayer(boolean rotateToPlayer): SurfaceSince1.8.4#
Sets whether the surface is rotated to face the camera during rendering. When enabled, this overwrites the configured rotations each frame.

Parameters:

  • rotateToPlayer: whether to face the camera
Returns: this surface

setRotations ​

setRotations(double x, double y, double z): voidSince1.6.5#
Sets the surface's rotations in degrees. The rotations are applied in the order y, then x, then z, so the y rotation is the one that swings the panel around to face a compass direction and the other two tilt it. They turn about the panel's corner unless rotateCenter is on, in which case they turn about its middle. Angles are not range-clamped. These rotations are overwritten during rendering while rotateToPlayer is enabled.

Parameters:

  • x: the rotation about the x axis, in degrees
  • y: the rotation about the y axis, in degrees
  • z: the rotation about the z axis, in degrees

setSizes ​

setSizes(double x, double y): voidSince1.6.5#
Sets the surface's physical width and height in blocks. This is the physical size of the panel in the world, not how much room its elements have: the pixels they are measured in are subdivisions of this, so making the panel bigger with the subdivision count fixed gives each pixel more physical space. The size object is updated in place, and the pixel-to-block scale is recomputed.

Parameters:

  • x: the width of the surface, in blocks
  • y: the height of the surface, in blocks

setWorldLight ​

setWorldLight(): SurfaceSince2.0.0#
Makes elements use the block and sky light at the surface's render position, sampled each frame. Sky light is reduced by the world's sky darkening; cast shadows are not modelled. If no world is loaded, this uses full-bright lighting.
Returns: self for chaining.