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.

Topics - AeroShark333

Pages: [1] 2
Support / Bug with diffuse lighting
« on: November 09, 2022, 02:33:03 am »

I have noticed a minor bug while working on something.

Bug: It seems that the "diffuseColors" are not all set properly.
For the first two light sources the colors seem fine, but for 3 and 4 (and possibly till 8 ), the diffuseColor seems white instead of the color supplied through #setIntensity(R,G,B).
I have tried to use the "diffuseColors" from 1&2 for 3&4 by changing the default shader code. And this seems to be working as intended.
So my suspect is that in the Java code of the library, the diffuse colors are not set to the uniform "diffuseColors" properly.

Thanks in advance! :)

Support / jPCT-AE vs. jPCT (and the future of jPCT-AE)
« on: January 17, 2022, 06:14:21 pm »

I'm back with some questions I had wondered about for quite some time but never really bothered to ask.
Maybe a few things could be suggestions for the future of jPCT-AE as well...
It's a long list (and I'm not necessarily in a rush/hurry for answers so please take your time...) but anyway, here goes:

1. Why can a Light object only be assigned to one World? As far as I know you can only add a Light to the World using the constructor of Light.
When you look further, World does have the option to remove all lights with World.removeAll() or World.removeAllLights().
But there is no World.addLight(Light light) or World.addLights(Light[] lights) option... ???
In one of my projects, I remember having had 2 Worlds with diffent fogging parameters but same Lights, where I had to declare the 'same' Lights twice.

