Jump to content

[1.8] [SOLVED] Custom Painting is BLACK (front, back & sides, all black)


Recommended Posts

I've been following Jimi's custom painting travails with great interest. Unfortunately for me, I seem to have fallen into a pit trap that he has not already illuminated.


I can see my painting items in inventory , and I can place my paintings in the world, and they read the resource file, and they render all of their quads, but they're pure black. All of the quads (front, sides, and back) are black. The texture is completely ignored even though it was read from its file and bound to its object (whatever that means).


I've stepped through all relevant functions in the debugger, both for placing a painting and loading a saved world. Everything appears to be correct (callback, texture file, world coords, texture coords). I am completely buffaloed. I'm now wondering if the problem is something completely unrelated, like failing to set light level (a beautiful painting at zero light level would be black).


Any hints would be appreciated, especially what to peek at in the debugger. Is there a trick to loading resources that it might be read but not used? I thought I saw the binding happen, but I might have been tricked.


Source code files...



package jrfpaintings;

import io.netty.buffer.ByteBuf;

import java.util.ArrayList;

import net.minecraft.entity.Entity;
import net.minecraft.entity.item.EntityPainting;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.BlockPos;
import net.minecraft.util.EnumFacing;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.network.ByteBufUtils;
import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;

*  @author Jeff Fisher
*  @version 1.8: This class creates 16 complete collections (files) of 31 paintings (canvases) each.
*  To make any use of the painting renderer (like being registered), we need to struggle to be a subclass
*  of EntityPainting. However, its constructors "do too much", and the renderer relies too much on its
*  enum for our liking. Being an EntityPainting may eventually get us into trouble with a client/server
*  packet utility too.
*  Each texture file will have the same pattern of paintings (canvasses) tiled within. This will let us
*  use one enum's data regardless of "lot".
*  The texture resource strings are defined in classRenderAltPainting.
public class classAltPainting extends EntityPainting implements IEntityAdditionalSpawnData {

  public EnumAltArt canvas;     // Designates a standardized patch within an indeterminate texture file.
  protected int lot;            // Designates which of the 16 texture files, frozen by carpet color in crafting.

