Terrain and GenericVertexController..

Started by LowPolyMan, March 21, 2013, 05:33:23 PM

Previous topic - Next topic

LowPolyMan

#15
Quote from: EgonOlsen on March 28, 2013, 08:01:11 AM
I can't try the code ATM and i won't be able to until after easter, but there are at least two things to consider:


  • Don't do these operations directly on the event listener. While this might not be responsible for your problem, it's bad practice anyway. jPCT-AE isn't thread safe, so you aren't supposed to modify jPCT related stuff from anywhere outside the rendering thread (in this case the onDrawFrame() method) once the scene has been setup. Just set a flag in the listener method and evaluate that in onDrawFrame() instead.
  • Your logic implies that reTexture() always starts from scratch, but that's not the case. It works based on the current coordinates, i.e. if you apply a tileFactor of 0.5 earlier, you'll reTexture with uOrg/vOrg0.5*-0.5 instead of uOrg/vOrg*-0.5

Hi EgonOlsen,

I think jPCT is a realy great library, docs and examples miss a bit but with the things i already know and the forums i get very far, i have managed to get a lot working without any help. But this..... Grrrr... :)

I tried and tried but i can't get it working. I also searched the forums for hours, a bit of help, or better yet a working example would be great..

Here's my code so far:
https://dl.dropbox.com/s/4yj3ygon78sdgoh/HelloWorld.zip?token_hash=AAG_t63ZFsDJbIMgZ1tHAEKr5YbGkOdeyhDJUD5P_sYyMg&dl=1

Regarding your 2  points:

1. I removed the code from event listener and put it in the rendering thread.
2. It works when you uncomment line 255, reTexture is then apply'd earlier also.

EgonOlsen

I'll have a look. I'll try tomorrow, but i can't promise...

EgonOlsen

Here you go...the code had several issues. One was that reTexture wasn't acting absolute but relative. I've fixed this by adding a currentTiling variable that holds the current tiling to apply the inverse for absolute results. Then it wasn't meant to be used for what you were doing. If was meant to change the tiling of the second texture layer, which you don't have. I've fixed that too. In addition, i've removed the texture-String from the method (wasn't used anyway).
The last problem was that you called build() before compile(). That way, it was compiled with stativ-uv, because build() does this by default. I've remove the call to compile (it's implicit anyway) and replaced build() by build(false).

The modified code:


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.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.ViewGroup.LayoutParams;
import com.threed.jpct.Camera;
import com.threed.jpct.Config;
import com.threed.jpct.FrameBuffer;
import com.threed.jpct.Interact2D;
import com.threed.jpct.Light;
import com.threed.jpct.Logger;
import com.threed.jpct.Object3D;
import com.threed.jpct.OcTree;
import com.threed.jpct.PolygonManager;
import com.threed.jpct.RGBColor;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.Texture;
import com.threed.jpct.TextureInfo;
import com.threed.jpct.TextureManager;
import com.threed.jpct.World;
import com.threed.jpct.util.BitmapHelper;
import com.threed.jpct.util.MemoryHelper;

@SuppressLint("NewApi")
public class HelloWorldTexture extends Activity {

private static HelloWorldTexture master = null;
private GLSurfaceView mGLView;
private MyRenderer renderer = null;
private FrameBuffer fb = null;
private World world = null;
private Camera camera = 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 terrain;
private int fps = 0;
private Light sun = null;
private String status = "Loading..";
private boolean status_midx = true;
private boolean status_midy = true;
private int polyIdOffset;
private String outputLine1 = "";
private String outputLine2 = "";
private String outputLine3 = "";
private float currentTiling = 1;

protected void onCreate(Bundle savedInstanceState) {
Logger.log("onCreate");
if (master != null) {
copy(master);
}
super.onCreate(savedInstanceState);
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
mGLView = new GLSurfaceView(getApplication());
mGLView.setEGLConfigChooser(new GLSurfaceView.EGLConfigChooser() {
@SuppressLint("NewApi")
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];
}
});
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
renderer = new MyRenderer();
mGLView.setRenderer(renderer);
setContentView(mGLView);
DrawOnTop mDraw = new DrawOnTop(this);
addContentView(mDraw, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
}

@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) {
float x, y;
if (me.getAction() == MotionEvent.ACTION_DOWN) {
x = me.getX();
y = me.getY();
renderer.repaintUV((int) x, (int) y); // Change UV
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) {
}

return super.onTouchEvent(me);
}

protected boolean isFullscreenOpaque() {
return true;
}

