Skip to content

Commit

Permalink
feat: adding support of file inspector to configure assets
Browse files Browse the repository at this point in the history
  • Loading branch information
julien-moreau committed Feb 7, 2023
1 parent 5bde70b commit 51bde1d
Show file tree
Hide file tree
Showing 6 changed files with 295 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { platform } from "os";
import { basename } from "path";
import { shell } from "electron";
import { readJSON } from "fs-extra";
import { basename, join } from "path";

import { Nullable } from "../../../../../shared/types";
import { IStringDictionary, Nullable } from "../../../../../shared/types";

import * as React from "react";
import { MenuItem, Icon as BPIcon, MenuDivider } from "@blueprintjs/core";
Expand All @@ -16,6 +17,9 @@ import { Tools } from "../../../tools/tools";
import { Alert } from "../../../gui/alert";
import { Confirm } from "../../../gui/confirm";

import { WorkSpace } from "../../../project/workspace";
import { IAssetFileConfiguration } from "../../../project/typings";

import { InspectorNotifier } from "../../../gui/inspector/notifier";

import { IWorkerConfiguration, Workers } from "../../../workers/workers";
Expand Down Expand Up @@ -73,18 +77,33 @@ export abstract class AssetsBrowserItemHandler extends React.Component<IAssetsBr
* Defines the reference to the assets worker.
*/
public static AssetWorker: IWorkerConfiguration;
/**
* Defines the reference to the object that collects the configuration of all assets available
* in the workspace. The key represents the releative path to the file and the value the configuration
* of the asset. This is typically used to let the user choose how to handle the assets during the export.
*/
public static AssetsConfiguration: IStringDictionary<IAssetFileConfiguration> = {};

/**
* Initialzes the item handler.
*/
public static async Init(): Promise<void> {
// Create worker
const canvas = document.createElement("canvas");
canvas.width = 100;
canvas.height = 100;

const offscreen = canvas.transferControlToOffscreen();

this.AssetWorker = await Workers.LoadWorker("assets.js", offscreen);

// Load files configuration
try {
const filesPath = join(WorkSpace.DirPath!, "projects/files.json");
this.AssetsConfiguration = await readJSON(filesPath, { encoding: "utf-8" });
} catch (e) {
// Catch silently.
}
}

private _dropListener: Nullable<(ev: DragEvent) => void> = null;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
import * as React from "react";

import { InspectorSection } from "../../../gui/inspector/fields/section";

import { AssetsBrowserItemHandler } from "../../assets-browser/files/item-handler";

import { AbstractInspector } from "../abstract-inspector";
import { Inspector, IObjectInspectorProps } from "../../inspector";
import { InspectorList } from "../../../gui/inspector/fields/list";
import { WorkSpace } from "../../../project/workspace";
import { IAssetFileConfiguration } from "../../../project/typings";

export class TextureFileInspectorObject {
public constructor(
public relativePath: string,
) {
// Empty.
}
}

export interface ITextureFileInspectorState {
// ...
}

export class TextureFileInspector extends AbstractInspector<TextureFileInspectorObject, ITextureFileInspectorState> {
/**
* Constructor.
* @param props defines the component's props.
*/
public constructor(props: IObjectInspectorProps) {
super(props);

this.state = {};
}

/**
* Renders the content of the inspector.
*/
public renderContent(): React.ReactNode {
return (
<TextureFileInspectorComponent object={this.selectedObject} />
);
}
}

export interface ITextureFileInspectorComponentProps {
/**
* Defines the reference to the asset file configuration object.
*/
object: TextureFileInspectorObject;
}

