Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Messages - MichaelJPCT

Pages: 1 ... 4 5 [6] 7 8 ... 12
Support / add/reduce texture stages at runtime?
« on: May 19, 2017, 06:20:06 am »
i have a terrain with 3 tex stages, each with different UV scaling. it was created with textureInfo/polygonManager technique.
i found tex stages affect render speed - the more stages the slower, on a powerVR 544 gpu.
i wonder if i could reduce/add a tex stage(a noise tex in my case) depending on camera distance.
is there a way to do so?

Support / Re: setProjector for JPCT-AE ?
« on: May 18, 2017, 09:37:59 am »
ok, thanks. i guess i can do it.

Support / setProjector for JPCT-AE ?
« on: May 18, 2017, 07:26:30 am »
i see Projector class in javadoc of jpct-ae, but no setProjector method in Texture class like the one in jpct-desktop. would it be added?

Support / Re: I can't find direct light, it is not be supported?
« on: January 03, 2017, 08:25:36 am »
i think the Light in JPCT is omni light (light ball, all directional).
if you want to simulate sunlight shining on earth, place a light 100000 units away, and make its intensity not fade.
if you want multiple lights with multiple directions in one scene, i don't know how.

Feedback / Re: would anyone want a sound engine for JPCT?
« on: January 03, 2017, 08:12:36 am »
1) python and pyglet must be installed, tested python version is python 2.7, pyglet version is 1.24
2) in java main module, call these functions at the right time: Snd.init() -> Snd.upd() / Snd.pause() -> Snd.shutdown()
3) if any object is to have a sndGrp, call upd() of the sndGrp after the object is updated (updated in graphics frame).
4) in example, bettyGrp is not attached to any object, so Snd.upd() should be called, say, each graphics frame.

Feedback / Re: would anyone want a sound engine for JPCT?
« on: January 03, 2017, 07:58:47 am »
here are all codes.
note that in my own code, i didn't write comments, these comments were added in about 2 hours as quick explanation.
these posted codes are a bit different from my own codes, as my codes have dependencies which other people don't have, but they should work with little modification.
and i am not a professional programmer, so some codes can be stupid.

Code: [Select]
// NOTE: this is prototype and lacks error checking etc.

// sck=socket buf=buffer snd=sound grp=group
// upd=update serv=server fn=function

// short2string is a function that converts a short value to 2 characters,
// store in 2nd arg, 3rd arg is position offset

import*; import;