2. Is there any beneficial multi-threading capabilities jPCT-AE has or could have?
I have tried World.setDefaultThread(...) for instance but I never really understood its purpose entirely in jPCT-AE...
I tried to set it to a "new Thread()" but the application only became slower I believe...
I am not entirely sure if jPCT-AE has any other beneficial multi-threading capabilities (I haven't really found so far)...
I believe OpenGL doesn't entirely allow it anyway. But maybe some non-OpenGL things that jPCT does before rendering could still be done using multi-threading..? Pre-processing or anything like that
I figured that since devices become much better at multi-threading, maybe it would be nice to have some multi-threading options.
I found something interesting in the jPCT documentation: and but I haven't found something similar for jPCT-AE.

3. Will ReflectionHelper be ported to jPCT-AE?
I am referring to:
I believe ShadowHelper has been ported to jPCT-AE at a later stage too but I thought ReflectionHelper would be interesting too.
For mirror-like surfaces I believe it would be nice to have.

4. Will BloomGLProcessor be ported to jPCT-AE?
Here, I am referring to:
I am not sure if it is heavy or something but I thought it would be interesting to have.

5. Why can a VertexController only be assigned to a single mesh?
When you try to apply the same VertexController to another mesh you will get an error like:
"java.lang.RuntimeException: [ 1639357199784 ] - ERROR: This instance has already been assigned to another Mesh!"
I thought that maybe it would work too if the same VertexController was applied to multiple meshes, but I guess not...

6. Why does jPCT-AE use a static TextureManager instance?
I thought it would have made more sense to make a TextureManager per renderer or something
I believe it would be possible to have both too (so even Textures loaded from other renderers are accessible for whatever reason you have...)
With having both I mean that you have a 'TextureManager' per renderer but also still the global static one.

7. Why does jPCT-AE still attempt to draw non-visible polygons?
I believe polygons that are not visible in the scene are still sent to the GPU to 'draw' while they won't really be drawn.
- polygons out of the FOV of the camera (or it seems jPCT still processes these unless they have been manually set to Object3D.setVisibility(false).
- polygons out of max fogging distance range.
- also this is not available in jPCT-AE:

8. Is there any other plans for the future of jPCT-AE?
Further development? (implement new techniques and such; better lighting (Phong), more control for lighting (specularity))
Optimizing? (speeding up/improving existing implementations, multi-threading, etc.)
New features? (support for OpenGL3+ (compute shaders or something) or Vulkan or something)
More future-proofing? (I believe some things in jPCT-AE have been made for when Android 2.2/2.3 was more popular; so maybe they need to be reconsidered; think of memory limitations, max. texture size, max. texture stages, Phong shading, loading newer 3D models (other/newer file types), etc.)
Open-sourcing? (on GitHub or something so people can contribute)
Porting from other graphics libraries or jPCT? (some features that are present in other graphics libraries or jPCT but missing in jPCT-AE)

9. Any idea what causes these crashes..?
Most of these are native crashes but they might still point to some clue in the stacktrace (as some refer to the Java code)
Code: [Select]
signal 11 (SIGSEGV), code 2 (SEGV_ACCERR)
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
pid: 0, tid: 0 >>> com.aeroshark333.artofearthify <<<

  #00  pc 000000000001706c  /vendor/lib64/
  #00  pc 00000000000cc808  /vendor/lib64/egl/
  #00  pc 000000000002dcc4  /vendor/lib64/egl/
  #00  pc 0000000000031fb0  /vendor/lib64/egl/
  #00  pc 000000000002c4c8  /vendor/lib64/egl/
  #00  pc 000000000002bf24  /vendor/lib64/egl/ (glDrawElements+120)
  #00  pc 00000000000e7e1c  /system/lib64/ (android_glDrawElements__IIILjava_nio_Buffer_2(_JNIEnv*, _jobject*, int, int, int, _jobject*)+276)
  #00  pc 00000000002d3504  /system/framework/arm64/boot-framework.oat (art_jni_trampoline+196)
  #00  pc 00000000020072fc  /memfd:/jit-cache (com.threed.jpct.GL20.glDrawElements+60)
  #00  pc 0000000002020fc0  /memfd:/jit-cache (com.threed.jpct.CompiledInstance.render+11664)
  #00  pc 000000000203cc88  /memfd:/jit-cache (com.threed.jpct.GLRenderer.drawVertexArray+2088)
  #00  pc 0000000002047390  /memfd:/jit-cache (com.threed.jpct.World.draw+704)
  #00  pc 000000000204a11c  /memfd:/jit-cache (com.threed.jpct.World.draw+60)
  #00  pc 0000000002018c28  /memfd:/jit-cache (com.aeroshark333.artofearthify.lw.ArtOfEarthify.onDrawFrame+9096)
  #00  pc 0000000000137334  /apex/ (art_quick_invoke_stub+548)
  #00  pc 00000000001460ac  /apex/ (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+244)
  #00  pc 00000000002e3758  /apex/ (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+384)
  #00  pc 00000000002de7e4  /apex/ (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+900)
  #00  pc 00000000005a8a8c  /apex/ (MterpInvokeVirtualQuick+596)
  #00  pc 0000000000135594  /apex/ (mterp_op_invoke_virtual_quick+20)
  #00  pc 000000000022cd84  /data/app/com.aeroshark333.artofearthify-yaNv3ycyylpEX_4FbNxKmA==/oat/arm64/base.vdex (com.aeroshark333.artofearthify.lw.LiveWallpaperRenderer.onDrawFrame+4)
  #00  pc 00000000005a4364  /apex/ (MterpInvokeInterface+1740)
  #00  pc 0000000000131a14  /apex/ (mterp_op_invoke_interface+20)
  #00  pc 00000000002f475c  /system/framework/framework.jar (android.opengl.GLSurfaceView$GLThread.guardedRun+2068)
  #00  pc 00000000005a4f00  /apex/ (MterpInvokeDirect+1168)
  #00  pc 0000000000131914  /apex/ (mterp_op_invoke_direct+20)
  #00  pc 00000000002f5152  /system/framework/framework.jar (android.opengl.GLSurfaceView$
  #00  pc 00000000002b4088  /apex/ (art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) (.llvm.13310094408155829753)+240)
  #00  pc 0000000000593d00  /apex/ (artQuickToInterpreterBridge+1024)
  #00  pc 0000000000140468  /apex/ (art_quick_to_interpreter_bridge+88)
  #00  pc 0000000000137334  /apex/ (art_quick_invoke_stub+548)
  #00  pc 00000000001460ac  /apex/ (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+244)
  #00  pc 00000000004b2da0  /apex/ (art::(anonymous namespace)::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, art::(anonymous namespace)::ArgArray*, art::JValue*, char const*)+104)
  #00  pc 00000000004b3e50  /apex/ (art::InvokeVirtualOrInterfaceWithJValues(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jmethodID*, jvalue const*)+416)
  #00  pc 00000000004f43a8  /apex/ (art::Thread::CreateCallback(void*)+1176)
  #00  pc 00000000000e5614  /apex/ (__pthread_start(void*)+36)
  #00  pc 0000000000085458  /apex/ (__start_thread+64)

Code: [Select]
signal 11 (SIGSEGV), code 2 (SEGV_ACCERR)
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
pid: 0, tid: 0 >>> com.aeroshark333.artofearthify <<<

  #00  pc 000000000001706c  /vendor/lib64/
  #00  pc 00000000000ce0d8  /vendor/lib64/egl/
  #00  pc 000000000002e2cc  /vendor/lib64/egl/
  #00  pc 000000000003264c  /vendor/lib64/egl/
  #00  pc 000000000002ca84  /vendor/lib64/egl/
  #00  pc 000000000002c4dc  /vendor/lib64/egl/ (glDrawElements+120)
  #00  pc 0000000000079d38  /vendor/lib64/egl/
  #00  pc 00000000000e6cac  /system/lib64/ (android_glDrawElements__IIILjava_nio_Buffer_2(_JNIEnv*, _jobject*, int, int, int, _jobject*)+276)
  #00  pc 00000000002ca994  /system/framework/arm64/boot-framework.oat (art_jni_trampoline+196)
  #00  pc 0000000000088d88  /data/app/com.aeroshark333.artofearthify-qsfIgfJfssMx7-jwHqMHFA==/oat/arm64/base.odex (com.threed.jpct.GL20.glDrawElements+72)
  #00  pc 0000000000064158  /data/app/com.aeroshark333.artofearthify-qsfIgfJfssMx7-jwHqMHFA==/oat/arm64/base.odex (com.threed.jpct.CompiledInstance.render+12008)
  #00  pc 000000000006cf88  /data/app/com.aeroshark333.artofearthify-qsfIgfJfssMx7-jwHqMHFA==/oat/arm64/base.odex (com.threed.jpct.GLRenderer.drawVertexArray+2264)
  #00  pc 000000000007f18c  /data/app/com.aeroshark333.artofearthify-qsfIgfJfssMx7-jwHqMHFA==/oat/arm64/base.odex (com.threed.jpct.World.draw+844)
  #00  pc 000000000007fc10  /data/app/com.aeroshark333.artofearthify-qsfIgfJfssMx7-jwHqMHFA==/oat/arm64/base.odex (com.threed.jpct.World.draw+64)
  #00  pc 0000000000051178  /data/app/com.aeroshark333.artofearthify-qsfIgfJfssMx7-jwHqMHFA==/oat/arm64/base.odex (com.aeroshark333.artofearthify.lw.ArtOfEarthify.onDrawFrame+9240)
  #00  pc 0000000000056930  /data/app/com.aeroshark333.artofearthify-qsfIgfJfssMx7-jwHqMHFA==/oat/arm64/base.odex (com.aeroshark333.artofearthify.lw.LiveWallpaperRenderer.onDrawFrame+64)
  #00  pc 0000000002006824  /memfd:/jit-cache (android.opengl.GLSurfaceView$GLThread.guardedRun+6852)
  #00  pc 0000000000137334  /apex/ (art_quick_invoke_stub+548)
  #00  pc 00000000001460ac  /apex/ (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+244)
  #00  pc 00000000002e3c38  /apex/ (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+384)
  #00  pc 00000000002decc4  /apex/ (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+900)
  #00  pc 00000000005a4a40  /apex/ (MterpInvokeDirect+400)
  #00  pc 0000000000131914  /apex/ (mterp_op_invoke_direct+20)
  #00  pc 00000000002d79b6  /system/framework/framework.jar (android.opengl.GLSurfaceView$
  #00  pc 00000000002b4568  /apex/ (art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) (.llvm.14186875840613789731)+240)
  #00  pc 0000000000593b40  /apex/ (artQuickToInterpreterBridge+1024)
  #00  pc 0000000000140468  /apex/ (art_quick_to_interpreter_bridge+88)
  #00  pc 0000000000137334  /apex/ (art_quick_invoke_stub+548)
  #00  pc 00000000001460ac  /apex/ (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+244)
  #00  pc 00000000004b2898  /apex/ (art::(anonymous namespace)::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, art::(anonymous namespace)::ArgArray*, art::JValue*, char const*)+104)
  #00  pc 00000000004b3948  /apex/ (art::InvokeVirtualOrInterfaceWithJValues(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jmethodID*, jvalue const*)+416)
  #00  pc 00000000004f3e98  /apex/ (art::Thread::CreateCallback(void*)+1176)
  #00  pc 00000000000e2364  /apex/ (__pthread_start(void*)+36)
  #00  pc 0000000000083d98  /apex/ (__start_thread+64)

Code: [Select]
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR)
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
pid: 0, tid: 0 >>> com.aeroshark333.artofearthify <<<

  #00  pc 0000000000019164  /system/lib/ (memcpy+96)
  #00  pc 00000000000b37db  /vendor/lib/ (ioctl_kgsl_sharedmem_write+114)
  #00  pc 00000000000f99b3  /vendor/lib/egl/ (rb_vbo_cache_vertex_attrib+278)
  #00  pc 000000000006a97d  /vendor/lib/egl/ (cache_vertex_array+1396)
  #00  pc 000000000006b643  /vendor/lib/egl/ (cache_vertex_elements+3162)
  #00  pc 0000000000074bfd  /vendor/lib/egl/ (core_glDrawElementsInstancedXXX+984)
  #00  pc 00000000000752bd  /vendor/lib/egl/ (core_glDrawElements+20)
  #00  pc 0000000000052a51  /vendor/lib/egl/ (glDrawElements+72)
  #00  pc 0000000000d6352b  /system/framework/arm/boot-framework.oat (offset 0x637000) (android.opengl.GLES10.glClearColorx [DEDUPED]+122)
  #00  pc 0000000000012c37  /dev/ashmem/dalvik-jit-code-cache_12126_12126 (deleted)

Code: [Select]
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR)
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
pid: 0, tid: 0 >>> com.aeroshark333.artofearthify <<<

  #00  pc 0000000000018da0  /system/lib/ (memcpy+100)
  #00  pc 0000000000093e03  /vendor/lib/egl/
  #00  pc 000000000001c137  /vendor/lib/egl/
  #00  pc 000000000001f1c7  /vendor/lib/egl/
  #00  pc 000000000001af75  /vendor/lib/egl/
  #00  pc 000000000001aabf  /vendor/lib/egl/ (glDrawElements+54)
  #00  pc 000000000008441d  /system/lib/ (android_glDrawElements__IIILjava_nio_Buffer_2(_JNIEnv*, _jobject*, int, int, int, _jobject*)+116)
  #00  pc 0000000000a09d75  /system/framework/arm/boot-framework.oat (offset 0x5ea000) ( [DEDUPED]+140)
  #00  pc 00000000000102f7  /dev/ashmem/dalvik-jit-code-cache (deleted)