class MyRenderer implements GLSurfaceView.Renderer {

private long time = System.currentTimeMillis();

public MyRenderer() {
Config.glTransparencyMul = (1.0f / 255);
Config.glTransparencyOffset = (1.0f / 255);
Config.farPlane = 10000;
Config.maxPolysVisible = 10000;
}

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(150, 150, 150);
sun = new Light(world);
sun.setIntensity(20, 20, 20);
SimpleVector sv = new SimpleVector(80, -160, 80);
sun.setPosition(sv);
status = "Loading textures..";
Texture Grey = new Texture(BitmapHelper.rescale(BitmapHelper.convert(getResources().getDrawable(R.drawable.grey)), 256, 256));
TextureManager.getInstance().addTexture("Grey", Grey);
Texture Red = new Texture(BitmapHelper.rescale(BitmapHelper.convert(getResources().getDrawable(R.drawable.red)), 256, 256));
TextureManager.getInstance().addTexture("Red", Red);
Texture texture = new Texture(BitmapHelper.rescale(BitmapHelper.convert(getResources().getDrawable(R.drawable.texture)), 1024, 512));
TextureManager.getInstance().addTexture("texture", texture);
status = "Creating object..";
createTerrain();
world.addObject(terrain);
terrain.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
world.buildAllObjects();
status = "Add camera and compact memory..";
camera = world.getCamera();
camera.setPosition(-80, -160, -80);
camera.lookAt(new SimpleVector(80, 0, 80));
MemoryHelper.compact();
status = "";
if (master == null) {
Logger.log("Saving master Activity!");
master = HelloWorldTexture.this;
}
}
}

public void reTexture(Object3D obj, float tileFactor) {
PolygonManager pm = obj.getPolygonManager();
int end = pm.getMaxPolygonID();

float bak=tileFactor;
tileFactor = (1f / currentTiling) * tileFactor;
currentTiling=bak;

for (int i = 0; i < end; i++) {
int t1 = pm.getPolygonTexture(i);
SimpleVector uv0 = pm.getTextureUV(i, 0);
SimpleVector uv1 = pm.getTextureUV(i, 1);
SimpleVector uv2 = pm.getTextureUV(i, 2);
uv0.scalarMul(tileFactor);
uv1.scalarMul(tileFactor);
uv2.scalarMul(tileFactor);
TextureInfo ti = new TextureInfo(t1, uv0.x, uv0.y, uv1.x, uv1.y, uv2.x, uv2.y);
pm.setPolygonTexture(i, ti);
}
obj.touch();
}

public void createTerrain() {
int x, z, id = TextureManager.getInstance().getTextureID("texture");
float xSizeF = 33, zSizeF = 33, scalemap = 5, deelx = 1;
TextureInfo ti;
terrain = new Object3D(2048);
for (z = 0; z < 32; z++) {
for (x = 0; x < 32; x++) {
float xx = x;
ti = new TextureInfo(id, (xx / xSizeF / deelx), (z / zSizeF), ((xx + 1) / xSizeF / deelx), (z / zSizeF), (xx / xSizeF / deelx), ((z + 1) / zSizeF));
terrain.addTriangle(new SimpleVector(x * scalemap, 1, z * scalemap), new SimpleVector((x + 1) * scalemap, 1, z * scalemap), new SimpleVector(x * scalemap, 1,
(z + 1) * scalemap), ti);
ti = new TextureInfo(id, (xx / xSizeF / deelx), ((z + 1) / zSizeF), ((xx + 1) / xSizeF / deelx), (z / zSizeF), ((xx + 1) / xSizeF / deelx), ((z + 1) / zSizeF));
terrain.addTriangle(new SimpleVector(x * scalemap, 1, (z + 1) * scalemap), new SimpleVector((x + 1) * scalemap, 1, z * scalemap), new SimpleVector((x + 1)
* scalemap, 1, (z + 1) * scalemap), ti);
}
}

// Retexture RIGHT lower part
reTexture(terrain, 0.5f);

// Retexture ONLT left upper part ..
// reTexture(terrain, "texture", -0.5f); //Uncomment here..

terrain.calcNormals();
terrain.setSpecularLighting(true);
terrain.forceGeometryIndices(true);
terrain.build(false); // (true);
OcTree ocTree = new OcTree(terrain.getMesh(), 512, OcTree.MODE_OPTIMIZED);
ocTree.setCollisionUse(OcTree.COLLISION_USE);
terrain.setOcTree(ocTree);
polyIdOffset = terrain.getPolygonManager().getMaxPolygonID() - terrain.getMesh().getTriangleCount();
}

public void repaintUV(int x, int y) {
SimpleVector position = new SimpleVector(Interact2D.reproject2D3D(camera, fb, (int) x, (int) y));
position.matMul(camera.getBack().invert3x3());
position.add(camera.getPosition());
SimpleVector direction = position.calcSub(camera.getPosition()).normalize();
float distance = world.calcMinDistance(position, direction, 10000);
if (distance != Object3D.COLLISION_NONE) {
SimpleVector collisionPoint = new SimpleVector(direction);
collisionPoint.scalarMul(distance);
collisionPoint.add(position);
int mapGridX = (int) collisionPoint.x / 5;
int mapGridY = (int) collisionPoint.z / 5;
int polyId1 = ((32 * mapGridY + mapGridX) * 2) + polyIdOffset;
terrain.getPolygonManager().setPolygonTexture(polyId1, TextureManager.getInstance().getTextureID("Red"));
terrain.getPolygonManager().setPolygonTexture(polyId1 + 1, TextureManager.getInstance().getTextureID("Red"));
outputLine1 = "Collision: " + collisionPoint;
outputLine2 = "    2D Map Coordinates: ( " + collisionPoint.x + ", " + collisionPoint.z + " )";
outputLine3 = "    Map Cell: ( " + mapGridX + ", " + mapGridY + " )";
}
renderer.reTexture(terrain, -0.5f);
}

