source: oup/current/Global/OniImgClass.pas@ 193

Last change on this file since 193 was 193, checked in by alloc, 18 years ago
File size: 15.2 KB
RevLine 
[97]1unit OniImgClass;
2
3interface
4
[181]5uses Math, Dialogs, Types, SysUtils, Classes, Data, ConnectionManager, TypeDefs,
[192]6 Imaging, ImagingTypes, Graphics;
[97]7
8
9type
10 TOniImage = class
11 private
[192]12 FImages: TDynImageDataArray;
13 function GetImage(MipGen: Integer): TImageData;
14 function GetWidth(MipGen: Integer): Integer;
15 function GetHeight(MipGen: Integer): Integer;
16 function GetImageFormat: TImageFormat;
17 procedure SetImageFormat(Format: TImageFormat);
18 function GetHasMipMaps: Boolean;
[97]19 protected
20 public
[192]21 property Images: TDynImageDataArray read FImages;
22 property Image[MipGen: Integer]: TImageData read GetImage;
23 property Width[MipGen: Integer]: Integer read GetWidth;
24 property Height[MipGen: Integer]: Integer read GetHeight;
25 property Format: TImageFormat read GetImageFormat write SetImageFormat;
26 property HasMipMaps: Boolean read GetHasMipMaps;
[97]27
28 constructor Create;
[192]29 procedure Free;
[97]30 function Load(ConnectionID, FileID: Integer): Boolean;
31 function LoadFromPSpc(ConnectionID, FileID: Integer): Boolean;
32 function LoadFromTXMP(ConnectionID, FileID: Integer): Boolean;
33 function LoadFromTXMB(ConnectionID, FileID: Integer): Boolean;
34
[192]35 procedure SaveDataToStream(MipMaps: Boolean; var Target: TStream);
[118]36
[192]37 function LoadFromFile(filename: String): Boolean;
38 function WriteToFile(filename: String): Boolean;
39
40 procedure DrawOnCanvas(Canvas: TCanvas; Index: Integer);
41 function GetImageSize(MipMaps: Boolean): Integer;
[97]42 published
43 end;
44
45
46implementation
47
48//uses Functions;
[192]49uses Img_DDSTypes, ImagingComponents;
[97]50
51
[192]52procedure TOniImage.DrawOnCanvas(Canvas: TCanvas; Index: Integer);
53var
54 singleimg: TImageData;
55 rect: TRect;
56begin
57 InitImage(singleimg);
[193]58 CloneImage(FImages[Index-1], singleimg);
[192]59 ConvertImage(singleimg, ifX8R8G8B8);
60 rect.Left := 0;
61 rect.Top := 0;
62 rect.Right := singleimg.Width - 1;
63 rect.Bottom := singleimg.Height - 1;
64 Canvas.Brush.Color := $C8D0D4;
65 Canvas.FillRect(Canvas.ClipRect);
66 DisplayImageData(Canvas, rect, singleimg, rect);
67 FreeImage(singleimg);
68end;
69
70
71
[97]72constructor TOniImage.Create;
73begin
[192]74end;
[181]75
[192]76
77
78procedure TOniImage.Free;
79begin
80 FreeImagesInArray(FImages);
[97]81end;
82
83
84
85
[192]86function TOniImage.GetImage(MipGen: Integer): TImageData;
[97]87begin
[192]88 if MipGen <= Length(FImages) then
[97]89 begin
[192]90 InitImage(Result);
91 CloneImage(FImages[MipGen-1], Result);
[97]92 end;
93end;
94
95
96
[192]97function TOniImage.GetWidth(MipGen: Integer): Integer;
[97]98begin
[192]99 if MipGen <= Length(FImages) then
100 Result := FImages[MipGen-1].Width
[97]101 else
[192]102 Result := -1;
[97]103end;
104
105
[192]106function TOniImage.GetHeight(MipGen: Integer): Integer;
107begin
108 if MipGen <= Length(FImages) then
109 Result := FImages[MipGen-1].Height
110 else
111 Result := -1;
112end;
[97]113
114
[192]115function TOniImage.GetImageFormat: TImageFormat;
[97]116begin
[192]117 if Length(FImages) > 0 then
118 Result := FImages[0].Format
119 else
120 Result := ifUnknown;
[97]121end;
122
[192]123procedure TOniImage.SetImageFormat(Format: TImageFormat);
[97]124var
[192]125 i: Integer;
[97]126begin
[192]127 if Length(FImages) > 0 then
128 for i := 0 to High(FImages) do
129 ConvertImage(FImages[i], Format);
[97]130end;
131
132
[192]133function TOniImage.GetHasMipMaps: Boolean;
134begin
135 Result := Length(FImages) > 1;
136end;
[97]137
138
139function TOniImage.Load(ConnectionID, FileID: Integer): Boolean;
140var
141 FileInfo: TFileInfo;
142begin
143 FileInfo := ConManager.Connection[ConnectionID].GetFileInfo(fileid);
144 if FileInfo.Extension = 'PSpc' then
145 Result := LoadFromPSpc(ConnectionID, fileid)
146 else if FileInfo.Extension = 'TXMB' then
147 Result := LoadFromTXMB(ConnectionID, fileid)
148 else if FileInfo.Extension = 'TXMP' then
149 Result := LoadFromTXMP(ConnectionID, fileid)
150 else
151 Result := False;
152end;
153
154
155
156
157function TOniImage.LoadFromPSpc(ConnectionID, FileID: Integer): Boolean;
158type
159 TPoint = packed record
160 X, Y: Word;
161 end;
162
163 TPSpc = packed record
164 p1: array[0..8] of TPoint;
165 p2: array[0..8] of TPoint;
166 TXMP: Integer;
167 end;
168
169 TPart = packed record
170 x_txmp, y_txmp: Word;
171 x_pspc, y_pspc: Word;
172 w, h: Word;
173 imgdata: TByteData;
174 used: Boolean;
175 end;
176const
177 PartMatch: array[0..8] of Byte = (0, 3, 6, 1, 4, 7, 2, 5, 8);
178var
179 x, y, pixel: Word;
180 i: Integer;
181
182 PSpc: TPSpc;
183 txmpimg: TOniImage;
184 txmpdata: TByteData;
185
186 parts: array[0..8] of TPart;
187 part: Byte;
188 cols: array[0..2] of Word;
189 rows: array[0..2] of Word;
190 col, row: Byte;
191begin
[192]192(*
[97]193 ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $08, SizeOf(PSpc), @PSpc);
194 PSpc.TXMP := PSpc.TXMP div 256;
195 if PSpc.TXMP = 0 then
196 begin
197 Result := False;
198 Exit;
199 end;
200 txmpimg := TOniImage.Create;
201 txmpimg.LoadFromTXMP(ConnectionID, PSpc.TXMP);
[118]202 txmpimg.DecodeImageTo32bit;
[97]203// txmpimg.WriteToBMP('C:\file.bmp');
[105]204 txmpimg.GetAs32bit(txmpdata);
[97]205{ ShowMessage(IntToStr(txmpimg.Width)+'x'+IntToStr(txmpimg.Height));
206 for i:=0 to High(txmpdata) do
207 txmpimg.Data[i]:=txmpdata[i];
208 txmpimg.WriteToBMP('D:\file2.bmp');
209}
210 with PSpc do
211 begin
212 for i := 0 to 2 do
213 begin
214 cols[i] := 0;
215 rows[i] := 0;
216 end;
217 for i := 0 to 8 do
218 begin
219 part := PartMatch[i];
220 col := i div 3;
221 row := i mod 3;
222 if (p2[i].X > 0) or (p2[i].Y > 0) then
223 begin
224 parts[part].x_txmp := p1[i].X - 1;
225 parts[part].y_txmp := p1[i].Y - 1;
226 parts[part].x_pspc := 0;
227 if col > 0 then
228 for x := 0 to col - 1 do
229 Inc(parts[part].x_pspc, cols[x]);
230 parts[part].y_pspc := 0;
231 if row > 0 then
232 for y := 0 to row - 1 do
233 Inc(parts[part].y_pspc, rows[y]);
234 parts[part].w := p2[i].X - p1[i].X + 1;
235 parts[part].h := p2[i].Y - p1[i].Y + 1;
236 parts[part].used := True;
237 cols[col] := parts[part].w;
238 rows[row] := parts[part].h;
239 SetLength(parts[part].imgdata, parts[part].w * parts[part].h * 4);
240 for y := 0 to parts[part].h - 1 do
241 begin
242 for x := 0 to parts[part].w - 1 do
243 begin
244 for pixel := 0 to 3 do
245 begin
246 parts[part].imgdata[(y * parts[part].w + x) * 4 + pixel] :=
247 txmpdata[((parts[part].y_txmp + y) * txmpimg.Width +
248 parts[part].x_txmp + x) * 4 + pixel];
249 end;
250 end;
251 end;
252 end
253 else
254 begin
255 parts[part].used := False;
256 end;
257 end;
258
259 end;
260
261 txmpimg.Free;
262 txmpimg := TOniImage.Create;
263 for i := 0 to 8 do
264 begin
265 if parts[i].used then
266 begin
267 SetLength(txmpimg.FData, Length(parts[i].imgdata));
268 for pixel := 0 to High(parts[i].imgdata) do
269 txmpimg.Data[pixel] := parts[i].imgdata[pixel];
270 txmpimg.Width := parts[i].w;
271 txmpimg.Height := parts[i].h;
272 txmpimg.StoreType := 8;
273 txmpimg.DataType := [DT_Decoded32];
274 txmpimg.Depth := 32;
275 txmpimg.WriteToBMP('M:\' + IntToStr(i) + '.bmp');
276 end;
277 end;
278 txmpimg.Free;
279
280 Self.FWidth := 0;
281 Self.FHeight := 0;
282 for i := 0 to 2 do
283 begin
284 Inc(Self.FWidth, cols[i]);
285 Inc(Self.FHeight, rows[i]);
286 end;
287 SetLength(Self.FData, Self.FWidth * Self.FHeight * 4);
288
289 //Combine data parts
290
291 Self.FDepth := 32;
292 Self.FStoreType := 8;
293 Self.FDataType := [DT_Decoded32];
294 // Self.RevertImage;
[192]295*)
[97]296end;
297
298
299
300
301function TOniImage.LoadFromTXMP(ConnectionID, FileID: Integer): Boolean;
302var
303 img_addr: Integer;
[181]304 data: TMemoryStream;
305 hdr: TDDSDXTHeader;
306 imginfo: Integer;
307 x,y, i: Integer;
[192]308
309 _width, _height: Word;
310 _storetype: Byte;
311 _depth: Byte;
[97]312begin
313 Result := True;
[192]314 ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $8C, SizeOf(_width), @_width);
315 ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $8E, SizeOf(_height), @_height);
316 ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $90, SizeOf(_storetype), @_storetype);
[181]317 ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $88, SizeOf(imginfo), @imginfo);
[97]318 if ConManager.Connection[ConnectionID].DataOS = DOS_WIN then
319 ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $9C, SizeOf(img_addr), @img_addr)
320 else
321 ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $A0, SizeOf(img_addr), @img_addr);
322
[192]323 case _storetype of
[97]324 0, 1, 2:
[192]325 _depth := 16;
326 7, 8:
327 _depth := 32;
[97]328 9:
[192]329 _depth := 16;
[97]330 else
331 Result := False;
332 Exit;
333 end;
334
[181]335 with hdr do
336 begin
337 FOURCC := 'DDS ';
338 with SURFACEDESC2 do
339 begin
340 Size := 124;
341 Flags := DDSD_CAPS or DDSD_PIXELFORMAT or DDSD_WIDTH or DDSD_HEIGHT;
[192]342 if _storetype = 9 then
[181]343 Flags := Flags or DDSD_LINEARSIZE
344 else
345 Flags := Flags or DDSD_PITCH;
346 if (imginfo and $01) > 0 then
347 Flags := Flags or DDSD_MIPMAPCOUNT;
[192]348 Height := _height;
349 Width := _width;
350 if _storetype = 9 then
351 PitchOrLinearSize := width * height div 2
[181]352 else
[192]353 PitchOrLinearSize := width * _depth div 8;
[181]354 Depth := 0;
355 MipMapCount := 1;
[192]356 if (imginfo and $01) > 0 then
[181]357 begin
[192]358 x := width;
359 y := height;
360 while (x > 1) and (y > 1) do
361 begin
362 x := x div 2;
363 y := y div 2;
364 Inc(MipMapCount);
365 end;
[181]366 end;
367 for i := 1 to 11 do
368 Reserved[i] := 0;
369 with PIXELFORMAT do
370 begin
371 Size := 32;
[192]372 if _storetype = 9 then
[181]373 Flags := DDPF_FOURCC
374 else
375 Flags := DDPF_RGB;
[192]376 if _storetype in [0, 2] then
377 Flags := Flags or DDPF_ALPHAPIXELS;
378 if _storetype = 9 then
379 FOURCC := 'DXT1'
380 else
381 begin
382 RGBBitCount := _depth;
383 case _storetype of
384 0: begin
385 RBitMask := $0F00;
386 GBitMask := $00F0;
387 BBitMask := $000F;
388 AlphaBitMask := $F000;
389 end;
390 1, 2: begin
391 RBitMask := $7C00;
392 GBitMask := $03E0;
393 BBitMask := $001F;
394 if _storetype = 2 then
395 AlphaBitMask := $8000
396 else
397 AlphaBitMask := $0000;
398 end;
399 8: begin
400 RBitMask := $00FF0000;
401 GBitMask := $0000FF00;
402 BBitMask := $000000FF;
403 AlphaBitMask := $00000000;
404 end;
405 end;
406 end;
[181]407 end;
[192]408 with DDSCAPS2 do
409 begin
410 Caps1 := DDSCAPS_TEXTURE;
411 if (imginfo and $01) > 0 then
412 Caps1 := Caps1 or DDSCAPS_COMPLEX or DDSCAPS_MIPMAP;
413 Caps2 := 0;
414 Reserved[1] := 0;
415 Reserved[2] := 0;
416 end;
[181]417 end;
[192]418 end;
419
420 data := TMemoryStream.Create;
421 data.Write(hdr, SizeOf(hdr));
[181]422 if ConManager.Connection[ConnectionID].DataOS = DOS_WIN then
[192]423 ConManager.Connection[ConnectionID].LoadRawFile(fileid, $9C, TStream(data))
[97]424 else
[192]425 ConManager.Connection[ConnectionID].LoadRawFile(fileid, $A0, TStream(data));
[193]426
427// data.Seek(0, soFromBeginning);
428// data.SaveToFile('m:\test.txmp');
429
[192]430 data.Seek(0, soFromBeginning);
431 result := LoadMultiImageFromStream(data, FImages);
432 data.Free;
[193]433{
434 if result then
435 begin
436 for i := 0 to High(FImages) do
437 begin
438 data := TMemoryStream.Create;
439 data.Write(FImages[i].Bits^, FImages[i].Size);
440 data.Seek(0, soFromBeginning);
441 data.SaveToFile('m:\test.txmp.'+IntToStr(i));
442 data.Free;
443 end;
444 end;
445}
[192]446 if not result then
447 begin
448 ShowMessage('Error while loading file' + #13#10 + DetermineStreamFormat(data));
449// data.SaveToFile('m:\prob.dds');
450 end;
[97]451end;
452
453
454
455
456function TOniImage.LoadFromTXMB(ConnectionID, FileID: Integer): Boolean;
457var
458 i, x, y, x2, y2, pixelid, imgid: Integer;
459 rows, cols: Word;
460 linkcount: Integer;
461 link: Integer;
[192]462 images: array of TOniImage;
[97]463 x_start, y_start: Integer;
[192]464
465 width, height: Word;
[97]466begin
[192]467 ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $10, SizeOf(width), @width);
468 ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $12, SizeOf(height), @height);
[97]469 ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $18, SizeOf(cols), @cols);
470 ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $1A, SizeOf(rows), @rows);
471 ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $1C, SizeOf(linkcount), @linkcount);
[192]472 SetLength(images, linkcount);
[97]473 for i := 0 to linkcount - 1 do
474 begin
475 ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $20 + i * 4, SizeOf(link), @link);
476 link := link div 256;
[192]477 images[i] := TOniImage.Create;
478 images[i].LoadFromTXMP(ConnectionID, link);
479 SetLength(FImages, 1);
480 NewImage(width, height, ifA1R5G5B5, FImages[0]);
[97]481 end;
482 for y := 0 to rows - 1 do
483 begin
484 for x := 0 to cols - 1 do
485 begin
[192]486 imgid := y * cols + x;
[97]487 x_start := 0;
488 y_start := 0;
489 for i := 0 to x do
490 if i < x then
[192]491 x_start := x_start + images[i].Image[0].Width;
[97]492 for i := 0 to y do
493 if i < y then
[192]494 y_start := y_start + images[i].Image[0].Height;
495 CopyRect(images[imgid].Image[0], 0, 0, images[imgid].Image[0].Width,
496 images[imgid].Image[0].Height, FImages[0], x_start, y_start);
[97]497 end;
498 end;
499 for i := 0 to linkcount - 1 do
[192]500 images[i].Free;
[97]501end;
502
503
504
[192]505procedure TOniImage.SaveDataToStream(MipMaps: Boolean; var Target: TStream);
[97]506var
[192]507 images: TDynImageDataArray;
508 mem: TMemoryStream;
509 i: Integer;
[128]510begin
[192]511 if Length(FImages) = 0 then
512 Exit;
513 if MipMaps then
[97]514 begin
[192]515 if Length(FImages) = 1 then
516 begin
517 if not GenerateMipMaps(FImages[0], 0, images) then
518 begin
519 ShowMessage('Could not generate MipMaps');
520 Exit;
521 end;
522 end
523 else
524 begin
525 SetLength(images, Length(FImages));
526 for i := 0 to High(FImages) do
527 CloneImage(FImages[i], images[i]);
528 end;
529 mem := TMemoryStream.Create;
530 if not SaveMultiImageToStream('dds', mem, images) then
531 begin
532 ShowMessage('Could not save images to stream');
533 Exit;
534 end;
535 FreeImagesInArray(images);
[97]536 end
537 else
538 begin
[192]539 mem := TMemoryStream.Create;
540 if not SaveImageToStream('dds', mem, FImages[0]) then
[97]541 begin
[192]542 ShowMessage('Could not save image to stream');
543 Exit;
[97]544 end;
545 end;
[192]546 if not Assigned(Target) then
547 Target := TMemoryStream.Create;
[97]548
[192]549// mem.Seek(0, soFromBeginning);
550// mem.SaveToFile('m:\dds.dds');
[97]551
[192]552 mem.Seek(128, soFromBeginning);
553 Target.CopyFrom(mem, mem.Size - 128);
554 mem.Free;
555 Target.Seek(0, soFromBeginning);
[97]556end;
557
558
[192]559function TOniImage.LoadFromFile(filename: String): Boolean;
[97]560begin
[192]561 if not LoadMultiImageFromFile(filename, FImages) then
562 ShowMessage('Couldn''t load image file');
[97]563end;
564
565
[192]566function TOniImage.WriteToFile(filename: String): Boolean;
[97]567begin
[192]568 SaveMultiImageToFile(filename, FImages);
[97]569end;
570
571
572
[192]573function TOniImage.GetImageSize(MipMaps: Boolean): Integer;
[97]574var
[192]575 i: Integer;
[97]576begin
[192]577 if Length(FImages) > 0 then
[97]578 begin
[192]579 Result := FImages[0].Size;
580 if mipmaps then
581 for i := 1 to High(FImages) do
582 Result := Result + FImages[i].Size;
[97]583 end
584 else
[192]585 Result := -1;
[97]586end;
587
588end.
Note: See TracBrowser for help on using the repository browser.