Skip to content

Commit

Permalink
Merge pull request #78 from 3Dpass/dev
Browse files Browse the repository at this point in the history
feat: Improve preview perfomance. Version 1.17.3
  • Loading branch information
L3odr0id authored Nov 23, 2024
2 parents 2e954f0 + 43b6b4e commit 73b87c5
Show file tree
Hide file tree
Showing 9 changed files with 191 additions and 165 deletions.
9 changes: 4 additions & 5 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,6 @@ android {
main.java.srcDirs += 'src/main/kotlin'
}

lintOptions {
disable 'InvalidPackage'
}

splits {
abi {
Expand Down Expand Up @@ -100,13 +97,15 @@ android {
// }
}
}
namespace 'com.threedpass.wallet'
lint {
disable 'InvalidPackage'
}

applicationVariants.configureEach { variant ->
variant.outputs.configureEach { output ->
def abiFilter = output.getFilter(com.android.build.OutputFile.ABI)
def abiVariant = abiFilter != null ? abiFilter : "universal"
// def abiFilter = output.variantOutputConfiguration.filters.find { it.filterType == FilterConfiguration.FilterType.ABI }
// def abiVariant = abiFilter != null ? abiFilter.identifier : "universal"
outputFileName = "threedpass" + "-" + versionName + "-" + abiVariant + ".apk"
}
}
Expand Down
3 changes: 1 addition & 2 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.threedpass.wallet">
xmlns:tools="http://schemas.android.com/tools">
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
calls FlutterMain.startInitialization(this); in its onCreate method.
In most cases you can leave this as-is, but you if you want to provide
Expand Down
20 changes: 19 additions & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ buildscript {
}

dependencies {
classpath 'com.android.tools.build:gradle:7.2.2'
classpath 'com.android.tools.build:gradle:7.4.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
Expand All @@ -21,6 +21,24 @@ allprojects {

rootProject.buildDir = '../build'
subprojects {
// fix for verifyReleaseResources https://github.com/isar/isar/issues/1662#issuecomment-2370929002
afterEvaluate { project ->
if (project.plugins.hasPlugin("com.android.application") ||
project.plugins.hasPlugin("com.android.library")) {
project.android {
compileSdkVersion 34
buildToolsVersion "34.0.0"
}
}
if (project.hasProperty("android")) {
project.android {
if (namespace == null) {
namespace project.group
}
}
}
}
// ===============================
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
Expand Down
147 changes: 108 additions & 39 deletions lib/features/legacy_preview/3d_engine.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,26 @@ import 'package:vector_math/vector_math.dart' as math;
import 'model.dart';
import 'utils.dart';

class RenderParams {
final bool backfaceCulling;

const RenderParams({
this.backfaceCulling = true,
});
}

class Object3D extends StatefulWidget {
final Size size;
final String value;
final double zoom;
// final double zoom;
// final double scale;
final Model model;
final RenderParams params;

Object3D({
required this.size,
// required this.path,
required this.value,
required this.zoom,
// this.scale = 1.0,
this.params = const RenderParams(),
super.key,
}) : model = Model()
..loadFromString(value)
Expand All @@ -37,30 +44,24 @@ class _Object3DState extends State<Object3D> {
double angleZ = 0.0;
double zoom = 0.0;

/*
* Load the 3D data from a file in our /assets folder.
*/
final Map<String, Color> colorCache = {};

void _dragX(final Offset delta) {
// setState(() {
angleX += delta.dy;
if (angleX > 360) {
angleX = angleX - 360;
} else if (angleX < 0) {
angleX = 360 - angleX;
}
// });
}

void _dragY(final Offset delta) {
// setState(() {
angleY += delta.dx;
if (angleY > 360) {
angleY = angleY - 360;
} else if (angleY < 0) {
angleY = 360 - angleY;
}
// });
}

@override
Expand All @@ -73,10 +74,12 @@ class _Object3DState extends State<Object3D> {
painter: _ObjectPainter(
size: widget.size,
model: widget.model,
params: widget.params,
colorCache: colorCache,
angleX: angleX,
angleY: angleY,
angleZ: angleZ,
zoom: widget.zoom,
// zoom: widget.zoom,
),
size: widget.size,
),
Expand All @@ -85,11 +88,11 @@ class _Object3DState extends State<Object3D> {
}

void onPointerMove(final PointerMoveEvent moveEvent) {
// print('D SCALE UPDATE $details');
// print('Delta ${moveEvent.delta}');
setState(() {
_dragX(moveEvent.delta);
_dragY(moveEvent.delta);
// print(
// 'Set state. moveX: ${moveEvent.delta.dx}, moveY: ${moveEvent.delta.dy}. Diff: ${now.difference(lastUpdate).inMilliseconds}');
});
}
}
Expand All @@ -100,9 +103,9 @@ class _Object3DState extends State<Object3D> {
* https://api.flutter.dev/flutter/rendering/CustomPainter-class.html
*/
class _ObjectPainter extends CustomPainter {
final double _viewPortX;
final double _viewPortY;
final double zoom;
// final double _viewPortX;
// final double _viewPortY;
static const double zoom = 1.0;

final math.Vector3 camera;
final math.Vector3 light;
Expand All @@ -116,32 +119,69 @@ class _ObjectPainter extends CustomPainter {
List<math.Vector3> verts;

final Model model;
final RenderParams params;

// The same paint draws paths on canvas
final Paint reusablePaint;
// The same matrix to transform the vertices
final math.Matrix4 reusableTrans;

final Map<String, Color> colorCache;

// Camera at origin
static final viewDirection = math.Vector3(0, 0, 1);
static const color = Color.fromRGBO(127, 127, 127, 1);

_ObjectPainter({
required this.size,
required this.model,
required this.params,
required this.colorCache,
required this.angleX,
required this.angleY,
required this.angleZ,
required this.zoom,
// required this.zoom,
}) : this.camera = math.Vector3(0.0, 0.0, 0.0),
light = math.Vector3(0.0, 0.0, 100.0),
verts = <math.Vector3>[],
_viewPortX = size.width / 2,
_viewPortY = size.height / 2;
reusablePaint = Paint()..style = PaintingStyle.fill,
// _viewPortX = size.width / 2,
// _viewPortY = size.height / 2,
reusableTrans =
math.Matrix4.translationValues(size.width / 2, size.height / 2, 1)
..scale(zoom, -zoom)
..rotateX(Utils.degreeToRadian(angleX))
..rotateY(Utils.degreeToRadian(angleY))
..rotateZ(Utils.degreeToRadian(angleZ));

/*
* We use a 4x4 matrix to perform our rotation, translation and scaling in
* a single pass.
* https://www.euclideanspace.com/maths/geometry/affine/matrix4x4/index.htm
*/
math.Vector3 _calcVertex(final math.Vector3 vertex) {
final trans = math.Matrix4.translationValues(_viewPortX, _viewPortY, 1);
trans.scale(zoom, -zoom);
trans.rotateX(Utils.degreeToRadian(angleX));
trans.rotateY(Utils.degreeToRadian(angleY));
trans.rotateZ(Utils.degreeToRadian(angleZ));
return trans.transform3(vertex);
return reusableTrans.transform3(vertex);
}

double dp(final double val, final int places) {
final num mod = pow(10.0, places);
return (val * mod).round().toDouble() / mod;
}

Color computeShadedColor(final Color baseColor, final double brightness) {
final roundedBrightness = dp(brightness, 3);
final key = '${baseColor.value}_${roundedBrightness}';
// print('Color: ${baseColor.value}');
final cachedColor = colorCache[key];
if (cachedColor != null) {
return cachedColor;
}
final r = (roundedBrightness * baseColor.red).toInt();
final g = (roundedBrightness * baseColor.green).toInt();
final b = (roundedBrightness * baseColor.blue).toInt();
final newColor = Color.fromARGB(255, r, g, b);
colorCache[key] = newColor;
return newColor;
}

/*
Expand All @@ -163,13 +203,12 @@ class _ObjectPainter extends CustomPainter {
final brightness = normal.clamp(0.0, 1.0);

// Assign a lighting color
final r = (brightness * color.red).toInt();
final g = (brightness * color.green).toInt();
final b = (brightness * color.blue).toInt();

final paint = Paint();
paint.color = Color.fromARGB(255, r, g, b);
paint.style = PaintingStyle.fill;
// final r = (brightness * color.red).toInt();
// final g = (brightness * color.green).toInt();
// final b = (brightness * color.blue).toInt();
// reusablePaint.color = Color.fromARGB(255, r, g, b);
final shadedColor = computeShadedColor(color, brightness);
reusablePaint.color = shadedColor;

// Paint the face
final path = Path();
Expand All @@ -178,7 +217,27 @@ class _ObjectPainter extends CustomPainter {
path.lineTo(v3.x, v3.y);
path.lineTo(v1.x, v1.y);
path.close();
canvas.drawPath(path, paint);
canvas.drawPath(path, reusablePaint);
}

/*
* Backface culling. If the polygon is facing the camera, then it is visible
*/
bool backfaceCullingSkip(
final math.Vector3 v1,
final math.Vector3 v2,
final math.Vector3 v3,
) {
if (!params.backfaceCulling) {
return false;
}

// Calculate the surface normal
final normalVector = Utils.normalVector3(v1, v2, v3);

// Backface culling: skip if normal points away from the camera
final dotProduct = normalVector.dot(viewDirection);
return dotProduct <= 0;
}

/*
Expand All @@ -188,15 +247,23 @@ class _ObjectPainter extends CustomPainter {
@override
void paint(final Canvas canvas, final Size size) {
// Rotate and translate the vertices
verts = <math.Vector3>[];
for (int i = 0; i < model.verts.length; i++) {
verts.add(_calcVertex(math.Vector3.copy(model.verts[i])));
}
verts = model.verts
.map((final v) => _calcVertex(math.Vector3.copy(v)))
.toList();

// Sort
final sorted = <Map<String, dynamic>>[];
for (var i = 0; i < model.faces.length; i++) {
final face = model.faces[i];
// Reference the rotated vertices
final v1 = verts[face[0] - 1];
final v2 = verts[face[1] - 1];
final v3 = verts[face[2] - 1];

if (backfaceCullingSkip(v1, v2, v3)) {
continue;
}

sorted.add(<String, dynamic>{
"index": i,
"order": Utils.zIndex(
Expand All @@ -214,9 +281,11 @@ class _ObjectPainter extends CustomPainter {
// Render
for (int i = 0; i < sorted.length; i++) {
final face = model.faces[sorted[i]["index"] as int];
final color = model.colors[sorted[i]["index"] as int];
// final color = model.colors[sorted[i]["index"] as int];
_drawFace(canvas, face, color);
}

// print(' Keys: ${colorCache.length}');
}

/*
Expand Down
26 changes: 13 additions & 13 deletions lib/features/legacy_preview/model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ class Model {
final List<Vector3> verts;
final List<List<int>> faces;

final List<Color> colors;
Map<String, Color> materials;
// final List<Color> colors;
// Map<String, Color> materials;

/*
* Converts normalised color values to a Color()
Expand All @@ -29,16 +29,16 @@ class Model {

Model()
: verts = <Vector3>[],
faces = <List<int>>[],
colors = <Color>[],
materials = {
"frontal": _toRGBA(0.848100, 0.607500, 1.000000),
"occipital": _toRGBA(1.000000, 0.572600, 0.392400),
"parietal": _toRGBA(0.379700, 0.830900, 1.000000),
"temporal": _toRGBA(1.000000, 0.930700, 0.468300),
"cerebellum": _toRGBA(0.506300, 1.000000, 0.598200),
"stem": _toRGBA(0.500000, 0.500000, 0.500000),
};
faces = <List<int>>[];
// colors = <Color>[],
// materials = {
// "frontal": _toRGBA(0.848100, 0.607500, 1.000000),
// "occipital": _toRGBA(1.000000, 0.572600, 0.392400),
// "parietal": _toRGBA(0.379700, 0.830900, 1.000000),
// "temporal": _toRGBA(1.000000, 0.930700, 0.468300),
// "cerebellum": _toRGBA(0.506300, 1.000000, 0.598200),
// "stem": _toRGBA(0.500000, 0.500000, 0.500000),
// };

void scale(final double value) {
double globalMaxCoord = 0.0;
Expand Down Expand Up @@ -88,7 +88,7 @@ class Model {
]),
);
//colors.add(materials[material]);
colors.add(_toRGBA(0.5, 0.5, 0.5));
// colors.add(_toRGBA(0.5, 0.5, 0.5));
}
});
}
Expand Down
2 changes: 0 additions & 2 deletions lib/features/legacy_preview/poscan_object_preview.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,7 @@ class _State extends State<PoscanObjectPreview> {
child: isLoaded
? Object3D(
size: widget.size,
zoom: 1.0,
value: content,
// scale: (widget.size.height - 32) / 2,
)
: const D3pProgressIndicator(size: 24),
);
Expand Down
Loading

0 comments on commit 73b87c5

Please sign in to comment.