Graphics API#
A commonly-seen feature among scripted vehicles is the inclusion of a passenger LCD screen, or some form of destination LED signs. But they aren't just any other texture slapped onto it, they have to be dynamically drawn in order to make it show the correct information in the player's world. How do they do it then?
The GraphicsTexture class allows you to create a texture of a fixed resolution, in which you can draw things dynamically with Java's AWT Graphics.
GraphicsTexture#
| Functions And Objects | Description |
|---|---|
new GraphicsTexture(width: int, height: int): GraphicsTexture |
Create a GraphicsTexture with width and height pixels.If you plan to draw contents related to per-block/per-train, you should use this in the create function and store in state. |
GraphicsTexture.identifier: Identifier |
The Identifier of the virtual resource of this dynamic texture. You can use this to replace the model texture/draw a texture with this id. |
GraphicsTexture.bufferedImage: BufferedImage |
Java AWT's BufferedImage for use as a temporary canvas. |
GraphicsTexture.graphics: Graphics2D |
This is the Java AWT's Graphics for this texture. You can call different functions to draw on the bufferedImage. |
GraphicsTexture.upload(): void |
Loads the contents of bufferedImage into video memory and immediately displays it on the model. This operation can significantly reduce FPS. It is recommended to use it in combination with RateLimit to reduce the frequency of texture updates.For example, the screen can be updated only 10 times per second, and it may not be updated at far distances, in some cases the information may not be updated at all. |
GraphicsTexture.upload(x: int, y: int, width: int, height: int): void |
Same as upload() but limited to a sub-region. See Sub-region texture uploading for detail. |
GraphicsTexture.close(): void |
Releases the memory used by this texture. It cannot be used after that. If it was created in the create train function, it must be deleted in the dispose function, otherwise it will continue to occupy memory, thus creating a memory leak. |
Binding the texture in-game#
After creating your GraphicsTexture (new GraphicsTexture...), JCM will tell Minecraft to register this texture with a specific ID (Randomly generated).
To access the ID, simply use GraphicsTexture.identifier.
When your script is in Runtime Stage, you can then invoke calls like QuadDrawCall, and set the texture id to GraphicsTexture.identifier, and it will render the texture out.
Note: After using AWT Graphics to draw things, you must invoke upload() for the texture data to be transferred to the game. See GraphicsTexture.upload() for details.
AWT-related classes#
You can use the importPackage function from Rhino to satisfy the java.awt dependency when using AWT classes.
You can find some AWT tutorials on the Internet or look at the JavaDoc to see what drawing capabilities are available in Graphics2D:
- JavaDoc: Graphics (is a parent class for Graphics2D, which means everything in it can be used in GraphicsTexture.graphics as well)
- JavaDoc: Graphics2D
The following functions can be used:
static Color.decode,Color.WHITE…,new ColorGraphics.setColor,Graphics.setFont,Graphics.setStroke(new BasicStroke(…))Graphics.drawRect,Graphics.fillRect,Graphics.drawRoundRect,Graphics.fillRoundRectGraphics.drawImage,Graphics.drawString,Font.deriveFontGraphics.setPaint(new GradientPaint(…)),Graphics.fill(new Rectangle(…))Graphics.getTransform,Graphics.transform,Graphics.setTransform,AffineTransform.getTranslateInstance,AffineTransform.getRotateInstanceGraphics.setClipGraphics.getComposite,Graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, …)),Graphics.setComposite
Advanced texture uploading#
Sub-region texture uploading#
When we run GraphicsTexture.upload(), we upload the full image for display in-game.
This is relatively intuitive to use, however for large resolution displays with frequent update, this may harm in-game performance. (In the main render thread, not only on the script thread)
Hence, an overload function of GraphicsTexture.upload(x: int, y: int, width: int, height: int) has been added. If you think your script is complex enough where texture uploading is seriously hurting performance, and that no other shortcuts/tradeoff can be made, you can use this to only update a certain region of the image. This way, the old content will be retained, and only the content within x, y, x+width and y+height will be uploaded.
Note that smart coordination among scripts may be needed on which region needs to be uploaded and when should it be uploaded, otherwise you may encounter graphical glitches where one part of the image may not be updated when they should be.