public class Snd {
static byte fps; // used for timing, in this case framerate is constant
static float[] updResult=new float[2]; // pass data from game to this module
static byte[] outBuf=new byte[8]; // pass data from this module to socket
static Socket sck;
static boolean servOn=true, muteSnd;
static int servPort, maxVol=64000, maxPitch=64000;
static OutputStream outStream;
static String servFolder, sndFolder;
static SndType[] sndType;
static SndChannel[] sndChannel=new SndChannel[512];
static SndGrp bettyGrp; // example sound group

static short[] sndUpdFn={0,1,2};
static short[] sndTypeID={0,1,2};

static short[] sndGrpUpdFn={0,1,2};
static short[][] sndGrpItem={{0},{1},{2}};

static byte exampleFn1(SndChannel a) { updResult[0]=0f; return 1; }
static byte exampleFn2(SndChannel a) { updResult[0]=0.9f; return 1; }
static byte exampleFn3(SndChannel a) { updResult[0]=0.6f; updResult[1]=0.8f; return 2; }

interface GrpEnable { boolean enable(SndGrp a); }
interface UpdChannel { byte upd(SndChannel a); }

static GrpEnable[] grpEnable=new GrpEnable[] {
new GrpEnable() { public boolean enable(SndGrp a) { return true; } },
new GrpEnable() { public boolean enable(SndGrp a) { return true; } },
new GrpEnable() { public boolean enable(SndGrp a) { return true; } },

static UpdChannel[] updChannel=new UpdChannel[] {
new UpdChannel() { public byte upd(SndChannel a) { return exampleFn1(a); } },
new UpdChannel() { public byte upd(SndChannel a) { return exampleFn2(a); } },
new UpdChannel() { public byte upd(SndChannel a) { return exampleFn3(a); } },

static void shutdown() { if (!servOn) return;
try { outStream.close(); sck.close(); }
catch (Exception e) {} }

static void init() {
try { Runtime.getRuntime().exec(servFolder+"pysound.exe",null,new File(servFolder)); }
// in case python server app is not compiled as exe,
// run "python.exe folder/"

catch (Exception e) { servOn=false; return; }

if (!servOn) return;

for (byte m=50;m>0;m--) {
try {
sck=new Socket("localhost",servPort); // only local machine, as example
m=0; }
catch (Exception e) { if (m>1) continue; servOn=false; return; } }

outBuf[0]=-128; // one byte 0x80
bettyGrp=new SndGrp(0,null);

// setting.txt specifies socket port, same as python side.
// must be 5 digits in this simple function.
static void readCFG() {
short e=1024;
char[] u=new char[e];
int i;
String s,w="";
try { FileReader r=new FileReader(servFolder+"setting.txt");,0,e); r.close(); }
catch (Exception x) { servOn=false; return; }

s=new String(u); i=s.indexOf("PORT=");
if (i<0) { servOn=false; return; }

for (byte q=0;q<5;q++) { char h=u[5+i+q]; if ((h>47)&&(h<58)) w+=h; }
try { servPort=Integer.parseInt(w); }
catch (Exception x) { servOn=false; return; }

// an example: provide a binary file that stores sound type attributes
// the binary file also used by python side
static void readSndType() {
int h; byte[] u,q=new byte[8];
try { FileInputStream d=new FileInputStream(sndFolder+"snd.dat");
h=d.available(); u=new byte[h];; d.close(); }
catch (Exception x) { servOn=false; return; }
sndType=new SndType[h/8];
for (h=0;h<sndType.length;h++)
{ System.arraycopy(u,h*8,q,0,8); sndType[h]=new SndType(h,q); }

static void upd() { if (gamePaused||muteSnd||(!servOn)) return; bettyGrp.upd(); }

static void pause() { if (!servOn) return;
SndChannel s;
for (short z=0;z<sndChannel.length;z++)
{ s=sndChannel[z]; if ((s!=null)&&s.playing) { s.playing=false; s.endFrm=0; } }

static void send(int a) { outBuf[1]=(byte)a;
try { outStream.write(outBuf); } catch (Exception i) {} }

static void delChannel(int a) { if (sndChannel[a]==null) return;
sndChannel[a].play(0f,0f); sndChannel[a]=null; }

static int findEmptyChannel() {
for (short n=0;n<sndChannel.length;n++)
{ if (sndChannel[n]==null) return n; } return -1; }

static class SndType { int typeID; float duration; boolean loop, single;
public SndType(int a,byte[] b) { typeID=a;
duration=b[3]*0.2f; single=(b[5]>0); loop=(b[3]==0); } }

static class SndChannel { boolean playing; SndType sndType;
byte[] chID=new byte[2]; short updFnID,channelID,servGrp; Object hostObj;
float vol=1f,pitch=1f; long endFrm;
// endFrm is frameID for timing in case framerate is constant
// servGrp means sound group in server, not used

// constructor: this sound channel is store in java and sent to python side
public SndChannel(SndType a,int b,int c,short d,Object e)
{ sndType=a; channelID=(short)b; servGrp=(short)c; updFnID=d; hostObj=e;
short2string_unsigned(b,chID,0); outBuf[4]=chID[0]; outBuf[5]=chID[1];
short2string(c,outBuf,6); send(80); }

void play(float a,float b) {
if (a>0) { boolean s=false;
if (Math.abs(a-vol)>0.003f) { s=true; vol=a; }
if ((b>0)&&(Math.abs(b-pitch)>0.003f)) { s=true; pitch=b; }
if ((!playing)||(!sndType.loop)) { s=true; playing=true; }
if (!s) return;
short2string_unsigned(Math.min(maxPitch,(int)(pitch*16000)),outBuf,6); }

else if (!playing) return;
else { outBuf[4]=0; outBuf[5]=0; playing=false; endFrm=0; }

outBuf[2]=chID[0]; outBuf[3]=chID[1]; send(81); }

void upd() { if (updFnID<0) return;
byte r=updChannel[updFnID].upd(this);
if (!sndType.loop)
{ if (updResult[0]!=0) { endFrm=currentFrameID+(int)(sndType.duration*fps);
if (r==1) play(updResult[0],0);
else play(updResult[0],updResult[1]); } }
else if (updResult[0]!=0)
{ if (r==1) play(updResult[0],0);
else play(updResult[0],updResult[1]); }
else if (playing) play(0f,0f); }

static class SndGrp { boolean on; SndChannel[] item;
short grpTypeID,updFnID; Object hostObj;

public SndGrp(int a,Object b) { grpTypeID=(short)a; hostObj=b; short x;
short[] k=sndGrpItem[a];
item=new SndChannel[k.length];
for (byte m=0;m<k.length;m++)
{ x=k[m]; int i=findEmptyChannel();
item[m]=new SndChannel(sndType[sndTypeID[x]],i,-1,sndUpdFn[x],b);
sndChannel[i]=item[m]; }

void upd() { boolean v=on;
if (updFnID>=0) on=grpEnable[updFnID].enable(this);
if (on) { for (byte j=0;j<item.length;j++) item[j].upd(); }
else if (v) { for (byte j=0;j<item.length;j++) item[j].play(0f,0f); }


Code: [Select]
import os,sys,time,socket; import
r=os.getcwd(); folder=[r+'\\',''];
# folder[0] is sound program folder , folder[1] is sound data folder, modify to suit your case

sndChannel=[0 for r in range(512)]
sndGrp=[0 for r in range(256)]
netFn=[0 for r in range(256)]

def f020(a):
for h in xrange(len(sndChannel)):
if o and o.playing:
o.player.pause(); o.playing=0
if o.sndType.duration:

def f032(a): setGrp(string2short_unsigned(a[2:4]))

def f033(a):
if k:

def f034(a):
if k: k.pause()

def f080(a):

def f081(a):
if j:[4:6])*0.0000625,string2short_unsigned(a[6:8])*0.0000625)
# 0.0000625=1/16000, max 64000

def string2short_unsigned(a): return ord(a[0])+ord(a[1])*256

def string2short(a): b=ord(a[0])+ord(a[1])*256; return b-65536*bool(b>32767)

def setGrp(a):
g=sndGrp[a]; sndGrp[a]=SNDGRP(a)
if g:
for m in xrange(g.qty): sndChannel[g.item[m].channelID]=0

# arg: typeID, channelID, grpID
# sound group in server is not used yet
def setChannel(a,b,c):
n=sndChannel[b]; e=sndType[a]; sndChannel[b]=0
if n and n.grpID+1: sndGrp[n.grpID].subItem(n)
if e.src==0: e.loadSrc()
if e.src<0: return
if c+1 and sndGrp[c]: sndGrp[c].addItem(sndChannel[b])

# in example, all wav files are named like "00000000.wav" "00000001.wav" etc.
# sound type definition binary file format:
# each 8 bytes define a sound type, where:
# byte 0: file extention name type - wav ogg mp3
# byte 1/2: volume multiplier / pitch multiplier
# byte 3: sound duration, should be longer than sound file
# byte 4: preload or not
# byte 5: only allow single instance
class SNDTYPE(object):
def __init__(s,a,b):
s.typeID=a; s.fileName=('0'*8+str(a))[-8:]+sndFileType[ord(b[0])]; s.src=0
s.volMul=ord(b[1])*0.01; s.pitchMul=ord(b[2])*0.01; s.duration=ord(b[3])*0.2
s.preload=bool(ord(b[4])); s.single=bool(ord(b[5])); s.loop=bool(s.duration==0)
if s.preload: s.loadSrc()
def loadSrc(s):
if s.src: return
except (IOError,MediaException): s.src=-1; return

class SNDCHANNEL(object):
def __init__(s,a,b):
s.sndType=a;; p.queue(a.src); p.eos_action=sndEOS[a.loop]
s.pitchMul=p.pitch=a.pitchMul; s.volMul=p.volume=a.volMul; s.playing=s.tmpStop=0; s.vol=s.pitch=1
s.grpID=-1; s.channelID=b
def play(s,a,b):
if a>0:
if a-s.vol: s.player.volume=a*s.volMul; s.vol=a
if b and b-s.pitch: s.player.pitch=b*s.pitchMul; s.pitch=b
if s.playing-1:; s.playing=1
elif s.sndType.duration:;
elif s.playing:
s.player.pause(); s.playing=0
if s.sndType.duration:

class SNDGRP(object):
def __init__(s,a): s.qty=0; s.item=[]; s.grpID=a
def addItem(s,a): s.item.append(a); s.qty+=1; a.grpID=s.grpID
def subItem(s,a): s.item.remove(a); s.qty-=1; a.grpID=-1
def play(s):
for h in xrange(s.qty):
if i.tmpStop:; i.tmpStop=0; i.playing=1
def pause(s):
for h in xrange(s.qty):
if i.playing: i.player.pause(); i.tmpStop=i.sndType.loop; i.playing=0

def initSnd():
try: w=file(folder[1]+'snd.dat',mode='rb');; w.close()
except IOError: sys.exit()
for y in xrange(len(r)/8): sndType.append(SNDTYPE(y,r[y*8:y*8+8]))
for y in xrange(256):
try: netFn[y]=eval('f'+('000'+str(y))[-3:])
except NameError: continue

class CFG(object):
def __init__(s):
i=file(folder[0]+'setting.txt');; i.close()
if p<0 or r<0: sys.exit()
except (IOError,ValueError): sys.exit()

class SERVERSOCKET(object):
def __init__(s,a):
s.port,s.remote=a.servPort,a.acceptRemote; s.running=1
k=s.sck=socket.socket(socket.AF_INET, socket.SOCK_STREAM); k.bind(('localhost'*(1-s.remote),s.port))
k.listen(1); k.setblocking(1); s.conn,s.connAddr=k.accept()
def shutdown(s): s.conn.close(); s.sck.close(); s.running=0
def run(s):
while s.running:
if not n: s.shutdown(); break
if n[0]=='\x80':
if netFn[u]: netFn[u](n)
except socket.error: s.shutdown()

cfg=CFG(); initSnd(); servSck=SERVERSOCKET(cfg);

Feedback / would anyone want a sound engine for JPCT?
« on: December 06, 2016, 11:58:16 pm »
since JPCT doesn't provide a sound engine, and openAL looks too complicated for me, i searched for a sound engine which can play sound with volume and pitch control like this: setVolume(0.6) , setPitch(0.8).
i ended up using socket and a sound server made with a Python module.
socket is chosen for IPC because it's easy to program and another(and same) machine can be used as server.
Python module PyGLET is used as the server app because it's simple to use and it fullfils my need to control volume and pitch directly.
i have used the engine to play several sounds simutaneously and it looked reliable on local machine.
i can post all source code here, would anyone be interested in this?

Feedback / Developing JPCT-AE program on Android device
« on: September 16, 2016, 02:18:34 pm »

Most people develop Android apps on a PC, then test run in Android Emulator, then do further testing on real Android device. But sometimes you don't need a PC to develop Android apps - you can write code, compile, and test run on an Android device.
I'm introducing the basic usage of AIDE - an Android app which can compile another Android app, with JPCT-AE.
For this to work well, you need these:
1) latest version (2016) of AIDE, free version will do
2) an Android device fast enough, such as quadcore A53/A72 CPU
3) a real keyboard
4) a not-so-small screen, say 10 inch or more
5) jpct-ae.jar

when AIDE is launched, if no project is opened, AIDE lets you choose whether to learn lessons or to code, just choose "for experts".
then if no project is created yet, you choose to create a new Gradle project.
by default AIDE creates project folder inside /mnt/sdcard/AppProjects/.
after project is created, you create a folder named "libs" in /YourProjectFolder/app/, then copy jpct-ae.jar into folder "libs".
then you are ready to write codes.

you can also copy your Gradle or Eclipse project folder from PC to Android device and continue with the old project.

here are some basic operations you need to know when you work with AIDE:
1) to handle files, choose menu VIEW, then FILES, then click on the file to open. on the top of screen there are file tabs that you can click and a menu shows up providing CLOSE FILE options.
2) to build, just click the button looking like a triangle on top right corner of the screen.
3) in menu VIEW, there is LOGCAT, which is important for debugging.
4) in menu PROJECTS, there is REFRESH BUILD, you need to do that sometimes - when you find your app behaves like un-updated.