Code: [Select]
  at com.threed.jpct.Logger.log (
  at com.threed.jpct.GL20.checkFrameBufferObject (
  at com.threed.jpct.GL20.setRenderTarget (
  at com.threed.jpct.GLRenderer.setRenderTarget (
  at com.threed.jpct.FrameBuffer.setRenderTarget (
  at com.threed.jpct.FrameBuffer.setRenderTarget (
  at com.aeroshark333.blackhole3d.BlackHole3D.onDrawFrame (
  at com.aeroshark333.blackhole3d.livewallpaper.LiveWallpaperRenderer.onDrawFrame (
  at android.opengl.GLSurfaceView$GLThread.guardedRun (
  at android.opengl.GLSurfaceView$ (

I guess this is all I have to ask for now. Looking forward to your reply!


Support / Lighting on merged Object3Ds
« on: December 03, 2021, 01:37:22 am »
Hello again,

I'm having some lighting issues when using Object3D.mergeObjects(obj1, obj2)

See image:

I believe the main cause of this is that the Object3D's overlap..?
(road and the dirt on the side are different layers for instance, at slightly different heights (dirt layer is above road layer).
When rendering it as separate Object3D's the issue is not there.

Any way to solve this without having to flatten the layers in height? I believe the merging of Object3D's messes up the normal vectors or something..? Can this be prevented so it renders similarly as if it were two separate Object3D's?

I'm having similar issues when merging other parts of the scene. Sometimes things appear too bright, sometimes there's dark areas.
It was worse like this before (because one Object3D accidentally had setTransparency, affecting the final merged Object3D...) Removing setTransparency improves it but sometimes there's still random brightly lit parts in the scene.. I wish to get the same visual results as if it was not merged. (Merging seems to boost FPS so that's why..)

Cheers :)

sideview of road:
Code: [Select]
dirt layer:   ____________                                _____________
road layer:          -----------------------------------------

Support / Are merged Object3D able to have shared submeshes?
« on: November 16, 2021, 10:06:27 am »

Let's say I have 300 dynamic Object3D's and 300 static Object3D's.
The 300 static ones share the same mesh, the dynamic one does not.
However, in the world scene these objects will always be rendered together (one dynamic Object3D with one static Object3D). Each of the 300 Object3D's have different positions and rotations, but every dynamic Object3D is 'coupled' with a static Object3D.

Would it be better to have 600 Object3D's with a child/parent relationship? Or is it possible to merge these to 300 Object3D's which could be cheaper to render (because the submesh could be shared..?). I wonder which is best in terms of memory usage and performance. Or is there another better way to implement this..? (The Object3D's have between 12 to 60 triangles each for further information)

In the documentation it said merged Object3D's aren't compressed by default but I am not sure how or if that holds if one of two Object3D shares their mesh.


Edit: I'm also having issues with my multiple Overlays. When I use Overlay#setDepth() the Overlay seems to vanish..? I can solve the sorting problem of multiple Overlays using Object3D#setSortingOffset on its Object3D. However, it is still possible for my other World Object3D's to appear in front of the Overlay... (even without the sorting offset). How can I make sure the Overlay is always on top?
Edit2: Nevermind... apparently setDepth allows negative values (although documentation says it should always be positive..?) Maybe having Config.nearPlane = 0f and Config.ignoreNearPlane = true ruins compatibility or something. setDepth with negative values do seem to work and also fix my issue...
Edit3: Sometimes the other Object3Ds in the world still seem to clip through the overlay... (it appears as flickering but it's barely noticable but still weird...) Well whatever... I give up for now

Support / Diffuse vs. Specular light color
« on: November 01, 2021, 07:12:56 am »

I was trying to create a glass/mirror-like object.
For this I needed to get rid of the World's ambient lighting and the Light's diffuse lighting.

I was able to get rid of the World's ambient lighting (which affected all objects in the scene unfortunately, but for those objects I used Object3D#setAdditionalColor again to mimic ambient lighting)
However, I wasn't able to change the diffuse nor specular color seperately..? Or I wouldn't know how to...
The Light class has a Light#setIntensity() method but I suppose that works on both diffuse and specular color.

According to the Wiki, the shaders do seem ready to support distinctive diffuse and specular lighting colors
Code: [Select]
uniform vec3 diffuseColors[8]; - The diffuse color of each light source.
uniform vec3 specularColors[8]; - The specular color of each light source.
It seemed a little odd to me that these variables are seperately declared there but they seem to always be the same arrays basically..? (If I'm not mistaken and didn't overlook something)

I believe the following three (or four) things would help me a lot:
- Allow Object3D#setAdditionalColor(r,g,b) to have negative values for r, g and b so they can cancel out the World's ambient lighting (rather than having to do it in the opposite way...)
- Add Light#setSpecularIntensity(r,g,b) to control specular lighting intensity seperately
- Add Light#setDiffuseIntensity(r,g,b) to control diffuse lighting intensity seperately
(- Perhaps extra Object3D lighting modes (ambient only, additional only, diffuse only, specular only; and different combinations of these 4).)

Thank you for your time :)


Support / Increase number of texture units
« on: July 29, 2020, 06:55:13 pm »
I received a crash from an user with the following stacktrace:
Code: [Select]
  at com.threed.jpct.Logger.log (
  at com.threed.jpct.GL20.checkError (
  at com.threed.jpct.GL20.glGenBuffers (
  at com.threed.jpct.CompiledInstance.compileToVBO (
  at com.threed.jpct.CompiledInstance.render (
  at com.threed.jpct.GLRenderer.drawWireframe (
  at com.threed.jpct.World.draw (
  at com.threed.jpct.World.drawWireframe (
  at com.aeroshark333.artofearthify.lw.ArtOfEarthify$ (
  at com.aeroshark333.artofearthify.utils.WorkerThread$ (
  at com.aeroshark333.artofearthify.lw.ArtOfEarthify.onDrawFrame (
  at com.aeroshark333.artofearthify.lw.LiveWallpaperRenderer.onDrawFrame (
  at android.opengl.GLSurfaceView$GLThread.guardedRun (
  at android.opengl.GLSurfaceView$ (
Any idea what this could be? I've only received this once so maybe it could be ignored...

PS: The question is unrelated to the original thread but I thought the topic title suited... so...

PPS: Although jPCT has Config.maxTextureLayers, the hard limit seems to be 4. Would it be possible to increase this value to 8 (or arbitrary)? Or assign these extra textures using a hack or something? I'd like to be able to access 8 textures in my fragment shader in a single pass

Support / Minor blitshader bug
« on: April 23, 2020, 12:20:58 am »

I believe I've found a minor blitshader bug, it's mostly about the blits that follow (whether these use another blitshader or no blitshader) after you are done using the blitshader in a single draw call.
I do follow the instructions I've read elsewhere on this forums:
It should work. At least I see no reason, why it shouldn't. Just make sure not to do this:

Code: [Select]

That doesn't work, because blits are buffered but the shader isn't. If you need to reset the shader in the process, make sure to execute the blits before. You can force this by blitting a dummy blit from some other texture. Like:

Code: [Select]
fb.blit(...); // <- Dummy-blit (1x1 transparent pixel with some other texture or something)

Now in my case, I use:
Code: [Select]
fb.blit(...); // <- Dummy-blit (1x1 transparent pixel with some other texture or something)
fb.blit(...); // <- Dummy-blit (1x1 transparent pixel with some other texture or something)
fb.blit(...); // <- Dummy-blit (1x1 transparent pixel with some other texture or something)

Every blit using the first shader seems to go fine but once another shader or no shader is used, blitting is kinda broken (not on all devices but most).
- When you blit (after having used the first shader) with no shader, something that doesn't match the original texture you're trying to blit is shown.
- When you blit (after having used the first shader) with another shader, either nothing is shown or the correct result is shown. (50/50 depending on device)
- When you blit (after having used the first shader) with no/another shader AND you used fb.display() before these blits, then the correct result will be shown in all cases.

So it seems that now fb.display() is required if
- you want to keep blitting normally after the first blits with shader
- you want to use another blitshader to blit with
Though, I'm not sure if fb.display() is intended to be used like that


Support / [Tips] Huge texture uploading (memory tricks)
« on: April 03, 2020, 08:52:58 pm »

I have been digging around a little for the memory issues I have concerning texture uploading since I do use pretty huge textures.
It seems that jPCT-AE requires twice the size of a texture (in peak memory usage) in JVM RAM: the original pixeldata of the texture + the buffer used for uploading.
But I believe that on modern day devices you can actually use tricks to consume near nothing in the JVM RAM when loading such huge textures.
I believe jPCT-AE doesn't support these features out of the box because it's been directly ported from the PC version and to provide backwards compatibility with the very old devices.

Here's the class I use to upload textures now (feel free to use it or make your own modifications to it):
Code: [Select]
package com.aeroshark333.artofearthify.utils;

import android.opengl.GLES20;
import android.opengl.GLUtils;

import com.threed.jpct.RGBColor;
import com.threed.jpct.Texture;

// Created by Abiram/AeroShark333
public class CustomTexture extends Texture {
    final Bitmap bmp;

    public CustomTexture(Bitmap image) {
        super(2, 2, RGBColor.BLACK);
        this.bmp = image;

    public int loadTexture(final boolean forceNearest, final boolean keepInMemory){
        final int[] textureHandle = new int[1];

        GLES20.glGenTextures(1, textureHandle, 0);

        if (textureHandle[0] != 0)
            // Bind to the texture in OpenGL
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);

            // Set filtering
            if (!forceNearest) {
                GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
                GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
            }else {
                GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
                GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);

            // Load the bitmap into the bound texture.
            GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);

            // Recycle the bitmap, since its data has been loaded into OpenGL.
            if (!keepInMemory) {

        if (textureHandle[0] == 0)
            throw new RuntimeException("Error loading texture.");

        return textureHandle[0];

One could use the CustomTexture constructor from any Thread but the CustomTexture#loadTexture(boolean,boolean) method needs to be called from the GLThread.
This implementation is kinda very simple and it doesn't cover all of jPCT-AE's texture features (and it probably isn't really (easily) possible to have texture manipulation/effects like jPCT-AE supports them out of the box). However, the uploading process seems much faster using this method too. Also, this could potentially solve memory issues if you have them.

Now, I did say you could use near nothing in JVM RAM, so what about the Bitmap that is passed to this CustomTexture?
Well, as since Android 8.0, you can load Bitmap's immediately into the hardware-level (probably GPU..?), meaning that the Bitmap is not stored in the JVM RAM.
That is if you use Bitmap.Config.HARDWARE when you decode your image file (from resources, online of file):
Unfortunately, jPCT-AE does not seem to support Bitmap's that have been created using this Config, because of the immutability and inaccessibility of the Bitmap pixels.
However, but the CustomTexture class would work with Bitmap's that are using this Config.

I hope this could be useful for someone someday.
Feel free to give your thoughts and ideas :)


Support / Object3D generating issue
« on: July 23, 2018, 06:05:48 pm »

I've been trying to create some code to generate a geosphere/icosphere, I got somewhere but the results aren't exactly perfect.
Issue 1: UV mapping still does not seem perfect (especially around the top and bottom, where texCoord.y is around 0.0 or 1.0) but around the middle (0.5) all seems fine
Issue 2: I seem to get black polygons on some devices (but I don't get these black polygons on an emulator..?)

The code till now (it's not really optimized yet since I ported most of the code from some C# code:
Code: [Select]
private class TriangleIndices {
public int v1;
public int v2;
public int v3;

public TriangleIndices(int v1, int v2, int v3) {
this.v1 = v1;
this.v2 = v2;
this.v3 = v3;

private ArrayList<SimpleVector> vertexData;
private ArrayList<Integer> vertexDataIndices;
private int index;
private Map<Long, Integer> middlePointIndexCache;

// add vertex to mesh, fix position to be on unit sphere, return index
private int addVertex(SimpleVector p) {
// 0.5 is a scale factor here...
double length = Math.sqrt(p.x * p.x + p.y * p.y + p.z * p.z) / 0.5;
vertexData.add(new SimpleVector(p.x / length, p.y / length, p.z
/ length));
return index++;

// return index of point in the middle of p1 and p2
private int getMiddlePoint(int p1, int p2) {
// first check if we have it already
boolean firstIsSmaller = p1 < p2;
long smallerIndex = firstIsSmaller ? p1 : p2;
long greaterIndex = firstIsSmaller ? p2 : p1;
long key = (smallerIndex << 32) + greaterIndex;

if (middlePointIndexCache.containsKey(key)) {
int ret = this.middlePointIndexCache.get(key);
return ret;

// not in cache, calculate it
SimpleVector point1 = this.vertexData.get(p1);
SimpleVector point2 = this.vertexData.get(p2);
SimpleVector middle = new SimpleVector((point1.x + point2.x) / 2.0,
(point1.y + point2.y) / 2.0, (point1.z + point2.z) / 2.0);

// add vertex makes sure point is on unit sphere
int i = addVertex(middle);

// store it, return index
this.middlePointIndexCache.put(key, i);
return i;

public Object3D create(int recursionLevel) {
this.vertexData = new ArrayList<SimpleVector>();
this.vertexDataIndices = new ArrayList<Integer>();
this.middlePointIndexCache = new HashMap<Long, Integer>();
this.index = 0;

// create 12 vertices of a icosahedron
float t = (float) ((1.0f + Math.sqrt(5.0f)) / 2.0f);

addVertex(new SimpleVector(-1, t, 0));
addVertex(new SimpleVector(1, t, 0));
addVertex(new SimpleVector(-1, -t, 0));
addVertex(new SimpleVector(1, -t, 0));

addVertex(new SimpleVector(0, -1, t));
addVertex(new SimpleVector(0, 1, t));
addVertex(new SimpleVector(0, -1, -t));
addVertex(new SimpleVector(0, 1, -t));

addVertex(new SimpleVector(t, 0, -1));
addVertex(new SimpleVector(t, 0, 1));
addVertex(new SimpleVector(-t, 0, -1));
addVertex(new SimpleVector(-t, 0, 1));

// create 20 triangles of the icosahedron
List<TriangleIndices> faces = new ArrayList<TriangleIndices>();

// 5 faces around point 0
faces.add(new TriangleIndices(0, 11, 5));
faces.add(new TriangleIndices(0, 5, 1));
faces.add(new TriangleIndices(0, 1, 7));
faces.add(new TriangleIndices(0, 7, 10));
faces.add(new TriangleIndices(0, 10, 11));

// 5 adjacent faces
faces.add(new TriangleIndices(1, 5, 9));
faces.add(new TriangleIndices(5, 11, 4));
faces.add(new TriangleIndices(11, 10, 2));
faces.add(new TriangleIndices(10, 7, 6));
faces.add(new TriangleIndices(7, 1, 8));

// 5 faces around point 3
faces.add(new TriangleIndices(3, 9, 4));
faces.add(new TriangleIndices(3, 4, 2));
faces.add(new TriangleIndices(3, 2, 6));
faces.add(new TriangleIndices(3, 6, 8));
faces.add(new TriangleIndices(3, 8, 9));

// 5 adjacent faces
faces.add(new TriangleIndices(4, 9, 5));
faces.add(new TriangleIndices(2, 4, 11));
faces.add(new TriangleIndices(6, 2, 10));
faces.add(new TriangleIndices(8, 6, 7));
faces.add(new TriangleIndices(9, 8, 1));

// refine triangles
for (int i = 0; i < recursionLevel; i++) {
List<TriangleIndices> faces2 = new ArrayList<TriangleIndices>();
for (TriangleIndices tri : faces) {
// replace triangle by 4 triangles
int a = getMiddlePoint(tri.v1, tri.v2);
int b = getMiddlePoint(tri.v2, tri.v3);
int c = getMiddlePoint(tri.v3, tri.v1);

faces2.add(new TriangleIndices(tri.v1, a, c));
faces2.add(new TriangleIndices(tri.v2, b, a));
faces2.add(new TriangleIndices(tri.v3, c, b));
faces2.add(new TriangleIndices(a, b, c));
faces = faces2;

// done, now add triangles to mesh
for (TriangleIndices tri : faces) {

Object3D obj = new Object3D(vertexDataIndices.size() / 3);

for (int c = 0; c < (vertexDataIndices.size() / 3); c++) {

final SimpleVector aa = vertexData
.get(vertexDataIndices.get(c * 3));
final SimpleVector aaP = cartesianToPolar(aa, true);
final SimpleVector bb = vertexData.get(vertexDataIndices
.get(c * 3 + 1));
final SimpleVector bbP = cartesianToPolar(bb, true);
final SimpleVector cc = vertexData.get(vertexDataIndices
.get(c * 3 + 2));
final SimpleVector ccP = cartesianToPolar(cc, true);

// texture corrections...
if (Math.abs(aaP.z - bbP.z) > 0.5f) {
if (Math.abs(aaP.z - ccP.z) > 0.5f) {
if (Math.abs(bbP.z - ccP.z) > 0.5f) {

obj.addTriangle(aa, aaP.z, aaP.y, bb, bbP.z, bbP.y, cc, ccP.z,

return obj;

public static SimpleVector cartesianToPolar(SimpleVector cartesian,
boolean normalize) {
if (normalize) {
return new SimpleVector(
1.0 - (Math.acos(cartesian.y / cartesian.length()) / Math.PI),
1.0 - (Math.atan2(cartesian.x, cartesian.z) + Math.PI / 2.0)
/ (Math.PI * 2.0) );
return new SimpleVector(cartesian.length(), Math.acos(cartesian.z
/ cartesian.length()), Math.atan2(cartesian.y, cartesian.x));


Any idea what I'm doing wrong here?

Support / Camera rotation issue
« on: July 14, 2018, 01:34:13 pm »

I got a small issue with camera rotations.
My camera automatically rotates around a spherical object like this:
1. Set camera position to center of sphere.
2. Apply rotations
3. Camera.MOVE_OUT
This all works fine but after a long while (let's say 8+ hours) the rotation around the sphere don't seem spherical any more (or the rotation pivot center has some offset).
But the spherical object that the camera is facing isn't in the center any more but slightly offset. The longer you wait the worse this offset gets.
I suppose it'd have to do something with floating point precision but I'm not sure.
Any solutions?


Support / Calculate visibility of an Object3D
« on: December 20, 2017, 08:00:22 pm »

My problem is the following.
Let's say I have 2 Object3D's and one camera.
Object1 is drawn first using FOV setting 1.
Object2 is drawn after using FOV setting 2.
Both objects are sphere's (if that's helpful information)
A part of Object1 is 'blocked' by Object2 (which is fine since Object2 is closer to the camera anyway).

How can I calculate if Object1 is blocked or if it is visible?
And if Object1 is a complex Object3D how can I calculate what percentage of the total of Object1 is visible?

In the past I was able to calculate if Object1 was visible or not using sine, but in that case FOV1 = FOV2. (see sketch)
Now that the FOV's are different, it doesn't work.


Support / OpenGLES 3.0+
« on: November 14, 2017, 05:30:46 pm »

I have some questions regarding the OpenGLES version that jPCT supports or can support.
-> Will OpenGLES 3.0 be supported any time soon by jPCT-AE?
-> Will OpenGLES 3.1 be supported any time soon by jPCT-AE?
-> Will OpenGLES 3.2 be supported any time soon by jPCT-AE?
-> Since OpenGLES 3.0 is backwards compatible, wouldn't it be possible to render applications that now use OpenGLES2.0 using OpenGLES3.0 with some performance increase without changing too much to the jPCT-AE libary?


Support / Crash (native)
« on: July 10, 2017, 07:29:06 pm »

There are some issues with my app on some devices and I don't really know what's causing it...
Code: [Select]
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'motorola/surnia_retbr_dstv/surnia_udstv:6.0/MPI24.65-39-4/3:user/release-keys'
Revision: 'p30d'
ABI: 'arm'
pid: 4182, tid: 4448, name: GLThread 17896  >>> com.aeroshark333.artofearthify <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xa336f000
    r0 a336dab0  r1 a336dd10  r2 00000190  r3 a336efec
    r4 00000654  r5 9daa3d00  r6 a336e9b8  r7 a336e364
    r8 00000208  r9 00000000  sl 00000004  fp 00000000
    ip 00000020  sp a1c05528  lr a336edac  pc ac7a5396  cpsr 200f0030

    #00 pc 000bc396  /system/vendor/lib/egl/ (oxili_tile_texture+637)
    #01 pc 000917a3  /system/vendor/lib/egl/
    #02 pc 000935c9  /system/vendor/lib/egl/ (rb_texture_update_hw_subimage+4204)
    #03 pc 000949d7  /system/vendor/lib/egl/ (rb_texture_loadimage+224)
    #04 pc 0006e6b9  /system/vendor/lib/egl/ (TexImageLoad+216)
    #05 pc 0006e933  /system/vendor/lib/egl/ (core_glTexImage2D+234)
    #06 pc 0004cd3b  /system/vendor/lib/egl/ (glTexImage2D+50)
    #07 pc 0006b5cf  /system/lib/
    #08 pc 02d6f84d  /system/framework/arm/boot.oat (offset 0x1feb000)
Code: [Select]
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'motorola/surnia_retbr_dstv/surnia_udstv:6.0/MPI24.65-39-4/3:user/release-keys'
Revision: 'p30d'
ABI: 'arm'
pid: 3892, tid: 4136, name: GLThread 17925  >>> com.aeroshark333.artofearthify <<<
signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 0x9fa331a8
    r0 9fa32500  r1 9fa32520  r2 00000190  r3 9fa337fc
    r4 00000654  r5 9f386e00  r6 9fa331a8  r7 9fa32b74
    r8 0000014c  r9 00000000  sl 00000004  fp 00000000
    ip 00000032  sp a02ff528  lr 9fa337fc  pc ac7a538e  cpsr 800f0030

    #00 pc 000bc38e  /system/vendor/lib/egl/ (oxili_tile_texture+629)
    #01 pc 000917a3  /system/vendor/lib/egl/
    #02 pc 000935c9  /system/vendor/lib/egl/ (rb_texture_update_hw_subimage+4204)
    #03 pc 000949d7  /system/vendor/lib/egl/ (rb_texture_loadimage+224)
    #04 pc 0006e6b9  /system/vendor/lib/egl/ (TexImageLoad+216)
    #05 pc 0006e933  /system/vendor/lib/egl/ (core_glTexImage2D+234)
    #06 pc 0004cd3b  /system/vendor/lib/egl/ (glTexImage2D+50)
    #07 pc 0006b5cf  /system/lib/
    #08 pc 02d6f84d  /system/framework/arm/boot.oat (offset 0x1feb000)

The device is a Motorola Moto E with 4G (2nd Gen) running Android 6.0.
I can't reproduce this crash myself on any of my devices.

Projects / Art of Earthify (3D live wallpaper)
« on: May 28, 2017, 02:34:19 am »
Hey everyone,

I wanted to share my newest live wallpaper I made using this library! :)
The live wallpaper is actually based on a previous live wallpaper I made but I was not really satisfied with the result there.
I didn't work on this project too much due to studies but when I had some free time I'd be working on this.
Anyhow, I am really satisfied with the outcome of how it is now. :D

Original project:,4784.0.html (I just noticed all these dead links but I blame DropBox for that... ::) )

Screenshot 1:
Screenshot 2:
Screenshot 3:
Screenshot 4:
Screenshot 5:
Screenshot 6:

Download link:

I'd like to thank 'Egon Olsen' as always for the amazing library :)

Feel free to comment :)


Support / Could not link shader program error
« on: April 30, 2017, 02:35:00 pm »

I have a weird crash that I can't really explain since the logs don't give me enough information nor does the error stacktrace...
Code: [Select]
java.lang.RuntimeException: [ 1493390702610 ] - ERROR: Could not link shader program:
at com.threed.jpct.Logger.log(
at com.threed.jpct.GLSLShader.createProgram(
at com.threed.jpct.GLSLShader.loadProgram(
at com.threed.jpct.GLSLShader.preInit(
at com.threed.jpct.GL20.setShader(
at com.threed.jpct.GLRenderer.setShader(
at com.threed.jpct.CompiledInstance.render(
at com.threed.jpct.GLRenderer.drawVertexArray(
at com.threed.jpct.World.draw(
at com.threed.jpct.World.draw(
at com.aeroshark333.artofearthify.lw.LiveWallpaperRenderer.onDrawFrame(
at android.opengl.GLSurfaceView$GLThread.guardedRun(
at android.opengl.
I am using custom shaders and they do seem to work fine on most devices...
The only device that gave me this error happens to be my brother's phone (Samsung Galaxy S3 mini).
It works fine on my phone and enough other phones, however...

Thanks in advance :)

Pages: [1] 2