-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTgaReader.h
More file actions
157 lines (129 loc) · 4.57 KB
/
TgaReader.h
File metadata and controls
157 lines (129 loc) · 4.57 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
150
151
152
153
154
155
156
157
//
// Created by Marrony Neris on 11/18/15.
//
#ifndef TGAREADER_H
#define TGAREADER_H
#include <stdio.h>
/*
A TGA file has a header that consists of 12 fields. These are:
# 0x00 - 0x00 - id (uchar)
# 0x01 - 0x01 - colour map type (uchar)
# 0x02 - 0x02 - image type (uchar)
# 0x03 - 0x04 - colour map first entry (short int)
# 0x05 - 0x06 - colour map length (short int)
# 0x07 - 0x07 - colour map depth (uchar)
# 0x08 - 0x09 - horizontal origin (short int)
# 0x0a - 0x0b - vertical origin (short int)
# 0x0c - 0x0d - width (short int)
# 0x0e - 0x0f - height (short int)
# 0x10 - 0x10 - pixel depth (uchar)
# 0x11 - 0x11 - image descriptor (uchar)
Some possible values for the image type are:
# 1 - colour map image
# 2 - RGB(A) uncompressed
# 3 - greyscale uncompressed
# 9 - greyscale RLE (compressed)
# 10 - RGB(A) RLE (compressed)
*/
struct TGAHeader {
uint8_t id;
uint8_t colour_map_type;
uint8_t image_type;
uint16_t colour_map_first_entry;
uint16_t colour_map_length;
uint8_t colour_map_depth;
uint16_t horizontal_origin;
uint16_t vertical_origin;
uint16_t width;
uint16_t height;
uint8_t pixel_depth;
uint8_t image_descriptor;
};
bool readTga(HeapAllocator& allocator, FILE* stream, Image& image) {
TGAHeader header;
fread(&header.id, sizeof(header.id), 1, stream);
fread(&header.colour_map_type, sizeof(header.colour_map_type), 1, stream);
fread(&header.image_type, sizeof(header.image_type), 1, stream);
fread(&header.colour_map_first_entry, sizeof(header.colour_map_first_entry), 1, stream);
fread(&header.colour_map_length, sizeof(header.colour_map_length), 1, stream);
fread(&header.colour_map_depth, sizeof(header.colour_map_depth), 1, stream);
fread(&header.horizontal_origin, sizeof(header.horizontal_origin), 1, stream);
fread(&header.vertical_origin, sizeof(header.vertical_origin), 1, stream);
fread(&header.width, sizeof(header.width), 1, stream);
fread(&header.height, sizeof(header.height), 1, stream);
fread(&header.pixel_depth, sizeof(header.pixel_depth), 1, stream);
fread(&header.image_descriptor, sizeof(header.image_descriptor), 1, stream);
if(header.image_type != 2 && header.image_type != 3 && header.image_type != 10) {
return false;
}
if(header.pixel_depth != 8 && header.pixel_depth != 24 && header.pixel_depth != 32) {
return false;
}
if(header.width == 0 || header.height == 0) {
return false;
}
int pixel_size = header.pixel_depth / 8;
int total_bytes = header.width * header.height * pixel_size;
uint8_t* data = (uint8_t*)allocator.allocate(total_bytes);
if(data == nullptr) {
return false;
}
if(header.image_type == 10) {
int bytes_to_process = total_bytes;
uint8_t* dst = data;
while(bytes_to_process > 0) {
int byte_read = fgetc(stream);
int bytes_to_read = (byte_read & 0x7f) + 1;
bytes_to_process -= bytes_to_read * pixel_size;
if(byte_read & 0x80) {
char pixels[8];
fread(pixels, sizeof(char), pixel_size, stream);
do {
memcpy(dst, pixels, pixel_size);
dst += pixel_size;
} while(--bytes_to_read);
} else {
bytes_to_read *= pixel_size;
assert(fread(dst, sizeof(char), bytes_to_read, stream) == bytes_to_read);
dst += bytes_to_read;
}
}
} else {
assert(fread(data, sizeof(char), total_bytes, stream) == total_bytes);
}
if(pixel_size >= 3) {
for(int i = 0; i < total_bytes; i += pixel_size) {
std::swap(data[i + 0], data[i + 2]);
}
}
switch(pixel_size) {
case 1:
image.width = header.width;
image.height = header.height;
image.format = 1;
image.pixels = data;
break;
case 3:
image.width = header.width;
image.height = header.height;
image.format = 3;
image.pixels = data;
break;
case 4:
image.width = header.width;
image.height = header.height;
image.format = 4;
image.pixels = data;
break;
default:
break;
}
return true;
}
void readTga(HeapAllocator& allocator, const char* filename, Image& tgaImage) {
FILE* stream = fopen(filename, "rb");
assert(stream != nullptr);
readTga(allocator, stream, tgaImage);
fclose(stream);
}
#endif //TGAREADER_H