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

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