1 //------------------------------------------------------------------------------
2 // emTgaImageFileModel.cpp
3 //
4 // Copyright (C) 2004-2009,2014,2018 Oliver Hamann.
5 //
6 // Homepage: http://eaglemode.sourceforge.net/
7 //
8 // This program is free software: you can redistribute it and/or modify it under
9 // the terms of the GNU General Public License version 3 as published by the
10 // Free Software Foundation.
11 //
12 // This program is distributed in the hope that it will be useful, but WITHOUT
13 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 // FOR A PARTICULAR PURPOSE. See the GNU General Public License version 3 for
15 // more details.
16 //
17 // You should have received a copy of the GNU General Public License version 3
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 //------------------------------------------------------------------------------
20 
21 #include <emTga/emTgaImageFileModel.h>
22 
23 
Acquire(emContext & context,const emString & name,bool common)24 emRef<emTgaImageFileModel> emTgaImageFileModel::Acquire(
25 	emContext & context, const emString & name, bool common
26 )
27 {
28 	EM_IMPL_ACQUIRE(emTgaImageFileModel,context,name,common)
29 }
30 
31 
emTgaImageFileModel(emContext & context,const emString & name)32 emTgaImageFileModel::emTgaImageFileModel(
33 	emContext & context, const emString & name
34 )
35 	: emImageFileModel(context,name)
36 {
37 	L=NULL;
38 }
39 
40 
~emTgaImageFileModel()41 emTgaImageFileModel::~emTgaImageFileModel()
42 {
43 	emTgaImageFileModel::QuitLoading();
44 	emTgaImageFileModel::QuitSaving();
45 }
46 
47 
TryStartLoading()48 void emTgaImageFileModel::TryStartLoading()
49 {
50 	int i,c;
51 
52 	L=new LoadingState;
53 	L->File=NULL;
54 	L->Palette=NULL;
55 	L->RunCol.SetGrey(0);
56 	L->IDLen=0;
57 	L->CMapType=0;
58 	L->IMapType=0;
59 	L->CMapSize=0;
60 	L->CMapBitsPP=0;
61 	L->Width=0;
62 	L->Height=0;
63 	L->BitsPP=0;
64 	L->Descriptor=0;
65 	L->ChannelCount=0;
66 	L->NextY=0;
67 	L->RunLen=0;
68 	L->ImagePrepared=false;
69 
70 	L->File=fopen(GetFilePath(),"rb");
71 	if (!L->File) goto ErrFile;
72 
73 	L->IDLen=Read8();
74 	L->CMapType=Read8();
75 	L->IMapType=Read8();
76 	Read16();
77 	L->CMapSize=Read16();
78 	L->CMapBitsPP=Read8();
79 	Read16();
80 	Read16();
81 	L->Width=Read16();
82 	L->Height=Read16();
83 	L->BitsPP=Read8();
84 	L->Descriptor=Read8();
85 	for (i=0; i<L->IDLen; i++) Read8();
86 
87 	if (ferror(L->File)) goto ErrFile;
88 	if (feof(L->File)) goto ErrFormat;
89 	if (L->Width<1 || L->Height<1) goto ErrFormat;
90 
91 	if ((L->IMapType&~8)==1) {
92 		if (L->CMapType!=1) goto ErrFormat;
93 		if (L->BitsPP!=8 && L->BitsPP!=16) goto ErrFormat;
94 		L->Palette=new emColor[L->CMapSize];
95 		L->ChannelCount=1;
96 		for (i=0; i<L->CMapSize; i++) {
97 			if (L->CMapBitsPP==16) {
98 				c=Read16();
99 				L->Palette[i].SetRed((emByte)((((c>>10)&31)*255)/31));
100 				L->Palette[i].SetGreen((emByte)((((c>>5)&31)*255)/31));
101 				L->Palette[i].SetBlue((emByte)(((c&31)*255)/31));
102 				L->Palette[i].SetAlpha((emByte)((c&0x8000)?255:0));
103 			}
104 			else if (L->CMapBitsPP==24) {
105 				L->Palette[i].SetBlue((emByte)Read8());
106 				L->Palette[i].SetGreen((emByte)Read8());
107 				L->Palette[i].SetRed((emByte)Read8());
108 				L->Palette[i].SetAlpha(255);
109 			}
110 			else if (L->CMapBitsPP==32) {
111 				L->Palette[i].SetBlue((emByte)Read8());
112 				L->Palette[i].SetGreen((emByte)Read8());
113 				L->Palette[i].SetRed((emByte)Read8());
114 				L->Palette[i].SetAlpha((emByte)Read8());
115 			}
116 			else goto ErrFormat;
117 			if (L->ChannelCount<3 && !L->Palette[i].IsGrey()) {
118 				L->ChannelCount+=2;
119 			}
120 			if ((L->ChannelCount&1)!=0 && L->Palette[i].GetAlpha()!=255) {
121 				L->ChannelCount+=1;
122 			}
123 		}
124 		if (ferror(L->File)) goto ErrFile;
125 		if (feof(L->File)) goto ErrFormat;
126 	}
127 	else if ((L->IMapType&~8)==2) {
128 		if (L->CMapType!=0) goto ErrFormat;
129 		if (L->BitsPP==16) L->ChannelCount=4;
130 		else if (L->BitsPP==24) L->ChannelCount=3;
131 		else if (L->BitsPP==32) L->ChannelCount=4;
132 		else goto ErrFormat;
133 	}
134 	else if ((L->IMapType&~8)==3) {
135 		if (L->CMapType!=0) goto ErrFormat;
136 		if (L->BitsPP==8) L->ChannelCount=1;
137 		else if (L->BitsPP==16) L->ChannelCount=2;
138 		else goto ErrFormat;
139 	}
140 	else goto ErrFormat;
141 
142 	if ((L->ChannelCount&1)==0 && (L->Descriptor&0x0f)==0) {
143 		L->ChannelCount--;
144 	}
145 
146 	FileFormatInfo=emString::Format("Targa - %d bits/pixel",L->BitsPP);
147 	switch (L->IMapType) {
148 	case  1: FileFormatInfo+=" uncompressed color-mapped"; break;
149 	case  2: FileFormatInfo+=" uncompressed RGB"; break;
150 	case  3: FileFormatInfo+=" uncompressed grey"; break;
151 	case  9: FileFormatInfo+=" RLE-compressed color-mapped"; break;
152 	case 10: FileFormatInfo+=" RLE-compressed RGB"; break;
153 	case 11: FileFormatInfo+=" RLE-compressed grey"; break;
154 	}
155 	if ((L->Descriptor&0x0f)!=0) FileFormatInfo+=" with alpha";
156 	FileFormatInfo+=emString::Format(" (%d channels)",L->ChannelCount);
157 	Signal(ChangeSignal);
158 
159 	return;
160 
161 ErrFile:
162 	throw emException("%s",emGetErrorText(errno).Get());
163 ErrFormat:
164 	throw emException("TGA format error");
165 }
166 
167 
TryContinueLoading()168 bool emTgaImageFileModel::TryContinueLoading()
169 {
170 	int i,x,c;
171 
172 	if (!L->ImagePrepared) {
173 		Image.Setup(L->Width,L->Height,L->ChannelCount);
174 		Signal(ChangeSignal);
175 		L->ImagePrepared=true;
176 		return false;
177 	}
178 
179 	for (x=0; x<L->Width; x++) {
180 		if ((L->IMapType&8)!=0 && L->RunLen<0) L->RunLen++;
181 		else {
182 			if ((L->IMapType&8)!=0 && L->RunLen==0) {
183 				L->RunLen=Read8();
184 				if (L->RunLen&0x80) L->RunLen=-(L->RunLen&0x7f)+1;
185 				else L->RunLen++;
186 			}
187 			L->RunLen--;
188 			for (c=0, i=0; i<L->BitsPP; i+=8) c|=(Read8()&255)<<i;
189 			if ((L->IMapType&~8)==1) {
190 				if (c<0 || c>=L->CMapSize) throw emException("TGA format error");
191 				L->RunCol=L->Palette[c];
192 			}
193 			else if ((L->IMapType&~8)==2) {
194 				if (L->BitsPP==16) {
195 					L->RunCol.SetRed((emByte)((((c>>10)&31)*255)/31));
196 					L->RunCol.SetGreen((emByte)((((c>>5)&31)*255)/31));
197 					L->RunCol.SetBlue((emByte)(((c&31)*255)/31));
198 					L->RunCol.SetAlpha((emByte)((c&0x8000)?255:0));
199 				}
200 				else {
201 					L->RunCol.SetRed((emByte)(c>>16));
202 					L->RunCol.SetGreen((emByte)(c>>8));
203 					L->RunCol.SetBlue((emByte)c);
204 					L->RunCol.SetAlpha((emByte)(L->BitsPP==24 ? 255 : c>>24));
205 				}
206 			}
207 			else {
208 				L->RunCol.SetRed((emByte)c);
209 				L->RunCol.SetGreen((emByte)c);
210 				L->RunCol.SetBlue((emByte)c);
211 				L->RunCol.SetAlpha((emByte)(L->BitsPP==8 ? 255 : c>>8));
212 			}
213 		}
214 		Image.SetPixel(
215 			x,
216 			(L->Descriptor&0x20)?L->NextY:L->Height-L->NextY-1,
217 			L->RunCol
218 		);
219 	}
220 
221 	Signal(ChangeSignal);
222 
223 	if (ferror(L->File)) throw emException("%s",emGetErrorText(errno).Get());
224 
225 	L->NextY++;
226 	if (L->NextY>=L->Height) {
227 		return true;
228 	}
229 	return false;
230 }
231 
232 
QuitLoading()233 void emTgaImageFileModel::QuitLoading()
234 {
235 	if (L) {
236 		if (L->File) fclose(L->File);
237 		if (L->Palette) delete [] L->Palette;
238 		delete L;
239 		L=NULL;
240 	}
241 }
242 
243 
TryStartSaving()244 void emTgaImageFileModel::TryStartSaving()
245 {
246 	throw emException("emTgaImageFileModel: Saving not implemented.");
247 }
248 
249 
TryContinueSaving()250 bool emTgaImageFileModel::TryContinueSaving()
251 {
252 	return true;
253 }
254 
255 
QuitSaving()256 void emTgaImageFileModel::QuitSaving()
257 {
258 }
259 
260 
CalcMemoryNeed()261 emUInt64 emTgaImageFileModel::CalcMemoryNeed()
262 {
263 	if (L) {
264 		return ((emUInt64)L->Width)*L->Height*L->ChannelCount;
265 	}
266 	else {
267 		return ((emUInt64)Image.GetWidth())*
268 		       Image.GetHeight()*
269 		       Image.GetChannelCount();
270 	}
271 }
272 
273 
CalcFileProgress()274 double emTgaImageFileModel::CalcFileProgress()
275 {
276 	if (L && L->Height>0) {
277 		return 100.0*L->NextY/L->Height;
278 	}
279 	else {
280 		return 0.0;
281 	}
282 }
283 
284 
Read8()285 int emTgaImageFileModel::Read8()
286 {
287 	return (unsigned char)fgetc(L->File);
288 }
289 
290 
Read16()291 int emTgaImageFileModel::Read16()
292 {
293 	int i;
294 
295 	i=Read8();
296 	i|=Read8()<<8;
297 	return i;
298 }
299