In this way, you can spend most development time on Android device - writing code. you only need a traditional PC to process images, sound, or build 3d models.

Support / Re: can the engine disable frustum cull ?
« on: September 12, 2016, 06:25:55 am »
i thought of another case where doing culling in app is more efficient than in engine. a group(say 20 or more) of Object3D are always stuck together, but they can rotate seperately, such as a vehicle. if i do culling on a bounding box/sphere of the group, the culling is done once instead of 20 times in engine. this advantage is multiplied by the quantity of object groups. i guess this can make a difference when quantity becomes large.

Support / Re: can the engine disable frustum cull ?
« on: September 11, 2016, 03:03:50 pm »
there is an API for frustum cull? i didn't find it.
i think in world.renderScene or world.draw , each Object3d is tested of frustum cull. if it's not in view , it's not sent to GPU.
in app, sometimes i need to test it too. for example if animation update of a group of Object3d is complex, i prefer to test frustum cull before updating animation.
if not in view, i just hide the objects.
for the non-hidden objects,
the test result is not communicated to the engine, so engine will test again.
if the world is rendered multiple times, frustum cull is tested multiple times. but in fact, it only need to be done once for a frame.
so it's better to turn of frustum cull in engine, in my case.

Support / Re: Black color is rendered as transparent !!!
« on: September 11, 2016, 11:01:19 am »
have you tried Object3D.setTransparency(-1)?