export class TextureFileInspectorComponent extends React.Component<ITextureFileInspectorComponentProps, ITextureFileInspectorState> {
/**
* Constructor.
* @param props defines the component's props.
*/
public constructor(props: ITextureFileInspectorComponentProps) {
super(props);
}

/**
* Renders the component.
*/
public render(): React.ReactNode {
if (!this.props.object) {
return null;
}

AssetsBrowserItemHandler.AssetsConfiguration[this.props.object.relativePath] ??= {};

const configuration = AssetsBrowserItemHandler.AssetsConfiguration[this.props.object.relativePath];

return (
<InspectorSection title="Asset File Configuration">
{this._getCompressionInspector(configuration)}
</InspectorSection>
);
}

/**
* Returns the inspector used to edit the compression options of the texture file.
*/
private _getCompressionInspector(configuration: IAssetFileConfiguration): React.ReactNode {
if (!WorkSpace.Workspace?.ktx2CompressedTextures?.pvrTexToolCliPath) {
return undefined;
}

configuration.ktxCompression ??= {};
configuration.ktxCompression.astc ??= {
quality: "automatic",
};
configuration.ktxCompression.dxt ??= {
type: "automatic",
};
configuration.ktxCompression.pvrtc ??= {
quality: "automatic",
};
configuration.ktxCompression.etc1 ??= {
quality: "automatic",
};
configuration.ktxCompression.etc2 ??= {
quality: "automatic",
};

return (
<InspectorSection title="Compression">
<InspectorSection title="ASTC">
<InspectorList object={configuration.ktxCompression.astc} property="quality" label="Quality" items={[
{ label: "None", data: "none" },
{ label: "Automatic", data: "automatic" },
{ label: "astcveryfast", data: "astcveryfast" },
{ label: "astcfast", data: "astcfast" },
{ label: "astcmedium", data: "astcmedium" },
{ label: "astcthorough", data: "astcthorough" },
{ label: "astcexhaustive", data: "astcexhaustive" },
]} onChange={(r) => {
configuration.ktxCompression!.astc!.quality = r as any;
}} />
</InspectorSection>

<InspectorSection title="DXT">
<InspectorList object={configuration.ktxCompression.dxt} property="type" label="Type" items={[
{ label: "None", data: "none" },
{ label: "Automatic", data: "automatic" },
{ label: "BC1", data: "BC1" },
{ label: "BC2", data: "BC2" },
{ label: "BC3", data: "BC3" },
{ label: "BC4", data: "BC4" },
{ label: "BC5", data: "BC5" },
]} onChange={(r) => {
configuration.ktxCompression!.dxt!.type = r as any;
}} />
</InspectorSection>

<InspectorSection title="PVRTC">
<InspectorList object={configuration.ktxCompression.pvrtc} property="quality" label="Quality" items={[
{ label: "None", data: "none" },
{ label: "Automatic", data: "automatic" },
{ label: "pvrtcfastest", data: "pvrtcfastest" },
{ label: "pvrtcfast", data: "pvrtcfast" },
{ label: "pvrtclow", data: "pvrtclow" },
{ label: "pvrtcnormal", data: "pvrtcnormal" },
{ label: "pvrtchigh", data: "pvrtchigh" },
{ label: "pvrtcveryhigh", data: "pvrtcveryhigh" },
{ label: "pvrtcthorough", data: "pvrtcthorough" },
{ label: "pvrtcbest", data: "pvrtcbest" },
]} onChange={(r) => {
configuration.ktxCompression!.pvrtc!.quality = r as any;
}} />
</InspectorSection>

<InspectorSection title="ETC1">
<InspectorList object={configuration.ktxCompression.etc1} property="quality" label="Quality" items={[
{ label: "None", data: "none" },
{ label: "Automatic", data: "automatic" },
{ label: "etcfast", data: "etcfast" },
{ label: "etcnormal", data: "etcnormal" },
{ label: "etcslow", data: "etcslow" },
]} onChange={(r) => {
configuration.ktxCompression!.etc1!.quality = r as any;
}} />
</InspectorSection>

<InspectorSection title="ETC2">
<InspectorList object={configuration.ktxCompression.etc2} property="quality" label="Quality" items={[
{ label: "None", data: "none" },
{ label: "Automatic", data: "automatic" },
{ label: "etcfast", data: "etcfast" },
{ label: "etcnormal", data: "etcnormal" },
{ label: "etcslow", data: "etcslow" },
]} onChange={(r) => {
configuration.ktxCompression!.etc2!.quality = r as any;
}} />
</InspectorSection>
</InspectorSection>
);
}
}

Inspector.RegisterObjectInspector({
title: "Asset",
ctor: TextureFileInspector,
ctorNames: ["TextureFileInspectorObject"],
});
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,17 @@ import { KTXTools } from "../../../tools/ktx";
import { AbstractInspector } from "../abstract-inspector";
import { Inspector, IObjectInspectorProps } from "../../inspector";

import { TextureFileInspectorComponent, TextureFileInspectorObject } from "./texture-file-inspector";

export interface ITextureInspectorState {
/**
* Defines the current sampling mode of the texture.
*/
samplingMode?: number;
/**
* Defines the reference to the optional texture file object used to edit the texture's file configuration.
*/
textureFileObject?: TextureFileInspectorObject;
}

export class TextureInspector<T extends Texture | CubeTexture | ColorGradingTexture, S extends ITextureInspectorState> extends AbstractInspector<T, S> {
Expand Down Expand Up @@ -68,10 +74,38 @@ export class TextureInspector<T extends Texture | CubeTexture | ColorGradingText
{this.getScaleInspector()}
{this.getOffsetInspector()}
{this.getCubeTextureInspector()}

{this.getTextureFileComponent()}
</>
);
}

