Skip to content

Commit

Permalink
fix(map): correct remaining normalization issues for map defs
Browse files Browse the repository at this point in the history
  • Loading branch information
fallenoak committed Jan 4, 2024
1 parent 499233c commit a67aaec
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 33 deletions.
13 changes: 12 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
"wowser"
],
"dependencies": {
"@wowserhq/io": "^2.0.2"
"@wowserhq/io": "^2.0.2",
"gl-matrix": "^3.4.3"
},
"devDependencies": {
"@commitlint/config-conventional": "^18.4.3",
Expand Down
32 changes: 32 additions & 0 deletions src/lib/map/Map.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { IoMode, IoSource, openStream } from '@wowserhq/io';
import { quat } from 'gl-matrix';
import * as wdtIo from './io/wdt.js';
import {
AREA_INFO_FLAG,
Expand Down Expand Up @@ -56,6 +57,37 @@ class Map {
};
}

/**
* Convert the given position vector in the doodad or map obj def coordinate system into a vector
* in the map coordinate system.
*
* @param defPosition - Vector in doodad / map obj def coordinate system
*/
static getNormalizedDefPosition(defPosition: Float32Array) {
const normalized = new Float32Array(3);

normalized[0] = MAP_CORNER_X - defPosition[2];
normalized[1] = MAP_CORNER_Y - defPosition[0];
normalized[2] = defPosition[1];

return normalized;
}

/**
* Convert the given Euler angle in the doodad or map obj def coordinate system into a quaternion
* in the map coordinate system.
*
* @param defRotation - Euler angle in doodad / map obj def coordinate system
*/
static getNormalizedDefRotation(defRotation: Float32Array) {
const normalized = quat.create();

// glMatrix defaults to the correct euler order (zyx) to convert to the map coordinate system
quat.fromEuler(normalized, defRotation[2], defRotation[0], defRotation[1] + 180);

return normalized as Float32Array;
}

load(source: IoSource) {
const stream = openStream(source, IoMode.Read);
const chunks = wdtIo.wdt.read(stream);
Expand Down
23 changes: 17 additions & 6 deletions src/lib/map/MapArea.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { IoMode, IoSource, openStream } from '@wowserhq/io';
import * as adtIo from './io/adt.js';
import * as commonIo from './io/common.js';
import { indexChunks } from '../util.js';
import Map from './Map.js';
import MapChunk from './MapChunk.js';
import MapLayer from './MapLayer.js';
import MapDoodadDef from './MapDoodadDef.js';
Expand Down Expand Up @@ -68,7 +69,7 @@ class MapArea {
return this;
}

#loadDoodadDefs(defs: any[], areaData: Map<string, any>) {
#loadDoodadDefs(defs: any[], areaData: globalThis.Map<string, any>) {
if (!defs || defs.length === 0) {
return;
}
Expand All @@ -80,13 +81,16 @@ class MapArea {
names.offset = nameOfs[def.nameId];
const name = commonIo.mapString.read(names);

const normalizedPosition = Map.getNormalizedDefPosition(def.position);
const normalizedRotation = Map.getNormalizedDefRotation(def.rotation);

this.#doodadDefs.push(
new MapDoodadDef(name, def.uniqueId, def.position, def.rotation, def.scale),
new MapDoodadDef(name, def.uniqueId, normalizedPosition, normalizedRotation, def.scale),
);
}
}

#loadObjDefs(defs: any[], areaData: Map<string, any>) {
#loadObjDefs(defs: any[], areaData: globalThis.Map<string, any>) {
if (!defs || defs.length === 0) {
return;
}
Expand All @@ -98,17 +102,24 @@ class MapArea {
names.offset = nameOfs[def.nameId];
const name = commonIo.mapString.read(names);

this.#objDefs.push(new MapObjDef(name, def.uniqueId, def.position, def.rotation));
const normalizedPosition = Map.getNormalizedDefPosition(def.position);
const normalizedRotation = Map.getNormalizedDefRotation(def.rotation);

this.#objDefs.push(new MapObjDef(name, def.uniqueId, normalizedPosition, normalizedRotation));
}
}

