Skip to content

Commit

Permalink
Add gobo resource handling (#1185)
Browse files Browse the repository at this point in the history
* Schema version 12.2.0:
  - Use JSON Schema definitions in manufacturer schema
  - Add gobo schema
  - Add references to gobo resources in `Gobo` wheel slots
* Model:
  - Embed resources into fixture JSON
  - Add and use Resource model class
* UI:
  - Preview gobo images in fixture pages' wheels
  - Preview gobo images in fixture pages' capability tables
  - Improve fixture page wheel styling
* Tests:
  - Test resource references in fixture test
  - Add fixture feature
* Support gobo import/export in QLC+ 4.12.1 plugin
* Add gobos for Showtec Phantom 50
* Update docs
  • Loading branch information
FloEdelmann committed Feb 11, 2020
1 parent 0a61c67 commit 6e759d2
Show file tree
Hide file tree
Showing 48 changed files with 943 additions and 192 deletions.
2 changes: 1 addition & 1 deletion cli/run-export-test.js
Expand Up @@ -71,7 +71,7 @@ const pluginExport = require(path.join(__dirname, `../plugins`, args.plugin, `ex

const outputPerFile = await Promise.all(files.map(async file => {
try {
await exportTest(file);
await exportTest(file, files);
return `${chalk.green(`[PASS]`)} ${file.name}`;
}
catch (err) {
Expand Down
1 change: 1 addition & 0 deletions docs/README.md
Expand Up @@ -11,6 +11,7 @@ This is the developer documentation for the *Open Fixture Library*. Please follo
- `fixture-features/`[Fixture features](fixture-features.md), special fixture characteristics used to determine a set of test fixtures
- `model/` – Classes of the [fixture model](fixture-model.md) that help ease processing fixture data (see the [model API reference](model-api.md))
* `plugins/`[Plugins](plugins.md) for export / import to / from other software's fixture formats
* `resources/` – Resources (e.g. [gobos](fixture-format.md#gobo-resources)) that fixtures can use
* `schemas/` – Schemas for the [fixture definitions](fixture-format.md#schema)
* `server/` – Load balancer config and auto-deploy script for everyone interested
* `tests/`[Unit tests](testing.md), much of them run automatically in GitHub with Travis
Expand Down
10 changes: 10 additions & 0 deletions docs/fixture-format.md
Expand Up @@ -19,6 +19,7 @@ This document gives a high-level overview of the concepts used in the JSON forma
- [Matrix structure](#matrix-structure)
- [Template channels](#template-channels)
- [Wheels](#wheels)
- [Gobo resources](#gobo-resources)
- [Using wheels in capabilities](#using-wheels-in-capabilities)
- [RDM (Remote Device Management) data](#rdm-remote-device-management-data)
- [Fixture redirects](#fixture-redirects)
Expand Down Expand Up @@ -329,6 +330,7 @@ The slots in a wheel have types, similar to [capability types](capability-types.
- `colors` (array of hex strings)
- `colorTemperature` ([Entity](capability-types.md#possible-entities-and-keywords) *ColorTemperature*)
* `Gobo`
- `resource` (resource reference string, see below)
- `name` (string)
* `Prism`
- `name` (string)
Expand All @@ -343,6 +345,14 @@ The slots in a wheel have types, similar to [capability types](capability-types.

Animation Gobo slots are wider than normal gobos (sometimes they fill the whole wheel); rotating the wheel over these slots creates an animation. To model the wider slots, an `AnimationGoboEnd` slot must be used directly after an `AnimationGoboStart` slot.

#### Gobo resources

Gobos are referenced with a resource reference in the form `gobos/<gobo key>`.

Gobo resources are stored in the [`resources/gobos/`](../resources/gobos/) directory. Each one consists of a JSON file (`<gobo key>.json`) describing the gobo (with name, keywords, and a source where the gobo image was extracted from) and the gobo image itself (`<gobo key>.svg` or `<gobo key>.png`).

In the [`resources/gobos/aliases/`](../resources/gobos/aliases/) directory, sets of aliases can be defined as separate JSON files in which aliases are mapped to gobo keys. This is useful for plugins (e.g. the QLC+ import plugin knows which OFL gobo key to use when QLC+ gobo `Others/0001.svg` is referenced in a fixture). It also enables referencing gobos in fixture files with an alias like `gobos/aliases/<alias file>/<alias key>` (e.g. a Robe fixture could reference `gobos/aliases/robe/15020246-rafia`) to make validating the gobo information easier with a manual where product numbers are specified.

#### Using wheels in capabilities

In wheel-related capabilities, the `wheel` property references the wheel by its name. If the `wheel` property is not set, the channel name is used as wheel name.
Expand Down
6 changes: 6 additions & 0 deletions docs/fixture-model.md
Expand Up @@ -71,3 +71,9 @@ export default class Fixture {
// ...
}
```

## Resource references

Resources (e.g. gobo images) are embedded by the model into the fixture JSON, i.e. instead of returning a string, `WheelSlot.resource` will return the resource object. The relevant code is in the `embedResourcesIntoFixtureJson` function in [`lib/model.js](../lib/model.js).

Thus, all information needed for the fixure is still included in the fixture JSON.
101 changes: 101 additions & 0 deletions docs/model-api.md
Expand Up @@ -42,6 +42,9 @@ Also called LSB (least significant byte) channel.</p>
<dt><a href="#Range">Range</a></dt>
<dd><p>Represents a range from one integer to a higher or equal integer. Primarily used for DMX ranges of capabilities.</p>
</dd>
<dt><a href="#Resource">Resource</a></dt>
<dd><p>Information about a resource.</p>
</dd>
<dt><a href="#SwitchingChannel">SwitchingChannel</a> ⇐ <code><a href="#AbstractChannel">AbstractChannel</a></code></dt>
<dd><p>Represents a channel that switches its behavior depending on trigger channel&#39;s value.
The different behaviors are implemented as different <a href="#CoarseChannel">CoarseChannel</a>s or <a href="#FineChannel">FineChannel</a>s.</p>
Expand Down Expand Up @@ -2254,6 +2257,98 @@ Merge specified Range objects. Asserts that ranges don't overlap and that all ra
| --- | --- | --- |
| ranges | [<code>Array.&lt;Range&gt;</code>](#Range) | Range objects to merge into as few ranges as possible. |

<a name="Resource"></a>

## Resource
Information about a resource.

**Kind**: global class

* [Resource](#Resource)
* [new Resource(jsonObject)](#new_Resource_new)
* [.name](#Resource+name) ⇒ <code>String</code>
* [.keywords](#Resource+keywords) ⇒ <code>Array.&lt;String&gt;</code>
* [.source](#Resource+source) ⇒ <code>String</code> \| <code>null</code>
* [.key](#Resource+key) ⇒ <code>String</code>
* [.type](#Resource+type) ⇒ <code>String</code>
* [.alias](#Resource+alias) ⇒ <code>String</code> \| <code>null</code>
* [.hasImage](#Resource+hasImage) ⇒ <code>Boolean</code>
* [.imageExtension](#Resource+imageExtension) ⇒ <code>String</code> \| <code>null</code>
* [.imageMimeType](#Resource+imageMimeType) ⇒ <code>String</code> \| <code>null</code>
* [.imageData](#Resource+imageData) ⇒ <code>String</code> \| <code>null</code>
* [.imageEncoding](#Resource+imageEncoding) ⇒ <code>&#x27;base64&#x27;</code> \| <code>&#x27;utf8&#x27;</code> \| <code>null</code>
* [.imageDataUrl](#Resource+imageDataUrl) ⇒ <code>String</code> \| <code>null</code>

<a name="new_Resource_new"></a>

### new Resource(jsonObject)
Creates a new Resource instance.


| Param | Type | Description |
| --- | --- | --- |
| jsonObject | <code>Object</code> | An embedded resource object from the fixture's JSON data. |

<a name="Resource+name"></a>

### resource.name ⇒ <code>String</code>
**Kind**: instance property of [<code>Resource</code>](#Resource)
**Returns**: <code>String</code> - The resource's name.
<a name="Resource+keywords"></a>

### resource.keywords ⇒ <code>Array.&lt;String&gt;</code>
**Kind**: instance property of [<code>Resource</code>](#Resource)
**Returns**: <code>Array.&lt;String&gt;</code> - An array of keywords belonging to this resource.
<a name="Resource+source"></a>

### resource.source ⇒ <code>String</code> \| <code>null</code>
**Kind**: instance property of [<code>Resource</code>](#Resource)
**Returns**: <code>String</code> \| <code>null</code> - The source this resource was taken from, or null if it's not specified.
<a name="Resource+key"></a>

### resource.key ⇒ <code>String</code>
**Kind**: instance property of [<code>Resource</code>](#Resource)
**Returns**: <code>String</code> - The resource key.
<a name="Resource+type"></a>

### resource.type ⇒ <code>String</code>
**Kind**: instance property of [<code>Resource</code>](#Resource)
**Returns**: <code>String</code> - The resource name, i.e. its directory.
<a name="Resource+alias"></a>

### resource.alias ⇒ <code>String</code> \| <code>null</code>
**Kind**: instance property of [<code>Resource</code>](#Resource)
**Returns**: <code>String</code> \| <code>null</code> - The resource alias, as specified in the fixture, or null if the resource was referenced directly.
<a name="Resource+hasImage"></a>

### resource.hasImage ⇒ <code>Boolean</code>
**Kind**: instance property of [<code>Resource</code>](#Resource)
**Returns**: <code>Boolean</code> - True if this resource has an associated image, false otherwise.
<a name="Resource+imageExtension"></a>

### resource.imageExtension ⇒ <code>String</code> \| <code>null</code>
**Kind**: instance property of [<code>Resource</code>](#Resource)
**Returns**: <code>String</code> \| <code>null</code> - The resource image's file extension, or null if there is no image.
<a name="Resource+imageMimeType"></a>

### resource.imageMimeType ⇒ <code>String</code> \| <code>null</code>
**Kind**: instance property of [<code>Resource</code>](#Resource)
**Returns**: <code>String</code> \| <code>null</code> - The resource image's MIME type, or null if there is no image.
<a name="Resource+imageData"></a>

### resource.imageData ⇒ <code>String</code> \| <code>null</code>
**Kind**: instance property of [<code>Resource</code>](#Resource)
**Returns**: <code>String</code> \| <code>null</code> - The resource image data (base64 or utf8 encoded), or null if there is no image.
<a name="Resource+imageEncoding"></a>

### resource.imageEncoding ⇒ <code>&#x27;base64&#x27;</code> \| <code>&#x27;utf8&#x27;</code> \| <code>null</code>
**Kind**: instance property of [<code>Resource</code>](#Resource)
**Returns**: <code>&#x27;base64&#x27;</code> \| <code>&#x27;utf8&#x27;</code> \| <code>null</code> - The resource image's data encoding, or null if there is no image.
<a name="Resource+imageDataUrl"></a>

### resource.imageDataUrl ⇒ <code>String</code> \| <code>null</code>
**Kind**: instance property of [<code>Resource</code>](#Resource)
**Returns**: <code>String</code> \| <code>null</code> - A data URL containing the resource image, or null if there is no image.
<a name="SwitchingChannel"></a>

## SwitchingChannel ⇐ [<code>AbstractChannel</code>](#AbstractChannel)
Expand Down Expand Up @@ -2540,6 +2635,7 @@ Information about a single wheel slot (or a split slot).
* [.isSplitSlot](#WheelSlot+isSplitSlot) ⇒ <code>Boolean</code>
* [.type](#WheelSlot+type) ⇒ <code>String</code>
* [.nthOfType](#WheelSlot+nthOfType) ⇒ <code>Number</code>
* [.resource](#WheelSlot+resource)[<code>Resource</code>](#Resource) \| <code>String</code> \| <code>null</code>
* [.name](#WheelSlot+name) ⇒ <code>String</code>
* [.colors](#WheelSlot+colors) ⇒ <code>Array.&lt;String&gt;</code> \| <code>null</code>
* [.colorTemperature](#WheelSlot+colorTemperature)[<code>Entity</code>](#Entity) \| <code>null</code>
Expand Down Expand Up @@ -2577,6 +2673,11 @@ Creates a new WheelSlot instance.
### wheelSlot.nthOfType ⇒ <code>Number</code>
**Kind**: instance property of [<code>WheelSlot</code>](#WheelSlot)
**Returns**: <code>Number</code> - The zero-based index of this slot amongst all slots with the same type in this wheel.
<a name="WheelSlot+resource"></a>

### wheelSlot.resource ⇒ [<code>Resource</code>](#Resource) \| <code>String</code> \| <code>null</code>
**Kind**: instance property of [<code>WheelSlot</code>](#WheelSlot)
**Returns**: [<code>Resource</code>](#Resource) \| <code>String</code> \| <code>null</code> - The gobo resource object if it was previously embedded, or the gobo resource reference string, or null if no resource is specified for the slot.
<a name="WheelSlot+name"></a>

### wheelSlot.name ⇒ <code>String</code>
Expand Down
16 changes: 8 additions & 8 deletions fixtures/showtec/phantom-50-led-spot.json
Expand Up @@ -6,7 +6,7 @@
"meta": {
"authors": ["Felix Edelmann", "Flo Edelmann"],
"createDate": "2017-04-29",
"lastModifyDate": "2018-09-04"
"lastModifyDate": "2020-02-11"
},
"comment": "Ordercode 40187",
"links": {
Expand Down Expand Up @@ -85,31 +85,31 @@
},
{
"type": "Gobo",
"name": "Gobo 1 Glass"
"resource": "gobos/glass-red-10-circles"
},
{
"type": "Gobo",
"name": "Gobo 2 Glass"
"resource": "gobos/glass-raindrops-on-window"
},
{
"type": "Gobo",
"name": "Gobo 3 Metal"
"resource": "gobos/3-fold-swirl"
},
{
"type": "Gobo",
"name": "Gobo 4 Metal"
"resource": "gobos/biohazard"
},
{
"type": "Gobo",
"name": "Gobo 5 Metal"
"resource": "gobos/rose-petal"
},
{
"type": "Gobo",
"name": "Gobo 6 Metal"
"resource": "gobos/triangle-hexagon-pattern"
},
{
"type": "Gobo",
"name": "Gobo 7 Metal"
"resource": "gobos/dot-spiral"
}
]
}
Expand Down
18 changes: 17 additions & 1 deletion lib/fixture-features/wheels.js
Expand Up @@ -37,4 +37,20 @@ const wheelSlotTypeFeatures = wheelSlotTypes.map(type => ({
)
}));

module.exports = wheelTypeFeatures.concat(wheelSlotTypeFeatures);
const resourceFeature = {
id: `wheel-slot-uses-resource`,
name: `Wheel slot uses resource`,
description: `Whether the fixture has at least one wheel slot that references a resource`,

/**
* @param {Fixture} fixture The Fixture instance
* @returns {Boolean} true if the fixture has at least one wheel slot that references a resource
*/
hasFeature: fixture => fixture.wheels.some(
wheel => wheel.slots.some(
slot => slot.resource !== null
)
)
};

module.exports = wheelTypeFeatures.concat(wheelSlotTypeFeatures, resourceFeature);

0 comments on commit 6e759d2

Please sign in to comment.