Skip to content

Commit

Permalink
Merge pull request k2d222#76 from k2d222/automap
Browse files Browse the repository at this point in the history
Automap
  • Loading branch information
k2d222 authored Aug 17, 2023
2 parents 5a89e7f + ee36e56 commit 6fcc8a2
Show file tree
Hide file tree
Showing 51 changed files with 3,781 additions and 438 deletions.
325 changes: 313 additions & 12 deletions client/package-lock.json

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,16 @@
"@carbon/styles": "^1.19.0",
"@sveltejs/vite-plugin-svelte": "^1.0.0-next.30",
"@tsconfig/svelte": "^2.0.1",
"@types/js-md5": "^0.4.3",
"@types/pako": "^2.0.0",
"carbon-components": "^10.58.3",
"carbon-components-svelte": "^0.70.12",
"carbon-icons-svelte": "^11.4.0",
"carbon-preprocess-svelte": "^0.9.1",
"codemirror": "^6.0.1",
"crc": "^4.1.1",
"gl-matrix": "^3.4.3",
"js-md5": "^0.7.3",
"pako": "^2.0.4",
"prettier": "^2.8.1",
"prettier-plugin-svelte": "^2.9.0",
Expand Down
25 changes: 20 additions & 5 deletions client/src/gl/renderMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ import { gl } from './global'
import { Image } from '../twmap/image'
import { Texture } from './texture'
import { isPhysicsLayer, Ctor } from '../ui/lib/util'
import { colorFromJson, coordFromJson, curveTypeFromString, fromFixedNum } from '../server/convert'
import { Config as AutomapperConfig, automap } from '../twmap/automap'
import { colorFromJson, coordFromJson, curveTypeFromString, fromFixedNum, uvFromJson } from '../server/convert'
import type { Brush } from 'src/ui/lib/editor'