public void onSurfaceCreated(GL10 gl, EGLConfig config) {
status_midx = true;
status_midy = true;
status = "";
}

public void onDrawFrame(GL10 gl) {
if (touchTurn != 0) {
touchTurn = 0;
}
if (touchTurnUp != 0) {
touchTurnUp = 0;
}
status = outputLine1 + ", " + outputLine2 + ", " + outputLine3;
fb.clear(back);
world.renderScene(fb);
world.draw(fb);
fb.display();
if (System.currentTimeMillis() - time >= 1000) {
Logger.log(fps + "fps");
fps = 0;
time = System.currentTimeMillis();
}
fps++;
}
}

class DrawOnTop extends View {
Paint paint = new Paint();
Rect bounds = new Rect();
int x;
int y;
int tmpx;
int tmpy;

public DrawOnTop(Context context) {
super(context);
}

public void drawing(Canvas canvas) {
if (status.length() > 0) {
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.BLACK);
paint.setTextSize(48);
paint.setAntiAlias(true);
paint.setAlpha(255);
if (status_midx) {
tmpx = (int) paint.measureText(status);
x = canvas.getWidth() / 2 - (tmpx / 2);
} else {
x = (canvas.getWidth() / 40);
}
if (status_midy) {
paint.getTextBounds(status, 0, status.length(), bounds);
tmpy = bounds.bottom;
y = canvas.getHeight() / 2 - (tmpy / 2);
} else {
y = 48;
}
canvas.drawText(status, x - 1, y - 1, paint);
canvas.drawText(status, x + 1, y - 1, paint);
canvas.drawText(status, x + 1, y + 1, paint);
canvas.drawText(status, x - 1, y + 1, paint);
paint.setColor(Color.WHITE);
canvas.drawText(status, x, y, paint);
}
}

@Override
protected void onDraw(Canvas canvas) {
drawing(canvas);
super.onDraw(canvas);
this.invalidate();
}
}

}


LowPolyMan

#18
Quote from: EgonOlsen on April 04, 2013, 08:35:05 PM
Here you go...the code had several issues. One was that reTexture wasn't acting absolute but relative. I've fixed this by adding a currentTiling variable that holds the current tiling to apply the inverse for absolute results. Then it wasn't meant to be used for what you were doing. If was meant to change the tiling of the second texture layer, which you don't have. I've fixed that too. In addition, i've removed the texture-String from the method (wasn't used anyway).
The last problem was that you called build() before compile(). That way, it was compiled with stativ-uv, because build() does this by default. I've remove the call to compile (it's implicit anyway) and replaced build() by build(false).

The modified code: ...

Thank you, It works great now!!

I know i used the reTexture the wrong way, it was intended to tile textures. I removed it and i just calculate the UV the way i need them now. Isn't build() called before compile() now also?

I have adjusted the source a bit and made a example so it might help other users get started changing UV's at runtime. This example i took from the web where you click on a point on the map and the texture changes from grey to red. The original example used 2 textures for the grey and red and this example only changes the UV coords. The texture contains both grey and red 256x128.
I removed the bin/ and libs/ drawer from the source so i could fit it under 64kb to attach it to this post.

Then i have another issue, this example works great BUT sometimes it gives a nullpointer on the'world.renderScene(fb)' or on the 'world.calcMinDistance(position, direction, 10000)' line. I discovered commenting the octree code fixes this, at keast on my S3. 



[attachment deleted by admin]

EgonOlsen

You are not supposed to access jPCT-AE related instances from inside your event handler methods. jPCT isn't thread safe and the render thread is different from the thread that handles the events. Mixing access from both can lead to nullpointer exceptions and other kind of errors.
Just let the handler methods set some flags and evaluate them in the render method: http://www.jpct.net/wiki/index.php/Hello_World_for_Android#onTouchEvent.28MotionEvent_me.29

LowPolyMan

#20
Quote from: EgonOlsen on April 05, 2013, 10:33:34 AM
You are not supposed to access jPCT-AE related instances from inside your event handler methods. jPCT isn't thread safe and the render thread is different from the thread that handles the events. Mixing access from both can lead to nullpointer exceptions and other kind of errors.
Just let the handler methods set some flags and evaluate them in the render method: http://www.jpct.net/wiki/index.php/Hello_World_for_Android#onTouchEvent.28MotionEvent_me.29

Ok, my misunderstanding of java i quess, i thought calling a function in render thread  from event handler was thread safe. Now i add a boolean and 2 ints in render thread so i set repeaint to true and set repaintx and repainty, from  onDrawFrame i check it and call the function repeaintUV.
Up until now i got no more nullpointer. I updated the source.

In my own app, i use a bigger terrain and i use a GenericVertexController. When i try to change for example coord 50,50 it changes a total different coord. I end up storing all polyid's in a array and look them up that way to get it working. I think i made some programming mistake, but you mabe know something about this?


[attachment deleted by admin]