Browse Source

move quantizeColors to MeshExporter

Sukolsak Sakshuwong 3 years ago
parent
commit
fab8c74365
2 changed files with 66 additions and 65 deletions
  1. 66 0
      src/extensions/geo-export/mesh-exporter.ts
  2. 0 65
      src/extensions/geo-export/obj-exporter.ts

+ 66 - 0
src/extensions/geo-export/mesh-exporter.ts

@@ -4,6 +4,7 @@
  * @author Sukolsak Sakshuwong <sukolsak@stanford.edu>
  */
 
+import { sort, arraySwap } from '../../mol-data/util';
 import { GraphicsRenderObject } from '../../mol-gl/render-object';
 import { MeshValues } from '../../mol-gl/renderable/mesh';
 import { LinesValues } from '../../mol-gl/renderable/lines';
@@ -22,6 +23,7 @@ import { addCylinder } from '../../mol-geo/geometry/mesh/builder/cylinder';
 import { sizeDataFactor } from '../../mol-geo/geometry/size-data';
 import { Vec3 } from '../../mol-math/linear-algebra';
 import { RuntimeContext } from '../../mol-task';
+import { Color } from '../../mol-util/color/color';
 import { decodeFloatRGB } from '../../mol-util/float-packing';
 import { RenderObjectExporter, RenderObjectExportData } from './render-object-exporter';
 
@@ -111,6 +113,70 @@ export abstract class MeshExporter<D extends RenderObjectExportData> implements
         return interpolated.array;
     }
 