  // Called by reflection from EntityList.createEntityFromNBT
  // If only the client-server messaging used the same protocol...
  public classAltPainting(World w) {
    super (w);

  // Internal constructor shared by public constructors.
  protected classAltPainting(World w, BlockPos pos) {
    this (w);

    this.hangingPosition = pos;     // Reach back to imitate the grandparent's xyz constructor.
    this.art = EnumArt.valueOf ("jrfAltArt");
    this.canvas = null;             // To be set by caller (larger local constructor below)

   * Imitate EntityPainting's place-random constructor. We can't do a direct override because we need the "lot" number. Unlike
   * EntityPainting, we limit our candidate pool to 8 canvases searched largest to smallest.
   * This constructor is called on server side to choose random canvas, which then through the magic of messaging will cause a spawn
   * on the client.
  public classAltPainting(World w, BlockPos pos, EnumFacing facing, int lot) {
    this (w, pos);                                  // Call the common constructor
    this.lot = lot;

    ArrayList q = new ArrayList ();
    EnumAltArt[] v = EnumAltArt.values ();
    for (int p = v.length - 1; (q.size () <  && (p >= 0); p-- ) {    // Start at the largest and search backward
      this.canvas = v[p];                               // Test fit
      this.func_174859_a (facing);                      // Both orients *AND* positions; *MUST* call after every canvas assignment
      if (this.onValidSurface ()) q.add (this.canvas);  // Test depends on setDirection(); if passed, then save for later
    if (!q.isEmpty ()) {
      setCanvas ((EnumAltArt) q.get (this.rand.nextInt (q.size ())), facing.getHorizontalIndex ());

   * This constructor gets called on the client side in response to a message from the server, which constructed its own object
   * using a different constructor.
  public classAltPainting(World w, BlockPos pos, EnumFacing facing, int lot, String title) {
    this (w, pos);                              // Call the common constructor
    this.lot = lot;
    setCanvas (EnumAltArt.canvasNamed (title), facing.getHorizontalIndex ());

  protected void setCanvas(EnumAltArt a, int SWNE) {
    EnumFacing facing = EnumFacing.getHorizontal (SWNE);

    this.canvas = a;                                // Canvas must be assigned before setDirection()

    // Entity.setPosition is called in Vanilla where bounds box is mangled by width & height
// setSize ((float) (a.sizeX / 16), (float) (a.sizeY / 16));
    this.func_174859_a (facing);                       // Both orients & positions; must be called after every canvas assignment

  // Imitate vanilla's setting of the bounding box, but don't let vanilla code move the entity!
  protected void setSize(float width, float height) {
    if (width != this.width || height != this.height) {
      this.width = width;
      this.height = height;
      this.setEntityBoundingBox (new AxisAlignedBB (                    //
          this.getEntityBoundingBox ().minX,                            //
          this.getEntityBoundingBox ().minY,                            //
          this.getEntityBoundingBox ().minZ,                            //
          this.getEntityBoundingBox ().minX + (double) this.width,      //
          this.getEntityBoundingBox ().minY + (double) this.height,     //
          this.getEntityBoundingBox ().minZ + (double) this.width));

// if (this.width > local_old_width && !this.firstUpdate && !this.worldObj.isRemote) {
// this.moveEntity ((double) (local_old_width - this.width), 0.0D, (double) (local_old_width - this.width));
// }

  public int getLot() {     // Tell which cluster of images this entity is showing
    return lot;

  public int getWidthPixels() {
    return this.canvas.sizeX;

  public int getHeightPixels() {
    return this.canvas.sizeY;

   * Called when this entity is broken. Entity parameter may be null.
  public void onBroken(Entity e) {
    if (e instanceof EntityPlayer && ((EntityPlayer) e).capabilities.isCreativeMode) return;
    this.entityDropItem (new ItemStack (classAltPaintingsMod.itemAltPainting, 1, lot), 0.0F);

   * Helper method to write subclass entity data to NBT.
   * The tag itself is not sent anywhere by any of the methods in the class stack, so
   * we can add/replace after call to super.
  public void writeEntityToNBT(NBTTagCompound tag) {
    super.writeEntityToNBT (tag);
    tag.setInteger ("jrfAltArtLot", this.lot);
    tag.setString ("Canvas", this.canvas.title);        // Replace string set by super

   * Helper method to read subclass entity data from NBT.
   * Must set lot & canvas before calling super, which calls back getWidthPixels (& Height)
  public void readEntityFromNBT(NBTTagCompound tag) {
    this.lot = tag.getInteger ("jrfAltArtLot");
    this.canvas = EnumAltArt.canvasNamed (tag.getString ("Canvas"));
    super.readEntityFromNBT (tag);          // Calls setDirection() after loading other data

  // Writing occurs on server side.
  // Entity's posX, Y & Z have been set, but nothing from EntityHanging or below is set yet.
  public void writeSpawnData(ByteBuf b) {   // FIXME: How much of this must change?
    b.writeInt (this.hangingPosition.getX ());             // world tile x (+ is East)
    b.writeInt (this.hangingPosition.getY ());              // world tile y (+ is Up)
    b.writeInt (this.hangingPosition.getZ ());              // world tile z (+ is South)
    b.writeByte ((byte) this.field_174860_b.ordinal ());    // Facing 0-6 is D, U, N, S, W, E
    b.writeByte (lot);                      // Texture number 0-15 taken from carpet color used to craft item
    ByteBufUtils.writeUTF8String (b, this.canvas.title);

  public void readSpawnData(ByteBuf b) {
    // No-op; we stole our data in classAltPaintingSpawnCallback.apply(), which then called the long constructor.

   * This mod completely fills each 256x256 pixel image (texture file), using the same pattern of "canvases" in each. Instead of
   * actual painting titles, the canvases have abstract names denoting the same patch in each file. Thus, this one enum can be used
   * for all 16 texture files.
  public static enum EnumAltArt {
    Ace1("Ace1", 16, 16, 0, 0),
    Ace2("Ace2", 16, 16, 16, 0),
    Ace3("Ace3", 16, 16, 0, 16),
    Ace4("Ace4", 16, 16, 16, 16),
    Window2x1a("Window2x1a", 32, 16, 32, 0),
    Window2x1b("Window2x1b", 32, 16, 32, 16),
    Door1x2a("Door1x2a", 16, 32, 0, 32),
    Door1x2b("Door1x2b", 16, 32, 16, 32),
    Triptych("Triptych", 48, 16, 176, 0),
    Quad2x2a("Quad2x2a", 32, 32, 112, 0),
    Quad2x2b("Quad2x2b", 32, 32, 144, 0),
    Quad2x2c("Quad2x2c", 32, 32, 32, 32),
    Hex3x2a("Hex3x2a", 48, 32, 64, 0),
    Hexup2x3a("Hexup2x3a", 32, 48, 0, 64),
    Hex3x2b("Hex3x2b", 48, 32, 64, 32),
    Hex3x2c("Hex3x2c", 48, 32, 80, 176),
    Hexup2x3b("Hexup2x3b", 32, 48, 32, 64),
    Hex3x2d("Hex3x2d", 48, 32, 128, 176),
    Double4x2("Double4x2", 64, 32, 112, 32),
    Square3x3a("Square3x3a", 48, 48, 64, 64),
    Square3x3b("Square3x3b", 48, 48, 80, 208),
    Square3x3c("Square3x3c", 48, 48, 128, 208),
    Port3x4("Port3x4", 48, 64, 64, 112),
    Land4x3("Land4x3", 64, 48, 112, 64),
    Square4x4a("Square4x4a", 64, 64, 0, 112),
    Square4x4b("Square4x4b", 64, 64, 112, 112),
    Wide5x3a("Wide5x3a", 80, 48, 176, 16),
    Wide5x3b("Wide5x3b", 80, 48, 176, 64),
    Large5x4("Large5x4", 80, 64, 176, 112),
    Giant5x5a("Giant5x5a", 80, 80, 0, 176),
    Giant5x5b("Giant5x5b", 80, 80, 176, 176);

    // public static final int maxTitleLength = 12;

    public final String title;
    public final int sizeX;         // Horizontal size in pixels
    public final int sizeY;         // Vertical size in pixels
    public final int offsetX;       // Pixels right from the left edge
    public final int offsetY;       // Pixels down from top

    private EnumAltArt(String title, int width, int height, int offX, int offY) {
      this.title = title;
      this.sizeX = width;
      this.sizeY = height;
      this.offsetX = offX;
      this.offsetY = offY;

    // Find the canvas by name (title)
    public static EnumAltArt canvasNamed(String canvasName) {
      for (EnumAltArt a : EnumAltArt.values ()) {
        if (a.title.equals (canvasName)) return a;
      return EnumAltArt.Ace1;



package jrfpaintings;

import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.entity.RenderPainting;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.EntityPainting;
import net.minecraft.util.BlockPos;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.MathHelper;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.EnumSkyBlock;

import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;

import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;

* @author Jeff Fisher
* Overrides almost all of RenderPainting. That's partly because parent is tied so tightly to EntityPainting's enum and partly
* because I wanted to render each painting's reverse using its underlying carpet (wool).
* However, there's nothing to be gained from accessing Minecraft's wool textures, so each is copied into one tile within its
* corresponding texture file. If there's a gain here, it is from reducing the backing/edging to two tiles that can be repeated as
* many times as needed (the original texture file has 16 tiles (4x4) of wood for backing & edging).
* This mod also completely fills each texture file, using the same pattern of "canvases" in each. Instead of actual painting
* titles, the canvases have abstract names.
public class classRenderAltPainting extends RenderPainting {

  protected static ResourceLocation[] fileHandle = new ResourceLocation[16];

  static {
    for (int p = 0; p < 16; p++ ) {       // Compose all 16 file resource strings
      fileHandle[p] = new ResourceLocation (classAltPaintingsMod.MODID, String.format ("textures/painting/paintings_jrf_%02d.png", p));

  classRenderAltPainting(RenderManager mgr) {
    super (mgr);

   * Returns the domain:path location of an entity's texture file.
   * Called via Render.bindEntityTexture.
   * Because textures are cached, this will only be called the first time a file is needed.
  protected ResourceLocation getEntityTexture(Entity p) {
    classAltPainting ap = (classAltPainting) p;
    return fileHandle[ap.getLot ()];

   * AltPainting version of painting-specific setup method
  public void doRender(EntityPainting p, double posX, double posY, double posZ, float SWNE, float ignored) {
    float sixteenth = 0.0625F;             // 1/16
    classAltPainting ap = (classAltPainting) p;
    classAltPainting.EnumAltArt canvas = ap.canvas;
    int tileWidth = canvas.sizeX / 16;

    GL11.glPushMatrix ();
    GL11.glTranslated (posX, posY, posZ);               // Establish drawing origin at painting's world coords
    GL11.glRotatef (SWNE, 0.0F, 1.0F, 0.0F);            // Orient the drawing coordinate system South-West-North-East around the Y-axis
    GL11.glEnable (GL12.GL_RESCALE_NORMAL);
    this.bindEntityTexture (ap);                        // Open (retrieve) the corresponding texture file
    GL11.glScalef (sixteenth, sixteenth, sixteenth);    // 16 pixels per tile (block-face)
    this.drawQuads (ap, canvas.sizeX, canvas.sizeY, canvas.offsetX, canvas.offsetY);
    GL11.glDisable (GL12.GL_RESCALE_NORMAL);
    GL11.glPopMatrix ();

   * Offsets passed are pixel counts right and down from upper-left corner of the composite texture image to the upper-left corner
   * of a canvas within it.
   * Each painting is drawn as a very flat box* having six rectangular faces. Only one face of the box is actually the painting's
   * object of art (what I call the "canvas"), an array of tiles (a tile covers one block) containing 16x16 pixels. Its opposite
   * face is the backing. In vanilla MC, the back is oak plank texture, but in this mod the backs are carpet (wool) texture in the
   * color that was used to craft the painting item. The other four "faces" are the thin wooden frame one world-pixel deep.
   * Textures for all six faces are found in the texture file, with only the selected canvas being variable. The carpet (wool)
   * backing and the wood frame are repeated constants (a tile each at the right end of the top row in the texture image).
   * Coords given to graphics lib are percentages right or down from upper-left corner. Drawing coords (x, y, z) are pixels (horiz,
   * vert, depth), with positive values meaning rightward, upward, and away (deeper into entity as viewed from in "front"). This
   * drawing coordinate system has already been shifted, scaled and oriented in the world so that this method can concentrate on
   * drawing the object independent from its position, size and facing.
   * *Actually, a painting larger than 1 tile will be drawn as an array of boxes, each complete with a wooden frame on all four
   * edges, many of which can never be seen. For now at least, this is an unavoidable inefficiency because I'm unwilling to dive
   * into the Tessellator to learn how it works.
  protected void drawQuads(EntityPainting p, int pxWidth, int pxHeight, int pxOffRight, int pxOffDn) {
    Tessellator tess = Tessellator.getInstance ();
    WorldRenderer wr = tess.getWorldRenderer ();
    float drHalfDepth = 0.5F;                        // Half world-pixel depth each way from origin (painting-face versus back)

     * These two constants center the painting around the translated origin. If I am smart enough, I will incorporate this shifting
     * into the call to "translate" in the doRender function above (especially since we *want* the centering done on a whole-tile
     * basis).
    float drCenteredHoriz = (float) (-pxWidth) / 2.0F;      // minus half painting px width (center painting horizontally)
    float drCenteredVert = (float) (-pxHeight) / 2.0F;      // minus half painting px height (center painting vertically)
     * The following constants are percentage offsets right or down within the texture file's image. They address the back and frame
     * of the painting (5 of 6 box-faces). In the texture file, there's just one tile of carpet (wool) and one tile of wood. These
     * tiles are used over and over.
    float txTop = 0.0F;                 // Top edge of carpet or backing
    float txCenterPixel = 0.001953125F;       // 1/512 of texture image
    float txTileSize = 0.0625F;         // Also coord of bottom edge of top row
    float txCarpetLeftEdge = 0.875F;    // Carpet is tile 15 of 16 in top row (1/8 of a row shy of end)
    float txCarpetRightEdge = txCarpetLeftEdge + txTileSize;
    float txWoodRightEnd = 1F;
    float txWoodLeftEnd = txWoodRightEnd - txTileSize;
    float txWoodPixel = txWoodLeftEnd + txCenterPixel;     // Backing's left edge + 1/512

    for (int tileColumn = 0; tileColumn < pxWidth / 16; ++tileColumn) {      // Each tile column of canvas, left to right
      float drTileLeftEdge = drCenteredHoriz + (float) (tileColumn * 16);     //
      float drTileRightEdge = drTileLeftEdge + 16F;
      float txCanvasTileRight = (float) (pxOffRight + pxWidth - tileColumn * 16) / 256.0F;
      float txCanvasTileLeft = (float) (pxOffRight + pxWidth - (tileColumn + 1) * 16) / 256.0F;

      for (int tileRow = 0; tileRow < pxHeight / 16; ++tileRow) {    // Each tile in canvas column, bottom to top
        float drTileBottomEdge = drCenteredVert + (float) (tileRow * 16);
        float drTileTopEdge = drTileBottomEdge + 16F;
        this.fixLightLevel (p, (drTileRightEdge + drTileLeftEdge) / 2.0F, (drTileTopEdge + drTileBottomEdge) / 2.0F);
        float txCanvasTileBottom = (float) (pxOffDn + pxHeight - tileRow * 16) / 256.0F;         // Canvas bottom minus tile+0
        float txCanvasTileTop = (float) (pxOffDn + pxHeight - (tileRow + 1) * 16) / 256.0F;      // Canvas bottom minus tile+1

        wr.startDrawingQuads ();
        wr.setNormal (0.0F, 0.0F, -1.0F);  // Looking at the painting ("normal" vector toward neg depth)
        wr.addVertexWithUV ((double) drTileRightEdge, (double) drTileBottomEdge, (double) (-drHalfDepth), (double) txCanvasTileLeft, (double) txCanvasTileBottom);
        wr.addVertexWithUV ((double) drTileLeftEdge, (double) drTileBottomEdge, (double) (-drHalfDepth), (double) txCanvasTileRight, (double) txCanvasTileBottom);
        wr.addVertexWithUV ((double) drTileLeftEdge, (double) drTileTopEdge, (double) (-drHalfDepth), (double) txCanvasTileRight, (double) txCanvasTileTop);
        wr.addVertexWithUV ((double) drTileRightEdge, (double) drTileTopEdge, (double) (-drHalfDepth), (double) txCanvasTileLeft, (double) txCanvasTileTop);

        wr.setNormal (0.0F, 0.0F, 1.0F);   // Looking at back ("normal" vector toward positive depth)
        wr.addVertexWithUV ((double) drTileRightEdge, (double) drTileTopEdge, (double) drHalfDepth, (double) txCarpetLeftEdge, (double) txTop);
        wr.addVertexWithUV ((double) drTileLeftEdge, (double) drTileTopEdge, (double) drHalfDepth, (double) txCarpetRightEdge, (double) txTop);
        wr.addVertexWithUV ((double) drTileLeftEdge, (double) drTileBottomEdge, (double) drHalfDepth, (double) txCarpetRightEdge, (double) txTileSize);
        wr.addVertexWithUV ((double) drTileRightEdge, (double) drTileBottomEdge, (double) drHalfDepth, (double) txCarpetLeftEdge, (double) txTileSize);

        wr.setNormal (0.0F, 1.0F, 0.0F);   // Looking down onto frame top ("normal" vector up)
        wr.addVertexWithUV ((double) drTileRightEdge, (double) drTileTopEdge, (double) (-drHalfDepth), (double) txWoodLeftEnd, (double) txCenterPixel);
        wr.addVertexWithUV ((double) drTileLeftEdge, (double) drTileTopEdge, (double) (-drHalfDepth), (double) txWoodRightEnd, (double) txCenterPixel);
        wr.addVertexWithUV ((double) drTileLeftEdge, (double) drTileTopEdge, (double) drHalfDepth, (double) txWoodRightEnd, (double) txCenterPixel);
        wr.addVertexWithUV ((double) drTileRightEdge, (double) drTileTopEdge, (double) drHalfDepth, (double) txWoodLeftEnd, (double) txCenterPixel);

        wr.setNormal (0.0F, -1.0F, 0.0F);   // Looking up at frame bottom ("normal" vector down)
        wr.addVertexWithUV ((double) drTileRightEdge, (double) drTileBottomEdge, (double) drHalfDepth, (double) txWoodLeftEnd, (double) txCenterPixel);
        wr.addVertexWithUV ((double) drTileLeftEdge, (double) drTileBottomEdge, (double) drHalfDepth, (double) txWoodRightEnd, (double) txCenterPixel);
        wr.addVertexWithUV ((double) drTileLeftEdge, (double) drTileBottomEdge, (double) (-drHalfDepth), (double) txWoodRightEnd, (double) txCenterPixel);
        wr.addVertexWithUV ((double) drTileRightEdge, (double) drTileBottomEdge, (double) (-drHalfDepth), (double) txWoodLeftEnd, (double) txCenterPixel);

        wr.setNormal (-1.0F, 0.0F, 0.0F);   // Looking right at left frame ("normal" vector toward left)
        wr.addVertexWithUV ((double) drTileRightEdge, (double) drTileTopEdge, (double) drHalfDepth, (double) txWoodPixel, (double) txTop);
        wr.addVertexWithUV ((double) drTileRightEdge, (double) drTileBottomEdge, (double) drHalfDepth, (double) txWoodPixel, (double) txTileSize);
        wr.addVertexWithUV ((double) drTileRightEdge, (double) drTileBottomEdge, (double) (-drHalfDepth), (double) txWoodPixel, (double) txTileSize);
        wr.addVertexWithUV ((double) drTileRightEdge, (double) drTileTopEdge, (double) (-drHalfDepth), (double) txWoodPixel, (double) txTop);

        wr.setNormal (1.0F, 0.0F, 0.0F);   // Looking left at right frame ("normal" vector toward right)
        wr.addVertexWithUV ((double) drTileLeftEdge, (double) drTileTopEdge, (double) (-drHalfDepth), (double) txWoodPixel, (double) txTop);
        wr.addVertexWithUV ((double) drTileLeftEdge, (double) drTileBottomEdge, (double) (-drHalfDepth), (double) txWoodPixel, (double) txTileSize);
        wr.addVertexWithUV ((double) drTileLeftEdge, (double) drTileBottomEdge, (double) drHalfDepth, (double) txWoodPixel, (double) txTileSize);
        wr.addVertexWithUV ((double) drTileLeftEdge, (double) drTileTopEdge, (double) drHalfDepth, (double) txWoodPixel, (double) txTop);
        tess.draw ();

  // Sets the light level for the center of a tile.
  // These poor, abused coords have gone from double to int, and now they go back again. Who designed this program?
  protected void fixLightLevel(EntityPainting p, float pxRight, float pxUp) {
    int i = MathHelper.floor_double (p.posX);
    int j = MathHelper.floor_double (p.posY + (double) (pxUp / 16.0F));  // Center height is always +Y
    int k = MathHelper.floor_double (p.posZ);

    switch (p.field_174860_b) {
      case SOUTH:   // Looking South, Right-ward is Westward
        i = MathHelper.floor_double (p.posX - (double) (pxRight / 16.0F));
      case WEST: { // Looking West
        k = MathHelper.floor_double (p.posZ - (double) (pxRight / 16.0F));
      case NORTH: { // Looking North
        i = MathHelper.floor_double (p.posX + (double) (pxRight / 16.0F));
      case EAST:   // Looking East
        k = MathHelper.floor_double (p.posZ + (double) (pxRight / 16.0F));
        System.out.println ("Oy! How'd a paintin' get on a floor or ceiling?!?");
        // TODO: Punish programmer for putting painting on floor or ceiling
    int l = this.renderManager.worldObj.getLightFor (EnumSkyBlock.SKY, new BlockPos (i, j, k));
    int i1 = l % 65536;
    int j1 = l / 65536;
    OpenGlHelper.setLightmapTextureCoords (OpenGlHelper.lightmapTexUnit, (float) i1, (float) j1);
    GL11.glColor3f (1.0F, 1.0F, 1.0F);


The debugger is a powerful and necessary tool in any IDE, so learn how to use it. You'll be able to tell us more and get better help here if you investigate your runtime problems in the debugger before posting.

Link to comment
Share on other sites

Major improvement:


By replacing a lighting function call, I've dispelled the blackness. Apparently a call that worked in 1.7.10 no longer works (but still compiles). The old statement is commented out, and its replacement is beneath it in this snippet:

//  int l = this.renderManager.worldObj.getLightFor (EnumSkyBlock.SKY, new BlockPos (i, j, k));
    int l = this.renderManager.worldObj.getCombinedLight (new BlockPos (i, j, k), 0);


This is within my renderer's fixLightLevel method, the equivalent of func_77008_a() in class RenderPainting.


I still have a small bug, but I think I'll sort it shortly. You might be amused by this one: When I hang one of my alt paintings on an East or West wall, it displays correctly. When I hang it on a North or South wall, the pic faces the wall so that I see the "back" of the frame (my wall of glass blocks lets me see what's what from all sides).

The debugger is a powerful and necessary tool in any IDE, so learn how to use it. You'll be able to tell us more and get better help here if you investigate your runtime problems in the debugger before posting.

Link to comment
Share on other sites

Finally solved the canvas rotation. New for mc1.8, doRender's call to GlStateManager.rotate must pass (180F-orientation) instead of simply passing rotation. I have no idea why that only affected my North-South facing alt-paintings and not my East-West ones, but all directions now work correctly.

The debugger is a powerful and necessary tool in any IDE, so learn how to use it. You'll be able to tell us more and get better help here if you investigate your runtime problems in the debugger before posting.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • Hi I have an issue with a server it solved deleting the ice and fire but my friends and me really want to use it does any of these mods are causing the issue due to incompatibility  Security craft Aquaculture Architectury Artifacts Astikorcarts Baubles BetterCaves yungs BetterStrongholds yungs BetterMineshafts yungs Bountiful Byg  Callablehorses Carry on Chococraft Citadel Clumps Collective Comforts Corailrecycler Craftable horse armor Comes alive Curios forge Decocraft Dungeonsarise  Open blocks elevator Expandability Farlanders Goblin traders Hwyla  Ice and fire Infernal expansion Jei Jump over fences Mantle  Macaws bridges Macaws doors Macaws fences Macaws furniture  Macaws fencesbyg Morpheus Mouse tweaks Mowzies mobs Obfuscate Paraglider Patchouli  Pick up notifier Random village names Spartan shields Small ships Sophisticated backpacks Spartan weaponry Storage drawers straw golem Structure gel Twilight forest  Tinkers construct Two players one horse  Valhesia core  Valhesia structures  Way stones  Vehicle mod  Wall jump Wings Wolves with armor Xptome  Xaeros minimap  Yungsapi  
    • { "type": "magic_overhaul:rune_inscribing", "base": { "item": "//base item" }, "template": { "item": "//template item" }, "output": { "count": 1, "item": "//output item" } } ^ Ok, where is your recipe JSON placed in your file structure? What's it called? And paste the actual JSON you're testing with, because it needs to be valid.
    • I'm trying to run Forge 1.12.2 on Minecraft  so I can use certain mods, but this error popped up. I've seen multiple errors but I just can't figure this one out. Unable to locate the Java runtime. Error details: 0x00000000 - system: The operation completed successfully. Filename on disk:  Path: . Exists: Directory
    • https://mclo.gs/b422RFc
    • Плагин и Приват
  • Topics

  • Create New...

Important Information

By using this site, you agree to our Terms of Use.