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