Version updates!

Started by EgonOlsen, March 28, 2010, 09:47:50 PM

Previous topic - Next topic

EgonOlsen

As Kaiidyn mentions, you have to do a complete render cycle, i.e. with renderScene, draw, display. A simple blit isn't sufficient. It might work to use display only if all you do is blitting into the render target, but i'm not 100% sure about this. If it doesn't work, just use a dummy world.

Thomas.

I use code without renderScene and draw in another case and it is working... so now I add fb.display() (also tried renderScene and draw), same result with texture, but it look like every rendered frame is in lower resolution...
fb.setRenderTarget(tex);
fb.clear();
textureBlitter();
fb.display();
fb.removeRenderTarget();
fb.clear();


Kaiidyn

I think you should not set and remove the renderTarget in every frame, set it in your initialization.. then put the clear, blitter and display in your loop, also remove the 2nd clear, as there is no point in doing it twice (except for making your render slower)
Clean code is simple and direct. Clean code reads like well-written prose. Clean code never obscures the designer's intent but rather is full of crisp abstractions and straightforward lines of control. - Grady Booch

EgonOlsen

No, you have to add and remove it in every frame or otherwise, you'll render everything into the texture and nothing on screen. Maybe it helps if i clarify a little what this actually does (at least in the Android implementation, because it lacks fbo support):

When setting a render target, the view port is limited to the texture size. Then you render your scene as usual. After calling display, the rendered image is copied from the frame buffer into the render target texture. If you remove the render target, the viewport is reset to match the frame buffer's size.

@Thomas: I don't get that "lower resolution" description...do you have a screen shot?

Thomas.

In my app I use this test code... Can anybody provide some part of code, that render to texture working?

if (first) {
Thread lb = new GameLoader();
lb.start();
fb.setRenderTarget(tex);
fb.clear();
textureBlitter();
fb.display();
fb.removeRenderTarget();
fb.clear();
}
showLoading(loaded);
fb.display();
first = false;


and here is screen ... after I call renderScene and draw it, "resolution" is correct

EgonOlsen


Thomas.

this happens when I blit something or render world... is there any solution?

EgonOlsen

Have you tried to add a clear like i've mentioned in the linked thread? If not, please provide a test case as i don't fully understand what you are doing there.

EgonOlsen

Example that works in the emulator and on my phone:

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.FrameBuffer;
import com.threed.jpct.Logger;
import com.threed.jpct.Object3D;
import com.threed.jpct.Primitives;
import com.threed.jpct.RGBColor;
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;

/**
* @author EgonOlsen
*
*/
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 cube0 = null;
private Object3D cube1 = null;
private Object3D cube2 = null;
private Object3D cube3 = null;
private Object3D dummy = null;

private Texture renderTarget = null;

private int fps = 0;

private int cnt = 0;

protected void onCreate(Bundle savedInstanceState) {

Logger.log("onCreate");

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

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

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();
}

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();
private boolean stop = false;

public MyRenderer() {
}

public void stop() {
stop = true;
}

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

if (master == null) {

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

Texture texture = new Texture(BitmapHelper.rescale(BitmapHelper.convert(getResources().getDrawable(R.drawable.icon)), 64, 64));
TextureManager.getInstance().addTexture("texture", texture);

dummy = Object3D.createDummyObj();

cube0 = Primitives.getCube(10);
cube0.rotateY(-(float) Math.PI / 4f);
cube0.rotateMesh();
cube0.clearRotation();
cube0.calcTextureWrapSpherical();
cube0.setTexture("texture");
cube0.strip();
cube0.build();

cube1 = cube0.cloneObject();
cube2 = cube0.cloneObject();
cube3 = cube0.cloneObject();

world.addObject(cube0);
world.addObject(cube1);
world.addObject(cube2);
world.addObject(cube3);

cube0.translate(-20, -20, 0);
cube1.translate(20, -20, 0);
cube2.translate(-20, 20, 0);
cube3.translate(20, 20, 0);

cube0.setAdditionalColor(RGBColor.WHITE);
cube1.setAdditionalColor(RGBColor.BLUE);
cube2.setAdditionalColor(RGBColor.GREEN);
cube3.setAdditionalColor(RGBColor.RED);

cube0.addParent(dummy);
cube1.addParent(dummy);
cube2.addParent(dummy);
cube3.addParent(dummy);

Camera cam = world.getCamera();
cam.moveCamera(Camera.CAMERA_MOVEOUT, 100);

renderTarget = new Texture(256, 256, RGBColor.RED);

MemoryHelper.compact();

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

//Logger.setLogLevel(Logger.DEBUG);
}
}

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

public void onDrawFrame(GL10 gl) {

try {
if (!stop) {
if (touchTurn != 0) {
dummy.rotateY(touchTurn);
touchTurn = 0;
}

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

cnt++;

fb.setRenderTarget(renderTarget);
fb.clear(RGBColor.BLUE);
world.renderScene(fb);
world.draw(fb);
fb.display();
fb.removeRenderTarget();

fb.clear(back);
world.renderScene(fb);
world.draw(fb);
fb.blit(renderTarget, 0, 0, 0, 0, 256, 256, false);
fb.display();

if (System.currentTimeMillis() - time >= 1000) {
Logger.log(fps + "fps");
fps = 0;
time = System.currentTimeMillis();
}
fps++;
} else {
if (fb != null) {
fb.dispose();
fb = null;
}
}
} catch (Exception e) {
Logger.log(e, Logger.MESSAGE);
}
}
}
}



EgonOlsen

