-
Notifications
You must be signed in to change notification settings - Fork 0
/
test2.html
256 lines (218 loc) · 11.9 KB
/
test2.html
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>makewadjs</title>
</head>
<body>
<button id="download">Download WAD2</button>
<script>
function createWAD2() {
// Define dimensions and sizes
const textureWidth = 64;
const textureHeight = 64;
const textureSize = textureWidth * textureHeight; // Total pixels
const textureLumpSize = 8 + textureSize; // Header + pixel data
const paletteLumpSize = 768; // 256 colors * 3 bytes per color
const directoryEntrySize = 32; // Size of a directory entry
// Create an ArrayBuffer to hold the WAD2 file
const buffer = new ArrayBuffer(12 + textureLumpSize + paletteLumpSize + 2 * directoryEntrySize);
const view = new DataView(buffer);
// Function to write a name for a texture or palette after writing it's lump
function writeName(lumpName, directoryOffset){
for (let i = 0; i < 16; i++) {
if (i < lumpName.length) {
view.setUint8(directoryOffset + 16 + i, lumpName[i]); // Lump name (up to 16 characters)
} else {
view.setUint8(directoryOffset + 16 + i, 0); // Null padding
}
}
}
// Write the WAD2 header
const textEncoder = new TextEncoder();
const wadHeader = textEncoder.encode("WAD2");
for (let i = 0; i < wadHeader.length; i++) {
view.setUint8(i, wadHeader[i]);
}
// Number of lumps is 2 (one for texture, one for palette)
view.setInt32(4, 2, true);
view.setInt32(8, 12 + textureLumpSize + paletteLumpSize, true); // directoryOffset
// Create a simple checkerboard pattern using two palette colors
const textureData = new Uint8Array(textureSize); // Define textureData
const color1Index = 192; // Red from the palette (palette index 192)
const color2Index = 80; // Dark Blue from the palette (palette index 255)
for (let y = 0; y < textureHeight; y++) {
for (let x = 0; x < textureWidth; x++) {
if ((x + y) % 2 === 0) {
textureData[y * textureWidth + x] = color1Index; // Set to first color
} else {
textureData[y * textureWidth + x] = color2Index; // Set to second color
}
}
}
// Write the texture lump data
const textureLumpOffset = 12; // Start after the header
view.setInt32(textureLumpOffset, textureWidth, true); // Set width
view.setInt32(textureLumpOffset + 4, textureHeight, true); // Set height
for (let i = 0; i < textureSize; i++) {
view.setUint8(textureLumpOffset + 8 + i, textureData[i]); // Set pixel data
}
// Write the palette lump data (made a simple test color palette)
const paletteLumpOffset = textureLumpOffset + textureLumpSize; // Start after texture lump
generatePalette(view,paletteLumpOffset)
// Write directory entries
const directoryOffset = 12 + textureLumpSize + paletteLumpSize; // Start after all lumps
const LUMPTYPE = {
PALETTE : 0x40, //Color Palette
STATUS_BAR : 0x42, //Pictures for status bar
TEXTURE : 0x44, //Used to be Mip Texture
FLAT : 0x45, //Console picture (flat)
}
/// Create Lump Function
//int LUMP_OFFSET
//int LUMP_SIZE
//int TEXTURE_SIZE
//hex LUMP_TYPE
//string LUMP_NAME
function createLump(LUMP_OFFSET, LUMP_SIZE, TEXTURE_SIZE, LUMP_TYPE, LUMP_NAME, directoryOffset){
view.setInt32(directoryOffset, LUMP_OFFSET, true); // Lump offset
view.setInt32(directoryOffset + 4, LUMP_SIZE, true); // Lump size (on disk)
view.setInt32(directoryOffset + 8, TEXTURE_SIZE, true); // Lump size (in memory)
view.setUint8(directoryOffset + 12, LUMP_TYPE); // Lump type
view.setUint8(directoryOffset + 13, 0); // Compression (0 = none)
view.setInt16(directoryOffset + 14, 0, true); // Dummy (not used)
const lumpName = textEncoder.encode(LUMP_NAME);
writeName(lumpName, directoryOffset);
}
createLump(textureLumpOffset, textureLumpSize, textureSize, LUMPTYPE.STATUS_BAR, "TEXTURE", directoryOffset);
// Create a lump for palette
createLump(paletteLumpOffset, paletteLumpSize, paletteLumpSize, LUMPTYPE.PALETTE, "PALETTE", directoryOffset + directoryEntrySize);
// Create a blob from the ArrayBuffer and trigger a download
const blob = new Blob([buffer], { type: 'application/octet-stream' });
const url = URL.createObjectURL(blob);
// Trigger a download
const a = document.createElement('a');
a.href = url;
a.download = 'mywad.wad';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url); // Clean up the URL object
}
document.getElementById('download').addEventListener('click', createWAD2);
function generatePalette(view, paletteLumpOffset) {
let index = 0;
// Grayscale ramp (0-31)
for (let i = 0; i < 32; i++) {
const gray = Math.floor(i * 255 / 31); // Scale from 0 to 255
view.setUint8(paletteLumpOffset + index * 3, gray); // R
view.setUint8(paletteLumpOffset + index * 3 + 1, gray); // G
view.setUint8(paletteLumpOffset + index * 3 + 2, gray); // B
index++;
}
// Brownish ramp (32-47)
for (let i = 0; i < 16; i++) {
const r = 109 - Math.floor(i * 5.75); // Decrease R
const g = 70 - Math.floor(i * 4.375); // Decrease G
const b = 47 - Math.floor(i * 2.9375); // Decrease B
view.setUint8(paletteLumpOffset + index * 3, r); // R
view.setUint8(paletteLumpOffset + index * 3 + 1, g); // G
view.setUint8(paletteLumpOffset + index * 3 + 2, b); // B
index++;
}
// Red to yellow ramp (48-63)
for (let i = 0; i < 16; i++) {
view.setUint8(paletteLumpOffset + index * 3, 255); // R stays max
view.setUint8(paletteLumpOffset + index * 3 + 1, Math.floor(i * 255 / 15)); // G increases
view.setUint8(paletteLumpOffset + index * 3 + 2, 0); // B stays 0
index++;
}
// Yellow to Green ramp (64-79)
for (let i = 0; i < 16; i++) {
view.setUint8(paletteLumpOffset + index * 3, 255 - Math.floor(i * 255 / 15)); // R decreases
view.setUint8(paletteLumpOffset + index * 3 + 1, 255); // G stays max
view.setUint8(paletteLumpOffset + index * 3 + 2, 0); // B stays 0
index++;
}
// Green to Cyan ramp (80-95)
for (let i = 0; i < 16; i++) {
view.setUint8(paletteLumpOffset + index * 3, 0); // R stays 0
view.setUint8(paletteLumpOffset + index * 3 + 1, 255); // G stays max
view.setUint8(paletteLumpOffset + index * 3 + 2, Math.floor(i * 255 / 15)); // B increases
index++;
}
// Cyan to Blue ramp (96-111)
for (let i = 0; i < 16; i++) {
view.setUint8(paletteLumpOffset + index * 3, 0); // R stays 0
view.setUint8(paletteLumpOffset + index * 3 + 1, 255 - Math.floor(i * 255 / 15)); // G decreases
view.setUint8(paletteLumpOffset + index * 3 + 2, 255); // B stays max
index++;
}
// Blue to Purple ramp (112-127)
for (let i = 0; i < 16; i++) {
view.setUint8(paletteLumpOffset + index * 3, Math.floor(i * 128 / 15)); // R increases
view.setUint8(paletteLumpOffset + index * 3 + 1, 0); // G stays 0
view.setUint8(paletteLumpOffset + index * 3 + 2, 255); // B stays max
index++;
}
// Pinkish tones (128-143)
for (let i = 0; i < 16; i++) {
view.setUint8(paletteLumpOffset + index * 3, 255); // R stays max
view.setUint8(paletteLumpOffset + index * 3 + 1, Math.floor(i * 128 / 15)); // G increases
view.setUint8(paletteLumpOffset + index * 3 + 2, Math.floor(i * 255 / 15)); // B increases
index++;
}
// Dark tones (144-159)
for (let i = 0; i < 16; i++) {
view.setUint8(paletteLumpOffset + index * 3, Math.floor(i * 128 / 15)); // R increases slowly
view.setUint8(paletteLumpOffset + index * 3 + 1, Math.floor(i * 64 / 15)); // G increases slowly
view.setUint8(paletteLumpOffset + index * 3 + 2, Math.floor(i * 32 / 15)); // B increases slowly
index++;
}
// Purple to red shades (160-191)
for (let i = 0; i < 32; i++) {
view.setUint8(paletteLumpOffset + index * 3, 128 + Math.floor(i * 127 / 31)); // R increases
view.setUint8(paletteLumpOffset + index * 3 + 1, 0); // G stays 0
view.setUint8(paletteLumpOffset + index * 3 + 2, 128 + Math.floor(i * 127 / 31)); // B increases
index++;
}
// *** Filling in Colors 192-255 ***
// Blood Red to Dark Red (192-207)
for (let i = 0; i < 16; i++) {
view.setUint8(paletteLumpOffset + index * 3, 128 + Math.floor(i * 127 / 15)); // R increases to bright red
view.setUint8(paletteLumpOffset + index * 3 + 1, 0); // G stays 0
view.setUint8(paletteLumpOffset + index * 3 + 2, 0); // B stays 0 (pure red shades)
index++;
}
// Fire (208-223)
for (let i = 0; i < 16; i++) {
const r = 255;
const g = Math.floor(i * 180 / 15); // G increases from dark to bright
const b = 0; // B stays 0
view.setUint8(paletteLumpOffset + index * 3, r); // R stays max
view.setUint8(paletteLumpOffset + index * 3 + 1, g); // G increases
view.setUint8(paletteLumpOffset + index * 3 + 2, b); // B stays 0
index++;
}
// Dark Greenish Tones (224-239)
for (let i = 0; i < 16; i++) {
view.setUint8(paletteLumpOffset + index * 3, Math.floor(i * 64 / 15)); // R increases slightly
view.setUint8(paletteLumpOffset + index * 3 + 1, Math.floor(i * 192 / 15)); // G increases more
view.setUint8(paletteLumpOffset + index * 3 + 2, Math.floor(i * 32 / 15)); // B increases slightly
index++;
}
// Dark Purple to Blue (240-255)
for (let i = 0; i < 16; i++) {
const r = Math.floor(i * 128 / 15); // R increases slowly
const g = 0; // G stays 0
const b = 255 - Math.floor(i * 127 / 15); // B decreases from bright to darker blue
view.setUint8(paletteLumpOffset + index * 3, r); // R increases
view.setUint8(paletteLumpOffset + index * 3 + 1, g); // G stays 0
view.setUint8(paletteLumpOffset + index * 3 + 2, b); // B decreases
index++;
}
}
</script>
</body>
</html>