Author Topic: More FrameBuffers in one program  (Read 8192 times)

Offline Darai

  • byte
  • *
  • Posts: 45
    • View Profile
Re: More FrameBuffers in one program
« Reply #15 on: February 04, 2016, 02:07:54 pm »
Sure, here is the screenshot (attachment):
If attachment is a bad approach, let me know and I will upload it to ImageShack
I admit, twisted is not a good description... so let's say cutted and zoomed.

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12298
    • View Profile
    • http://www.jpct.net
Re: More FrameBuffers in one program
« Reply #16 on: February 04, 2016, 02:11:29 pm »
But obviously only the second one? I'll look into it.

Offline Darai

  • byte
  • *
  • Posts: 45
    • View Profile
Re: More FrameBuffers in one program
« Reply #17 on: February 04, 2016, 02:19:49 pm »
And third and fourth... All but the first one are wrong...

This examle has only two objects because I wanted it to be simple, but I foud this problem on a more complex  implementation and I backtracked it here, so I can tell you also this one additional information.  :)

Interrestingly also in every onSurfaceChanged() the first texture you will blit-in will be done succesfully no matter how many times you will blit into it. But once you will try to blit to one and than switch and blit to another one... the second e.t.c. will be wrong. And no only in the first frame or second, but in every frame you will try it in.

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12298
    • View Profile
    • http://www.jpct.net
Re: More FrameBuffers in one program
« Reply #18 on: February 04, 2016, 02:47:33 pm »
I'm actually doing the same thing and it works fine. I'll look into it...

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12298
    • View Profile
    • http://www.jpct.net
Re: More FrameBuffers in one program
« Reply #19 on: February 04, 2016, 04:54:33 pm »
Ok, I think I got it now. It always confuses me as well...sorry about that. The trick is to make the blitting operations operate on the actual framebuffer size (even when using a render target) and NOT on the ones of the texture. One solution is this dummyWorld-approach, but it wasn't the right place where I putted it. It has to be done BEFORE setting the render target and it's sufficient to do it once. But a better solution is to tell the framebuffer which values to use directly. There's a method for this: http://www.jpct.net/jpct-ae/doc/com/threed/jpct/FrameBuffer.html#setVirtualDimensions(int, int).

So here's the modified example. If you don't want to use this method, you can still use the dummyWorld-approach: Just replace the call to setVirtualDimensions() with the renderScene()/draw()-sequence.

Hope this helps.

Code: [Select]
package com.threed.jpct.example;

import java.lang.reflect.Field;

import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.opengles.GL10;

import android.app.Activity;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.view.MotionEvent;

import com.threed.jpct.Camera;
import com.threed.jpct.Config;
import com.threed.jpct.FrameBuffer;
import com.threed.jpct.Light;
import com.threed.jpct.Logger;
import com.threed.jpct.Object3D;
import com.threed.jpct.Primitives;
import com.threed.jpct.RGBColor;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.Texture;
import com.threed.jpct.TextureManager;
import com.threed.jpct.World;
import com.threed.jpct.util.BitmapHelper;
import com.threed.jpct.util.MemoryHelper;

public class HelloWorld extends Activity {

private static HelloWorld master = null;

private GLSurfaceView mGLView;
private MyRenderer renderer = null;
private FrameBuffer fb = null;
private World world = null;
private RGBColor back = new RGBColor(50, 50, 100);

private float touchTurn = 0;
private float touchTurnUp = 0;

private float xpos = -1;
private float ypos = -1;

private Object3D cube = null;
private int fps = 0;
private boolean gl2 = true;

private Light sun = null;

private Texture target = null;
private Texture target2 = null;
private Texture texture = null;
private boolean firstRun = true;

protected void onCreate(Bundle savedInstanceState) {

Logger.log("onCreate");

if (master != null) {
copy(master);
}

super.onCreate(savedInstanceState);
mGLView = new GLSurfaceView(getApplication());

if (gl2) {
mGLView.setEGLContextClientVersion(2);
} else {
mGLView.setEGLConfigChooser(new GLSurfaceView.EGLConfigChooser() {
public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
int[] attributes = new int[] { EGL10.EGL_DEPTH_SIZE, 16, EGL10.EGL_NONE };
EGLConfig[] configs = new EGLConfig[1];
int[] result = new int[1];
egl.eglChooseConfig(display, attributes, configs, 1, result);
return configs[0];
}
});

}

renderer = new MyRenderer();
mGLView.setRenderer(renderer);
setContentView(mGLView);
}

@Override
protected void onPause() {
super.onPause();
mGLView.onPause();
}

@Override
protected void onResume() {
super.onResume();
mGLView.onResume();
}

@Override
protected void onStop() {
super.onStop();
}

