Software Render Color Depth

Started by AGP, February 07, 2025, 11:08:25 PM

Previous topic - Next topic

AGP

If I'm not mistaken, the software renderer works with 16 bits for color (and a third byte for transparency?). Is it trivial giving it all 24 bits (plus a byte for transparency). If so, would you?

EgonOlsen

No, it's working on full 24 bit color depth.

AGP

I thought that it was a color thing that nothing I do makes an object fade in or out with the software render. This is a basic test I wrote (several different attempts in there, none of which work):


import java.awt.*;
import java.awt.event.*;
import com.threed.jpct.*;

public class Transparency extends Frame implements WindowListener {
    private World theWorld;
    private FrameBuffer buffer;
    private Camera cam;
    private Object3D obj;
    private boolean keepGoing, turnRight, turnLeft;
    private com.threed.jpct.util.KeyMapper keyMapper;
    private Texture boxMap;
    private int transparency = 0;
    private FadeoutEffect effect;

    public Transparency() {
       this.setTitle("BR's");
       theWorld = new World();
       buffer = new FrameBuffer(1440, 900, FrameBuffer.SAMPLINGMODE_NORMAL);
       obj = com.threed.jpct.util.ExtendedPrimitives.createBox(new SimpleVector(2f, 2f, 2f));//Primitives.getCube(1f);
       TextureManager.getInstance().addTexture("boxMap", (boxMap=new Texture("BoxMap.png", true)));
       boxMap.setEffect((effect=new FadeoutEffect()));
       obj.setTexture("boxMap");
       obj.build();
       obj.setTransparencyMode(Object3D.TRANSPARENCY_MODE_DEFAULT);
       obj.setTransparency(transparency);
       Object3D backgroundPlane = Primitives.getPlane(1, 4f);
       backgroundPlane.build();
       backgroundPlane.translate(0f, -2f, 0f);
       theWorld.addObject(backgroundPlane);
       cam = theWorld.getCamera();
       cam.moveCamera(Camera.CAMERA_MOVEOUT, 8f);
       theWorld.addObject(obj);
       obj.setLighting( Object3D.LIGHTING_NO_LIGHTS );
       keyMapper = new com.threed.jpct.util.KeyMapper(this);
       this.addWindowListener(this);
       this.setSize(buffer.getWidth(), buffer.getHeight());
       this.setVisible(true);
       loop();
    }

    public void loop() {
       keepGoing = true;
       while (keepGoing) {
           buffer.clear();
           com.threed.jpct.util.KeyState keyState = keyMapper.poll();
           if (keyState.getState() == com.threed.jpct.util.KeyState.PRESSED)
              keyPressed(keyState.getKeyCode());
           else if (keyState.getState() == com.threed.jpct.util.KeyState.RELEASED)
              keyReleased(keyState.getKeyCode());
           if (turnRight)
              obj.rotateY(-.01f);
           if (turnLeft)
              obj.rotateY(.01f);
           theWorld.renderScene(buffer);
           theWorld.draw(buffer);
           //theWorld.drawWireframe(buffer, Color.yellow);
           buffer.display(this.getGraphics());
           Thread.yield();
       }
       buffer.dispose();
       this.dispose();
       System.exit(0);
    }

    private void keyPressed(int keyCode) {
       if (keyCode == KeyEvent.VK_RIGHT)
           turnRight = true;
       if (keyCode == KeyEvent.VK_LEFT)
           turnLeft = true;
    }
    private void keyReleased(int keyCode) {
       if (keyCode == KeyEvent.VK_RIGHT)
           turnRight = false;
       if (keyCode == KeyEvent.VK_LEFT)
           turnLeft = false;
       if (keyCode == KeyEvent.VK_T) {
           float fade = 1.00f;
           if (transparency < 255)
              fade = (float)((transparency+=8)/255f);
           effect.transparency = 255-transparency;
           obj.setTransparency(255-transparency);
           //boxMap.setAlpha(255-transparency);
           TextureManager.getInstance().replaceTexture("boxMap", boxMap);
           //obj.setAdditionalColor(intensity(boxColor, fade));
           //boxMap.applyEffect();
           Logger.log("Transparency: "+transparency, Logger.MESSAGE);
       }
    }
    public void windowClosing(WindowEvent e) {
       keepGoing = false;
    }
    public void windowClosed(WindowEvent e) {}
    public void windowOpened(WindowEvent e) {}
    public void windowActivated(WindowEvent e) {}
    public void windowDeactivated(WindowEvent e) {}
    public void windowIconified(WindowEvent e) {}
    public void windowDeiconified(WindowEvent e) {}

    public static void main(String[] args) {
       new Transparency();
    }
}
class FadeoutEffect implements ITextureEffect {
    public int transparency;
    private Texture tex;
    public FadeoutEffect() {
    }

    public void init(Texture texture) {
       this.tex = texture;
    }

    public void apply(int[] dest, int[] src) {
       /*for (int y =0; y < 512;y++) {
              for (int x = 0; x < 512; x++) {
                     dest[y*x] = transparency;
              }
       }*/
       tex.setAlpha(transparency);
    }

    public boolean containsAlpha() {
       return false;
    }
}

