TGALoader.js 10.5 KB
Newer Older
1 2 3 4 5
/*
 * @author Daosheng Mu / https://github.com/DaoshengMu/
 * @author mrdoob / http://mrdoob.com/
 */

V
Vincent Lark 已提交
6 7 8 9 10
THREE.TGALoader = function ( manager ) {

	this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;

};
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
// extend THREE.BinaryTextureLoader
THREE.TGALoader.prototype = Object.create( THREE.BinaryTextureLoader.prototype );

// reference from vthibault, https://github.com/vthibault/roBrowser/blob/master/src/Loaders/Targa.js
THREE.TGALoader.prototype._parser = function ( buffer ) {

	// TGA Constants
	var TGA_TYPE_NO_DATA = 0,
	TGA_TYPE_INDEXED = 1,
	TGA_TYPE_RGB = 2,
	TGA_TYPE_GREY = 3,
	TGA_TYPE_RLE_INDEXED = 9,
	TGA_TYPE_RLE_RGB = 10,
	TGA_TYPE_RLE_GREY = 11,

	TGA_ORIGIN_MASK = 0x30,
	TGA_ORIGIN_SHIFT = 0x04,
	TGA_ORIGIN_BL = 0x00,
	TGA_ORIGIN_BR = 0x01,
	TGA_ORIGIN_UL = 0x02,
	TGA_ORIGIN_UR = 0x03;


	if ( buffer.length < 19 )
36
		console.error( 'THREE.TGALoader.parse: Not enough data to contain header.' );
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56

	var content = new Uint8Array( buffer ),
		offset = 0,
		header = {
			id_length:       content[ offset ++ ],
			colormap_type:   content[ offset ++ ],
			image_type:      content[ offset ++ ],
			colormap_index:  content[ offset ++ ] | content[ offset ++ ] << 8,
			colormap_length: content[ offset ++ ] | content[ offset ++ ] << 8,
			colormap_size:   content[ offset ++ ],

			origin: [
				content[ offset ++ ] | content[ offset ++ ] << 8,
				content[ offset ++ ] | content[ offset ++ ] << 8
			],
			width:      content[ offset ++ ] | content[ offset ++ ] << 8,
			height:     content[ offset ++ ] | content[ offset ++ ] << 8,
			pixel_size: content[ offset ++ ],
			flags:      content[ offset ++ ]
		};
V
Vincent Lark 已提交
57

58
	function tgaCheckHeader( header ) {
59

G
gero3 已提交
60
		switch ( header.image_type ) {
61

62 63 64 65
			// Check indexed type
			case TGA_TYPE_INDEXED:
			case TGA_TYPE_RLE_INDEXED:
				if ( header.colormap_length > 256 || header.colormap_size !== 24 || header.colormap_type !== 1) {
66
					console.error('THREE.TGALoader.parse.tgaCheckHeader: Invalid type colormap data for indexed type');
67 68
				}
				break;
69

70 71 72 73 74 75
			// Check colormap type
			case TGA_TYPE_RGB:
			case TGA_TYPE_GREY:
			case TGA_TYPE_RLE_RGB:
			case TGA_TYPE_RLE_GREY:
				if (header.colormap_type) {
76
					console.error('THREE.TGALoader.parse.tgaCheckHeader: Invalid type colormap data for colormap type');
77 78
				}
				break;
79

80 81
			// What the need of a file without data ?
			case TGA_TYPE_NO_DATA:
82
				console.error('THREE.TGALoader.parse.tgaCheckHeader: No data');
83

84 85
			// Invalid type ?
			default:
86
				console.error('THREE.TGALoader.parse.tgaCheckHeader: Invalid type " ' + header.image_type + '"');
87

88
		}
89

90
		// Check image width and height
G
gero3 已提交
91
		if ( header.width <= 0 || header.height <= 0 ) {
92
			console.error( 'THREE.TGALoader.parse.tgaCheckHeader: Invalid image size' );
93
		}
V
Vincent Lark 已提交
94

95 96 97 98 99
		// Check image pixel size
		if (header.pixel_size !== 8  &&
			header.pixel_size !== 16 &&
			header.pixel_size !== 24 &&
			header.pixel_size !== 32) {
100
			console.error('THREE.TGALoader.parse.tgaCheckHeader: Invalid pixel size "' + header.pixel_size + '"');
101
		}
102

103
	}
104

105 106
	// Check tga if it is valid format
	tgaCheckHeader( header );
V
Vincent Lark 已提交
107

108
	if ( header.id_length + offset > buffer.length ) {
109
		console.error('THREE.TGALoader.parse: No data');
110
	}
V
Vincent Lark 已提交
111

112 113
	// Skip the needn't data
	offset += header.id_length;
M
Mr.doob 已提交
114

115 116 117 118
	// Get targa information about RLE compression and palette
	var use_rle = false,
		use_pal = false,
		use_grey = false;
V
Vincent Lark 已提交
119

120
	switch ( header.image_type ) {
M
Mr.doob 已提交
121

122 123 124 125
		case TGA_TYPE_RLE_INDEXED:
			use_rle = true;
			use_pal = true;
			break;
M
Mr.doob 已提交
126

127 128 129
		case TGA_TYPE_INDEXED:
			use_pal = true;
			break;
M
Mr.doob 已提交
130

131 132 133
		case TGA_TYPE_RLE_RGB:
			use_rle = true;
			break;
134

135 136
		case TGA_TYPE_RGB:
			break;
137

138 139 140 141
		case TGA_TYPE_RLE_GREY:
			use_rle = true;
			use_grey = true;
			break;
142

143 144 145
		case TGA_TYPE_GREY:
			use_grey = true;
			break;
146

147
	}
148

149 150
	// Parse tga image buffer
	function tgaParse( use_rle, use_pal, header, offset, data ) {
151

152 153 154 155
		var pixel_data,
			pixel_size,
			pixel_total,
			palettes;
V
Vincent Lark 已提交
156

G
gero3 已提交
157 158
		pixel_size = header.pixel_size >> 3;
		pixel_total = header.width * header.height * pixel_size;
M
Mr.doob 已提交
159

160 161 162 163
		 // Read palettes
		 if ( use_pal ) {
			 palettes = data.subarray( offset, offset += header.colormap_length * ( header.colormap_size >> 3 ) );
		 }
164

165 166 167
		 // Read RLE
		 if ( use_rle ) {
			 pixel_data = new Uint8Array(pixel_total);
V
Vincent Lark 已提交
168

169 170 171
			var c, count, i;
			var shift = 0;
			var pixels = new Uint8Array(pixel_size);
172

173
			while (shift < pixel_total) {
G
gero3 已提交
174
				c     = data[offset ++];
175
				count = (c & 0x7f) + 1;
176

177 178 179
				// RLE pixels.
				if (c & 0x80) {
					// Bind pixel tmp array
G
gero3 已提交
180
					for (i = 0; i < pixel_size; ++ i) {
G
gero3 已提交
181
						pixels[i] = data[offset ++];
182
					}
183

184
					// Copy pixel array
G
gero3 已提交
185
					for (i = 0; i < count; ++ i) {
G
gero3 已提交
186
						pixel_data.set(pixels, shift + i * pixel_size);
187
					}
M
Mr.doob 已提交
188

189
					shift += pixel_size * count;
V
Vincent Lark 已提交
190

191 192 193
				} else {
					// Raw pixels.
					count *= pixel_size;
G
gero3 已提交
194
					for (i = 0; i < count; ++ i) {
G
gero3 已提交
195
						pixel_data[shift + i] = data[offset ++];
196
					}
197
					shift += count;
198
				}
199 200 201 202 203 204 205 206 207 208 209 210 211
			}
		 } else {
			// RAW Pixels
			pixel_data = data.subarray(
				 offset, offset += (use_pal ? header.width * header.height : pixel_total)
			);
		 }

		 return {
			pixel_data: pixel_data,
			palettes: palettes
		 };
	}
V
Vincent Lark 已提交
212

213
	function tgaGetImageData8bits(imageData, y_start, y_step, y_end, x_start, x_step, x_end, image, palettes) {
M
Mr.doob 已提交
214

215 216
		var colormap = palettes;
		var color, i = 0, x, y;
G
gero3 已提交
217
		var width = header.width;
V
Vincent Lark 已提交
218

219
		for (y = y_start; y !== y_end; y += y_step) {
G
gero3 已提交
220
			for (x = x_start; x !== x_end; x += x_step, i ++) {
221 222 223 224 225
				color = image[i];
				imageData[(x + width * y) * 4 + 3] = 255;
				imageData[(x + width * y) * 4 + 2] = colormap[(color * 3) + 0];
				imageData[(x + width * y) * 4 + 1] = colormap[(color * 3) + 1];
				imageData[(x + width * y) * 4 + 0] = colormap[(color * 3) + 2];
M
Mr.doob 已提交
226
			}
227
		}
228

229
		return imageData;
M
Mr.doob 已提交
230

B
brason 已提交
231
	}
M
Mr.doob 已提交
232

233
	function tgaGetImageData16bits(imageData, y_start, y_step, y_end, x_start, x_step, x_end, image) {
234

235 236
		var color, i = 0, x, y;
		var width = header.width;
237

238 239 240 241 242 243 244
		for (y = y_start; y !== y_end; y += y_step) {
			for (x = x_start; x !== x_end; x += x_step, i += 2) {
				color = image[i + 0] + (image[i + 1] << 8); // Inversed ?
				imageData[(x + width * y) * 4 + 0] = (color & 0x7C00) >> 7;
				imageData[(x + width * y) * 4 + 1] = (color & 0x03E0) >> 2;
				imageData[(x + width * y) * 4 + 2] = (color & 0x001F) >> 3;
				imageData[(x + width * y) * 4 + 3] = (color & 0x8000) ? 0 : 255;
245
			}
246
		}
247

248
		return imageData;
249

B
brason 已提交
250
	}
M
Mr.doob 已提交
251

252
	function tgaGetImageData24bits(imageData, y_start, y_step, y_end, x_start, x_step, x_end, image) {
M
Mr.doob 已提交
253

254 255
		var i = 0, x, y;
		var width = header.width;
256

257 258 259 260 261 262
		for (y = y_start; y !== y_end; y += y_step) {
			for (x = x_start; x !== x_end; x += x_step, i += 3) {
				imageData[(x + width * y) * 4 + 3] = 255;
				imageData[(x + width * y) * 4 + 2] = image[i + 0];
				imageData[(x + width * y) * 4 + 1] = image[i + 1];
				imageData[(x + width * y) * 4 + 0] = image[i + 2];
263
			}
264
		}
265

266
		return imageData;
M
Mr.doob 已提交
267

B
brason 已提交
268
	}
V
Vincent Lark 已提交
269

270
	function tgaGetImageData32bits(imageData, y_start, y_step, y_end, x_start, x_step, x_end, image) {
M
Mr.doob 已提交
271

272 273
		var i = 0, x, y;
		var width = header.width;
274

275 276 277 278 279 280
		for (y = y_start; y !== y_end; y += y_step) {
			for (x = x_start; x !== x_end; x += x_step, i += 4) {
				imageData[(x + width * y) * 4 + 2] = image[i + 0];
				imageData[(x + width * y) * 4 + 1] = image[i + 1];
				imageData[(x + width * y) * 4 + 0] = image[i + 2];
				imageData[(x + width * y) * 4 + 3] = image[i + 3];
281
			}
282
		}
283

284
		return imageData;
285

B
brason 已提交
286
	}
M
Mr.doob 已提交
287

288
	function tgaGetImageDataGrey8bits( imageData, y_start, y_step, y_end, x_start, x_step, x_end, image ) {
M
Mr.doob 已提交
289

290 291
		var color, i = 0, x, y;
		var width = header.width;
292

293
		for (y = y_start; y !== y_end; y += y_step) {
G
gero3 已提交
294
			for (x = x_start; x !== x_end; x += x_step, i ++) {
295 296 297 298 299
				color = image[i];
				imageData[(x + width * y) * 4 + 0] = color;
				imageData[(x + width * y) * 4 + 1] = color;
				imageData[(x + width * y) * 4 + 2] = color;
				imageData[(x + width * y) * 4 + 3] = 255;
300
			}
301
		}
302

303
		return imageData;
304

B
brason 已提交
305
	}
M
Mr.doob 已提交
306

307
	function tgaGetImageDataGrey16bits(imageData, y_start, y_step, y_end, x_start, x_step, x_end, image) {
M
Mr.doob 已提交
308

309 310
		var i = 0, x, y;
		var width = header.width;
311

312 313 314 315 316 317
		for (y = y_start; y !== y_end; y += y_step) {
			for (x = x_start; x !== x_end; x += x_step, i += 2) {
				imageData[(x + width * y) * 4 + 0] = image[i + 0];
				imageData[(x + width * y) * 4 + 1] = image[i + 0];
				imageData[(x + width * y) * 4 + 2] = image[i + 0];
				imageData[(x + width * y) * 4 + 3] = image[i + 1];
318
			}
319 320 321 322
		}

		return imageData;

B
brason 已提交
323
	}
324 325 326 327 328 329 330 331 332 333 334

	function getTgaRGBA( width, height, image, palette ) {

		var x_start,
			y_start,
			x_step,
			y_step,
			x_end,
			y_end,
			data = new Uint8Array(width * height * 4);

G
gero3 已提交
335
		switch ( (header.flags & TGA_ORIGIN_MASK) >> TGA_ORIGIN_SHIFT ) {
336 337 338 339 340 341 342 343 344
			default:
			case TGA_ORIGIN_UL:
				x_start = 0;
				x_step = 1;
				x_end = width;
				y_start = 0;
				y_step = 1;
				y_end = height;
				break;
345

346 347 348 349 350 351 352 353
			case TGA_ORIGIN_BL:
				x_start = 0;
				x_step = 1;
				x_end = width;
				y_start = height - 1;
				y_step = -1;
				y_end = -1;
				break;
M
Mr.doob 已提交
354

355 356 357 358 359 360 361 362
			case TGA_ORIGIN_UR:
				x_start = width - 1;
				x_step = -1;
				x_end = -1;
				y_start = 0;
				y_step = 1;
				y_end = height;
				break;
V
Vincent Lark 已提交
363

364 365 366 367 368 369 370 371
			case TGA_ORIGIN_BR:
				x_start = width - 1;
				x_step = -1;
				x_end = -1;
				y_start = height - 1;
				y_step = -1;
				y_end = -1;
				break;
M
Mr.doob 已提交
372

373
		}
V
Vincent Lark 已提交
374

375
		if ( use_grey ) {
V
Vincent Lark 已提交
376

G
gero3 已提交
377
			switch ( header.pixel_size ) {
378 379
				case 8:
					tgaGetImageDataGrey8bits( data, y_start, y_step, y_end, x_start, x_step, x_end, image );
M
Mr.doob 已提交
380
					break;
381 382
				case 16:
					tgaGetImageDataGrey16bits( data, y_start, y_step, y_end, x_start, x_step, x_end, image );
M
Mr.doob 已提交
383
					break;
384
				default:
385
					console.error( 'THREE.TGALoader.parse.getTgaRGBA: not support this format' );
M
Mr.doob 已提交
386
					break;
V
Vincent Lark 已提交
387 388
			}

389
		} else {
V
Vincent Lark 已提交
390

G
gero3 已提交
391
			switch ( header.pixel_size ) {
392 393 394
				case 8:
					tgaGetImageData8bits( data, y_start, y_step, y_end, x_start, x_step, x_end, image, palette );
					break;
V
Vincent Lark 已提交
395

396 397 398
				case 16:
					tgaGetImageData16bits( data, y_start, y_step, y_end, x_start, x_step, x_end, image );
					break;
399

400 401 402
				case 24:
					tgaGetImageData24bits( data, y_start, y_step, y_end, x_start, x_step, x_end, image );
					break;
V
Vincent Lark 已提交
403

404 405 406
				case 32:
					tgaGetImageData32bits( data, y_start, y_step, y_end, x_start, x_step, x_end, image );
					break;
M
Mr.doob 已提交
407

408
				default:
409
					console.error( 'THREE.TGALoader.parse.getTgaRGBA: not support this format' );
410
					break;
411
			}
M
Mr.doob 已提交
412

413
		}
V
Vincent Lark 已提交
414

415 416 417 418
		// Load image data according to specific method
		// var func = 'tgaGetImageData' + (use_grey ? 'Grey' : '') + (header.pixel_size) + 'bits';
		// func(data, y_start, y_step, y_end, x_start, x_step, x_end, width, image, palette );
		return data;
419 420 421

	}

422 423 424 425 426 427 428 429 430
	var result = tgaParse( use_rle, use_pal, header, offset, content );
	var rgbaData = getTgaRGBA( header.width, header.height, result.pixel_data, result.palettes );

	return {
		width: header.width,
		height: header.height,
		data: rgbaData
	};

V
Vincent Lark 已提交
431
};