/**
* Called on the component did mount.
*/
public componentDidMount(): void {
super.componentDidMount();
this._checkTextureFile();
}

private async _checkTextureFile(): Promise<void> {
if (!(this.selectedObject instanceof Texture) || !this.selectedObject.url) {
return;
}

let textureUrl = this.selectedObject.url;
if (!isAbsolute(textureUrl)) {
textureUrl = join(WorkSpace.DirPath!, "assets", textureUrl);
}

if (!await pathExists(textureUrl)) {
return;
}

const relativeUrl = textureUrl.replace(join(WorkSpace.DirPath!, "assets/"), "");
this.setState({ textureFileObject: new TextureFileInspectorObject(relativeUrl) });
}

/**
* Returns the preview inspector that draws the texture preview.
*/
Expand Down Expand Up @@ -244,6 +278,19 @@ export class TextureInspector<T extends Texture | CubeTexture | ColorGradingText
);
}

/**
* Returns the inspector used to configure the texture's file configuration.
*/
protected getTextureFileComponent(): React.ReactNode {
if (!this.state.textureFileObject) {
return undefined;
}

return (
<TextureFileInspectorComponent object={this.state.textureFileObject} />
);
}

/**
* Reloads the texture in case the user taps the "Reload" button.
* Takes care of the compressed version of the texture.
Expand Down
1 change: 1 addition & 0 deletions src/renderer/editor/editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ import "./components/inspectors/materials/gradient-inspector";
import "./components/inspectors/materials/tri-planar-inspector";

import "./components/inspectors/textures/texture-inspector";
import "./components/inspectors/textures/texture-file-inspector";

import "./components/inspectors/particle-systems/particle-system-inspector";
import "./components/inspectors/particle-systems/particle-system-gradients-inspector";
Expand Down
26 changes: 25 additions & 1 deletion src/renderer/editor/project/typings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -432,4 +432,28 @@ export interface IBabylonFile {
id: string;
}[];
};
}
}

export interface IAssetFileConfiguration {
ktxCompression?: {
astc?: {
quality?: "none" | "automatic" | "astcveryfast" | "astcfast" | "astcmedium" | "astcthorough" | "astcexhaustive";
};

dxt?: {
type?: "none" | "automatic" | "BC1" | "BC2" | "BC3" | "BC4" | "BC5";
};

pvrtc?: {
quality?: "none" | "automatic" | "pvrtcfastest" | "pvrtcfast" | "pvrtclow" | "pvrtcnormal" | "pvrtchigh" | "pvrtcveryhigh" | "pvrtcthorough" | "pvrtcbest";
};

etc1?: {
quality?: "none" | "automatic" | "etcfast" | "etcnormal" | "etcslow";
};

etc2?: {
quality?: "none" | "automatic" | "etcfast" | "etcnormal" | "etcslow";
};
};
}
20 changes: 16 additions & 4 deletions src/renderer/editor/tools/ktx.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -234,15 +234,18 @@ export class KTXTools {
private static async _CompressUsingPVRTexTool(editor: Editor, texturePath: string, destinationFolder: string, type: KTXToolsType): Promise<void> {
const ktx2CliPath = this.GetCliPath();
const ktx2CompressedTextures = WorkSpace.Workspace!.ktx2CompressedTextures!;

const name = basename(texturePath);
const extension = extname(name).toLocaleLowerCase();

if (KTXTools.SupportedExtensions.indexOf(extension) === -1) {
return;
}

let editorProcess: Nullable<IEditorProcess> = null;

const relativePath = texturePath.replace(join(WorkSpace.DirPath!, "assets/"), "");
const configuration = AssetsBrowserItemHandler.AssetsConfiguration[relativePath];

const filename = `${name.substr(0, name.lastIndexOf("."))}${type}`;
const destination = join(destinationFolder, filename);
Expand Down Expand Up @@ -272,7 +275,16 @@ export class KTXTools {
break;

case "-dxt.ktx":
command = `"${ktx2CliPath}" -i "${texturePath}" -flip y -pot + -m -ics lRGB ${hasAlpha ? "-l" : ""} -f ${hasAlpha ? "BC2" : "BC1"},UBN,lRGB -o "${destination}"`;
let type = configuration?.ktxCompression?.dxt?.type ?? "automatic";
if (type === "none") {
command = null;
} else {
if (type === "automatic") {
type = hasAlpha ? "BC2" : "BC1";
}

command = `"${ktx2CliPath}" -i "${texturePath}" -flip y -pot + -m -ics lRGB ${hasAlpha ? "-l" : ""} -f ${type},UBN,lRGB -o "${destination}"`;
}
break;

case "-pvrtc.ktx":
Expand Down

0 comments on commit 51bde1d

Please sign in to comment.