Reapply tilelist processing changes

This commit is contained in:
Colin Kallemein 2025-02-06 23:31:50 +01:00
parent ec6f3031b8
commit 9f866fea72

View File

@ -7,7 +7,7 @@
:src="`${config.server_endpoint}/textures/tiles/${group.parent.id}.png`"
:alt="group.parent.name"
@click="openGroup(group)"
@load="() => processTile(group.parent)"
@load="() => tileProcessor.processTile(group.parent)"
:class="{
'border-cyan shadow-lg': isActiveTile(group.parent),
'border-transparent hover:border-gray-300': !isActiveTile(group.parent)
@ -60,13 +60,14 @@
import config from '@/application/config'
import type { Tile } from '@/application/types'
import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
import { useTileProcessingComposable } from '@/composables/useTileProcessingComposable'
import { TileStorage } from '@/storage/storages'
import { liveQuery } from 'dexie'
import { computed, onMounted, onUnmounted, ref, useTemplateRef } from 'vue'
import { computed, onMounted, onUnmounted, ref } from 'vue'
const isOpen = ref(false)
const tileStorage = new TileStorage()
const mapEditor = useMapEditorComposable()
const tileProcessor = useTileProcessingComposable()
const searchQuery = ref('')
const selectedTags = ref<string[]>([])
const tileCategories = ref<Map<string, string>>(new Map())
@ -93,7 +94,7 @@ const groupedTiles = computed(() => {
})
filteredTiles.forEach((tile) => {
const parentGroup = groups.find((group) => areTilesRelated(group.parent, tile))
const parentGroup = groups.find((group) => tileProcessor.areTilesRelated(group.parent, tile))
if (parentGroup && parentGroup.parent.id !== tile.id) {
parentGroup.children.push(tile)
} else {
@ -104,32 +105,6 @@ const groupedTiles = computed(() => {
return groups
})
const tileColorData = ref<Map<string, { r: number; g: number; b: number }>>(new Map())
const tileEdgeData = ref<Map<string, number>>(new Map())
function areTilesRelated(tile1: Tile, tile2: Tile): boolean {
const colorSimilarityThreshold = 30 // Adjust this value as needed
const edgeComplexitySimilarityThreshold = 20 // Adjust this value as needed
const color1 = tileColorData.value.get(tile1.id)
const color2 = tileColorData.value.get(tile2.id)
const edge1 = tileEdgeData.value.get(tile1.id)
const edge2 = tileEdgeData.value.get(tile2.id)
if (!color1 || !color2 || edge1 === undefined || edge2 === undefined) {
return false
}
const colorDifference = Math.sqrt(Math.pow(color1.r - color2.r, 2) + Math.pow(color1.g - color2.g, 2) + Math.pow(color1.b - color2.b, 2))
const edgeComplexityDifference = Math.abs(edge1 - edge2)
const namePrefix1 = tile1.name.split('_')[0]
const namePrefix2 = tile2.name.split('_')[0]
return colorDifference <= colorSimilarityThreshold && edgeComplexityDifference <= edgeComplexitySimilarityThreshold && namePrefix1 === namePrefix2
}
const toggleTag = (tag: string) => {
if (selectedTags.value.includes(tag)) {
selectedTags.value = selectedTags.value.filter((t) => t !== tag)
@ -138,59 +113,6 @@ const toggleTag = (tag: string) => {
}
}
function processTile(tile: Tile) {
const img = new Image()
img.crossOrigin = 'Anonymous'
img.onload = () => {
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
canvas.width = img.width
canvas.height = img.height
ctx!.drawImage(img, 0, 0, img.width, img.height)
const imageData = ctx!.getImageData(0, 0, canvas.width, canvas.height)
tileColorData.value.set(tile.id, getDominantColor(imageData))
tileEdgeData.value.set(tile.id, getEdgeComplexity(imageData))
}
img.src = `${config.server_endpoint}/textures/tiles/${tile.id}.png`
}
function getDominantColor(imageData: ImageData) {
let r = 0,
g = 0,
b = 0,
total = 0
for (let i = 0; i < imageData.data.length; i += 4) {
if (imageData.data[i + 3] > 0) {
// Only consider non-transparent pixels
r += imageData.data[i]
g += imageData.data[i + 1]
b += imageData.data[i + 2]
total++
}
}
return {
r: Math.round(r / total),
g: Math.round(g / total),
b: Math.round(b / total)
}
}
function getEdgeComplexity(imageData: ImageData) {
let edgePixels = 0
for (let y = 0; y < imageData.height; y++) {
for (let x = 0; x < imageData.width; x++) {
const i = (y * imageData.width + x) * 4
if (imageData.data[i + 3] > 0 && (x === 0 || y === 0 || x === imageData.width - 1 || y === imageData.height - 1 || imageData.data[i - 1] === 0 || imageData.data[i + 7] === 0)) {
edgePixels++
}
}
}
return edgePixels
}
function getTileCategory(tile: Tile): string {
return tileCategories.value.get(tile.id) || ''
}
@ -211,22 +133,19 @@ function isActiveTile(tile: Tile): boolean {
return mapEditor.selectedTile.value === tile.id
}
let subscription: any = null
onMounted(async () => {
tiles.value = await tileStorage.getAll()
const initialBatchSize = 20
const initialTiles = tiles.value.slice(0, initialBatchSize)
initialTiles.forEach((tile) => tileProcessor.processTile(tile))
onMounted(() => {
subscription = liveQuery(() => tileStorage.liveQuery()).subscribe({
next: (result) => {
tiles.value = result
},
error: (error) => {
console.error('Failed to fetch tiles:', error)
}
})
// Process remaining tiles in background
setTimeout(() => {
tiles.value.slice(initialBatchSize).forEach((tile) => tileProcessor.processTile(tile))
}, 1000)
})
onUnmounted(() => {
if (subscription) {
subscription.unsubscribe()
}
tileProcessor.cleanup()
})
</script>