private void copy(Object src) {
try {
Logger.log("Copying data from master Activity!");
Field[] fs = src.getClass().getDeclaredFields();
for (Field f : fs) {
f.setAccessible(true);
f.set(this, f.get(src));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}

public boolean onTouchEvent(MotionEvent me) {

if (me.getAction() == MotionEvent.ACTION_DOWN) {
xpos = me.getX();
ypos = me.getY();
return true;
}

if (me.getAction() == MotionEvent.ACTION_UP) {
xpos = -1;
ypos = -1;
touchTurn = 0;
touchTurnUp = 0;
return true;
}

if (me.getAction() == MotionEvent.ACTION_MOVE) {
float xd = me.getX() - xpos;
float yd = me.getY() - ypos;

xpos = me.getX();
ypos = me.getY();

touchTurn = xd / -100f;
touchTurnUp = yd / -100f;
return true;
}

try {
Thread.sleep(15);
} catch (Exception e) {
// No need for this...
}

return super.onTouchEvent(me);
}

protected boolean isFullscreenOpaque() {
return true;
}

class MyRenderer implements GLSurfaceView.Renderer {

private long time = System.currentTimeMillis();

public MyRenderer() {
}

public void onSurfaceChanged(GL10 gl, int w, int h) {
if (fb != null) {
fb.dispose();
}

if (gl2) {
fb = new FrameBuffer(w, h); // OpenGL ES 2.0 constructor
} else {
fb = new FrameBuffer(gl, w, h); // OpenGL ES 1.x constructor
}

Config.viewportOffsetY = -0.15f;

if (master == null) {

world = new World();
world.setAmbientLight(20, 20, 20);

sun = new Light(world);
sun.setIntensity(250, 250, 250);

// Create a texture out of the icon...:-)
texture = new Texture(BitmapHelper.rescale(BitmapHelper.convert(getResources().getDrawable(R.drawable.icon)), 64, 64));
TextureManager.getInstance().addTexture("texture", texture);

cube = Primitives.getCube(10);
cube.calcTextureWrapSpherical();
cube.setTexture("texture");
cube.strip();
cube.build();

target = new Texture(256, 256);
target2 = new Texture(256, 256);

world.addObject(cube);

Camera cam = world.getCamera();
cam.moveCamera(Camera.CAMERA_MOVEOUT, 50);
cam.lookAt(cube.getTransformedCenter());

SimpleVector sv = new SimpleVector();
sv.set(cube.getTransformedCenter());
sv.y -= 100;
sv.z -= 100;
sun.setPosition(sv);
MemoryHelper.compact();

if (master == null) {
Logger.log("Saving master Activity!");
master = HelloWorld.this;
}
}
}

public void onSurfaceCreated(GL10 gl, EGLConfig config) {
}

public void onDrawFrame(GL10 gl) {
if (touchTurn != 0) {
cube.rotateY(touchTurn);
touchTurn = 0;
}

if (touchTurnUp != 0) {
cube.rotateX(touchTurnUp);
touchTurnUp = 0;
}

// Snip
// First

if (firstRun) {
fb.setVirtualDimensions(fb.getWidth(), fb.getHeight());

fb.sync();
fb.setRenderTarget(target);
int x = convertX(fb, target, 0);
int y = convertY(fb, target, target.getHeight() - 0);
int width = convertX(fb, target, target.getWidth());
int height = -convertY(fb, target, target.getHeight());
fb.blit(texture, 0, 0, x, y, 64, 64, width, height, -1, false, null);
fb.display();
fb.removeRenderTarget();

// second
fb.setRenderTarget(target2);
x = convertX(fb, target2, 0);
y = convertY(fb, target2, target2.getHeight() - 0);
width = convertX(fb, target2, target2.getWidth());
height = -convertY(fb, target2, target2.getHeight());
fb.blit(texture, 0, 0, x, y, 64, 64, width, height, -1, false, null);
fb.display();
fb.removeRenderTarget();

firstRun=false;
}
// Snap

fb.clear(back);
world.renderScene(fb);
world.draw(fb);
world.getCamera().moveCamera(Camera.CAMERA_MOVEOUT, 0.1f);
world.getCamera().rotateCameraZ(0.01f);

// And blit the result
fb.blit(target, 0, 0, 10, 10, 256, 256, 400, 400, -1, false, null);
fb.blit(target2, 0, 0, 10, 410, 256, 256, 400, 400, -1, false, null);

fb.display();

if (System.currentTimeMillis() - time >= 1000) {
Logger.log(fps + "fps");
fps = 0;
time = System.currentTimeMillis();
}
fps++;
}

public int convertX(FrameBuffer buffer, Texture target, int x) {
return (int) ((float) x * ((float) buffer.getWidth() / (float) target.getWidth()));
}

public int convertY(FrameBuffer buffer, Texture target, int y) {
return (int) ((float) y * ((float) buffer.getHeight() / (float) target.getHeight()));
}

public int getHeight(Texture target) {
return target.getHeight();
}
}
}

This whole issue is caused by a design flaw in the way in which jPCT as well as jPCT-AE calculates the actual blitting coordinates. It needs the current camera to do this, but neither FrameBuffer itself nor the blit-method have it, so it does some crude things internally to deal with it and when using a render target, this goes wrong if you don't offer it some support. I should really revise this somehow...sometime...