diff --git a/app/build.gradle b/app/build.gradle index 724e01f1..539f7fcb 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -93,10 +93,13 @@ android { leia { dimension 'version' applicationIdSuffix '.leia' + minSdkVersion 30 + dependencies { + implementation files("../leia-cnsdk/cnsdk.aar") + } } } - packagingOptions { jniLibs { // https://issuetracker.google.com/issues/147096055#comment3 diff --git a/app/src/leia/java/com/simongellis/vvb/game/LeiaSurfaceViewAdapter.kt b/app/src/leia/java/com/simongellis/vvb/game/LeiaSurfaceViewAdapter.kt new file mode 100644 index 00000000..8c46268a --- /dev/null +++ b/app/src/leia/java/com/simongellis/vvb/game/LeiaSurfaceViewAdapter.kt @@ -0,0 +1,122 @@ +package com.simongellis.vvb.game + +import android.content.Context +import android.graphics.SurfaceTexture +import android.opengl.GLES20 +import android.util.AttributeSet +import android.util.Log +import com.leia.sdk.LeiaSDK +import com.leia.sdk.views.InputViewsAsset +import com.leia.sdk.views.InterlacedSurfaceView +import javax.microedition.khronos.egl.EGLConfig +import javax.microedition.khronos.opengles.GL10 + +class LeiaSurfaceViewAdapter : InterlacedSurfaceView, SurfaceViewAdapter, LeiaSDK.Delegate { + constructor(context: Context) : super(context) + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) + + private var inner: com.simongellis.vvb.emulator.Renderer? = null + + init { + val initArgs = LeiaSDK.InitArgs() + initArgs.delegate = this + initArgs.platform.context = context.applicationContext + initArgs.platform.activity = getActivity(context) + initArgs.enableFaceTracking = true + initArgs.requiresFaceTrackingPermissionCheck = false + LeiaSDK.createSDK(initArgs) + } + + override fun setRenderer(renderer: Renderer) { + val adapter = RendererAdapter(renderer) + super.setRenderer(adapter) + setViewAsset(adapter.asset) + } + + override fun setRenderer(renderer: com.simongellis.vvb.emulator.Renderer) { + inner = renderer + } + + inner class RendererAdapter(private val interlacer: Renderer) : Renderer { + val asset = InputViewsAsset() + private var framebuffer: Int? = null + private var textureId: Int? = null + private var texture: SurfaceTexture? = null + private var newSize: Pair? = null + + init { + asset.CreateEmptySurfaceForPicture(768, 224) { + texture = it + textureId = asset.GetSurfaceId() + } + } + + override fun onSurfaceCreated(gl: GL10?, p1: EGLConfig?) { + interlacer.onSurfaceCreated(gl, p1) + inner?.onSurfaceCreated() + } + + override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) { + newSize = width to height + texture?.setDefaultBufferSize(width, height) + interlacer.onSurfaceChanged(gl, width, height) + inner?.onSurfaceChanged(width, height) + } + + override fun onDrawFrame(gl: GL10) { + ensureInitialized() + framebuffer?.also { + GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, it) + inner?.onDrawFrame() + } + interlacer.onDrawFrame(gl) + } + + private fun ensureInitialized() { + val (width, height) = newSize ?: return + val textureId = this.textureId ?: return + + Log.i("LeiaSurfaceViewAdapter", "width: $width height: $height texture: $textureId") + + // TODO: clean up old framebuffer + Log.i("LeiaSurfaceViewAdapter", "setting up $textureId (error 0x${GLES20.glGetError().toString(16)})") + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId) + Log.i("LeiaSurfaceViewAdapter", "bound $textureId (error 0x${GLES20.glGetError().toString(16)})") + GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGB, width * 2, height, 0, GLES20.GL_RGB, GLES20.GL_UNSIGNED_BYTE, null) + Log.i("LeiaSurfaceViewAdapter", "initialized $textureId (error 0x${GLES20.glGetError().toString(16)})") + + val framebuffers = IntArray(1) + GLES20.glGenFramebuffers(1, framebuffers, 0) + val framebuffer = framebuffers[0] + this.framebuffer = framebuffer + Log.i("LeiaSurfaceViewAdapter", "initialized FB $framebuffer (error 0x${GLES20.glGetError().toString(16)})") + GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, framebuffer) + Log.i("LeiaSurfaceViewAdapter", "bound FB $framebuffer (error 0x${GLES20.glGetError().toString(16)})") + GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, textureId, 0) + Log.i("LeiaSurfaceViewAdapter", "set texture of FB (error 0x${GLES20.glGetError().toString(16)})") + GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0) + Log.i("LeiaSurfaceViewAdapter", "unbound FB (error 0x${GLES20.glGetError().toString(16)})") + + newSize = null + } + } + + override fun didInitialize(sdk: LeiaSDK) { + Log.i("LeiaSurfaceViewAdapter", "didInitialize") + } + + override fun onFaceTrackingFatalError(sdk: LeiaSDK) { + Log.i("LeiaSurfaceViewAdapter", "onFaceTrackingFatalError") + sdk.isFaceTrackingInFatalError?.let { + Log.i("LeiaSurfaceViewAdapter", "${it.code}: ${it.message}") + } + } + + override fun onFaceTrackingStarted(sdk: LeiaSDK) { + Log.i("LeiaSurfaceViewAdapter", "onFaceTrackingStarted") + } + + override fun onFaceTrackingStopped(sdk: LeiaSDK) { + Log.i("LeiaSurfaceViewAdapter", "onFaceTrackingStopped") + } +} \ No newline at end of file diff --git a/app/src/leia/res/layout/wrapper_surface_view_adapter.xml b/app/src/leia/res/layout/wrapper_surface_view_adapter.xml new file mode 100644 index 00000000..5514affc --- /dev/null +++ b/app/src/leia/res/layout/wrapper_surface_view_adapter.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/leia-cnsdk/cnsdk.aar b/leia-cnsdk/cnsdk.aar new file mode 100644 index 00000000..abc13a99 Binary files /dev/null and b/leia-cnsdk/cnsdk.aar differ diff --git a/src/video/renderers/leia.rs b/src/video/renderers/leia.rs index f7713856..2713ade8 100644 --- a/src/video/renderers/leia.rs +++ b/src/video/renderers/leia.rs @@ -16,7 +16,7 @@ uniform mat4 u_MV; varying vec2 v_TexCoord; void main() { gl_Position = u_MV * a_Pos; - v_TexCoord = a_TexCoord; + v_TexCoord = vec2(a_TexCoord.x, 1.0 - a_TexCoord.y); } "; @@ -28,19 +28,11 @@ varying vec2 v_TexCoord; void main() { - // + alignment_offset - float view_id = mod(floor(gl_FragCoord.x), 4.0); - if (view_id < 0.5) { gl_FragColor = texture2D(u_Textures[0], v_TexCoord); } - else if (view_id < 1.5) { gl_FragColor = texture2D(u_Textures[0], v_TexCoord); } - else if (view_id < 2.5) { gl_FragColor = texture2D(u_Textures[1], v_TexCoord); } + float view_id = mod(floor(gl_FragCoord.x), 2.0); + float other_id = mod(floor(gl_FragCoord.y), 2.0); + if ((view_id < 0.5) == (other_id < 0.5)) { gl_FragColor = texture2D(u_Textures[0], v_TexCoord); } else { gl_FragColor = texture2D(u_Textures[1], v_TexCoord); } gl_FragColor = mix(u_Colors[1], u_Colors[0], gl_FragColor.g); - - // // scanline - // vec2 uv = gl_FragCoord.xy / vec2(384.0,224.0); - // float scanline = clamp( 0.95 + 0.05 * cos( 3.14 * ( uv.y + 0.008 ) * 240.0 * 1.0 ), 0.0, 1.0 ); - // float grille = 0.85 + 0.15 * clamp( 1.5 * cos( 3.14 * uv.x * 640.0 * 1.0 ), 0.0, 1.0 ); - // gl_FragColor *= scanline * grille * 1.2; } ";