#loadChunks(chunks: any[], areaData: Map<string, any>) {
#loadChunks(chunks: any[], areaData: globalThis.Map<string, any>) {
for (const chunk of chunks) {
this.#loadChunk(chunk.header, indexChunks(chunk.data), areaData);
}
}

#loadChunk(chunkHeader: any, chunkData: Map<string, any>, areaData: Map<string, any>) {
#loadChunk(
chunkHeader: any,
chunkData: globalThis.Map<string, any>,
areaData: globalThis.Map<string, any>,
) {
const chunk = new MapChunk(chunkHeader.position, chunkHeader.holes);

// Vertices
Expand Down
30 changes: 6 additions & 24 deletions src/lib/map/MapDoodadDef.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import { MAP_CORNER_X, MAP_CORNER_Y } from './const.js';

class MapDoodadDef {
#name: string;
#id: number;
#position: Float32Array;
#mapPosition: Float32Array;
#rotation: Float32Array;
#mapRotation: Float32Array;
#scale: number;

constructor(
Expand All @@ -21,18 +17,6 @@ class MapDoodadDef {
this.#position = position;
this.#rotation = rotation;
this.#scale = scale;

// Doodad defs (map placements) are stored in a Y-up right-handed coordinate system

this.#mapPosition = new Float32Array(3);
this.#mapPosition[0] = MAP_CORNER_X - position[2];
this.#mapPosition[1] = MAP_CORNER_Y - position[0];
this.#mapPosition[2] = position[1];

this.#mapRotation = new Float32Array(3);
this.#mapRotation[0] = rotation[2];
this.#mapRotation[1] = rotation[0];
this.#mapRotation[2] = rotation[1] - 180;
}

get name() {
Expand All @@ -43,22 +27,20 @@ class MapDoodadDef {
return this.#id;
}

/**
* Returns vector representing doodad placement position in the map coordinate system.
*/
get position() {
return this.#position;
}

get mapPosition() {
return this.#mapPosition;
}

/**
* Returns quaternion representing doodad placement rotation in the map coordinate system.
*/
get rotation() {
return this.#rotation;
}

get mapRotation() {
return this.#mapRotation;
}

get scale() {
return this.#scale;
}
Expand Down
8 changes: 7 additions & 1 deletion src/lib/map/MapObjDef.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ class MapObjDef {
#position: Float32Array;
#rotation: Float32Array;

constructor(name, id, position, rotation) {
constructor(name: string, id: number, position: Float32Array, rotation: Float32Array) {
this.#name = name;
this.#id = id;
this.#position = position;
Expand All @@ -19,10 +19,16 @@ class MapObjDef {
return this.#id;
}

/**
* Returns vector representing doodad placement position in the map coordinate system.
*/
get position() {
return this.#position;
}

/**
* Returns quaternion representing doodad placement rotation in the map coordinate system.
*/
get rotation() {
return this.#rotation;
}
Expand Down
17 changes: 17 additions & 0 deletions src/spec/map/MapArea.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,23 @@ describe('MapArea', () => {
expect(mapArea.doodadDefs.length).toBe(381);
expect(mapArea.objDefs.length).toBe(19);
});

test('should contain doodad defs in the expected format', () => {
const map = new Map().load('./fixture/map/continent.wdt');
const mapArea = new MapArea(map.layerSplatDepth).load('./fixture/map/continent4229.adt');

const doodadDef1 = mapArea.doodadDefs.find((def) => def.id === 206410);
expect(doodadDef1.name.split(/\\/).at(-1)).toBe('TIRISFALLGLADECANOPYTREE05.M2');
expect(doodadDef1.rotation).toEqual(new Float32Array([0, 0, 1, 6.123234262925839e-17]));

const doodadDef2 = mapArea.doodadDefs.find((def) => def.id === 2542963);
expect(doodadDef2.name.split(/\\/).at(-1)).toBe('TIRISFALLGLADECANOPYTREE05.M2');
expect(doodadDef2.rotation).toEqual(
new Float32Array([
0.0701502189040184, -0.038644179701805115, 0.9901213645935059, 0.11508788913488388,
]),
);
});
});

describe('pvpzone', () => {
Expand Down

0 comments on commit a67aaec

Please sign in to comment.