Another version that does an initial blit into the texture:
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.FrameBuffer;
import com.threed.jpct.Logger;
import com.threed.jpct.Object3D;
import com.threed.jpct.Primitives;
import com.threed.jpct.RGBColor;
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;

/**
* @author EgonOlsen
*
*/
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 cube0 = null;
private Object3D cube1 = null;
private Object3D cube2 = null;
private Object3D cube3 = null;
private Object3D dummy = null;

private Texture renderTarget = null;

private int fps = 0;
private int cnt = 0;

private boolean firstRun = true;

protected void onCreate(Bundle savedInstanceState) {

Logger.log("onCreate");

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

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

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();
}

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();
private boolean stop = false;

public MyRenderer() {
}

public void stop() {
stop = true;
}

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

if (master == null) {

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

Texture texture = new Texture(BitmapHelper.rescale(BitmapHelper.convert(getResources().getDrawable(R.drawable.icon)), 64, 64));
TextureManager.getInstance().addTexture("texture", texture);

dummy = Object3D.createDummyObj();

cube0 = Primitives.getCube(10);
cube0.rotateY(-(float) Math.PI / 4f);
cube0.rotateMesh();
cube0.clearRotation();
cube0.calcTextureWrapSpherical();
cube0.setTexture("texture");
cube0.strip();
cube0.build();

cube1 = cube0.cloneObject();
cube2 = cube0.cloneObject();
cube3 = cube0.cloneObject();

world.addObject(cube0);
world.addObject(cube1);
world.addObject(cube2);
world.addObject(cube3);

cube0.translate(-20, -20, 0);
cube1.translate(20, -20, 0);
cube2.translate(-20, 20, 0);
cube3.translate(20, 20, 0);

cube0.setAdditionalColor(RGBColor.WHITE);
cube1.setAdditionalColor(RGBColor.BLUE);
cube2.setAdditionalColor(RGBColor.GREEN);
cube3.setAdditionalColor(RGBColor.RED);

cube0.addParent(dummy);
cube1.addParent(dummy);
cube2.addParent(dummy);
cube3.addParent(dummy);

Camera cam = world.getCamera();
cam.moveCamera(Camera.CAMERA_MOVEOUT, 100);

renderTarget = new Texture(256, 256, RGBColor.RED);

MemoryHelper.compact();

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

// Logger.setLogLevel(Logger.DEBUG);
}
}

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

public void onDrawFrame(GL10 gl) {

try {
if (!stop) {
if (touchTurn != 0) {
dummy.rotateY(touchTurn);
touchTurn = 0;
}

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

cnt++;

if (firstRun) {
fb.setRenderTarget(renderTarget);
fb.clear(RGBColor.BLUE);

Texture t = TextureManager.getInstance().getTexture("texture");
for (int i = 0; i < fb.getWidth(); i += 10) {
fb.blit(t, 0, 0, i, i, t.getWidth(), t.getHeight(), false);
}
fb.display();
fb.removeRenderTarget();
firstRun = false;
}

fb.clear(back);
world.renderScene(fb);
world.draw(fb);
fb.blit(renderTarget, 0, 0, 0, 0, 256, 256, false);
fb.display();

if (System.currentTimeMillis() - time >= 1000) {
Logger.log(fps + "fps");
fps = 0;
time = System.currentTimeMillis();
}
fps++;
} else {
if (fb != null) {
fb.dispose();
fb = null;
}
}
} catch (Exception e) {
Logger.log(e, Logger.MESSAGE);
}
}
}
}


If you want to use render to texture as a blit container, you'll run into the problem that the result is displayed upside-down. That's caused by the way OpenGL maps frame buffer to texture coordinates. For blitting, it's a better idea to compose the texture on the bitmap level anyway, The results will look cleaner because they are unaffected by gpu filtering and potential dithering and its more compatible.

Thomas.

#190
sorry, problem is on my side... I wrote new test app, too, and it work, so I will have to look where I have bug in my game... and is normal, that texture is flipped around x axis?
PS: ok :)

EgonOlsen

Quote from: Thomas. on February 17, 2011, 05:24:28 PM
... and is normal, that texture is flipped around x axis?
Yes. As said above, it's caused by the way how OpenGL maps the frame buffer to the texture.

Polomease


I tried the new version of jPCT you released using the two examples you posted.
My phone is having a problem with the render targets as well.

I have a Samsung Galaxy S (model: SAMSUNG-SGH-I897) with Android 2.1.

GL Info from LogCat
02-17 16:29:09.463: INFO/jPCT-AE(27067): OpenGL vendor:     Imagination Technologies
02-17 16:29:09.463: INFO/jPCT-AE(27067): OpenGL renderer:   PowerVR SGX 540
02-17 16:29:09.463: INFO/jPCT-AE(27067): OpenGL version:    OpenGL ES-CM 1.1


Here are some screen shots of the first example code you posted, one from the emulator and one from my phone.




Here are some screen shots of the second example code you posted, one from the emulator and one from my phone.


EgonOlsen

Which version of jPCT-AE is that? The latest that i've posted in this thread?

EgonOlsen

Quote from: EgonOlsen on February 17, 2011, 09:35:04 PM
]Yes. As said above, it's caused by the way how OpenGL maps the frame buffer to the texture.
BTW: You can flip a blit by doing something like


fb.blit(renderTarget, 0, 0, 0, 256, 256, 256, 256, -256, -1, false, null);


instead of


fb.blit(renderTarget, 0, 0, 0, 0, 256, 256, 256, 256, -1, false, null);


It's not an official feature but it works due to the way blitting is implemented.