EgonOlsen

That's because the usage of alpha in the texture itself overrides the global transparency setting. Or in other words, if a texture uses an alpha channel, it doesn't allow for setting the global transparency using setTransparency(). IIRC, this is a limitation of the software renderer. However, transpancy using setTransparency is pretty coarse anyway. But that's not related to color depth but to the way in which it's applied.

AGP

So is there no way to do a proper fadeout?

EgonOlsen

Either use a texture with no alpha channel and do setTransparency()...but that might look a bit coarse. Or use a texture with alpha and use Texture.setAlpha(). But that will alter the texture, which is slower and might not be feasible if you intend to do that on objects of which some are supposed to fade out while others won't.

AGP

#6
I tried texture.setAlpha(). Even tried replacing the texture in the texture manager. It doesn't change the object's opacity in any way.

EgonOlsen

setAlpha really means the alpha value as it's represented in the texture, i.e. shifted up by 24. Here's an example of how it works:

import java.awt.*;
import java.awt.event.*;
import com.threed.jpct.*;

public class Transparency extends Frame implements WindowListener {
    private World theWorld;
    private FrameBuffer buffer;
    private Camera cam;
    private Object3D obj;
    private boolean keepGoing, turnRight, turnLeft;
    private com.threed.jpct.util.KeyMapper keyMapper;
    private Texture boxMap;
    private int transparency = 0;

    public Transparency() {
      this.setTitle("BR's");
      theWorld = new World();
      buffer = new FrameBuffer(1440, 900, FrameBuffer.SAMPLINGMODE_NORMAL);
      obj = com.threed.jpct.util.ExtendedPrimitives.createBox(new SimpleVector(2f, 2f, 2f));//Primitives.getCube(1f);
      TextureManager.getInstance().addTexture("boxMap", (boxMap=new Texture("test.jpg", true)));
      obj.setTexture("boxMap");
      obj.setTransparency(0);
      //obj.setTransparencyMode(Object3D.TRANSPARENCY_MODE_ADD);
      obj.build();
      Object3D backgroundPlane = Primitives.getPlane(1, 4f);
      backgroundPlane.build();
      backgroundPlane.translate(0f, -2f, 0f);
      theWorld.addObject(backgroundPlane);
      cam = theWorld.getCamera();
      cam.moveCamera(Camera.CAMERA_MOVEOUT, 8f);
      theWorld.addObject(obj);
      theWorld.setAmbientLight(255, 255, 255);
      keyMapper = new com.threed.jpct.util.KeyMapper(this);
      this.addWindowListener(this);
      this.setSize(buffer.getWidth(), buffer.getHeight());
      this.setVisible(true);
      loop();
    }

    public void loop() {
      keepGoing = true;
      transparency=0;
      int dir = 1;
      int its= 0;
      while (keepGoing) {
          buffer.clear();
          com.threed.jpct.util.KeyState keyState = keyMapper.poll();
          if (keyState.getState() == com.threed.jpct.util.KeyState.PRESSED)
              keyPressed(keyState.getKeyCode());
          else if (keyState.getState() == com.threed.jpct.util.KeyState.RELEASED)
              keyReleased(keyState.getKeyCode());
          if (turnRight)
              obj.rotateY(-.01f);
          if (turnLeft)
              obj.rotateY(.01f);
          theWorld.renderScene(buffer);
          theWorld.draw(buffer);
          //theWorld.drawWireframe(buffer, Color.yellow);
          buffer.display(this.getGraphics());
          its++;
              if (its>10)  {
              transparency+=dir;
              if (Math.abs(transparency)>255 || transparency==0) {
                  dir*=-1;
              }
              //obj.setTransparency(transparency);
              TextureManager.getInstance().getTexture("boxMap").setAlpha(transparency<<24);
              System.out.println("Trans: "+transparency);
              its = 0;
          }
          Thread.yield();
      }
      buffer.dispose();
      this.dispose();
      System.exit(0);
    }

    private void keyPressed(int keyCode) {
      if (keyCode == KeyEvent.VK_RIGHT)
          turnRight = true;
      if (keyCode == KeyEvent.VK_LEFT)
          turnLeft = true;
    }
    private void keyReleased(int keyCode) {
      if (keyCode == KeyEvent.VK_RIGHT)
          turnRight = false;
      if (keyCode == KeyEvent.VK_LEFT)
          turnLeft = false;
    }
    public void windowClosing(WindowEvent e) {
      keepGoing = false;
    }
    public void windowClosed(WindowEvent e) {}
    public void windowOpened(WindowEvent e) {}
    public void windowActivated(WindowEvent e) {}
    public void windowDeactivated(WindowEvent e) {}
    public void windowIconified(WindowEvent e) {}
    public void windowDeiconified(WindowEvent e) {}

    public static void main(String[] args) {
      new Transparency();
    }
}


AGP

Thanks a lot. It is unnecessarily complicated, though, isn't it?

EgonOlsen

#9
Yes, a little bit...  ;) It's actually a performance issue. The "old" transparency code is optimized for speed and not accuracy, which is why its results are  not on par with what the GL renderer could do. The alpha stuff has been added much later. It's more flexible but also slower.