Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1 | daniel-mar | 1 | unit DXTexImg; |
2 | |||
3 | interface |
||
4 | |||
5 | uses |
||
6 | Windows, SysUtils, Classes, DXConsts; |
||
7 | |||
8 | const |
||
9 | DXTextureImageGroupType_Normal = 0; // Normal group |
||
10 | DXTextureImageGroupType_Mipmap = 1; // Mipmap group |
||
11 | |||
12 | type |
||
13 | EDXTextureImageError = class(Exception); |
||
14 | |||
15 | TDXTextureImageChannel = record |
||
16 | Mask: DWORD; |
||
17 | BitCount: Integer; |
||
18 | |||
19 | { Internal use } |
||
20 | _Mask2: DWORD; |
||
21 | _rshift: Integer; |
||
22 | _lshift: Integer; |
||
23 | _BitCount2: Integer; |
||
24 | end; |
||
25 | |||
26 | TDXTextureImage_PaletteEntries = array[0..255] of TPaletteEntry; |
||
27 | |||
28 | TDXTextureImageType = ( |
||
29 | DXTextureImageType_PaletteIndexedColor, |
||
30 | DXTextureImageType_RGBColor |
||
31 | ); |
||
32 | |||
33 | TDXTextureImage = class; |
||
34 | |||
35 | TDXTextureImageLoadFunc = procedure(Stream: TStream; Image: TDXTextureImage); |
||
36 | |||
37 | TDXTextureImage = class |
||
38 | private |
||
39 | FOwner: TDXTextureImage; |
||
40 | FSubImage: TList; |
||
41 | FImageType: TDXTextureImageType; |
||
42 | FWidth: Integer; |
||
43 | FHeight: Integer; |
||
44 | FPBits: Pointer; |
||
45 | FBitCount: Integer; |
||
46 | FPackedPixelOrder: Boolean; |
||
47 | FWidthBytes: Integer; |
||
48 | FNextLine: Integer; |
||
49 | FSize: Integer; |
||
50 | FTopPBits: Pointer; |
||
51 | FTransparent: Boolean; |
||
52 | FTransparentColor: DWORD; |
||
53 | FImageGroupType: DWORD; |
||
54 | FImageID: DWORD; |
||
55 | FImageName: string; |
||
56 | FAutoFreeImage: Boolean; |
||
57 | procedure ClearImage; |
||
58 | function GetPixel(x, y: Integer): DWORD; |
||
59 | procedure SetPixel(x, y: Integer; c: DWORD); |
||
60 | function GetScanLine(y: Integer): Pointer; |
||
61 | function GetSubGroupImageCount(GroupTypeID: DWORD): Integer; |
||
62 | function GetSubGroupImage(GroupTypeID: DWORD; Index: Integer): TDXTextureImage; |
||
63 | function GetSubImageCount: Integer; |
||
64 | function GetSubImage(Index: Integer): TDXTextureImage; |
||
65 | public |
||
66 | idx_index: TDXTextureImageChannel; |
||
67 | idx_alpha: TDXTextureImageChannel; |
||
68 | idx_palette: TDXTextureImage_PaletteEntries; |
||
69 | rgb_red: TDXTextureImageChannel; |
||
70 | rgb_green: TDXTextureImageChannel; |
||
71 | rgb_blue: TDXTextureImageChannel; |
||
72 | rgb_alpha: TDXTextureImageChannel; |
||
73 | constructor Create; |
||
74 | constructor CreateSub(AOwner: TDXTextureImage); |
||
75 | destructor Destroy; override; |
||
76 | procedure Assign(Source: TDXTextureImage); |
||
77 | procedure Clear; |
||
78 | procedure SetImage(ImageType: TDXTextureImageType; Width, Height, BitCount, WidthBytes, NextLine: Integer; |
||
79 | PBits, TopPBits: Pointer; Size: Integer; AutoFree: Boolean); |
||
80 | procedure SetSize(ImageType: TDXTextureImageType; Width, Height, BitCount, WidthBytes: Integer); |
||
81 | procedure LoadFromFile(const FileName: string); |
||
82 | procedure LoadFromStream(Stream: TStream); |
||
83 | procedure SaveToFile(const FileName: string); |
||
84 | procedure SaveToStream(Stream: TStream); |
||
85 | function EncodeColor(R, G, B, A: Byte): DWORD; |
||
86 | function PaletteIndex(R, G, B: Byte): DWORD; |
||
87 | class procedure RegisterLoadFunc(LoadFunc: TDXTextureImageLoadFunc); |
||
88 | class procedure UnRegisterLoadFunc(LoadFunc: TDXTextureImageLoadFunc); |
||
89 | property BitCount: Integer read FBitCount; |
||
90 | property PackedPixelOrder: Boolean read FPackedPixelOrder write FPackedPixelOrder; |
||
91 | property Height: Integer read FHeight; |
||
92 | property ImageType: TDXTextureImageType read FImageType; |
||
93 | property ImageGroupType: DWORD read FImageGroupType write FImageGroupType; |
||
94 | property ImageID: DWORD read FImageID write FImageID; |
||
95 | property ImageName: string read FImageName write FImageName; |
||
96 | property NextLine: Integer read FNextLine; |
||
97 | property PBits: Pointer read FPBits; |
||
98 | property Pixels[x, y: Integer]: DWORD read GetPixel write SetPixel; |
||
99 | property ScanLine[y: Integer]: Pointer read GetScanLine; |
||
100 | property Size: Integer read FSize; |
||
101 | property SubGroupImageCount[GroupTypeID: DWORD]: Integer read GetSubGroupImageCount; |
||
102 | property SubGroupImages[GroupTypeID: DWORD; Index: Integer]: TDXTextureImage read GetSubGroupImage; |
||
103 | property SubImageCount: Integer read GetSubImageCount; |
||
104 | property SubImages[Index: Integer]: TDXTextureImage read GetSubImage; |
||
105 | property TopPBits: Pointer read FTopPBits; |
||
106 | property Transparent: Boolean read FTransparent write FTransparent; |
||
107 | property TransparentColor: DWORD read FTransparentColor write FTransparentColor; |
||
108 | property Width: Integer read FWidth; |
||
109 | property WidthBytes: Integer read FWidthBytes; |
||
110 | end; |
||
111 | |||
112 | function dxtMakeChannel(Mask: DWORD; indexed: Boolean): TDXTextureImageChannel; |
||
113 | function dxtEncodeChannel(const Channel: TDXTextureImageChannel; c: DWORD): DWORD; |
||
114 | function dxtDecodeChannel(const Channel: TDXTextureImageChannel; c: DWORD): DWORD; |
||
115 | |||
116 | implementation |
||
117 | |||
118 | function GetWidthBytes(Width, BitCount: Integer): Integer; |
||
119 | begin |
||
120 | Result := (((Width*BitCount)+31) div 32)*4; |
||
121 | end; |
||
122 | |||
123 | function dxtEncodeChannel(const Channel: TDXTextureImageChannel; c: DWORD): DWORD; |
||
124 | begin |
||
125 | Result := ((c shl Channel._rshift) shr Channel._lshift) and Channel.Mask; |
||
126 | end; |
||
127 | |||
128 | function dxtDecodeChannel(const Channel: TDXTextureImageChannel; c: DWORD): DWORD; |
||
129 | begin |
||
130 | Result := ((c and Channel.Mask) shr Channel._rshift) shl Channel._lshift; |
||
131 | Result := Result or (Result shr Channel._BitCount2); |
||
132 | end; |
||
133 | |||
134 | function dxtMakeChannel(Mask: DWORD; indexed: Boolean): TDXTextureImageChannel; |
||
135 | |||
136 | function GetMaskBitCount(b: Integer): Integer; |
||
137 | var |
||
138 | i: Integer; |
||
139 | begin |
||
140 | i := 0; |
||
141 | while (i<31) and (((1 shl i) and b)=0) do Inc(i); |
||
142 | |||
143 | Result := 0; |
||
144 | while ((1 shl i) and b)<>0 do |
||
145 | begin |
||
146 | Inc(i); |
||
147 | Inc(Result); |
||
148 | end; |
||
149 | end; |
||
150 | |||
151 | function GetBitCount2(b: Integer): Integer; |
||
152 | begin |
||
153 | Result := 0; |
||
154 | while (Result<31) and (((1 shl Result) and b)=0) do Inc(Result); |
||
155 | end; |
||
156 | |||
157 | begin |
||
158 | Result.BitCount := GetMaskBitCount(Mask); |
||
159 | Result.Mask := Mask; |
||
160 | |||
161 | if indexed then |
||
162 | begin |
||
163 | Result._rshift := GetBitCount2(Mask); |
||
164 | Result._lshift := 0; |
||
165 | Result._Mask2 := 1 shl Result.BitCount-1; |
||
166 | Result._BitCount2 := 0; |
||
167 | end else |
||
168 | begin |
||
169 | Result._rshift := GetBitCount2(Mask)-(8-Result.BitCount); |
||
170 | if Result._rshift<0 then |
||
171 | begin |
||
172 | Result._lshift := -Result._rshift; |
||
173 | Result._rshift := 0; |
||
174 | end else |
||
175 | Result._lshift := 0; |
||
176 | Result._Mask2 := (1 shl Result.BitCount-1) shl (8-Result.BitCount); |
||
177 | Result._BitCount2 := 8-Result.BitCount; |
||
178 | end; |
||
179 | end; |
||
180 | |||
181 | { TDXTextureImage } |
||
182 | |||
183 | var |
||
184 | _DXTextureImageLoadFuncList: TList; |
||
185 | |||
186 | procedure DXTextureImage_LoadDXTextureImageFunc(Stream: TStream; Image: TDXTextureImage); forward; |
||
187 | procedure DXTextureImage_LoadBitmapFunc(Stream: TStream; Image: TDXTextureImage); forward; |
||
188 | |||
189 | function DXTextureImageLoadFuncList: TList; |
||
190 | begin |
||
191 | if _DXTextureImageLoadFuncList=nil then |
||
192 | begin |
||
193 | _DXTextureImageLoadFuncList := TList.Create; |
||
194 | _DXTextureImageLoadFuncList.Add(@DXTextureImage_LoadDXTextureImageFunc); |
||
195 | _DXTextureImageLoadFuncList.Add(@DXTextureImage_LoadBitmapFunc); |
||
196 | end; |
||
197 | Result := _DXTextureImageLoadFuncList; |
||
198 | end; |
||
199 | |||
200 | class procedure TDXTextureImage.RegisterLoadFunc(LoadFunc: TDXTextureImageLoadFunc); |
||
201 | begin |
||
202 | if DXTextureImageLoadFuncList.IndexOf(@LoadFunc)=-1 then |
||
203 | DXTextureImageLoadFuncList.Add(@LoadFunc); |
||
204 | end; |
||
205 | |||
206 | class procedure TDXTextureImage.UnRegisterLoadFunc(LoadFunc: TDXTextureImageLoadFunc); |
||
207 | begin |
||
208 | DXTextureImageLoadFuncList.Remove(@LoadFunc); |
||
209 | end; |
||
210 | |||
211 | constructor TDXTextureImage.Create; |
||
212 | begin |
||
213 | inherited Create; |
||
214 | FSubImage := TList.Create; |
||
215 | end; |
||
216 | |||
217 | constructor TDXTextureImage.CreateSub(AOwner: TDXTextureImage); |
||
218 | begin |
||
219 | Create; |
||
220 | |||
221 | FOwner := AOwner; |
||
222 | try |
||
223 | FOwner.FSubImage.Add(Self); |
||
224 | except |
||
225 | FOwner := nil; |
||
226 | raise; |
||
227 | end; |
||
228 | end; |
||
229 | |||
230 | destructor TDXTextureImage.Destroy; |
||
231 | begin |
||
232 | Clear; |
||
233 | FSubImage.Free; |
||
234 | if FOwner<>nil then |
||
235 | FOwner.FSubImage.Remove(Self); |
||
236 | inherited Destroy; |
||
237 | end; |
||
238 | |||
239 | procedure TDXTextureImage.Assign(Source: TDXTextureImage); |
||
240 | var |
||
241 | y: Integer; |
||
242 | begin |
||
243 | SetSize(Source.ImageType, Source.Width, Source.Height, Source.BitCount, Source.WidthBytes); |
||
244 | |||
245 | idx_index := Source.idx_index; |
||
246 | idx_alpha := Source.idx_alpha; |
||
247 | idx_palette := Source.idx_palette; |
||
248 | |||
249 | rgb_red := Source.rgb_red; |
||
250 | rgb_green := Source.rgb_green; |
||
251 | rgb_blue := Source.rgb_blue; |
||
252 | rgb_alpha := Source.rgb_alpha; |
||
253 | |||
254 | for y:=0 to Height-1 do |
||
255 | Move(Source.ScanLine[y]^, ScanLine[y]^, WidthBytes); |
||
256 | |||
257 | Transparent := Source.Transparent; |
||
258 | TransparentColor := Source.TransparentColor; |
||
259 | ImageGroupType := Source.ImageGroupType; |
||
260 | ImageID := Source.ImageID; |
||
261 | ImageName := Source.ImageName; |
||
262 | end; |
||
263 | |||
264 | procedure TDXTextureImage.ClearImage; |
||
265 | begin |
||
266 | if FAutoFreeImage then |
||
267 | FreeMem(FPBits); |
||
268 | |||
269 | FImageType := DXTextureImageType_PaletteIndexedColor; |
||
270 | FWidth := 0; |
||
271 | FHeight := 0; |
||
272 | FBitCount := 0; |
||
273 | FWidthBytes := 0; |
||
274 | FNextLine := 0; |
||
275 | FSize := 0; |
||
276 | FPBits := nil; |
||
277 | FTopPBits := nil; |
||
278 | FAutoFreeImage := False; |
||
279 | end; |
||
280 | |||
281 | procedure TDXTextureImage.Clear; |
||
282 | begin |
||
283 | ClearImage; |
||
284 | |||
285 | while SubImageCount>0 do |
||
286 | SubImages[SubImageCount-1].Free; |
||
287 | |||
288 | FImageGroupType := 0; |
||
289 | FImageID := 0; |
||
290 | FImageName := ''; |
||
291 | |||
292 | FTransparent := False; |
||
293 | FTransparentColor := 0; |
||
294 | |||
295 | FillChar(idx_index, SizeOf(idx_index), 0); |
||
296 | FillChar(idx_alpha, SizeOf(idx_alpha), 0); |
||
297 | FillChar(idx_palette, SizeOf(idx_palette), 0); |
||
298 | FillChar(rgb_red, SizeOf(rgb_red), 0); |
||
299 | FillChar(rgb_green, SizeOf(rgb_green), 0); |
||
300 | FillChar(rgb_blue, SizeOf(rgb_blue), 0); |
||
301 | FillChar(rgb_alpha, SizeOf(rgb_alpha), 0); |
||
302 | end; |
||
303 | |||
304 | procedure TDXTextureImage.SetImage(ImageType: TDXTextureImageType; Width, Height, BitCount, WidthBytes, NextLine: Integer; |
||
305 | PBits, TopPBits: Pointer; Size: Integer; AutoFree: Boolean); |
||
306 | begin |
||
307 | ClearImage; |
||
308 | |||
309 | FAutoFreeImage := AutoFree; |
||
310 | FImageType := ImageType; |
||
311 | FWidth := Width; |
||
312 | FHeight := Height; |
||
313 | FBitCount := BitCount; |
||
314 | FWidthBytes := WidthBytes; |
||
315 | FNextLine := NextLine; |
||
316 | FSize := Size; |
||
317 | FPBits := PBits; |
||
318 | FTopPBits := TopPBits; |
||
319 | end; |
||
320 | |||
321 | procedure TDXTextureImage.SetSize(ImageType: TDXTextureImageType; Width, Height, BitCount, WidthBytes: Integer); |
||
322 | var |
||
323 | APBits: Pointer; |
||
324 | begin |
||
325 | ClearImage; |
||
326 | |||
327 | if WidthBytes=0 then |
||
328 | WidthBytes := GetWidthBytes(Width, BitCount); |
||
329 | |||
330 | GetMem(APBits, WidthBytes*Height); |
||
331 | SetImage(ImageType, Width, Height, BitCount, WidthBytes, WidthBytes, APBits, APBits, WidthBytes*Height, True); |
||
332 | end; |
||
333 | |||
334 | function TDXTextureImage.GetScanLine(y: Integer): Pointer; |
||
335 | begin |
||
336 | Result := Pointer(Integer(FTopPBits)+FNextLine*y); |
||
337 | end; |
||
338 | |||
339 | function TDXTextureImage.GetSubGroupImageCount(GroupTypeID: DWORD): Integer; |
||
340 | var |
||
341 | i: Integer; |
||
342 | begin |
||
343 | Result := 0; |
||
344 | for i:=0 to SubImageCount-1 do |
||
345 | if SubImages[i].ImageGroupType=GroupTypeID then |
||
346 | Inc(Result); |
||
347 | end; |
||
348 | |||
349 | function TDXTextureImage.GetSubGroupImage(GroupTypeID: DWORD; Index: Integer): TDXTextureImage; |
||
350 | var |
||
351 | i, j: Integer; |
||
352 | begin |
||
353 | j := 0; |
||
354 | for i:=0 to SubImageCount-1 do |
||
355 | if SubImages[i].ImageGroupType=GroupTypeID then |
||
356 | begin |
||
357 | if j=Index then |
||
358 | begin |
||
359 | Result := SubImages[i]; |
||
360 | Exit; |
||
361 | end; |
||
362 | |||
363 | Inc(j); |
||
364 | end; |
||
365 | |||
366 | Result := nil; |
||
367 | SubImages[-1]; |
||
368 | end; |
||
369 | |||
370 | function TDXTextureImage.GetSubImageCount: Integer; |
||
371 | begin |
||
372 | Result := FSubImage.Count; |
||
373 | end; |
||
374 | |||
375 | function TDXTextureImage.GetSubImage(Index: Integer): TDXTextureImage; |
||
376 | begin |
||
377 | Result := FSubImage[Index]; |
||
378 | end; |
||
379 | |||
380 | function TDXTextureImage.EncodeColor(R, G, B, A: Byte): DWORD; |
||
381 | begin |
||
382 | if ImageType=DXTextureImageType_PaletteIndexedColor then |
||
383 | begin |
||
384 | Result := dxtEncodeChannel(idx_index, PaletteIndex(R, G, B)) or |
||
385 | dxtEncodeChannel(idx_alpha, A); |
||
386 | end else |
||
387 | begin |
||
388 | Result := dxtEncodeChannel(rgb_red, R) or |
||
389 | dxtEncodeChannel(rgb_green, G) or |
||
390 | dxtEncodeChannel(rgb_blue, B) or |
||
391 | dxtEncodeChannel(rgb_alpha, A); |
||
392 | end; |
||
393 | end; |
||
394 | |||
395 | function TDXTextureImage.PaletteIndex(R, G, B: Byte): DWORD; |
||
396 | var |
||
397 | i, d, d2: Integer; |
||
398 | begin |
||
399 | Result := 0; |
||
400 | if ImageType=DXTextureImageType_PaletteIndexedColor then |
||
401 | begin |
||
402 | d := MaxInt; |
||
403 | for i:=0 to (1 shl idx_index.BitCount)-1 do |
||
404 | with idx_palette[i] do |
||
405 | begin |
||
406 | d2 := Abs((peRed-R))*Abs((peRed-R)) + Abs((peGreen-G))*Abs((peGreen-G)) + Abs((peBlue-B))*Abs((peBlue-B)); |
||
407 | if d>d2 then |
||
408 | begin |
||
409 | d := d2; |
||
410 | Result := i; |
||
411 | end; |
||
412 | end; |
||
413 | end; |
||
414 | end; |
||
415 | |||
416 | const |
||
417 | Mask1: array[0..7] of DWORD= (1, 2, 4, 8, 16, 32, 64, 128); |
||
418 | Mask2: array[0..3] of DWORD= (3, 12, 48, 192); |
||
419 | Mask4: array[0..1] of DWORD= ($0F, $F0); |
||
420 | |||
421 | Shift1: array[0..7] of DWORD= (0, 1, 2, 3, 4, 5, 6, 7); |
||
422 | Shift2: array[0..3] of DWORD= (0, 2, 4, 6); |
||
423 | Shift4: array[0..1] of DWORD= (0, 4); |
||
424 | |||
425 | type |
||
426 | PByte3 = ^TByte3; |
||
427 | TByte3 = array[0..2] of Byte; |
||
428 | |||
429 | function TDXTextureImage.GetPixel(x, y: Integer): DWORD; |
||
430 | begin |
||
431 | Result := 0; |
||
432 | if (x>=0) and (x<FWidth) and (y>=0) and (y<FHeight) then |
||
433 | begin |
||
434 | case FBitCount of |
||
435 | 1 : begin |
||
436 | if FPackedPixelOrder then |
||
437 | Result := (PByte(Integer(FTopPBits)+FNextLine*y+x shr 3)^ and Mask1[7-x and 7]) shr Shift1[7-x and 7] |
||
438 | else |
||
439 | Result := (PByte(Integer(FTopPBits)+FNextLine*y+x shr 3)^ and Mask1[x and 7]) shr Shift1[x and 7]; |
||
440 | end; |
||
441 | 2 : begin |
||
442 | if FPackedPixelOrder then |
||
443 | Result := (PByte(Integer(FTopPBits)+FNextLine*y+x shr 2)^ and Mask2[3-x and 3]) shr Shift2[3-x and 3] |
||
444 | else |
||
445 | Result := (PByte(Integer(FTopPBits)+FNextLine*y+x shr 2)^ and Mask2[x and 3]) shr Shift2[x and 3]; |
||
446 | end; |
||
447 | 4 : begin |
||
448 | if FPackedPixelOrder then |
||
449 | Result := (PByte(Integer(FTopPBits)+FNextLine*y+x shr 1)^ and Mask4[1-x and 1]) shr Shift4[1-x and 1] |
||
450 | else |
||
451 | Result := (PByte(Integer(FTopPBits)+FNextLine*y+x shr 1)^ and Mask4[x and 1]) shr Shift4[x and 1]; |
||
452 | end; |
||
453 | 8 : Result := PByte(Integer(FTopPBits)+FNextLine*y+x)^; |
||
454 | 16: Result := PWord(Integer(FTopPBits)+FNextLine*y+x*2)^; |
||
455 | 24: PByte3(@Result)^ := PByte3(Integer(FTopPBits)+FNextLine*y+x*3)^; |
||
456 | 32: Result := PDWORD(Integer(FTopPBits)+FNextLine*y+x*4)^; |
||
457 | end; |
||
458 | end; |
||
459 | end; |
||
460 | |||
461 | procedure TDXTextureImage.SetPixel(x, y: Integer; c: DWORD); |
||
462 | var |
||
463 | P: PByte; |
||
464 | begin |
||
465 | if (x>=0) and (x<FWidth) and (y>=0) and (y<FHeight) then |
||
466 | begin |
||
467 | case FBitCount of |
||
468 | 1 : begin |
||
469 | P := Pointer(Integer(FTopPBits)+FNextLine*y+x shr 3); |
||
470 | if FPackedPixelOrder then |
||
471 | P^ := (P^ and (not Mask1[7-x and 7])) or ((c and 1) shl Shift1[7-x and 7]) |
||
472 | else |
||
473 | P^ := (P^ and (not Mask1[x and 7])) or ((c and 1) shl Shift1[x and 7]); |
||
474 | end; |
||
475 | 2 : begin |
||
476 | P := Pointer(Integer(FTopPBits)+FNextLine*y+x shr 2); |
||
477 | if FPackedPixelOrder then |
||
478 | P^ := (P^ and (not Mask2[3-x and 3])) or ((c and 3) shl Shift2[3-x and 3]) |
||
479 | else |
||
480 | P^ := (P^ and (not Mask2[x and 3])) or ((c and 3) shl Shift2[x and 3]); |
||
481 | end; |
||
482 | 4 : begin |
||
483 | P := Pointer(Integer(FTopPBits)+FNextLine*y+x shr 1); |
||
484 | if FPackedPixelOrder then |
||
485 | P^ := (P^ and (not Mask4[1-x and 1])) or ((c and 7) shl Shift4[1-x and 1]) |
||
486 | else |
||
487 | P^ := (P^ and (not Mask4[x and 1])) or ((c and 7) shl Shift4[x and 1]); |
||
488 | end; |
||
489 | 8 : PByte(Integer(FTopPBits)+FNextLine*y+x)^ := c; |
||
490 | 16: PWord(Integer(FTopPBits)+FNextLine*y+x*2)^ := c; |
||
491 | 24: PByte3(Integer(FTopPBits)+FNextLine*y+x*3)^ := PByte3(@c)^; |
||
492 | 32: PDWORD(Integer(FTopPBits)+FNextLine*y+x*4)^ := c; |
||
493 | end; |
||
494 | end; |
||
495 | end; |
||
496 | |||
497 | procedure TDXTextureImage.LoadFromFile(const FileName: string); |
||
498 | var |
||
499 | Stream: TFileStream; |
||
500 | begin |
||
501 | Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); |
||
502 | try |
||
503 | LoadFromStream(Stream); |
||
504 | finally |
||
505 | Stream.Free; |
||
506 | end; |
||
507 | end; |
||
508 | |||
509 | procedure TDXTextureImage.LoadFromStream(Stream: TStream); |
||
510 | var |
||
511 | i, p: Integer; |
||
512 | begin |
||
513 | Clear; |
||
514 | |||
515 | p := Stream.Position; |
||
516 | for i:=0 to DXTextureImageLoadFuncList.Count-1 do |
||
517 | begin |
||
518 | Stream.Position := p; |
||
519 | try |
||
520 | TDXTextureImageLoadFunc(DXTextureImageLoadFuncList[i])(Stream, Self); |
||
521 | Exit; |
||
522 | except |
||
523 | Clear; |
||
524 | end; |
||
525 | end; |
||
526 | |||
527 | raise EDXTextureImageError.Create(SNotSupportGraphicFile); |
||
528 | end; |
||
529 | |||
530 | procedure TDXTextureImage.SaveToFile(const FileName: string); |
||
531 | var |
||
532 | Stream: TFileStream; |
||
533 | begin |
||
534 | Stream := TFileStream.Create(FileName, fmCreate); |
||
535 | try |
||
536 | SaveToStream(Stream); |
||
537 | finally |
||
538 | Stream.Free; |
||
539 | end; |
||
540 | end; |
||
541 | |||
542 | procedure DXTextureImage_SaveDXTextureImageFunc(Stream: TStream; Image: TDXTextureImage); forward; |
||
543 | |||
544 | procedure TDXTextureImage.SaveToStream(Stream: TStream); |
||
545 | begin |
||
546 | DXTextureImage_SaveDXTextureImageFunc(Stream, Self); |
||
547 | end; |
||
548 | |||
549 | { DXTextureImage_LoadDXTextureImageFunc } |
||
550 | |||
551 | const |
||
552 | DXTextureImageFile_Type = 'dxt:'; |
||
553 | DXTextureImageFile_Version = $100; |
||
554 | |||
555 | DXTextureImageCompress_None = 0; |
||
556 | |||
557 | DXTextureImageFileCategoryType_Image = $100; |
||
558 | |||
559 | DXTextureImageFileBlockID_EndFile = 0; |
||
560 | DXTextureImageFileBlockID_EndGroup = 1; |
||
561 | DXTextureImageFileBlockID_StartGroup = 2; |
||
562 | DXTextureImageFileBlockID_Image_Format = DXTextureImageFileCategoryType_Image + 1; |
||
563 | DXTextureImageFileBlockID_Image_PixelData = DXTextureImageFileCategoryType_Image + 2; |
||
564 | DXTextureImageFileBlockID_Image_GroupInfo = DXTextureImageFileCategoryType_Image + 3; |
||
565 | DXTextureImageFileBlockID_Image_Name = DXTextureImageFileCategoryType_Image + 4; |
||
566 | DXTextureImageFileBlockID_Image_TransparentColor = DXTextureImageFileCategoryType_Image + 5; |
||
567 | |||
568 | type |
||
569 | TDXTextureImageFileHeader = packed record |
||
570 | FileType: array[0..4] of Char; |
||
571 | ver: DWORD; |
||
572 | end; |
||
573 | |||
574 | TDXTextureImageFileBlockHeader = packed record |
||
575 | ID: DWORD; |
||
576 | Size: Integer; |
||
577 | end; |
||
578 | |||
579 | TDXTextureImageFileBlockHeader_StartGroup = packed record |
||
580 | CategoryType: DWORD; |
||
581 | end; |
||
582 | |||
583 | TDXTextureImageHeader_Image_Format = packed record |
||
584 | ImageType: TDXTextureImageType; |
||
585 | Width: DWORD; |
||
586 | Height: DWORD; |
||
587 | BitCount: DWORD; |
||
588 | WidthBytes: DWORD; |
||
589 | end; |
||
590 | |||
591 | TDXTextureImageHeader_Image_Format_Index = packed record |
||
592 | idx_index_Mask: DWORD; |
||
593 | idx_alpha_Mask: DWORD; |
||
594 | idx_palette: array[0..255] of TPaletteEntry; |
||
595 | end; |
||
596 | |||
597 | TDXTextureImageHeader_Image_Format_RGB = packed record |
||
598 | rgb_red_Mask: DWORD; |
||
599 | rgb_green_Mask: DWORD; |
||
600 | rgb_blue_Mask: DWORD; |
||
601 | rgb_alpha_Mask: DWORD; |
||
602 | end; |
||
603 | |||
604 | TDXTextureImageHeader_Image_GroupInfo = packed record |
||
605 | ImageGroupType: DWORD; |
||
606 | ImageID: DWORD; |
||
607 | end; |
||
608 | |||
609 | TDXTextureImageHeader_Image_TransparentColor = packed record |
||
610 | Transparent: Boolean; |
||
611 | TransparentColor: DWORD; |
||
612 | end; |
||
613 | |||
614 | procedure DXTextureImage_LoadDXTextureImageFunc(Stream: TStream; Image: TDXTextureImage); |
||
615 | |||
616 | procedure ReadGroup_Image(Image: TDXTextureImage); |
||
617 | var |
||
618 | i: Integer; |
||
619 | BlockHeader: TDXTextureImageFileBlockHeader; |
||
620 | NextPos: Integer; |
||
621 | SubImage: TDXTextureImage; |
||
622 | Header_StartGroup: TDXTextureImageFileBlockHeader_StartGroup; |
||
623 | Header_Image_Format: TDXTextureImageHeader_Image_Format; |
||
624 | Header_Image_Format_Index: TDXTextureImageHeader_Image_Format_Index; |
||
625 | Header_Image_Format_RGB: TDXTextureImageHeader_Image_Format_RGB; |
||
626 | Header_Image_GroupInfo: TDXTextureImageHeader_Image_GroupInfo; |
||
627 | Header_Image_TransparentColor: TDXTextureImageHeader_Image_TransparentColor; |
||
628 | ImageName: string; |
||
629 | begin |
||
630 | while True do |
||
631 | begin |
||
632 | Stream.ReadBuffer(BlockHeader, SizeOf(BlockHeader)); |
||
633 | NextPos := Stream.Position + BlockHeader.Size; |
||
634 | |||
635 | case BlockHeader.ID of |
||
636 | DXTextureImageFileBlockID_EndGroup: |
||
637 | begin |
||
638 | { End of group } |
||
639 | Break; |
||
640 | end; |
||
641 | DXTextureImageFileBlockID_StartGroup: |
||
642 | begin |
||
643 | { Beginning of group } |
||
644 | Stream.ReadBuffer(Header_StartGroup, SizeOf(Header_StartGroup)); |
||
645 | case Header_StartGroup.CategoryType of |
||
646 | DXTextureImageFileCategoryType_Image: |
||
647 | begin |
||
648 | { Image group } |
||
649 | SubImage := TDXTextureImage.CreateSub(Image); |
||
650 | try |
||
651 | ReadGroup_Image(SubImage); |
||
652 | except |
||
653 | SubImage.Free; |
||
654 | raise; |
||
655 | end; |
||
656 | end; |
||
657 | end; |
||
658 | end; |
||
659 | DXTextureImageFileBlockID_Image_Format: |
||
660 | begin |
||
661 | { Image information reading (size etc.) } |
||
662 | Stream.ReadBuffer(Header_Image_Format, SizeOf(Header_Image_Format)); |
||
663 | |||
664 | if (Header_Image_Format.ImageType<>DXTextureImageType_PaletteIndexedColor) and |
||
665 | (Header_Image_Format.ImageType<>DXTextureImageType_RGBColor) then |
||
666 | raise EDXTextureImageError.Create(SInvalidDXTFile); |
||
667 | |||
668 | Image.SetSize(Header_Image_Format.ImageType, Header_Image_Format.Width, Header_Image_Format.Height, |
||
669 | Header_Image_Format.BitCount, Header_Image_Format.Widthbytes); |
||
670 | |||
671 | if Header_Image_Format.ImageType=DXTextureImageType_PaletteIndexedColor then |
||
672 | begin |
||
673 | { INDEX IMAGE } |
||
674 | Stream.ReadBuffer(Header_Image_Format_Index, SizeOf(Header_Image_Format_Index)); |
||
675 | |||
676 | Image.idx_index := dxtMakeChannel(Header_Image_Format_Index.idx_index_Mask, True); |
||
677 | Image.idx_alpha := dxtMakeChannel(Header_Image_Format_Index.idx_alpha_Mask, False); |
||
678 | |||
679 | for i:=0 to 255 do |
||
680 | Image.idx_palette[i] := Header_Image_Format_Index.idx_palette[i]; |
||
681 | end else if Header_Image_Format.ImageType=DXTextureImageType_RGBColor then |
||
682 | begin |
||
683 | { RGB IMAGE } |
||
684 | Stream.ReadBuffer(Header_Image_Format_RGB, SizeOf(Header_Image_Format_RGB)); |
||
685 | |||
686 | Image.rgb_red := dxtMakeChannel(Header_Image_Format_RGB.rgb_red_Mask, False); |
||
687 | Image.rgb_green := dxtMakeChannel(Header_Image_Format_RGB.rgb_green_Mask, False); |
||
688 | Image.rgb_blue := dxtMakeChannel(Header_Image_Format_RGB.rgb_blue_Mask, False); |
||
689 | Image.rgb_alpha := dxtMakeChannel(Header_Image_Format_RGB.rgb_alpha_Mask, False); |
||
690 | end; |
||
691 | end; |
||
692 | DXTextureImageFileBlockID_Image_Name: |
||
693 | begin |
||
694 | { Name reading } |
||
695 | SetLength(ImageName, BlockHeader.Size); |
||
696 | Stream.ReadBuffer(ImageName[1], BlockHeader.Size); |
||
697 | |||
698 | Image.ImageName := ImageName; |
||
699 | end; |
||
700 | DXTextureImageFileBlockID_Image_GroupInfo: |
||
701 | begin |
||
702 | { Image group information reading } |
||
703 | Stream.ReadBuffer(Header_Image_GroupInfo, SizeOf(Header_Image_GroupInfo)); |
||
704 | |||
705 | Image.ImageGroupType := Header_Image_GroupInfo.ImageGroupType; |
||
706 | Image.ImageID := Header_Image_GroupInfo.ImageID; |
||
707 | end; |
||
708 | DXTextureImageFileBlockID_Image_TransparentColor: |
||
709 | begin |
||
710 | { Transparent color information reading } |
||
711 | Stream.ReadBuffer(Header_Image_TransparentColor, SizeOf(Header_Image_TransparentColor)); |
||
712 | |||
713 | Image.Transparent := Header_Image_TransparentColor.Transparent; |
||
714 | Image.TransparentColor := Header_Image_TransparentColor.TransparentColor; |
||
715 | end; |
||
716 | DXTextureImageFileBlockID_Image_PixelData: |
||
717 | begin |
||
718 | { Pixel data reading } |
||
719 | for i:=0 to Image.Height-1 do |
||
720 | Stream.ReadBuffer(Image.ScanLine[i]^, Header_Image_Format.Widthbytes); |
||
721 | end; |
||
722 | end; |
||
723 | |||
724 | Stream.Seek(NextPos, soFromBeginning); |
||
725 | end; |
||
726 | end; |
||
727 | |||
728 | var |
||
729 | FileHeader: TDXTextureImageFileHeader; |
||
730 | BlockHeader: TDXTextureImageFileBlockHeader; |
||
731 | Header_StartGroup: TDXTextureImageFileBlockHeader_StartGroup; |
||
732 | NextPos: Integer; |
||
733 | begin |
||
734 | { File header reading } |
||
735 | Stream.ReadBuffer(FileHeader, SizeOf(FileHeader)); |
||
736 | |||
737 | if FileHeader.FileType<>DXTextureImageFile_Type then |
||
738 | raise EDXTextureImageError.Create(SInvalidDXTFile); |
||
739 | if FileHeader.ver<>DXTextureImageFile_Version then |
||
740 | raise EDXTextureImageError.Create(SInvalidDXTFile); |
||
741 | |||
742 | while True do |
||
743 | begin |
||
744 | Stream.ReadBuffer(BlockHeader, SizeOf(BlockHeader)); |
||
745 | NextPos := Stream.Position + BlockHeader.Size; |
||
746 | |||
747 | case BlockHeader.ID of |
||
748 | DXTextureImageFileBlockID_EndFile: |
||
749 | begin |
||
750 | { End of file } |
||
751 | Break; |
||
752 | end; |
||
753 | DXTextureImageFileBlockID_StartGroup: |
||
754 | begin |
||
755 | { Beginning of group } |
||
756 | Stream.ReadBuffer(Header_StartGroup, SizeOf(Header_StartGroup)); |
||
757 | case Header_StartGroup.CategoryType of |
||
758 | DXTextureImageFileCategoryType_Image: ReadGroup_Image(Image); |
||
759 | end; |
||
760 | end; |
||
761 | end; |
||
762 | |||
763 | Stream.Seek(NextPos, soFromBeginning); |
||
764 | end; |
||
765 | end; |
||
766 | |||
767 | type |
||
768 | PDXTextureImageFileBlockHeaderWriter_BlockInfo = ^TDXTextureImageFileBlockHeaderWriter_BlockInfo; |
||
769 | TDXTextureImageFileBlockHeaderWriter_BlockInfo = record |
||
770 | BlockID: DWORD; |
||
771 | StreamPos: Integer; |
||
772 | end; |
||
773 | |||
774 | TDXTextureImageFileBlockHeaderWriter = class |
||
775 | private |
||
776 | FStream: TStream; |
||
777 | FList: TList; |
||
778 | public |
||
779 | constructor Create(Stream: TStream); |
||
780 | destructor Destroy; override; |
||
781 | procedure StartBlock(BlockID: DWORD); |
||
782 | procedure EndBlock; |
||
783 | procedure WriteBlock(BlockID: DWORD); |
||
784 | procedure StartGroup(CategoryType: DWORD); |
||
785 | procedure EndGroup; |
||
786 | end; |
||
787 | |||
788 | constructor TDXTextureImageFileBlockHeaderWriter.Create(Stream: TStream); |
||
789 | begin |
||
790 | inherited Create; |
||
791 | FStream := Stream; |
||
792 | FList := TList.Create; |
||
793 | end; |
||
794 | |||
795 | destructor TDXTextureImageFileBlockHeaderWriter.Destroy; |
||
796 | var |
||
797 | i: Integer; |
||
798 | begin |
||
799 | for i:=0 to FList.Count-1 do |
||
800 | Dispose(PDXTextureImageFileBlockHeaderWriter_BlockInfo(FList[i])); |
||
801 | FList.Free; |
||
802 | inherited Destroy; |
||
803 | end; |
||
804 | |||
805 | procedure TDXTextureImageFileBlockHeaderWriter.StartBlock(BlockID: DWORD); |
||
806 | var |
||
807 | BlockInfo: PDXTextureImageFileBlockHeaderWriter_BlockInfo; |
||
808 | BlockHeader: TDXTextureImageFileBlockHeader; |
||
809 | begin |
||
810 | New(BlockInfo); |
||
811 | BlockInfo.BlockID := BlockID; |
||
812 | BlockInfo.StreamPos := FStream.Position; |
||
813 | FList.Add(BlockInfo); |
||
814 | |||
815 | BlockHeader.ID := BlockID; |
||
816 | BlockHeader.Size := 0; |
||
817 | FStream.WriteBuffer(BlockHeader, SizeOf(BlockHeader)); |
||
818 | end; |
||
819 | |||
820 | procedure TDXTextureImageFileBlockHeaderWriter.EndBlock; |
||
821 | var |
||
822 | BlockHeader: TDXTextureImageFileBlockHeader; |
||
823 | BlockInfo: PDXTextureImageFileBlockHeaderWriter_BlockInfo; |
||
824 | CurStreamPos: Integer; |
||
825 | begin |
||
826 | CurStreamPos := FStream.Position; |
||
827 | try |
||
828 | BlockInfo := FList[FList.Count-1]; |
||
829 | |||
830 | FStream.Position := BlockInfo.StreamPos; |
||
831 | BlockHeader.ID := BlockInfo.BlockID; |
||
832 | BlockHeader.Size := CurStreamPos-(BlockInfo.StreamPos+SizeOf(TDXTextureImageFileBlockHeader)); |
||
833 | FStream.WriteBuffer(BlockHeader, SizeOf(BlockHeader)); |
||
834 | finally |
||
835 | FStream.Position := CurStreamPos; |
||
836 | |||
837 | Dispose(FList[FList.Count-1]); |
||
838 | FList.Count := FList.Count-1; |
||
839 | end; |
||
840 | end; |
||
841 | |||
842 | procedure TDXTextureImageFileBlockHeaderWriter.WriteBlock(BlockID: DWORD); |
||
843 | var |
||
844 | BlockHeader: TDXTextureImageFileBlockHeader; |
||
845 | begin |
||
846 | BlockHeader.ID := BlockID; |
||
847 | BlockHeader.Size := 0; |
||
848 | FStream.WriteBuffer(BlockHeader, SizeOf(BlockHeader)); |
||
849 | end; |
||
850 | |||
851 | procedure TDXTextureImageFileBlockHeaderWriter.StartGroup(CategoryType: DWORD); |
||
852 | var |
||
853 | Header_StartGroup: TDXTextureImageFileBlockHeader_StartGroup; |
||
854 | begin |
||
855 | StartBlock(DXTextureImageFileBlockID_StartGroup); |
||
856 | |||
857 | Header_StartGroup.CategoryType := CategoryType; |
||
858 | FStream.WriteBuffer(Header_StartGroup, SizeOf(Header_StartGroup)); |
||
859 | end; |
||
860 | |||
861 | procedure TDXTextureImageFileBlockHeaderWriter.EndGroup; |
||
862 | begin |
||
863 | WriteBlock(DXTextureImageFileBlockID_EndGroup); |
||
864 | EndBlock; |
||
865 | end; |
||
866 | |||
867 | procedure DXTextureImage_SaveDXTextureImageFunc(Stream: TStream; Image: TDXTextureImage); |
||
868 | var |
||
869 | BlockHeaderWriter: TDXTextureImageFileBlockHeaderWriter; |
||
870 | |||
871 | function CalcProgressCount(Image: TDXTextureImage): Integer; |
||
872 | var |
||
873 | i: Integer; |
||
874 | begin |
||
875 | Result := Image.WidthBytes*Image.Height; |
||
876 | for i:=0 to Image.SubImageCount-1 do |
||
877 | Inc(Result, CalcProgressCount(Image.SubImages[i])); |
||
878 | end; |
||
879 | |||
880 | procedure WriteGroup_Image(Image: TDXTextureImage); |
||
881 | var |
||
882 | i: Integer; |
||
883 | Header_Image_Format: TDXTextureImageHeader_Image_Format; |
||
884 | Header_Image_Format_Index: TDXTextureImageHeader_Image_Format_Index; |
||
885 | Header_Image_Format_RGB: TDXTextureImageHeader_Image_Format_RGB; |
||
886 | Header_Image_GroupInfo: TDXTextureImageHeader_Image_GroupInfo; |
||
887 | Header_Image_TransparentColor: TDXTextureImageHeader_Image_TransparentColor; |
||
888 | begin |
||
889 | BlockHeaderWriter.StartGroup(DXTextureImageFileCategoryType_Image); |
||
890 | try |
||
891 | { Image format writing } |
||
892 | if Image.Size>0 then |
||
893 | begin |
||
894 | Header_Image_Format.ImageType := Image.ImageType; |
||
895 | Header_Image_Format.Width := Image.Width; |
||
896 | Header_Image_Format.Height := Image.Height; |
||
897 | Header_Image_Format.BitCount := Image.BitCount; |
||
898 | Header_Image_Format.WidthBytes := Image.WidthBytes; |
||
899 | |||
900 | BlockHeaderWriter.StartBlock(DXTextureImageFileBlockID_Image_Format); |
||
901 | try |
||
902 | Stream.WriteBuffer(Header_Image_Format, SizeOf(Header_Image_Format)); |
||
903 | |||
904 | case Image.ImageType of |
||
905 | DXTextureImageType_PaletteIndexedColor: |
||
906 | begin |
||
907 | { INDEX IMAGE } |
||
908 | Header_Image_Format_Index.idx_index_Mask := Image.idx_index.Mask; |
||
909 | Header_Image_Format_Index.idx_alpha_Mask := Image.idx_alpha.Mask; |
||
910 | for i:=0 to 255 do |
||
911 | Header_Image_Format_Index.idx_palette[i] := Image.idx_palette[i]; |
||
912 | |||
913 | Stream.WriteBuffer(Header_Image_Format_Index, SizeOf(Header_Image_Format_Index)); |
||
914 | end; |
||
915 | DXTextureImageType_RGBColor: |
||
916 | begin |
||
917 | { RGB IMAGE } |
||
918 | Header_Image_Format_RGB.rgb_red_Mask := Image.rgb_red.Mask; |
||
919 | Header_Image_Format_RGB.rgb_green_Mask := Image.rgb_green.Mask; |
||
920 | Header_Image_Format_RGB.rgb_blue_Mask := Image.rgb_blue.Mask; |
||
921 | Header_Image_Format_RGB.rgb_alpha_Mask := Image.rgb_alpha.Mask; |
||
922 | |||
923 | Stream.WriteBuffer(Header_Image_Format_RGB, SizeOf(Header_Image_Format_RGB)); |
||
924 | end; |
||
925 | end; |
||
926 | finally |
||
927 | BlockHeaderWriter.EndBlock; |
||
928 | end; |
||
929 | end; |
||
930 | |||
931 | { Image group information writing } |
||
932 | BlockHeaderWriter.StartBlock(DXTextureImageFileBlockID_Image_GroupInfo); |
||
933 | try |
||
934 | Header_Image_GroupInfo.ImageGroupType := Image.ImageGroupType; |
||
935 | Header_Image_GroupInfo.ImageID := Image.ImageID; |
||
936 | |||
937 | Stream.WriteBuffer(Header_Image_GroupInfo, SizeOf(Header_Image_GroupInfo)); |
||
938 | finally |
||
939 | BlockHeaderWriter.EndBlock; |
||
940 | end; |
||
941 | |||
942 | { Name writing } |
||
943 | BlockHeaderWriter.StartBlock(DXTextureImageFileBlockID_Image_Name); |
||
944 | try |
||
945 | Stream.WriteBuffer(Image.ImageName[1], Length(Image.ImageName)); |
||
946 | finally |
||
947 | BlockHeaderWriter.EndBlock; |
||
948 | end; |
||
949 | |||
950 | { Transparent color writing } |
||
951 | BlockHeaderWriter.StartBlock(DXTextureImageFileBlockID_Image_TransparentColor); |
||
952 | try |
||
953 | Header_Image_TransparentColor.Transparent := Image.Transparent; |
||
954 | Header_Image_TransparentColor.TransparentColor := Image.TransparentColor; |
||
955 | |||
956 | Stream.WriteBuffer(Header_Image_TransparentColor, SizeOf(Header_Image_TransparentColor)); |
||
957 | finally |
||
958 | BlockHeaderWriter.EndBlock; |
||
959 | end; |
||
960 | |||
961 | { Pixel data writing } |
||
962 | if Image.Size>0 then |
||
963 | begin |
||
964 | BlockHeaderWriter.StartBlock(DXTextureImageFileBlockID_Image_PixelData); |
||
965 | try |
||
966 | for i:=0 to Image.Height-1 do |
||
967 | Stream.WriteBuffer(Image.ScanLine[i]^, Image.Widthbytes); |
||
968 | finally |
||
969 | BlockHeaderWriter.EndBlock; |
||
970 | end; |
||
971 | end; |
||
972 | |||
973 | { Sub-image writing } |
||
974 | for i:=0 to Image.SubImageCount-1 do |
||
975 | WriteGroup_Image(Image.SubImages[i]); |
||
976 | finally |
||
977 | BlockHeaderWriter.EndGroup; |
||
978 | end; |
||
979 | end; |
||
980 | |||
981 | var |
||
982 | FileHeader: TDXTextureImageFileHeader; |
||
983 | begin |
||
984 | { File header writing } |
||
985 | FileHeader.FileType := DXTextureImageFile_Type; |
||
986 | FileHeader.ver := DXTextureImageFile_Version; |
||
987 | Stream.WriteBuffer(FileHeader, SizeOf(FileHeader)); |
||
988 | |||
989 | { Image writing } |
||
990 | BlockHeaderWriter := TDXTextureImageFileBlockHeaderWriter.Create(Stream); |
||
991 | try |
||
992 | { Image writing } |
||
993 | WriteGroup_Image(Image); |
||
994 | |||
995 | { End of file } |
||
996 | BlockHeaderWriter.WriteBlock(DXTextureImageFileBlockID_EndFile); |
||
997 | finally |
||
998 | BlockHeaderWriter.Free; |
||
999 | end; |
||
1000 | end; |
||
1001 | |||
1002 | { DXTextureImage_LoadBitmapFunc } |
||
1003 | |||
1004 | procedure DXTextureImage_LoadBitmapFunc(Stream: TStream; Image: TDXTextureImage); |
||
1005 | type |
||
1006 | TDIBPixelFormat = packed record |
||
1007 | RBitMask, GBitMask, BBitMask: DWORD; |
||
1008 | end; |
||
1009 | var |
||
1010 | TopDown: Boolean; |
||
1011 | BF: TBitmapFileHeader; |
||
1012 | BI: TBitmapInfoHeader; |
||
1013 | |||
1014 | procedure DecodeRGB; |
||
1015 | var |
||
1016 | y: Integer; |
||
1017 | begin |
||
1018 | for y:=0 to Image.Height-1 do |
||
1019 | begin |
||
1020 | if TopDown then |
||
1021 | Stream.ReadBuffer(Image.ScanLine[y]^, Image.WidthBytes) |
||
1022 | else |
||
1023 | Stream.ReadBuffer(Image.ScanLine[Image.Height-y-1]^, Image.WidthBytes); |
||
1024 | end; |
||
1025 | end; |
||
1026 | |||
1027 | procedure DecodeRLE4; |
||
1028 | var |
||
1029 | SrcDataP: Pointer; |
||
1030 | B1, B2, C: Byte; |
||
1031 | Dest, Src, P: PByte; |
||
1032 | X, Y, i: Integer; |
||
1033 | begin |
||
1034 | GetMem(SrcDataP, BI.biSizeImage); |
||
1035 | try |
||
1036 | Stream.ReadBuffer(SrcDataP^, BI.biSizeImage); |
||
1037 | |||
1038 | Dest := Image.TopPBits; |
||
1039 | Src := SrcDataP; |
||
1040 | X := 0; |
||
1041 | Y := 0; |
||
1042 | |||
1043 | while True do |
||
1044 | begin |
||
1045 | B1 := Src^; Inc(Src); |
||
1046 | B2 := Src^; Inc(Src); |
||
1047 | |||
1048 | if B1=0 then |
||
1049 | begin |
||
1050 | case B2 of |
||
1051 | 0: begin { End of line } |
||
1052 | X := 0; Inc(Y); |
||
1053 | Dest := Image.ScanLine[Y]; |
||
1054 | end; |
||
1055 | 1: Break; { End of bitmap } |
||
1056 | 2: begin { Difference of coordinates } |
||
1057 | Inc(X, B1); Inc(Y, B2); Inc(Src, 2); |
||
1058 | Dest := Image.ScanLine[Y]; |
||
1059 | end; |
||
1060 | else |
||
1061 | { Absolute mode } |
||
1062 | C := 0; |
||
1063 | for i:=0 to B2-1 do |
||
1064 | begin |
||
1065 | if i and 1=0 then |
||
1066 | begin |
||
1067 | C := Src^; Inc(Src); |
||
1068 | end else |
||
1069 | begin |
||
1070 | C := C shl 4; |
||
1071 | end; |
||
1072 | |||
1073 | P := Pointer(Integer(Dest)+X shr 1); |
||
1074 | if X and 1=0 then |
||
1075 | P^ := (P^ and $0F) or (C and $F0) |
||
1076 | else |
||
1077 | P^ := (P^ and $F0) or ((C and $F0) shr 4); |
||
1078 | |||
1079 | Inc(X); |
||
1080 | end; |
||
1081 | end; |
||
1082 | end else |
||
1083 | begin |
||
1084 | { Encoding mode } |
||
1085 | for i:=0 to B1-1 do |
||
1086 | begin |
||
1087 | P := Pointer(Integer(Dest)+X shr 1); |
||
1088 | if X and 1=0 then |
||
1089 | P^ := (P^ and $0F) or (B2 and $F0) |
||
1090 | else |
||
1091 | P^ := (P^ and $F0) or ((B2 and $F0) shr 4); |
||
1092 | |||
1093 | Inc(X); |
||
1094 | |||
1095 | // Swap nibble |
||
1096 | B2 := (B2 shr 4) or (B2 shl 4); |
||
1097 | end; |
||
1098 | end; |
||
1099 | |||
1100 | { Word arrangement } |
||
1101 | Inc(Src, Longint(Src) and 1); |
||
1102 | end; |
||
1103 | finally |
||
1104 | FreeMem(SrcDataP); |
||
1105 | end; |
||
1106 | end; |
||
1107 | |||
1108 | procedure DecodeRLE8; |
||
1109 | var |
||
1110 | SrcDataP: Pointer; |
||
1111 | B1, B2: Byte; |
||
1112 | Dest, Src: PByte; |
||
1113 | X, Y: Integer; |
||
1114 | begin |
||
1115 | GetMem(SrcDataP, BI.biSizeImage); |
||
1116 | try |
||
1117 | Stream.ReadBuffer(SrcDataP^, BI.biSizeImage); |
||
1118 | |||
1119 | Dest := Image.TopPBits; |
||
1120 | Src := SrcDataP; |
||
1121 | X := 0; |
||
1122 | Y := 0; |
||
1123 | |||
1124 | while True do |
||
1125 | begin |
||
1126 | B1 := Src^; Inc(Src); |
||
1127 | B2 := Src^; Inc(Src); |
||
1128 | |||
1129 | if B1=0 then |
||
1130 | begin |
||
1131 | case B2 of |
||
1132 | 0: begin { End of line } |
||
1133 | X := 0; Inc(Y); |
||
1134 | Dest := Pointer(Longint(Image.TopPBits)+Y*Image.NextLine+X); |
||
1135 | end; |
||
1136 | 1: Break; { End of bitmap } |
||
1137 | 2: begin { Difference of coordinates } |
||
1138 | Inc(X, B1); Inc(Y, B2); Inc(Src, 2); |
||
1139 | Dest := Pointer(Longint(Image.TopPBits)+Y*Image.NextLine+X); |
||
1140 | end; |
||
1141 | else |
||
1142 | { Absolute mode } |
||
1143 | Move(Src^, Dest^, B2); Inc(Dest, B2); Inc(Src, B2); |
||
1144 | end; |
||
1145 | end else |
||
1146 | begin |
||
1147 | { Encoding mode } |
||
1148 | FillChar(Dest^, B1, B2); Inc(Dest, B1); |
||
1149 | end; |
||
1150 | |||
1151 | { Word arrangement } |
||
1152 | Inc(Src, Longint(Src) and 1); |
||
1153 | end; |
||
1154 | finally |
||
1155 | FreeMem(SrcDataP); |
||
1156 | end; |
||
1157 | end; |
||
1158 | |||
1159 | var |
||
1160 | BC: TBitmapCoreHeader; |
||
1161 | RGBTriples: array[0..255] of TRGBTriple; |
||
1162 | RGBQuads: array[0..255] of TRGBQuad; |
||
1163 | i, PalCount, j: Integer; |
||
1164 | OS2: Boolean; |
||
1165 | PixelFormat: TDIBPixelFormat; |
||
1166 | begin |
||
1167 | { File header reading } |
||
1168 | i := Stream.Read(BF, SizeOf(TBitmapFileHeader)); |
||
1169 | if i=0 then Exit; |
||
1170 | if i<>SizeOf(TBitmapFileHeader) then |
||
1171 | raise EDXTextureImageError.Create(SInvalidDIB); |
||
1172 | |||
1173 | { Is the head 'BM'? } |
||
1174 | if BF.bfType<>Ord('B') + Ord('M')*$100 then |
||
1175 | raise EDXTextureImageError.Create(SInvalidDIB); |
||
1176 | |||
1177 | { Reading of size of header } |
||
1178 | i := Stream.Read(BI.biSize, 4); |
||
1179 | if i<>4 then |
||
1180 | raise EDXTextureImageError.Create(SInvalidDIB); |
||
1181 | |||
1182 | { Kind check of DIB } |
||
1183 | OS2 := False; |
||
1184 | |||
1185 | case BI.biSize of |
||
1186 | SizeOf(TBitmapCoreHeader): |
||
1187 | begin |
||
1188 | { OS/2 type } |
||
1189 | Stream.ReadBuffer(Pointer(Integer(@BC)+4)^, SizeOf(TBitmapCoreHeader)-4); |
||
1190 | |||
1191 | FilLChar(BI, SizeOf(BI), 0); |
||
1192 | with BI do |
||
1193 | begin |
||
1194 | biClrUsed := 0; |
||
1195 | biCompression := BI_RGB; |
||
1196 | biBitCount := BC.bcBitCount; |
||
1197 | biHeight := BC.bcHeight; |
||
1198 | biWidth := BC.bcWidth; |
||
1199 | end; |
||
1200 | |||
1201 | OS2 := True; |
||
1202 | end; |
||
1203 | SizeOf(TBitmapInfoHeader): |
||
1204 | begin |
||
1205 | { Windows type } |
||
1206 | Stream.ReadBuffer(Pointer(Integer(@BI)+4)^, SizeOf(TBitmapInfoHeader)-4); |
||
1207 | end; |
||
1208 | else |
||
1209 | raise EDXTextureImageError.Create(SInvalidDIB); |
||
1210 | end; |
||
1211 | |||
1212 | { Bit mask reading } |
||
1213 | if BI.biCompression = BI_BITFIELDS then |
||
1214 | begin |
||
1215 | Stream.ReadBuffer(PixelFormat, SizeOf(PixelFormat)); |
||
1216 | end else |
||
1217 | begin |
||
1218 | if BI.biBitCount=16 then |
||
1219 | begin |
||
1220 | PixelFormat.RBitMask := $7C00; |
||
1221 | PixelFormat.GBitMask := $03E0; |
||
1222 | PixelFormat.BBitMask := $001F; |
||
1223 | end else if (BI.biBitCount=24) or (BI.biBitCount=32) then |
||
1224 | begin |
||
1225 | PixelFormat.RBitMask := $00FF0000; |
||
1226 | PixelFormat.GBitMask := $0300FF00; |
||
1227 | PixelFormat.BBitMask := $000000FF; |
||
1228 | end; |
||
1229 | end; |
||
1230 | |||
1231 | { DIB making } |
||
1232 | if BI.biHeight<0 then |
||
1233 | begin |
||
1234 | BI.biHeight := -BI.biHeight; |
||
1235 | TopDown := True; |
||
1236 | end else |
||
1237 | TopDown := False; |
||
1238 | |||
1239 | if BI.biBitCount in [1, 4, 8] then |
||
1240 | begin |
||
1241 | Image.SetSize(DXTextureImageType_PaletteIndexedColor, BI.biWidth, BI.biHeight, BI.biBitCount, |
||
1242 | (((BI.biWidth*BI.biBitCount)+31) div 32)*4); |
||
1243 | |||
1244 | Image.idx_index := dxtMakeChannel(1 shl BI.biBitCount-1, True); |
||
1245 | Image.PackedPixelOrder := True; |
||
1246 | end else |
||
1247 | begin |
||
1248 | Image.SetSize(DXTextureImageType_RGBColor, BI.biWidth, BI.biHeight, BI.biBitCount, |
||
1249 | (((BI.biWidth*BI.biBitCount)+31) div 32)*4); |
||
1250 | |||
1251 | Image.rgb_red := dxtMakeChannel(PixelFormat.RBitMask, False); |
||
1252 | Image.rgb_green := dxtMakeChannel(PixelFormat.GBitMask, False); |
||
1253 | Image.rgb_blue := dxtMakeChannel(PixelFormat.BBitMask, False); |
||
1254 | |||
1255 | j := Image.rgb_red.BitCount+Image.rgb_green.BitCount+Image.rgb_blue.BitCount; |
||
1256 | if j<BI.biBitCount then |
||
1257 | Image.rgb_alpha := dxtMakeChannel((1 shl (BI.biBitCount-j)-1) shl j, False); |
||
1258 | |||
1259 | Image.PackedPixelOrder := False; |
||
1260 | end; |
||
1261 | |||
1262 | { palette reading } |
||
1263 | PalCount := BI.biClrUsed; |
||
1264 | if (PalCount=0) and (BI.biBitCount<=8) then |
||
1265 | PalCount := 1 shl BI.biBitCount; |
||
1266 | if PalCount>256 then PalCount := 256; |
||
1267 | |||
1268 | if OS2 then |
||
1269 | begin |
||
1270 | { OS/2 type } |
||
1271 | Stream.ReadBuffer(RGBTriples, SizeOf(TRGBTriple)*PalCount); |
||
1272 | for i:=0 to PalCount-1 do |
||
1273 | begin |
||
1274 | Image.idx_palette[i].peRed := RGBTriples[i].rgbtRed; |
||
1275 | Image.idx_palette[i].peGreen := RGBTriples[i].rgbtGreen; |
||
1276 | Image.idx_palette[i].peBlue := RGBTriples[i].rgbtBlue; |
||
1277 | end; |
||
1278 | end else |
||
1279 | begin |
||
1280 | { Windows type } |
||
1281 | Stream.ReadBuffer(RGBQuads, SizeOf(TRGBQuad)*PalCount); |
||
1282 | for i:=0 to PalCount-1 do |
||
1283 | begin |
||
1284 | Image.idx_palette[i].peRed := RGBQuads[i].rgbRed; |
||
1285 | Image.idx_palette[i].peGreen := RGBQuads[i].rgbGreen; |
||
1286 | Image.idx_palette[i].peBlue := RGBQuads[i].rgbBlue; |
||
1287 | end; |
||
1288 | end; |
||
1289 | |||
1290 | { Pixel data reading } |
||
1291 | case BI.biCompression of |
||
1292 | BI_RGB : DecodeRGB; |
||
1293 | BI_BITFIELDS: DecodeRGB; |
||
1294 | BI_RLE4 : DecodeRLE4; |
||
1295 | BI_RLE8 : DecodeRLE8; |
||
1296 | else |
||
1297 | raise EDXTextureImageError.Create(SInvalidDIB); |
||
1298 | end; |
||
1299 | end; |
||
1300 | |||
1301 | initialization |
||
1302 | finalization |
||
1303 | _DXTextureImageLoadFuncList.Free; |
||
1304 | end. |