-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgrid_image.ts
More file actions
149 lines (127 loc) · 4.77 KB
/
Copy pathgrid_image.ts
File metadata and controls
149 lines (127 loc) · 4.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
import { createCanvas, loadImage } from '@napi-rs/canvas';
import { writeFile, readFile } from 'fs/promises';
import {
SCALE,
GRID_CONFIG,
detectTreeContentPosition,
drawIsoBlock,
calculateCanvasDimensions,
generateGridPositions,
sortPositionsForRendering,
calculateTreeDrawPosition,
} from './core/grid';
import type { GridPosition } from './core/grid';
import { applyCanvasFilter, type FilterName } from './core/filters';
export { SCALE, GRID_CONFIG as DEFAULT_CONFIG };
export type { GridPosition };
export interface TreeConfig {
imagePath: string;
gridX: number;
gridY: number;
scale: number;
}
const IMAGE_CONFIG = {
filename: 'isometric_grid_with_trees.png',
dataFilename: 'grid_positions.json',
treeConfigFilename: 'tree-config.json',
};
export interface GridOptions {
trees: TreeConfig[];
outputFilename: string;
dataFilename?: string;
filter?: FilterName;
}
export async function generateGrid(options: GridOptions): Promise<Buffer> {
const { trees, outputFilename, dataFilename, filter = 'none' } = options;
let maxGridDim = 1;
for (const tree of trees) {
if (tree.gridX > maxGridDim - 1) maxGridDim = tree.gridX + 1;
if (tree.gridY > maxGridDim - 1) maxGridDim = tree.gridY + 1;
}
GRID_CONFIG.gridSize = maxGridDim;
const dimensions = calculateCanvasDimensions(maxGridDim);
GRID_CONFIG.canvasWidth = dimensions.width;
GRID_CONFIG.canvasHeight = dimensions.height;
const canvas = createCanvas(GRID_CONFIG.canvasWidth, GRID_CONFIG.canvasHeight);
const ctx = canvas.getContext('2d');
console.log(`Generating ${GRID_CONFIG.gridSize}x${GRID_CONFIG.gridSize} Grid at ${SCALE}x Resolution...`);
// Create a map for quick lookup of trees by grid position
const treeMap = new Map<string, TreeConfig>();
for (const tree of trees) {
treeMap.set(`${tree.gridX},${tree.gridY}`, tree);
}
// Load all unique tree images and detect content position
const loadedTrees = new Map<string, any>();
const treeOffsets = new Map<string, { xOffset: number, yPadding: number, contentWidth: number }>();
for (const tree of trees) {
if (!loadedTrees.has(tree.imagePath)) {
try {
const image = await loadImage(tree.imagePath);
loadedTrees.set(tree.imagePath, image);
const offsets = detectTreeContentPosition(image);
treeOffsets.set(tree.imagePath, offsets);
console.log(`Loaded image: ${tree.imagePath} (xOffset: ${offsets.xOffset.toFixed(1)}px, yPadding: ${offsets.yPadding}px)`);
} catch (e) {
console.error(`Could not load image: ${tree.imagePath}`);
}
}
}
// Generate all grid positions
const positions = generateGridPositions(GRID_CONFIG.gridSize, GRID_CONFIG.canvasWidth);
const sortedPositions = sortPositionsForRendering(positions);
for (const pos of sortedPositions) {
const treeConfig = treeMap.get(`${pos.gridX},${pos.gridY}`);
const offsets = treeConfig ? treeOffsets.get(treeConfig.imagePath) : undefined;
drawIsoBlock(ctx, pos, {
hasShadow: !!treeConfig,
shadowWidth: offsets ? offsets.contentWidth * (treeConfig?.scale || 0.5) : undefined,
drawTufts: !treeConfig,
gridX: pos.gridX,
gridY: pos.gridY,
});
if (treeConfig) {
const image = loadedTrees.get(treeConfig.imagePath);
if (image && offsets) {
const treeScale = treeConfig.scale || 0.5;
const { drawX, drawY, drawWidth, drawHeight } = calculateTreeDrawPosition(
pos, image.width, image.height, offsets, treeScale
);
ctx.drawImage(image, drawX, drawY, drawWidth, drawHeight);
}
}
}
// Apply filter if specified
if (filter && filter !== 'none') {
console.log(`Applying '${filter}' filter...`);
applyCanvasFilter(ctx, GRID_CONFIG.canvasWidth, GRID_CONFIG.canvasHeight, filter);
}
const buffer = await canvas.encode('png');
await writeFile(outputFilename, buffer);
if (dataFilename) {
await writeFile(dataFilename, JSON.stringify(positions, null, 2));
console.log(`✅ Positions saved: ${dataFilename}`);
}
console.log(`✅ HD Grid generated: ${outputFilename} (${GRID_CONFIG.canvasWidth}x${GRID_CONFIG.canvasHeight})`);
return buffer;
}
async function main() {
console.log("Reading configuration files...");
let treePlacements: TreeConfig[] = [];
try {
const treeConfigFile = await readFile(IMAGE_CONFIG.treeConfigFilename, 'utf-8');
const treeConfigData = JSON.parse(treeConfigFile);
treePlacements = treeConfigData.trees;
} catch (error) {
console.error(`Error reading or parsing configuration files:`, error);
return;
}
await generateGrid({
trees: treePlacements,
outputFilename: IMAGE_CONFIG.filename,
dataFilename: IMAGE_CONFIG.dataFilename,
filter: 'winter'
});
}
if (require.main === module) {
main().catch(console.error);
}