Support / can the engine disable frustum cull ?
« on: September 11, 2016, 07:34:45 am »
for some special case , an app may do frustum cull by itself, if the engine does frustum cull also, then the work is done twice. so i wish the engine can disable frustum cull.

Support / Re: default shader lighting problem
« on: September 10, 2016, 01:52:47 pm »
it seems to work correctly like the desktop version now. thanks.
i see the specTerm param is gone, but i never knew what it was - it didn't make difference in my desktop app.

Support / Re: default shader lighting problem
« on: September 07, 2016, 08:17:39 am »
i made a test case.
if gl2=false, you can see the color of a box changes a bit, while with gl2=true, color doesn't change.

package abc.def;
import com.threed.jpct.*;
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.opengl.GLSurfaceView;
import android.os.Bundle; import;
import java.lang.reflect.Field;

public class Sim extends Activity {
   static GLSurfaceView GLview; static MyRenderer renderer;
   static FrameBuffer fb;
   static World world=new World();
   static Camera cam=world.getCamera();
   static Object3D box=Primitives.getBox(5,1),gnd=Primitives.getPlane(1,500);
   static float yaw;
   static SimpleVector vec=new SimpleVector();
   static Light sun;
   static Texture tex=new Texture(1,1,new RGBColor(200,200,200));
   static boolean gl2=false;