+    protected static quantizeColors(colorArray: Uint8Array, vertexCount: number) {
+        if (vertexCount <= 1024) return;
+        const rgb = Vec3();
+        const min = Vec3();
+        const max = Vec3();
+        const sum = Vec3();
+        const colorMap = new Map<Color, Color>();
+        const colorComparers = [
+            (colors: Color[], i: number, j: number) => (Color.toVec3(rgb, colors[i])[0] - Color.toVec3(rgb, colors[j])[0]),
+            (colors: Color[], i: number, j: number) => (Color.toVec3(rgb, colors[i])[1] - Color.toVec3(rgb, colors[j])[1]),
+            (colors: Color[], i: number, j: number) => (Color.toVec3(rgb, colors[i])[2] - Color.toVec3(rgb, colors[j])[2]),
+        ];
+
+        const medianCut = (colors: Color[], l: number, r: number, depth: number) => {
+            if (l > r) return;
+            if (l === r || depth >= 10) {
+                // Find the average color.
+                Vec3.set(sum, 0, 0, 0);
+                for (let i = l; i <= r; ++i) {
+                    Color.toVec3(rgb, colors[i]);
+                    Vec3.add(sum, sum, rgb);
+                }
+                Vec3.round(rgb, Vec3.scale(rgb, sum, 1 / (r - l + 1)));
+                const averageColor = Color.fromArray(rgb, 0);
+                for (let i = l; i <= r; ++i) colorMap.set(colors[i], averageColor);
+                return;
+            }
+
+            // Find the color channel with the greatest range.
+            Vec3.set(min, 255, 255, 255);
+            Vec3.set(max, 0, 0, 0);
+            for (let i = l; i <= r; ++i) {
+                Color.toVec3(rgb, colors[i]);
+                for (let j = 0; j < 3; ++j) {
+                    Vec3.min(min, min, rgb);
+                    Vec3.max(max, max, rgb);
+                }
+            }
+            let k = 0;
+            if (max[1] - min[1] > max[k] - min[k]) k = 1;
+            if (max[2] - min[2] > max[k] - min[k]) k = 2;
+
+            sort(colors, l, r + 1, colorComparers[k], arraySwap);
+
+            const m = (l + r) >> 1;
+            medianCut(colors, l, m, depth + 1);
+            medianCut(colors, m + 1, r, depth + 1);
+        };
+
+        // Create an array of unique colors and use the median cut algorithm.
+        const colorSet = new Set<Color>();
+        for (let i = 0; i < vertexCount; ++i) {
+            colorSet.add(Color.fromArray(colorArray, i * 3));
+        }
+        const colors = Array.from(colorSet);
+        medianCut(colors, 0, colors.length - 1, 0);
+
+        // Map actual colors to quantized colors.
+        for (let i = 0; i < vertexCount; ++i) {
+            const color = colorMap.get(Color.fromArray(colorArray, i * 3));
+            Color.toArray(color!, colorArray, i * 3);
+        }
+    }
+
     protected static getInstance(input: AddMeshInput, instanceIndex: number) {
         const { mesh, meshes } = input;
         if (mesh !== undefined) {

+ 0 - 65
src/extensions/geo-export/obj-exporter.ts

@@ -4,7 +4,6 @@
  * @author Sukolsak Sakshuwong <sukolsak@stanford.edu>
  */
 
-import { sort, arraySwap } from '../../mol-data/util';
 import { asciiWrite } from '../../mol-io/common/ascii';
 import { Box3D } from '../../mol-math/geometry';
 import { Vec3, Mat3, Mat4 } from '../../mol-math/linear-algebra';
@@ -69,70 +68,6 @@ export class ObjExporter extends MeshExporter<ObjData> {
         }
     }
 
-    private static quantizeColors(colorArray: Uint8Array, vertexCount: number) {
-        if (vertexCount <= 1024) return;
-        const rgb = Vec3();
-        const min = Vec3();
-        const max = Vec3();
-        const sum = Vec3();
-        const colorMap = new Map<Color, Color>();
-        const colorComparers = [
-            (colors: Color[], i: number, j: number) => (Color.toVec3(rgb, colors[i])[0] - Color.toVec3(rgb, colors[j])[0]),
-            (colors: Color[], i: number, j: number) => (Color.toVec3(rgb, colors[i])[1] - Color.toVec3(rgb, colors[j])[1]),
-            (colors: Color[], i: number, j: number) => (Color.toVec3(rgb, colors[i])[2] - Color.toVec3(rgb, colors[j])[2]),
-        ];
-
-        const medianCut = (colors: Color[], l: number, r: number, depth: number) => {
-            if (l > r) return;
-            if (l === r || depth >= 10) {
-                // Find the average color.
-                Vec3.set(sum, 0, 0, 0);
-                for (let i = l; i <= r; ++i) {
-                    Color.toVec3(rgb, colors[i]);
-                    Vec3.add(sum, sum, rgb);
-                }
-                Vec3.round(rgb, Vec3.scale(rgb, sum, 1 / (r - l + 1)));
-                const averageColor = Color.fromArray(rgb, 0);
-                for (let i = l; i <= r; ++i) colorMap.set(colors[i], averageColor);
-                return;
-            }
-
-            // Find the color channel with the greatest range.
-            Vec3.set(min, 255, 255, 255);
-            Vec3.set(max, 0, 0, 0);
-            for (let i = l; i <= r; ++i) {
-                Color.toVec3(rgb, colors[i]);
-                for (let j = 0; j < 3; ++j) {
-                    Vec3.min(min, min, rgb);
-                    Vec3.max(max, max, rgb);
-                }
-            }
-            let k = 0;
-            if (max[1] - min[1] > max[k] - min[k]) k = 1;
-            if (max[2] - min[2] > max[k] - min[k]) k = 2;
-
-            sort(colors, l, r + 1, colorComparers[k], arraySwap);
-
-            const m = (l + r) >> 1;
-            medianCut(colors, l, m, depth + 1);
-            medianCut(colors, m + 1, r, depth + 1);
-        };
-
-        // Create an array of unique colors and use the median cut algorithm.
-        const colorSet = new Set<Color>();
-        for (let i = 0; i < vertexCount; ++i) {
-            colorSet.add(Color.fromArray(colorArray, i * 3));
-        }
-        const colors = Array.from(colorSet);
-        medianCut(colors, 0, colors.length - 1, 0);
-
-        // Map actual colors to quantized colors.
-        for (let i = 0; i < vertexCount; ++i) {
-            const color = colorMap.get(Color.fromArray(colorArray, i * 3));
-            Color.toArray(color!, colorArray, i * 3);
-        }
-    }
-
     protected async addMeshWithColors(input: AddMeshInput) {
         const { mesh, values, isGeoTexture, webgl, ctx } = input;