(new NativeCameraSessionImplementation(cameraId, targetFps));
236 | }
237 | NativeCameraSession::~NativeCameraSession() = default;
--------------------------------------------------------------------------------
/app/src/arcore/java/org/example/viotester/arcore/BackgroundRenderer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package org.example.viotester.arcore; // NOTE: changed package name
16 |
17 | import android.content.Context;
18 | import android.opengl.GLES11Ext;
19 | import android.opengl.GLES20;
20 | import android.opengl.GLSurfaceView;
21 | import com.google.ar.core.Coordinates2d;
22 | import com.google.ar.core.Frame;
23 | import java.io.IOException;
24 | import java.nio.ByteBuffer;
25 | import java.nio.ByteOrder;
26 | import java.nio.FloatBuffer;
27 |
28 | import org.example.viotester.ext_ar.ShaderUtil; // NOTE: changed
29 | import androidx.annotation.NonNull; // NOTE: updated
30 |
31 | /**
32 | * This class renders the AR background from camera feed. It creates and hosts the texture given to
33 | * ARCore to be filled with the camera image.
34 | */
35 | public class BackgroundRenderer {
36 | private static final String TAG = BackgroundRenderer.class.getSimpleName();
37 |
38 | // Shader names.
39 | private static final String VERTEX_SHADER_NAME = "shaders/screenquad.vert";
40 | private static final String FRAGMENT_SHADER_NAME = "shaders/screenquad.frag";
41 |
42 | private static final int COORDS_PER_VERTEX = 2;
43 | private static final int TEXCOORDS_PER_VERTEX = 2;
44 | private static final int FLOAT_SIZE = 4;
45 |
46 | private FloatBuffer quadCoords;
47 | private FloatBuffer quadTexCoords;
48 |
49 | private int quadProgram;
50 |
51 | private int quadPositionParam;
52 | private int quadTexCoordParam;
53 | private int textureId = -1;
54 |
55 | public int getTextureId() {
56 | return textureId;
57 | }
58 |
59 | /**
60 | * Allocates and initializes OpenGL resources needed by the background renderer. Must be called on
61 | * the OpenGL thread, typically in {@link GLSurfaceView.Renderer#onSurfaceCreated(GL10,
62 | * EGLConfig)}.
63 | *
64 | * @param context Needed to access shader source.
65 | */
66 | public void createOnGlThread(Context context) throws IOException {
67 | // Generate the background texture.
68 | int[] textures = new int[1];
69 | GLES20.glGenTextures(1, textures, 0);
70 | textureId = textures[0];
71 | int textureTarget = GLES11Ext.GL_TEXTURE_EXTERNAL_OES;
72 | GLES20.glBindTexture(textureTarget, textureId);
73 | GLES20.glTexParameteri(textureTarget, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
74 | GLES20.glTexParameteri(textureTarget, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
75 | GLES20.glTexParameteri(textureTarget, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
76 | GLES20.glTexParameteri(textureTarget, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
77 |
78 | int numVertices = 4;
79 | if (numVertices != QUAD_COORDS.length / COORDS_PER_VERTEX) {
80 | throw new RuntimeException("Unexpected number of vertices in BackgroundRenderer.");
81 | }
82 |
83 | ByteBuffer bbCoords = ByteBuffer.allocateDirect(QUAD_COORDS.length * FLOAT_SIZE);
84 | bbCoords.order(ByteOrder.nativeOrder());
85 | quadCoords = bbCoords.asFloatBuffer();
86 | quadCoords.put(QUAD_COORDS);
87 | quadCoords.position(0);
88 |
89 | ByteBuffer bbTexCoordsTransformed =
90 | ByteBuffer.allocateDirect(numVertices * TEXCOORDS_PER_VERTEX * FLOAT_SIZE);
91 | bbTexCoordsTransformed.order(ByteOrder.nativeOrder());
92 | quadTexCoords = bbTexCoordsTransformed.asFloatBuffer();
93 |
94 | int vertexShader =
95 | ShaderUtil.loadGLShader(TAG, context, GLES20.GL_VERTEX_SHADER, VERTEX_SHADER_NAME);
96 | int fragmentShader =
97 | ShaderUtil.loadGLShader(TAG, context, GLES20.GL_FRAGMENT_SHADER, FRAGMENT_SHADER_NAME);
98 |
99 | quadProgram = GLES20.glCreateProgram();
100 | GLES20.glAttachShader(quadProgram, vertexShader);
101 | GLES20.glAttachShader(quadProgram, fragmentShader);
102 | GLES20.glLinkProgram(quadProgram);
103 | GLES20.glUseProgram(quadProgram);
104 |
105 | ShaderUtil.checkGLError(TAG, "Program creation");
106 |
107 | quadPositionParam = GLES20.glGetAttribLocation(quadProgram, "a_Position");
108 | quadTexCoordParam = GLES20.glGetAttribLocation(quadProgram, "a_TexCoord");
109 |
110 | ShaderUtil.checkGLError(TAG, "Program parameters");
111 | }
112 |
113 | /**
114 | * Draws the AR background image. The image will be drawn such that virtual content rendered with
115 | * the matrices provided by {@link com.google.ar.core.Camera#getViewMatrix(float[], int)} and
116 | * {@link com.google.ar.core.Camera#getProjectionMatrix(float[], int, float, float)} will
117 | * accurately follow static physical objects. This must be called before drawing virtual
118 | * content.
119 | *
120 | * @param frame The current {@code Frame} as returned by {@link Session#update()}.
121 | */
122 | public void draw(@NonNull Frame frame) {
123 | // If display rotation changed (also includes view size change), we need to re-query the uv
124 | // coordinates for the screen rect, as they may have changed as well.
125 | if (frame.hasDisplayGeometryChanged()) {
126 | frame.transformCoordinates2d(
127 | Coordinates2d.OPENGL_NORMALIZED_DEVICE_COORDINATES,
128 | quadCoords,
129 | Coordinates2d.TEXTURE_NORMALIZED,
130 | quadTexCoords);
131 | }
132 |
133 | if (frame.getTimestamp() == 0) {
134 | // Suppress rendering if the camera did not produce the first frame yet. This is to avoid
135 | // drawing possible leftover data from previous sessions if the texture is reused.
136 | return;
137 | }
138 |
139 | draw();
140 | }
141 |
142 | /**
143 | * Draws the camera image using the currently configured {@link BackgroundRenderer#quadTexCoords}
144 | * image texture coordinates.
145 | *
146 | * The image will be center cropped if the camera sensor aspect ratio does not match the screen
147 | * aspect ratio, which matches the cropping behavior of {@link
148 | * Frame#transformCoordinates2d(Coordinates2d, float[], Coordinates2d, float[])}.
149 | */
150 | public void draw(
151 | int imageWidth, int imageHeight, float screenAspectRatio, int cameraToDisplayRotation) {
152 | // Crop the camera image to fit the screen aspect ratio.
153 | float imageAspectRatio = (float) imageWidth / imageHeight;
154 | float croppedWidth;
155 | float croppedHeight;
156 | if (screenAspectRatio < imageAspectRatio) {
157 | croppedWidth = imageHeight * screenAspectRatio;
158 | croppedHeight = imageHeight;
159 | } else {
160 | croppedWidth = imageWidth;
161 | croppedHeight = imageWidth / screenAspectRatio;
162 | }
163 |
164 | float u = (imageWidth - croppedWidth) / imageWidth * 0.5f;
165 | float v = (imageHeight - croppedHeight) / imageHeight * 0.5f;
166 |
167 | float[] texCoordTransformed;
168 | switch (cameraToDisplayRotation) {
169 | case 90:
170 | texCoordTransformed = new float[] {1 - u, 1 - v, u, 1 - v, 1 - u, v, u, v};
171 | break;
172 | case 180:
173 | texCoordTransformed = new float[] {1 - u, v, 1 - u, 1 - v, u, v, u, 1 - v};
174 | break;
175 | case 270:
176 | texCoordTransformed = new float[] {u, v, 1 - u, v, u, 1 - v, 1 - u, 1 - v};
177 | break;
178 | case 0:
179 | texCoordTransformed = new float[] {u, 1 - v, u, v, 1 - u, 1 - v, 1 - u, v};
180 | break;
181 | default:
182 | throw new IllegalArgumentException("Unhandled rotation: " + cameraToDisplayRotation);
183 | }
184 |
185 | // Write image texture coordinates.
186 | quadTexCoords.position(0);
187 | quadTexCoords.put(texCoordTransformed);
188 |
189 | draw();
190 | }
191 |
192 | /**
193 | * Draws the camera background image using the currently configured {@link
194 | * BackgroundRenderer#quadTexCoords} image texture coordinates.
195 | */
196 | private void draw() {
197 | // Ensure position is rewound before use.
198 | quadTexCoords.position(0);
199 |
200 | // No need to test or write depth, the screen quad has arbitrary depth, and is expected
201 | // to be drawn first.
202 | GLES20.glDisable(GLES20.GL_DEPTH_TEST);
203 | GLES20.glDepthMask(false);
204 |
205 | GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
206 | GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureId);
207 |
208 | GLES20.glUseProgram(quadProgram);
209 |
210 | // Set the vertex positions.
211 | GLES20.glVertexAttribPointer(
212 | quadPositionParam, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, 0, quadCoords);
213 |
214 | // Set the texture coordinates.
215 | GLES20.glVertexAttribPointer(
216 | quadTexCoordParam, TEXCOORDS_PER_VERTEX, GLES20.GL_FLOAT, false, 0, quadTexCoords);
217 |
218 | // Enable vertex arrays
219 | GLES20.glEnableVertexAttribArray(quadPositionParam);
220 | GLES20.glEnableVertexAttribArray(quadTexCoordParam);
221 |
222 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
223 |
224 | // Disable vertex arrays
225 | GLES20.glDisableVertexAttribArray(quadPositionParam);
226 | GLES20.glDisableVertexAttribArray(quadTexCoordParam);
227 |
228 | // Restore the depth state for further drawing.
229 | GLES20.glDepthMask(true);
230 | GLES20.glEnable(GLES20.GL_DEPTH_TEST);
231 |
232 | ShaderUtil.checkGLError(TAG, "BackgroundRendererDraw");
233 | }
234 |
235 | private static final float[] QUAD_COORDS =
236 | new float[] {
237 | -1.0f, -1.0f, -1.0f, +1.0f, +1.0f, -1.0f, +1.0f, +1.0f,
238 | };
239 | }
--------------------------------------------------------------------------------
/app/src/debug/res/raw/gps.csv:
--------------------------------------------------------------------------------
1 | 200.371064552,60.182793445160755,24.826193458997786
2 | 201.384210907,60.182785867536296,24.826154549056632
3 | 202.383826531,60.18277994759502,24.82612098311984
4 | 203.383370802,60.182774506558644,24.82608938465673
5 | 204.397980698,60.18276860633057,24.826060773220785
6 | 205.38093538500002,60.18276655552955,24.826008942634218
7 | 206.392215072,60.18276628262222,24.825968133546375
8 | 207.375989551,60.18276548424482,24.825938300077095
9 | 208.37935101,60.18276418351494,24.825912796636562
10 | 209.389193718,60.18275668346239,24.825897341553652
11 | 210.393516113,60.1827487083377,24.82588028304136
12 | 211.37945673800002,60.18273768794814,24.82586657881064
13 | 212.390412467,60.18272526910527,24.825854743513766
14 | 213.38430413400002,60.18271030264724,24.825844593510148
15 | 214.389761946,60.18269756052974,24.825835741290522
16 | 215.382515592,60.182685487214194,24.825826374433603
17 | 216.388901529,60.18267318222605,24.825818006902896
18 | 217.384123925,60.18266193971304,24.82580581828761
19 | 218.395007258,60.182649385182266,24.825790281953314
20 | 219.39496090400002,60.18263793962778,24.825770323793293
21 | 220.396499966,60.18262800144442,24.82574986381041
22 | 221.400903612,60.18261659476439,24.82572902517706
23 | 222.39517548700002,60.18259994812676,24.82571205767433
24 | 223.396109861,60.18258462647734,24.825696637505658
25 | 224.383082257,60.18257236369817,24.825677810358332
26 | 225.369905174,60.1825623096003,24.82566138902404
27 | 226.357105694,60.18255436175246,24.825645149992997
28 | 227.382470798,60.182546117318275,24.82562589875461
29 | 228.386028611,60.182538034413575,24.825599646756864
30 | 229.391907256,60.18252794495867,24.825576387306295
31 | 230.39260256900002,60.18251589129161,24.825553634073778
32 | 231.394130694,60.18250829527563,24.825534395259595
33 | 232.384898923,60.18249983805254,24.825522031732387
34 | 233.373431214,60.18249101114514,24.825507151872237
35 | 234.377302047,60.18247964318209,24.825491396234515
36 | 235.384457255,60.182470664506674,24.825469521327133
37 | 236.38654006800002,60.182460215925126,24.825442988581084
38 | 237.374124443,60.18244789551716,24.82541960253423
39 | 238.368296318,60.18243500758566,24.825403736818206
40 | 239.37801663000002,60.18242688806578,24.82538480311425
41 | 240.383894234,60.18241920957751,24.82536181049688
42 | 241.359953088,60.182413028914794,24.825342192210268
43 | 242.37852965000002,60.18240629340985,24.825323863472327
44 | 243.374402567,60.182400203413614,24.82530615474024
45 | 244.374087983,60.18239538860223,24.8252877901685
46 | 245.386412462,60.182390964179795,24.82526595802837
47 | 246.400222358,60.18238416723436,24.825243152033924
48 | 247.399353608,60.182375797572064,24.82522460547915
49 | 248.374307254,60.18236578717873,24.82520619619098
50 | 249.383215587,60.182358422639304,24.825192025655845
51 | 250.384701524,60.18234861554914,24.82517020466119
52 | 251.402759336,60.18233896162664,24.82515042416599
53 | 252.382314545,60.18233124096684,24.82512847783784
54 | 253.381919232,60.18232424626032,24.82510636891273
55 | 254.390485898,60.182319929417446,24.825082132178718
56 | 255.39453694,60.182315644555075,24.825054987667265
57 | 256.373709336,60.182311657471345,24.825024092585124
58 | 257.37693850200003,60.18230992199291,24.824993994712827
59 | 258.393104648,60.18230903021177,24.82497276437966
60 | 259.379466106,60.18230951051811,24.82495406616999
61 | 260.393590064,60.18230922156362,24.824931569623356
62 | 261.401682772,60.18230676451082,24.824906462146348
63 | 262.398317147,60.18230785850009,24.824885893709823
64 | 263.373485897,60.18231320722324,24.824860174158708
65 | 264.396287459,60.1823210452117,24.824830868195267
66 | 265.38892183400003,60.18232759781553,24.82480403108859
67 | 266.386811938,60.18233382464375,24.824775851512065
68 | 267.403432771,60.18233929512079,24.824743746864318
69 | 268.39288954200003,60.18234434090735,24.824713785660784
70 | 269.39034839600004,60.182348282375536,24.8246929246465
71 | 270.402186938,60.18235163012878,24.82467271743605
72 | 271.386532771,60.182356190972456,24.824652244508567
73 | 272.381154646,60.182361356174404,24.824629223069458
74 | 273.385305166,60.18235930086367,24.824587199777856
75 | 274.380979125,60.18235999778722,24.82456282585367
76 | 275.394436416,60.182359859151404,24.824537905057515
77 | 276.37661349900003,60.18235820325386,24.82449977814425
78 | 277.398725999,60.182355482294554,24.824457065207316
79 | 278.399553082,60.18235033426451,24.824421959521505
80 | 279.403187978,60.18234694472739,24.824393158275765
81 | 280.399154644,60.18234188545365,24.824373543687138
82 | 281.400660373,60.18233364369519,24.824361096216748
83 | 282.379643186,60.182326407181804,24.82434892495339
84 | 283.376073394,60.18232025011347,24.824328548437506
85 | 284.387818186,60.18231437821054,24.82430601097356
86 | 285.38594006,60.18230964561826,24.824282894870958
87 | 286.40655256,60.182304167528564,24.82425836189623
88 | 287.375678602,60.18229930990905,24.824235929750024
89 | 288.376692664,60.18229350894255,24.824216119972675
90 | 289.355032768,60.18228819840525,24.824199143267556
91 | 290.391641622,60.182281660122854,24.82418215723051
92 | 291.377176518,60.18227507341256,24.824166245184966
93 | 292.409004643,60.1822699745991,24.824147288670652
94 | 293.385603601,60.182265463538634,24.824127331644192
95 | 294.382011413,60.18226056848141,24.824107524813844
96 | 295.402881205,60.182257014383914,24.82408775545883
97 | 296.388616621,60.18225225357881,24.824069195792436
98 | 297.384069225,60.182247438516164,24.824047277514897
99 | 298.380632246,60.18224290197542,24.824023427748227
100 | 299.373005162,60.182238153740975,24.824002841434698
101 | 300.366658808,60.18223456817855,24.823984496494486
102 | 301.382133287,60.18223120203794,24.82396557996954
103 | 302.378325474,60.18222924699878,24.823944601865307
104 | 303.401684328,60.18222681862828,24.82391945495798
105 | 304.358723391,60.182224404483,24.823898247370746
106 | 305.371895786,60.182222767049716,24.82387693666631
107 | 306.37971089,60.182220019194084,24.82385543442835
108 | 307.401114015,60.18221754792224,24.823829574072768
109 | 308.374191619,60.182214006094384,24.823806010849538
110 | 309.376615578,60.1822130790488,24.8237823137975
111 | 310.373718182,60.182217188549984,24.823755656883495
112 | 311.385820265,60.18222032057494,24.823728561489403
113 | 312.372204119,60.182220238921396,24.823702460118447
114 | 313.370318702,60.18221742326677,24.82368588688221
115 | 314.37329526400003,60.182213363830925,24.823669262270272
116 | 315.387213493,60.18220793695855,24.823651364969184
117 | 316.374282764,60.18219998917984,24.823633871408717
118 | 317.373394222,60.18219226354759,24.823615779952892
119 | 318.376496826,60.18218301394895,24.823602836356812
120 | 319.375550993,60.18217382219339,24.82359056063942
121 | 320.373843701,60.18216628773506,24.823575153173795
122 | 321.39177443,60.18215911868228,24.823556114255048
123 | 322.37947599200004,60.18215101399966,24.82353553457915
124 | 323.38940463800003,60.18214464190669,24.82351010870584
125 | 324.378916096,60.18214056067044,24.823483363784433
126 | 325.400874429,60.182139096990745,24.82345349171316
127 | 326.37347286700003,60.182137163899235,24.82342720301755
128 | 327.384333804,60.18213518295109,24.82339885755578
129 | 328.384036929,60.182132722470456,24.82336759460071
130 | 329.35879838700004,60.182131123700046,24.823335841134526
131 | 330.384861928,60.1821299259094,24.823305023742503
132 | 331.405475991,60.18212957146819,24.8232783799694
133 | 332.385968699,60.18212864793629,24.82325141454091
134 | 333.37462547,60.18212757904055,24.823220542389926
135 | 334.387892657,60.182127834246295,24.823190893457916
136 | 335.40597859400003,60.18212827458697,24.823161081331854
137 | 336.38963796900003,60.182129185688076,24.82313438903593
138 | 337.379285365,60.18212842876169,24.823106848320734
139 | 338.378120781,60.18212397009198,24.823076334148197
140 | 339.384429635,60.18211819309775,24.82304517330815
141 | 340.379593698,60.182112321893264,24.82301705198201
142 | 341.37933484300004,60.182105466412814,24.822989763263394
143 | 342.378917656,60.182097678552154,24.822963395260945
144 | 343.37170619700004,60.18208935202935,24.822941379087307
145 | 344.393459322,60.18208062987026,24.82292208863883
146 | 345.382506718,60.18207157300891,24.822902380765953
147 | 346.38453484300004,60.18206459619729,24.82288413535867
148 | 347.38226348800004,60.18205681937556,24.822868373835963
149 | 348.387720259,60.1820472887313,24.82285783199741
150 | 349.38947703,60.182037540620094,24.822846782553672
151 | 350.38286765500004,60.18202919150095,24.822839990672037
152 | 351.381805675,60.18202049782886,24.82283357375467
153 | 352.378441092,60.182009342138905,24.822824493854284
154 | 353.394243175,60.18200009770923,24.822807815686538
155 | 354.385122862,60.18199008063512,24.82279576345942
156 | 355.379591091,60.18197917396813,24.822785177013877
157 | 356.385219216,60.181969480234,24.82277423570119
158 | 357.372008799,60.18195836278805,24.822762511710902
159 | 358.379855153,60.181946254447375,24.822748599686538
160 | 359.390194737,60.18193241042697,24.8227336661935
161 | 360.385713486,60.181919067322,24.822718322647948
162 | 361.38360202800004,60.18190466682662,24.822701700650878
163 | 362.388635882,60.181891187179644,24.822687148684864
164 | 363.382132757,60.181879191970005,24.822668661010496
165 | 364.373423382,60.181867284606504,24.82265127917305
166 | 365.39647546500004,60.181856285064804,24.822636242152093
167 | 366.41354161000004,60.18184642886477,24.822616323587727
168 | 367.38969056900004,60.1818379232001,24.822594689754066
169 | 368.387202027,60.18183215332153,24.82256789952964
170 | 369.386510881,60.18182588726173,24.822531450564743
171 | 370.38185202700004,60.18182218572059,24.822503022398735
172 | 371.386850985,60.18182112161765,24.82248094745807
173 | 372.407032755,60.18182325198307,24.822456366437105
174 | 373.38482181800003,60.18182669050266,24.822432734770626
175 | 374.386044213,60.18182863606111,24.822407849190242
176 | 375.383882234,60.18183034085141,24.82238280151583
177 | 376.38511296300004,60.181832524472824,24.822356288493683
178 | 377.394845775,60.181835819464226,24.822329711800197
179 | 378.396510359,60.181838439849344,24.822304155413462
180 | 379.399565046,60.18184954183727,24.822283590488063
181 | 380.40041504600003,60.181855040984956,24.82225302557687
182 | 381.379985358,60.18185765116072,24.822227135693762
183 | 382.3716364,60.181860630483364,24.82219902628544
184 | 383.383090045,60.18186376511474,24.82217465013536
185 | 384.371477545,60.18186602928863,24.82214894657238
186 | 385.356042649,60.18186785558692,24.822120449793534
187 | 386.379836399,60.18186992668898,24.82209340969806
188 | 387.360228066,60.18187100653585,24.822066117214156
189 | 388.376596295,60.18187260040578,24.822041083797277
190 | 389.37491504400003,60.18187459386945,24.822014970964666
191 | 390.376569732,60.18187521517382,24.821988489900537
192 | 391.395764523,60.18187657911298,24.82196679070308
193 | 392.394433794,60.18187793457216,24.821945169131716
194 | 393.39926296100003,60.181877985121474,24.821921172301842
195 | 394.40166296,60.18187793196916,24.821893126588982
196 | 395.390077023,60.181878165243866,24.821863454294796
197 | 396.374463481,60.18187890501683,24.82183276419234
198 | 397.374018689,60.1818790862296,24.821801217889877
199 | 398.379316085,60.181877946845184,24.821766420364757
200 | 399.383802022,60.181875482136014,24.821736881640916
201 |
--------------------------------------------------------------------------------
/app/src/arcore/java/org/example/viotester/arcore/ARCoreActivity.java:
--------------------------------------------------------------------------------
1 | package org.example.viotester.arcore;
2 |
3 | import android.media.Image;
4 | import android.opengl.GLES20;
5 | import android.opengl.GLSurfaceView;
6 | import android.os.Bundle;
7 | import android.util.Log;
8 | import android.util.Size;
9 |
10 | import androidx.preference.PreferenceManager;
11 |
12 | import com.google.ar.core.ArCoreApk;
13 | import com.google.ar.core.Camera;
14 | import com.google.ar.core.CameraConfig;
15 | import com.google.ar.core.CameraConfigFilter;
16 | import com.google.ar.core.CameraIntrinsics;
17 | import com.google.ar.core.Frame;
18 | import com.google.ar.core.PointCloud;
19 | import com.google.ar.core.Session;
20 | import com.google.ar.core.TrackingState;
21 |
22 | import java.io.IOException;
23 | import java.util.EnumSet;
24 | import java.util.List;
25 | import java.util.Set;
26 | import java.util.TreeSet;
27 |
28 | import javax.microedition.khronos.egl.EGLConfig;
29 | import javax.microedition.khronos.opengles.GL10;
30 |
31 | import org.example.viotester.PermissionHelper;
32 | import org.example.viotester.ext_ar.Renderer;
33 | import org.example.viotester.AlgorithmActivity;
34 |
35 | // Unfortunately, due to a bug in Gradle, https://github.com/gradle/gradle/issues/9202
36 | // sometimes modifying this file results to a "Unable to find source java class" error when
37 | // used through a symlink, as in the ARCore & AREngine activity. The workaround is to
38 | // "Rebuild project" with Gradle OR just deleted the folder app/build/intermediates/javac
39 | public class ARCoreActivity extends AlgorithmActivity implements GLSurfaceView.Renderer {
40 | private static final String TAG = ARCoreActivity.class.getName();
41 |
42 | private Session mArCoreSession;
43 | private boolean mArCoreInstallRequested;
44 | private DisplayRotationHelper mDisplayRotationHelper;
45 |
46 | private final BackgroundRenderer mBackgroundRenderer = new BackgroundRenderer();
47 | private Renderer mNativeRenderer = new Renderer();
48 |
49 | private long mLastPointCloudTimestamp = 0;
50 | private float[] mPointCloudBuffer = null;
51 | private float[] mPointCloudOutBuffer = null;
52 |
53 | private long frameNumber = 0;
54 | private int screenWidth, screenHeight;
55 |
56 | @Override
57 | public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
58 | try {
59 | mBackgroundRenderer.createOnGlThread(/*context=*/ this);
60 | } catch (IOException e) {
61 | throw new RuntimeException(e);
62 | }
63 | mNativeRenderer.onSurfaceCreated(gl10, eglConfig);
64 | }
65 |
66 |
67 | @Override
68 | public void onSurfaceChanged(GL10 gl10, int w, int h) {
69 | super.onSurfaceChanged(gl10, w, h);
70 | screenWidth = w;
71 | screenHeight = h;
72 | mDisplayRotationHelper.onSurfaceChanged(w, h);
73 | mNativeRenderer.onSurfaceChanged(gl10, w, h);
74 | }
75 |
76 | @Override
77 | public void onDrawFrame(GL10 gl10) {
78 | // The other shaders, like GPU texture -> video recorders may have changed the
79 | // viewport, so it must be set each time before rendering (unlike in the original example)
80 | GLES20.glViewport(0, 0, screenWidth, screenHeight);
81 | // Clear screen to notify driver it should not load any pixels from previous frame.
82 | GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
83 |
84 | if (mArCoreSession == null) {
85 | return;
86 | }
87 | // Notify ARCore session that the view size changed so that the perspective matrix and
88 | // the video background can be properly adjusted.
89 | mDisplayRotationHelper.updateSessionIfNeeded(mArCoreSession);
90 |
91 | try {
92 | mArCoreSession.setCameraTextureName(mBackgroundRenderer.getTextureId());
93 |
94 | // Obtain the current frame from ARSession. When the configuration is set to
95 | // UpdateMode.BLOCKING (it is by default), this will throttle the rendering to the
96 | // camera framerate.
97 | Frame frame = mArCoreSession.update();
98 | Camera camera = frame.getCamera();
99 |
100 | // If frame is ready, render camera preview image to the GL surface.
101 | mBackgroundRenderer.draw(frame);
102 |
103 | // Get projection matrix.
104 | float[] projmtx = new float[16];
105 | camera.getProjectionMatrix(projmtx, 0, 0.1f, 100.0f);
106 |
107 | // Send image to native code for recording
108 | CameraIntrinsics intrinsics = camera.getImageIntrinsics();
109 | long timeNs = frame.getAndroidCameraTimestamp();
110 | // intrinsics.getFocalLength()[0] is the same, but let's use same method as AREngine version
111 | logExternalImage(mBackgroundRenderer.getTextureId(),
112 | timeNs,
113 | frameNumber++, 0,
114 | intrinsics.getImageDimensions(),
115 | intrinsics.getFocalLength(),
116 | intrinsics.getPrincipalPoint());
117 |
118 | // If not tracking, don't draw 3D objects, show tracking failure reason instead.
119 | if (camera.getTrackingState() == TrackingState.PAUSED) {
120 | return;
121 | }
122 |
123 | // Get camera matrix and draw.
124 | float[] viewmtx = new float[16];
125 | camera.getViewMatrix(viewmtx, 0);
126 |
127 | // Get point cloud
128 | try (PointCloud pointCloud = frame.acquirePointCloud()) {
129 | if (pointCloud.getTimestamp() != mLastPointCloudTimestamp) {
130 | // Log.v(TAG, "Point cloud updated");
131 | mLastPointCloudTimestamp = pointCloud.getTimestamp();
132 |
133 | final int ARCORE_FLOATS_PER_POINT = 4;
134 | final int OUT_FLOATS_PER_POINT = 3;
135 | final int nElements = pointCloud.getPoints().remaining();
136 | if (mPointCloudBuffer == null || mPointCloudOutBuffer.length < nElements) {
137 | // allocate a bit more than required now so this does not have to be
138 | // reallocated very often
139 | final int newSize = nElements * 2;
140 | // Log.d(TAG, "Allocating point cloud buffer of size " + newSize);
141 | mPointCloudBuffer = new float[newSize];
142 | mPointCloudOutBuffer = new float[nElements/ARCORE_FLOATS_PER_POINT*OUT_FLOATS_PER_POINT];
143 | }
144 | pointCloud.getPoints().get(mPointCloudBuffer, 0, nElements);
145 | final int nPoints = nElements/ARCORE_FLOATS_PER_POINT;
146 | for (int i=0; i < nPoints; ++i) {
147 | final int inOffs = i*ARCORE_FLOATS_PER_POINT;
148 | final int outOffs = i*OUT_FLOATS_PER_POINT;
149 | for (int j = 0; j < OUT_FLOATS_PER_POINT; ++j) {
150 | mPointCloudOutBuffer[outOffs + j] = mPointCloudBuffer[inOffs + j];
151 | }
152 | }
153 | mNativeRenderer.setPointCloud(mPointCloudOutBuffer, nPoints*OUT_FLOATS_PER_POINT);
154 | }
155 | }
156 |
157 | logExternalPoseMatrix(timeNs, viewmtx);
158 | mNativeRenderer.onDrawFrame(timeNs * 1e-9, viewmtx, projmtx, screenWidth, screenHeight);
159 |
160 | } catch (Throwable t) {
161 | // Avoid crashing the application due to unhandled exceptions.
162 | Log.e(TAG, "Exception on the OpenGL thread", t);
163 | }
164 | }
165 |
166 | @Override
167 | public void onCreate(Bundle savedInstanceState) {
168 | mRecordPrefix = "arcore";
169 | mNativeModule = "external";
170 |
171 | super.onCreate(savedInstanceState);
172 |
173 | mDisplayRotationHelper = new DisplayRotationHelper(/*context=*/ this);
174 | mGlSurfaceView.setWillNotDraw(false); // TODO what is this?
175 |
176 | mArCoreInstallRequested = false;
177 | }
178 |
179 | @Override
180 | public void onPause()
181 | {
182 | Log.d(TAG, "onPause");
183 | super.onPause();
184 | if (mArCoreSession != null) mArCoreSession.pause();
185 | }
186 |
187 | @Override
188 | public void onResume()
189 | {
190 | Log.d(TAG, "onResume");
191 | super.onResume();
192 |
193 | try {
194 | if (mArCoreSession == null) {
195 | switch (ArCoreApk.getInstance().requestInstall(this, !mArCoreInstallRequested)) {
196 | case INSTALL_REQUESTED:
197 | mArCoreInstallRequested = true;
198 | return;
199 | case INSTALLED:
200 | break;
201 | }
202 |
203 | if (!PermissionHelper.havePermissions(this))
204 | throw new IllegalStateException("should have permissions by now");
205 |
206 | // Create the session.
207 | mArCoreSession = new Session(/* context= */ this);
208 | }
209 |
210 | CameraConfigFilter filter = new CameraConfigFilter(mArCoreSession);
211 | if (mAlgoWorkerSettings.targetFps == 30) {
212 | filter.setTargetFps(EnumSet.of(CameraConfig.TargetFps.TARGET_FPS_30));
213 | } else if (mAlgoWorkerSettings.targetFps == 60) {
214 | filter.setTargetFps(EnumSet.of(CameraConfig.TargetFps.TARGET_FPS_60));
215 | }
216 | List cameraConfigList = mArCoreSession.getSupportedCameraConfigs(filter);
217 | Set resolutionSet = new TreeSet<>();
218 | Set fpsSet = new TreeSet<>();
219 | for (CameraConfig config : cameraConfigList) {
220 | Size s = config.getImageSize();
221 | if (s.equals(mAlgoWorkerSettings.targetImageSize)) {
222 | Log.d(TAG, "Founding matching camera config for resolution "
223 | + config.getImageSize());
224 | mArCoreSession.setCameraConfig(config);
225 | }
226 | resolutionSet.add(s.getWidth() + "x" + s.getHeight());
227 | fpsSet.add(Integer.toString(config.getFpsRange().getLower()));
228 | }
229 | PreferenceManager.getDefaultSharedPreferences(this )
230 | .edit()
231 | .putStringSet("resolution_set", resolutionSet)
232 | .apply();
233 | PreferenceManager.getDefaultSharedPreferences(this )
234 | .edit()
235 | .putStringSet("fps_set", fpsSet)
236 | .apply();
237 |
238 | mArCoreSession.resume();
239 |
240 | } catch (Exception e) {
241 | throw new RuntimeException(e);
242 | }
243 |
244 | mDisplayRotationHelper.onResume();
245 | }
246 | }
247 |
--------------------------------------------------------------------------------
/app/src/main/java/org/example/viotester/SettingsActivity.java:
--------------------------------------------------------------------------------
1 | package org.example.viotester;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import android.os.Bundle;
6 | import android.text.InputType;
7 | import android.widget.EditText;
8 |
9 | import java.util.ArrayList;
10 | import java.util.Arrays;
11 | import java.util.Collections;
12 | import java.util.Comparator;
13 | import java.util.HashSet;
14 | import java.util.Set;
15 | import java.util.TreeSet;
16 |
17 | import androidx.annotation.NonNull;
18 | import androidx.appcompat.app.AppCompatActivity;
19 | import androidx.preference.EditTextPreference;
20 | import androidx.preference.ListPreference;
21 | import androidx.preference.Preference;
22 | import androidx.preference.PreferenceFragmentCompat;
23 | import androidx.preference.PreferenceGroup;
24 | import androidx.preference.PreferenceManager;
25 | import androidx.preference.PreferenceScreen;
26 |
27 | public class SettingsActivity extends AppCompatActivity {
28 | static private final String DEFAULT_RESO = "1280x720";
29 | static private final String DEFAULT_FPS = "30";
30 |
31 | static String[] DEMO_MODE_SETTINGS = {
32 | "target_size",
33 | "fps",
34 | "visualization",
35 | "overlay_visualization",
36 | "reset_preferences"
37 | };
38 | static Set DEMO_MODE_SETTINGS_SET = new HashSet<>(Arrays.asList(DEMO_MODE_SETTINGS));
39 |
40 | @Override
41 | protected void onCreate(Bundle savedInstanceState) {
42 | super.onCreate(savedInstanceState);
43 | setContentView(R.layout.settings_activity);
44 | getSupportFragmentManager()
45 | .beginTransaction()
46 | .replace(R.id.settings, new SettingsFragment())
47 | .commit();
48 | }
49 |
50 | private static class ResolutionComparator implements Comparator {
51 | @Override
52 | public int compare(String r1, String r2) {
53 | String[] dims1 = r1.split("x"), dims2 = r2.split("x");
54 | int xDiff = Integer.parseInt(dims1[0]) - Integer.parseInt(dims2[0]);
55 | int yDiff = Integer.parseInt(dims1[1]) - Integer.parseInt(dims2[1]);
56 | if (xDiff != 0) return xDiff;
57 | return yDiff;
58 | }
59 | }
60 |
61 | public static class SettingsFragment extends PreferenceFragmentCompat {
62 | private Set mCameraSet;
63 | private Set mResolutionSet;
64 | private Set mFpsSet;
65 | private boolean mHasAutoFocalLength;
66 | private boolean mSlamPossible;
67 |
68 | @Override
69 | public void onAttach(@NonNull Context context) {
70 | super.onAttach(context);
71 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
72 | mCameraSet = prefs.getStringSet("camera_set", new TreeSet());
73 | mResolutionSet = prefs.getStringSet("resolution_set", new TreeSet());
74 | mFpsSet = prefs.getStringSet("fps_set", new TreeSet());
75 | mHasAutoFocalLength = prefs.getBoolean("has_auto_focal_length", false);
76 | mSlamPossible = prefs.getBoolean(AssetCopier.HAS_SLAM_FILES_KEY, false) && BuildConfig.USE_SLAM;
77 | }
78 |
79 | @Override
80 | public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
81 | setPreferencesFromResource(R.xml.root_preferences, rootKey);
82 | populateCameras();
83 | populateResolutions();
84 | populateFps();
85 | setFocalLength();
86 |
87 | Preference slamPref = findPreference("enable_slam");
88 | if (slamPref != null) slamPref.setEnabled(mSlamPossible);
89 |
90 | Preference resetButton = findPreference("reset_preferences");
91 | resetButton.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
92 | @Override
93 | public boolean onPreferenceClick(Preference preference) {
94 | SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
95 | SharedPreferences.Editor editor = preferences.edit();
96 | editor.clear();
97 | editor.apply();
98 | PreferenceManager.setDefaultValues(getActivity(), R.xml.root_preferences, true);
99 | getPreferenceScreen().removeAll();
100 | onCreatePreferences(null,null);
101 | return true;
102 | }
103 | });
104 |
105 | autoFixThings();
106 | }
107 |
108 | private void autoFixThings() {
109 | // hide non-whitelisted settings and empty categories
110 | PreferenceScreen screen = getPreferenceScreen();
111 | for (int i = 0; i < screen.getPreferenceCount(); ++i) {
112 | Preference p = screen.getPreference(i);
113 | if (p instanceof PreferenceGroup) {
114 | PreferenceGroup group = (PreferenceGroup)p;
115 | boolean anyVisible = false;
116 | for (int j = 0; j < group.getPreferenceCount(); ++j) {
117 | Preference child = group.getPreference(j);
118 | // only allow decimal input to fields whose key ends with _numeric
119 | if (child.getKey().endsWith("_numeric") && child instanceof EditTextPreference) {
120 | EditTextPreference e = (EditTextPreference) child;
121 | e.setOnBindEditTextListener(new EditTextPreference.OnBindEditTextListener() {
122 | @Override
123 | public void onBindEditText(@NonNull EditText editText) {
124 | editText.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
125 | }
126 | });
127 | }
128 | if (!BuildConfig.DEMO_MODE ||
129 | DEMO_MODE_SETTINGS_SET.contains(child.getKey()) ||
130 | DEMO_MODE_SETTINGS_SET.contains(p.getKey())) {
131 | anyVisible = true;
132 | } else {
133 | child.setVisible(false);
134 | }
135 | }
136 | if (!anyVisible) group.setVisible(false);
137 | } else {
138 | p.setVisible(false);
139 | }
140 | }
141 | }
142 |
143 | private void populateCameras() {
144 | // Get the Preference Category which we want to add the ListPreference to
145 | ListPreference pref = findPreference("target_camera");
146 |
147 | ArrayList cameras = new ArrayList<>();
148 | final CharSequence[] entries, entryValues;
149 |
150 | if (mCameraSet.isEmpty()) {
151 | entries = new CharSequence[]{"open tracking view to populate!"};
152 | entryValues = new CharSequence[]{ "0" };
153 | } else {
154 | cameras.addAll(mCameraSet);
155 |
156 | entries = new CharSequence[cameras.size()];
157 | entryValues = new CharSequence[cameras.size()];
158 |
159 | Collections.sort(cameras);
160 |
161 | for (int i = 0; i < cameras.size(); ++i) {
162 | entries[i] = cameras.get(i);
163 | entryValues[i] = cameras.get(i);
164 | }
165 | pref.setDefaultValue(cameras.get(0));
166 | }
167 |
168 | pref.setEntries(entries);
169 | pref.setEntryValues(entryValues);
170 |
171 | if (mCameraSet.size() == 1) {
172 | pref.setEnabled(false);
173 | }
174 | }
175 |
176 | private void populateResolutions() {
177 | // Get the Preference Category which we want to add the ListPreference to
178 | ListPreference resolutionListPref = findPreference("target_size");
179 |
180 | ArrayList resolutions = new ArrayList<>();
181 | final CharSequence[] entries, entryValues;
182 |
183 | if (mResolutionSet.isEmpty()) {
184 | entries = new CharSequence[]{"open tracking view to populate!"};
185 | entryValues = new CharSequence[]{ DEFAULT_RESO };
186 | } else {
187 | resolutions.addAll(mResolutionSet);
188 |
189 | entries = new CharSequence[resolutions.size()];
190 | entryValues = new CharSequence[resolutions.size()];
191 |
192 | Collections.sort(resolutions, new ResolutionComparator());
193 |
194 | for (int i = 0; i < resolutions.size(); ++i) {
195 | entries[i] = resolutions.get(i);
196 | entryValues[i] = resolutions.get(i);
197 | }
198 | }
199 |
200 | resolutionListPref.setEntries(entries);
201 | resolutionListPref.setEntryValues(entryValues);
202 | resolutionListPref.setDefaultValue(DEFAULT_RESO);
203 | }
204 |
205 | private void populateFps() {
206 | // Get the Preference Category which we want to add the ListPreference to
207 | ListPreference resolutionListPref = findPreference("fps");
208 | ArrayList fps = new ArrayList<>();
209 | final CharSequence[] entries, entryValues;
210 | if (mFpsSet.isEmpty()) {
211 | entries = new CharSequence[]{"open tracking view to populate!"};
212 | entryValues = new CharSequence[]{ DEFAULT_FPS };
213 | } else {
214 | fps.addAll(mFpsSet);
215 | Collections.sort(fps, new Comparator() {
216 | @Override
217 | public int compare(String r1, String r2) {
218 | return Integer.compare(Integer.parseInt(r1), Integer.parseInt(r2));
219 | }
220 | });
221 | entries = new CharSequence[fps.size()];
222 | entryValues = new CharSequence[fps.size()];
223 |
224 | for (int i = 0; i < fps.size(); ++i) {
225 | entries[i] = fps.get(i);
226 | entryValues[i] = fps.get(i);
227 | }
228 | }
229 | resolutionListPref.setEntries(entries);
230 | resolutionListPref.setEntryValues(entryValues);
231 | resolutionListPref.setDefaultValue(DEFAULT_RESO);
232 | }
233 |
234 | private void setFocalLength() {
235 | // Get the Preference Category which we want to add the ListPreference to
236 | EditTextPreference focalLength = findPreference("focal_length_1280");
237 | if (mHasAutoFocalLength) {
238 | focalLength.setEnabled(false);
239 | }
240 | else {
241 | // only allow numeric input
242 | focalLength.setOnBindEditTextListener(new EditTextPreference.OnBindEditTextListener() {
243 | @Override
244 | public void onBindEditText(@NonNull EditText editText) {
245 | editText.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
246 | }
247 | });
248 | }
249 | }
250 | }
251 | }
252 |
--------------------------------------------------------------------------------
/app/src/arengine/java/org/example/viotester/arengine/AREngineActivity.java:
--------------------------------------------------------------------------------
1 | package org.example.viotester.arengine;
2 |
3 | import android.media.Image;
4 | import android.opengl.GLES20;
5 | import android.opengl.GLSurfaceView;
6 | import android.os.Bundle;
7 | import android.util.Log;
8 |
9 | import com.huawei.hiar.ARCamera;
10 | import com.huawei.hiar.AREnginesSelector;
11 | import com.huawei.hiar.ARFrame;
12 | import com.huawei.hiar.ARImageMetadata;
13 | import com.huawei.hiar.ARSession;
14 | import com.huawei.hiar.AREnginesApk;
15 | import com.huawei.hiar.ARTrackable;
16 | import com.huawei.hiar.ARWorldTrackingConfig;
17 | import com.huawei.hiar.ARPointCloud;
18 | import com.huawei.hiar.exceptions.ARFatalException;
19 |
20 | import java.io.IOException;
21 |
22 | import javax.microedition.khronos.egl.EGLConfig;
23 | import javax.microedition.khronos.opengles.GL10;
24 |
25 | import org.example.viotester.AlgorithmActivity;
26 | import org.example.viotester.PermissionHelper;
27 | import org.example.viotester.ext_ar.Renderer;
28 |
29 | // See the comment in ARCoreActivity about the Gradle bug if you get weird errors
30 | // from building this class
31 | public class AREngineActivity extends AlgorithmActivity implements GLSurfaceView.Renderer {
32 | private static final String TAG = AREngineActivity.class.getName();
33 |
34 | private ARSession mSession;
35 | private boolean mInstallRequested;
36 | private DisplayRotationHelper mDisplayRotationHelper;
37 | private Renderer mNativeRenderer = new Renderer();
38 | private final BackgroundRenderer mBackgroundRenderer = new BackgroundRenderer();
39 |
40 | private ARPointCloud mARPointCloud = null;
41 | private float[] mPointCloudBuffer = null;
42 | private float[] mPointCloudOutBuffer = null;
43 |
44 | private long frameNumber = 0;
45 | private int screenWidth, screenHeight;
46 |
47 | @Override
48 | public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
49 | try {
50 | mBackgroundRenderer.createOnGlThread(/*context=*/ this);
51 | } catch (IOException e) {
52 | throw new RuntimeException(e);
53 | }
54 | mNativeRenderer.onSurfaceCreated(gl10, eglConfig);
55 | }
56 |
57 |
58 | @Override
59 | public void onSurfaceChanged(GL10 gl10, int w, int h) {
60 | super.onSurfaceChanged(gl10, w, h);
61 | mDisplayRotationHelper.onSurfaceChanged(w, h);
62 | mNativeRenderer.onSurfaceChanged(gl10, w, h);
63 | screenWidth = w;
64 | screenHeight = h;
65 | }
66 |
67 | @Override
68 | public void onDrawFrame(GL10 gl10) {
69 | // The other shaders, like GPU texture -> video recorders may have changed the
70 | // viewport, so it must be set each time before rendering (unlike in the original example)
71 | GLES20.glViewport(0, 0, screenWidth, screenHeight);
72 | // Clear screen to notify driver it should not load any pixels from previous frame.
73 | GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
74 |
75 | if (mSession == null) {
76 | return;
77 | }
78 | // Notify ARCore session that the view size changed so that the perspective matrix and
79 | // the video background can be properly adjusted.
80 | mDisplayRotationHelper.updateSessionIfNeeded(mSession);
81 |
82 | try {
83 | mSession.setCameraTextureName(mBackgroundRenderer.getTextureId());
84 |
85 | // Obtain the current frame from ARSession. When the configuration is set to
86 | // UpdateMode.BLOCKING (it is by default), this will throttle the rendering to the
87 | // camera framerate.
88 | ARFrame frame = mSession.update();
89 | ARCamera camera = frame.getCamera();
90 |
91 | // If frame is ready, render camera preview image to the GL surface.
92 | mBackgroundRenderer.draw(frame);
93 |
94 | // Get projection matrix.
95 | float[] projmtx = new float[16];
96 | camera.getProjectionMatrix(projmtx, 0, 0.1f, 100.0f);
97 |
98 | // TODO: using image only for receiving the size, no need actually read it every frame
99 | Image image = frame.acquireCameraImage();
100 | int width = -1, height = -1;
101 | float focalLength = -1;
102 | try {
103 | width = image.getWidth();
104 | height = image.getHeight();
105 | focalLength = projmtx[0] * height / 2.f;
106 | } catch (ARFatalException e) {
107 | // TODO: find out why this sometimes happens
108 | Log.e(TAG, "Failure in AR image read", e);
109 | Log.w(TAG, "skipping frame");
110 | return;
111 | } finally {
112 | // While ARCore requires this, AREngine works without. However, to ensure future
113 | // compatibility, it feels safer to call it if AREngine gets more aligned with ARCore
114 | // in the future.
115 | image.close();
116 | }
117 |
118 | if (width <= 0 || height <= 0) {
119 | Log.e(TAG, "invalid dimenstions in AR image");
120 | return;
121 | }
122 |
123 | logExternalImage(mBackgroundRenderer.getTextureId(),
124 | frame.getTimestampNs(),
125 | frameNumber++, 0,
126 | new int[]{ width, height },
127 | new float[]{ focalLength, focalLength },
128 | new float[]{ width*0.5f, height*0.5f});
129 |
130 | // If not tracking, don't draw 3D objects, show tracking failure reason instead.
131 | if (camera.getTrackingState() == ARTrackable.TrackingState.PAUSED) {
132 | return;
133 | }
134 |
135 | // Get camera matrix and draw.
136 | float[] viewmtx = new float[16];
137 | camera.getViewMatrix(viewmtx, 0);
138 |
139 | // Get point cloud
140 | ARPointCloud pointCloud = frame.acquirePointCloud();
141 |
142 | // NOTE: this check is actually different from ARCore: If the point cloud has not
143 | // changed, AREngine returns the same object/pointer, while in ARCore, you are supposed
144 | // to check the timestamp
145 | if (pointCloud != mARPointCloud) {
146 | // Log.v(TAG, "Point cloud updated");
147 | mARPointCloud = pointCloud;
148 |
149 | final int ARCORE_FLOATS_PER_POINT = 4;
150 | final int OUT_FLOATS_PER_POINT = 3;
151 | final int nElements = pointCloud.getPoints().remaining();
152 | if (mPointCloudBuffer == null || mPointCloudOutBuffer.length < nElements) {
153 | // allocate a bit more than required now so this does not have to be
154 | // reallocated very often
155 | final int newSize = nElements * 2;
156 | // Log.d(TAG, "Allocating point cloud buffer of size " + newSize);
157 | mPointCloudBuffer = new float[newSize];
158 | mPointCloudOutBuffer = new float[nElements/ARCORE_FLOATS_PER_POINT*OUT_FLOATS_PER_POINT];
159 | }
160 | pointCloud.getPoints().get(mPointCloudBuffer, 0, nElements);
161 | final int nPoints = nElements/ARCORE_FLOATS_PER_POINT;
162 | for (int i=0; i < nPoints; ++i) {
163 | final int inOffs = i*ARCORE_FLOATS_PER_POINT;
164 | final int outOffs = i*OUT_FLOATS_PER_POINT;
165 | for (int j = 0; j < OUT_FLOATS_PER_POINT; ++j) {
166 | mPointCloudOutBuffer[outOffs + j] = mPointCloudBuffer[inOffs + j];
167 | }
168 | }
169 | mNativeRenderer.setPointCloud(mPointCloudOutBuffer, nPoints*OUT_FLOATS_PER_POINT);
170 | }
171 |
172 | long timeNs = frame.getTimestampNs();
173 | logExternalPoseMatrix(timeNs, viewmtx);
174 | mNativeRenderer.onDrawFrame(timeNs * 1e-9, viewmtx, projmtx, screenWidth, screenHeight);
175 |
176 | } catch (Throwable t) {
177 | // Avoid crashing the application due to unhandled exceptions.
178 | Log.e(TAG, "Exception on the OpenGL thread", t);
179 | }
180 | }
181 |
182 | @Override
183 | public void onCreate(Bundle savedInstanceState) {
184 | mRecordPrefix = "arengine";
185 | mNativeModule = "external";
186 |
187 | super.onCreate(savedInstanceState);
188 |
189 | mDisplayRotationHelper = new DisplayRotationHelper(/*context=*/ this);
190 | mGlSurfaceView.setWillNotDraw(false); // TODO what is this?
191 | mInstallRequested = false;
192 | }
193 |
194 | @Override
195 | public void onPause()
196 | {
197 | Log.d(TAG, "onPause");
198 | super.onPause();
199 | if (mSession != null) mSession.pause();
200 | }
201 |
202 | @Override
203 | public void onResume()
204 | {
205 | Log.d(TAG, "onResume");
206 | super.onResume();
207 |
208 | try {
209 |
210 | if (null == mSession) {
211 | //If you do not want to switch engines, AREnginesSelector is useless.
212 | // You just need to use AREnginesApk.requestInstall() and the default engine
213 | // is Huawei AR Engine.
214 | AREnginesSelector.AREnginesAvaliblity enginesAvaliblity = AREnginesSelector.checkAllAvailableEngines(this);
215 | if ((enginesAvaliblity.ordinal()
216 | & AREnginesSelector.AREnginesAvaliblity.HWAR_ENGINE_SUPPORTED.ordinal()) != 0) {
217 |
218 | AREnginesSelector.setAREngine(AREnginesSelector.AREnginesType.HWAR_ENGINE);
219 |
220 | Log.d(TAG, "installRequested:" + mInstallRequested);
221 | switch (AREnginesApk.requestInstall(this, !mInstallRequested)) {
222 | case INSTALL_REQUESTED:
223 | Log.d(TAG, "INSTALL_REQUESTED");
224 | mInstallRequested = true;
225 | return;
226 | case INSTALLED:
227 | break;
228 | }
229 |
230 | if (!PermissionHelper.havePermissions(this))
231 | throw new IllegalStateException("should have permissions at this point");
232 |
233 | mSession = new ARSession(/*context=*/this);
234 | ARWorldTrackingConfig config = new ARWorldTrackingConfig(mSession);
235 |
236 | int supportedSemanticMode = mSession.getSupportedSemanticMode();
237 | Log.d(TAG, "supportedSemanticMode:" + supportedSemanticMode);
238 |
239 | if (supportedSemanticMode != ARWorldTrackingConfig.SEMANTIC_NONE) {
240 | Log.d(TAG, "supported mode:" + supportedSemanticMode);
241 | config.setSemanticMode(supportedSemanticMode);
242 | final int modeSet = config.getSemanticMode();
243 | Log.d(TAG, "supportedSemanticMode:" + modeSet);
244 | }
245 |
246 | mSession.configure(config);
247 | mSession.resume();
248 | } else {
249 | throw new RuntimeException("This device does not support Huawei AR Engine");
250 | }
251 | }
252 | } catch (Exception e) {
253 | throw new RuntimeException(e);
254 | }
255 |
256 | mDisplayRotationHelper.onResume();
257 | }
258 | }
259 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------