export type Range = {
Expand Down Expand Up @@ -299,9 +300,9 @@ export class RenderMap {
const rlayer = rgroup.layers[change.layer] as RenderQuadsLayer

const quad: Quad = {
points: change.points.map(p => coordFromJson(p, 15)),
points: [...change.corners.map(p => coordFromJson(p, 15)), coordFromJson(change.position, 15)],
colors: change.colors,
texCoords: change.texCoords.map(p => coordFromJson(p, 10)),
texCoords: change.texCoords.map(p => uvFromJson(p, 10)),
posEnv:
change.posEnv === null ? null : (this.map.envelopes[change.posEnv] as PositionEnvelope),
posEnvOffset: change.posEnvOffset,
Expand All @@ -319,9 +320,9 @@ export class RenderMap {
const rlayer = rgroup.layers[change.layer] as RenderQuadsLayer
const quad = rlayer.layer.quads[change.quad]

if ('points' in change) quad.points = change.points.map(p => coordFromJson(p, 15))
if ('position' in change) quad.points[4] = coordFromJson(change.position, 15)
if ('colors' in change) quad.colors = change.colors
if ('texCoords' in change) quad.texCoords = change.texCoords.map(p => coordFromJson(p, 10))
if ('texCoords' in change) quad.texCoords = change.texCoords.map(p => uvFromJson(p, 10))
if ('posEnv' in change)
quad.posEnv =
change.posEnv === null ? null : (this.map.envelopes[change.posEnv] as PositionEnvelope)
Expand Down Expand Up @@ -394,6 +395,11 @@ export class RenderMap {
}
rlayer.recompute()
}
if ('automapper' in change) {
rlayer.layer.automapper.config = change.automapper.config === null ? -1 : change.automapper.config
rlayer.layer.automapper.seed = change.automapper.seed
rlayer.layer.automapper.automatic = change.automapper.automatic
}
} else if (rlayer instanceof RenderQuadsLayer) {
if ('image' in change) {
if (change.image === null) {
Expand Down Expand Up @@ -461,6 +467,15 @@ export class RenderMap {
return rlayer
}

automapLayer(g: number, l: number, automapper: AutomapperConfig, seed: number) {
const rgroup = this.groups[g]
const layer = rgroup.layers[l]
if (!(layer instanceof RenderTilesLayer)) return

automap(layer.layer, automapper, seed)
layer.recompute()
}

render() {
for (const group of this.groups) {
if (group === this.physicsGroup) {
Expand Down
112 changes: 109 additions & 3 deletions client/src/server/convert.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type * as Info from '../twmap/types'
import type * as MapDir from '../twmap/mapdir'
import type { CurveTypeStr } from './protocol'
import * as Info from '../twmap/types'
import * as MapDir from '../twmap/mapdir'
import type { CurveTypeStr, EditTileParams } from './protocol'
import * as Parser from '../twmap/parser'

const curveTypeStr: CurveTypeStr[] = ['step', 'linear', 'slow', 'fast', 'smooth', 'bezier']

Expand Down Expand Up @@ -33,6 +34,20 @@ export function coordFromJson(coord: MapDir.Point<string>, floating: number): In
}
}

export function uvToJson(uv: Info.Coord, floating: number): MapDir.Uv<string> {
return {
u: toFixedNum(uv.x, floating),
v: toFixedNum(uv.y, floating),
}
}

export function uvFromJson(uv: MapDir.Uv<string>, floating: number): Info.Coord {
return {
x: fromFixedNum(uv.u, floating),
y: fromFixedNum(uv.v, floating),
}
}

export function colorToJson(coord: Info.Color, floating: number): MapDir.Color<string> {
return {
r: toFixedNum(coord.r, floating),
Expand All @@ -50,3 +65,94 @@ export function colorFromJson(coord: MapDir.Color<string>, floating: number): In
a: fromFixedNum(coord.a, floating),
}
}

// see https://developer.mozilla.org/en-US/docs/Glossary/Base64
function base64ToBytes(base64: string): Uint8Array {
const binString = window.atob(base64);
return Uint8Array.from(binString, (m) => m.codePointAt(0));
}

function bytesToBase64(bytes: Uint8Array): string {
const binString = Array.from(bytes, (x) => String.fromCodePoint(x)).join("");
return window.btoa(binString);
}

export function tilesToData(tiles: EditTileParams[]): string {
let arr = []

for (const tile of tiles) {
if (tile.kind === 'tiles' || tile.kind === 'game' || tile.kind === 'front') {
arr.push(tile.id, tile.flags, 0, 0)
}
else if (tile.kind === 'tele') {
arr.push(tile.number, tile.id)
}
else if (tile.kind === 'speedup') {
arr.push(tile.force, tile.maxSpeed, tile.id, 0, tile.angle & 0xff, (tile.angle >> 8) & 0xff) // little endian for angle
}
else if (tile.kind === 'switch') {
arr.push(tile.number, tile.id, tile.flags, tile.delay)
}
else if (tile.kind === 'tune') {
arr.push(tile.number, tile.id)
}
else {
throw 'unsupported tile type'
}
}

return bytesToBase64(new Uint8Array(arr))
}

export function tileToData(tile: EditTileParams): string {
return tilesToData([tile])
}

export function dataToTiles(data: string, kind: MapDir.LayerKind): EditTileParams[] {
const arr = base64ToBytes(data).buffer

if (kind === 'tiles' || kind === 'game' || kind === 'front') {
return Parser.parseTiles(arr, arr.byteLength / 4)
.map(t => ({ kind, ...t }))
}
else if (kind === 'tele') {
return Parser.parseTeleTiles(arr, arr.byteLength / 2)
.map(t => ({ kind, ...t }))
}
else if (kind === 'speedup') {
return Parser.parseSpeedupTiles(arr, arr.byteLength / 6)
.map(t => ({ kind, ...t }))
}
else if (kind === 'switch') {
return Parser.parseSwitchTiles(arr, arr.byteLength / 4)
.map(t => ({ kind, ...t }))
}
else if (kind === 'tune') {
return Parser.parseTuneTiles(arr, arr.byteLength / 2)
.map(t => ({ kind, ...t }))
}
else {
throw 'unsupported tile type ' + kind
}
}

export function tilesLayerFlagsToLayerKind(flags: Info.TilesLayerFlags) {
if (flags === Info.TilesLayerFlags.FRONT) return MapDir.LayerKind.Front
else if (flags === Info.TilesLayerFlags.GAME) return MapDir.LayerKind.Game
else if (flags === Info.TilesLayerFlags.SPEEDUP) return MapDir.LayerKind.Speedup
else if (flags === Info.TilesLayerFlags.SWITCH) return MapDir.LayerKind.Switch
else if (flags === Info.TilesLayerFlags.TELE) return MapDir.LayerKind.Tele
else if (flags === Info.TilesLayerFlags.TILES) return MapDir.LayerKind.Tiles
else if (flags === Info.TilesLayerFlags.TUNE) return MapDir.LayerKind.Tune
}

export function layerKindToTilesLayerFlags(kind: MapDir.LayerKind) {
if (kind === MapDir.LayerKind.Front) return Info.TilesLayerFlags.FRONT
else if (kind === MapDir.LayerKind.Game) return Info.TilesLayerFlags.GAME
else if (kind === MapDir.LayerKind.Speedup) return Info.TilesLayerFlags.SPEEDUP
else if (kind === MapDir.LayerKind.Switch) return Info.TilesLayerFlags.SWITCH
else if (kind === MapDir.LayerKind.Tele) return Info.TilesLayerFlags.TELE
else if (kind === MapDir.LayerKind.Tiles) return Info.TilesLayerFlags.TILES
else if (kind === MapDir.LayerKind.Tune) return Info.TilesLayerFlags.TUNE
else throw "not a tile layer"
}
83 changes: 71 additions & 12 deletions client/src/server/protocol.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type * as Info from '../twmap/types'
import type * as MapDir from '../twmap/mapdir'
import type { AutomapperConfig } from '../twmap/mapdir'

// This file contains the type of messages sent and received via websocket.
// It must correspond with file protocol.rs in server.
Expand Down Expand Up @@ -111,6 +112,7 @@ export interface EditTilesLayer extends CommonLayerChange {
colorEnv?: number | null
colorEnvOffset?: number
image?: number | null
automapper?: AutomapperConfig
}

export interface EditQuadsLayer extends CommonLayerChange {
Expand All @@ -133,11 +135,13 @@ export interface DeleteLayer {
}

export type EditTileParams =
| (Info.Tile & { type: 'tile' })
| (Info.Tele & { type: 'tele' })
| (Info.Speedup & { type: 'speedup' })
| (Info.Switch & { type: 'switch' })
| (Info.Tune & { type: 'tune' })
| (Info.Tile & { kind: 'tiles' })
| (Info.Tile & { kind: 'game' })
| (Info.Tile & { kind: 'front' })
| (Info.Tele & { kind: 'tele' })
| (Info.Speedup & { kind: 'speedup' })
| (Info.Switch & { kind: 'switch' })
| (Info.Tune & { kind: 'tune' })

export type EditTile = EditTileParams & {
group: number
Expand All @@ -146,12 +150,29 @@ export type EditTile = EditTileParams & {
y: number
}

export type EditTiles = {
group: number,
layer: number,
x: number,
y: number,
kind: 'tiles' | 'game' | 'front' | 'tele' | 'speedup' | 'switch' | 'tune'
width: number,
height: number,
data: string, // binary data format in base64
}

export interface SendLayer {
group: number
layer: number
}

export type CreateQuad = {
group: number
layer: number
points: MapDir.Point<FixedNum>[]
colors: Info.Color[]
texCoords: MapDir.Point<FixedNum>[]
position: MapDir.Point<FixedNum>
corners: MapDir.Point<FixedNum>[] // 4 points
colors: MapDir.Color<number>[]
texCoords: MapDir.Uv<FixedNum>[]
posEnv: number | null
posEnvOffset: number
colorEnv: number | null
Expand All @@ -162,9 +183,10 @@ export type EditQuad = {
group: number
layer: number
quad: number
points: MapDir.Point<FixedNum>[]
colors: Info.Color[]
texCoords: MapDir.Point<FixedNum>[]
position: MapDir.Point<FixedNum>
corners: MapDir.Point<FixedNum>[] // 4 points
colors: MapDir.Color<number>[]
texCoords: MapDir.Uv<FixedNum>[]
posEnv: number | null
posEnvOffset: number
colorEnv: number | null
Expand Down Expand Up @@ -203,7 +225,7 @@ export interface EditEnvelope {
points?:
| {
type: 'color'
content: EnvPoint<MapDir.Color<string>>[]
content: EnvPoint<MapDir.Color<FixedNum>>[]
}
| {
type: 'position'
Expand Down Expand Up @@ -239,6 +261,27 @@ export interface ListMaps {
maps: MapInfo[]
}

// AUTOMAPPERS

export interface ListAutomappers {
configs: { [k in string]: string[] }
}

export interface UploadAutomapper {
image: string
content: string
}

export interface ApplyAutomapper {
group: number
layer: number
}

export interface AutomapperConfigs {
image: string
configs: string[]
}

// IMAGES

export interface ImageConfig {
Expand Down Expand Up @@ -306,6 +349,14 @@ export interface RequestContent {
deletelayer: DeleteLayer

edittile: EditTile
edittiles: EditTiles
sendlayer: SendLayer

listautomappers: null
sendautomapper: string
deleteautomapper: string
uploadautomapper: UploadAutomapper
applyautomapper: ApplyAutomapper

createquad: CreateQuad
editquad: EditQuad
Expand Down Expand Up @@ -347,6 +398,14 @@ export interface ResponseContent {
deletelayer: DeleteLayer

edittile: EditTile
edittiles: EditTiles
sendlayer: string

listautomappers: ListAutomappers
sendautomapper: string
deleteautomapper: string
uploadautomapper: AutomapperConfigs
applyautomapper: ApplyAutomapper

createquad: CreateQuad
editquad: EditQuad
Expand Down
8 changes: 8 additions & 0 deletions client/src/server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,14 @@ export class WebSocketServer implements Server {
deletelayer: [],

edittile: [],
edittiles: [],
sendlayer: [],

listautomappers: [],
sendautomapper: [],
deleteautomapper: [],
uploadautomapper: [],
applyautomapper: [],

createquad: [],
editquad: [],
Expand Down
Loading

0 comments on commit 6fcc8a2

Please sign in to comment.