   void init() { sun=new Light(world); sun.setAttenuation(-1f);
      sun.setDiscardDistance(-1f); vec.set(0,2000,10000);
      sun.setPosition(vec); TextureManager.getInstance().addTexture("tex",tex);
      world.addObject(box); box.setSpecularLighting(true);; world.addObject(gnd);
      vec.set(0,50,0); gnd.setOrigin(vec); gnd.rotateX((float)Math.PI/2);

   protected void onCreate(Bundle a) {
      super.onCreate(a); renderer=new MyRenderer();
      GLview=new GLSurfaceView(getApplication());
      if (gl2) GLview.setEGLContextClientVersion(2); else
      GLview.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];
            return configs[0]; } } );
      GLview.setRenderer(renderer); setContentView(GLview); }

   protected void onPause() { super.onPause(); GLview.onPause(); }
   protected void onResume() { super.onResume(); GLview.onResume(); }
   protected void onStop() { super.onStop(); }

   class MyRenderer implements GLSurfaceView.Renderer {
      public void onSurfaceCreated(GL10 g,EGLConfig c) {}
      public void onSurfaceChanged(GL10 g,int w,int h) {
         if (gl2) fb=new FrameBuffer(w,h);
         else fb=new FrameBuffer(g,w,h);
         init(); }

      public void onDrawFrame(GL10 g) {
         float a=0.01f; yaw-=a; cam.rotateY(a);
         fb.clear(); world.renderScene(fb);
         world.draw(fb); fb.display(); } }

Support / Re: app not run in Android 5.1
« on: September 07, 2016, 07:49:24 am »
you are right.
i added android.permission.WRITE_EXTERNAL_STORAGE in manifest.xml and it works now.

Pages: 1 ... 4 5 [6] 7 8 ... 12