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

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