20 |
20 |
21 unit uLand; |
21 unit uLand; |
22 interface |
22 interface |
23 uses SDLh, uLandTemplates, uFloat, uConsts, |
23 uses SDLh, uLandTemplates, uFloat, uConsts, |
24 {$IFDEF GLES11} |
24 {$IFDEF GLES11} |
25 gles11; |
25 gles11; |
26 {$ELSE} |
26 {$ELSE} |
27 GL; |
27 GL; |
28 {$ENDIF} |
28 {$ENDIF} |
29 |
29 |
30 type TLandArray = packed array[0 .. LAND_HEIGHT - 1, 0 .. LAND_WIDTH - 1] of LongWord; |
30 type TLandArray = packed array[0 .. LAND_HEIGHT - 1, 0 .. LAND_WIDTH - 1] of LongWord; |
31 TCollisionArray = packed array[0 .. LAND_HEIGHT - 1, 0 .. LAND_WIDTH - 1] of Word; |
31 TCollisionArray = packed array[0 .. LAND_HEIGHT - 1, 0 .. LAND_WIDTH - 1] of Word; |
32 TPreview = packed array[0..127, 0..31] of byte; |
32 TPreview = packed array[0..127, 0..31] of byte; |
33 TDirtyTag = packed array[0 .. LAND_HEIGHT div 32 - 1, 0 .. LAND_WIDTH div 32 - 1] of byte; |
33 TDirtyTag = packed array[0 .. LAND_HEIGHT div 32 - 1, 0 .. LAND_WIDTH div 32 - 1] of byte; |
34 |
34 |
35 var Land: TCollisionArray; |
35 var Land: TCollisionArray; |
36 LandPixels: TLandArray; |
36 LandPixels: TLandArray; |
37 LandDirty: TDirtyTag; |
37 LandDirty: TDirtyTag; |
38 hasBorder: boolean; |
38 hasBorder: boolean; |
312 end; |
312 end; |
313 |
313 |
314 function LandBackPixel(x, y: LongInt): LongWord; |
314 function LandBackPixel(x, y: LongInt): LongWord; |
315 var p: PLongWordArray; |
315 var p: PLongWordArray; |
316 begin |
316 begin |
317 if LandBackSurface = nil then LandBackPixel:= 0 |
317 if LandBackSurface = nil then LandBackPixel:= 0 |
318 else |
318 else |
319 begin |
319 begin |
320 p:= LandBackSurface^.pixels; |
320 p:= LandBackSurface^.pixels; |
321 LandBackPixel:= p^[LandBackSurface^.w * (y mod LandBackSurface^.h) + (x mod LandBackSurface^.w)];// or $FF000000; |
321 LandBackPixel:= p^[LandBackSurface^.w * (y mod LandBackSurface^.h) + (x mod LandBackSurface^.w)];// or $FF000000; |
322 end |
322 end |
323 end; |
323 end; |
324 |
324 |
325 procedure ColorizeLand(Surface: PSDL_Surface); |
325 procedure ColorizeLand(Surface: PSDL_Surface); |
326 var tmpsurf: PSDL_Surface; |
326 var tmpsurf: PSDL_Surface; |
327 r, rr: TSDL_Rect; |
327 r, rr: TSDL_Rect; |
328 x, yd, yu: LongInt; |
328 x, yd, yu: LongInt; |
329 begin |
329 begin |
330 tmpsurf:= LoadImage(Pathz[ptCurrTheme] + '/LandTex', ifCritical or ifIgnoreCaps); |
330 tmpsurf:= LoadImage(Pathz[ptCurrTheme] + '/LandTex', ifCritical or ifIgnoreCaps); |
331 r.y:= 0; |
331 r.y:= 0; |
332 while r.y < LAND_HEIGHT do |
332 while r.y < LAND_HEIGHT do |
333 begin |
333 begin |
334 r.x:= 0; |
334 r.x:= 0; |
335 while r.x < LAND_WIDTH do |
335 while r.x < LAND_WIDTH do |
336 begin |
336 begin |
337 SDL_UpperBlit(tmpsurf, nil, Surface, @r); |
337 SDL_UpperBlit(tmpsurf, nil, Surface, @r); |
338 inc(r.x, tmpsurf^.w) |
338 inc(r.x, tmpsurf^.w) |
339 end; |
339 end; |
340 inc(r.y, tmpsurf^.h) |
340 inc(r.y, tmpsurf^.h) |
341 end; |
341 end; |
342 SDL_FreeSurface(tmpsurf); |
342 SDL_FreeSurface(tmpsurf); |
343 |
343 |
344 // freed in free_uLand() below |
344 // freed in free_uLand() below |
345 LandBackSurface:= LoadImage(Pathz[ptCurrTheme] + '/LandBackTex', ifIgnoreCaps or ifTransparent); |
345 LandBackSurface:= LoadImage(Pathz[ptCurrTheme] + '/LandBackTex', ifIgnoreCaps or ifTransparent); |
346 |
346 |
347 tmpsurf:= LoadImage(Pathz[ptCurrTheme] + '/Border', ifCritical or ifIgnoreCaps or ifTransparent); |
347 tmpsurf:= LoadImage(Pathz[ptCurrTheme] + '/Border', ifCritical or ifIgnoreCaps or ifTransparent); |
348 for x:= 0 to LAND_WIDTH - 1 do |
348 for x:= 0 to LAND_WIDTH - 1 do |
349 begin |
349 begin |
350 yd:= LAND_HEIGHT - 1; |
350 yd:= LAND_HEIGHT - 1; |
351 repeat |
351 repeat |
352 while (yd > 0) and (Land[yd, x] = 0) do dec(yd); |
352 while (yd > 0) and (Land[yd, x] = 0) do dec(yd); |
353 |
353 |
354 if (yd < 0) then yd:= 0; |
354 if (yd < 0) then yd:= 0; |
355 |
355 |
356 while (yd < LAND_HEIGHT) and (Land[yd, x] <> 0) do inc(yd); |
356 while (yd < LAND_HEIGHT) and (Land[yd, x] <> 0) do inc(yd); |
357 dec(yd); |
357 dec(yd); |
358 yu:= yd; |
358 yu:= yd; |
359 |
359 |
360 while (yu > 0 ) and (Land[yu, x] <> 0) do dec(yu); |
360 while (yu > 0 ) and (Land[yu, x] <> 0) do dec(yu); |
361 while (yu < yd ) and (Land[yu, x] = 0) do inc(yu); |
361 while (yu < yd ) and (Land[yu, x] = 0) do inc(yu); |
362 |
362 |
363 if (yd < LAND_HEIGHT - 1) and ((yd - yu) >= 16) then |
363 if (yd < LAND_HEIGHT - 1) and ((yd - yu) >= 16) then |
364 begin |
364 begin |
365 rr.x:= x; |
365 rr.x:= x; |
366 rr.y:= yd - 15; |
366 rr.y:= yd - 15; |
367 r.x:= x mod tmpsurf^.w; |
367 r.x:= x mod tmpsurf^.w; |
368 r.y:= 16; |
368 r.y:= 16; |
369 r.w:= 1; |
369 r.w:= 1; |
370 r.h:= 16; |
370 r.h:= 16; |
371 SDL_UpperBlit(tmpsurf, @r, Surface, @rr); |
371 SDL_UpperBlit(tmpsurf, @r, Surface, @rr); |
372 end; |
372 end; |
373 if (yu > 0) then |
373 if (yu > 0) then |
374 begin |
374 begin |
375 rr.x:= x; |
375 rr.x:= x; |
376 rr.y:= yu; |
376 rr.y:= yu; |
377 r.x:= x mod tmpsurf^.w; |
377 r.x:= x mod tmpsurf^.w; |
378 r.y:= 0; |
378 r.y:= 0; |
379 r.w:= 1; |
379 r.w:= 1; |
380 r.h:= min(16, yd - yu + 1); |
380 r.h:= min(16, yd - yu + 1); |
381 SDL_UpperBlit(tmpsurf, @r, Surface, @rr); |
381 SDL_UpperBlit(tmpsurf, @r, Surface, @rr); |
382 end; |
382 end; |
383 yd:= yu - 1; |
383 yd:= yu - 1; |
384 until yd < 0; |
384 until yd < 0; |
385 end; |
385 end; |
386 SDL_FreeSurface(tmpsurf); |
386 SDL_FreeSurface(tmpsurf); |
387 end; |
387 end; |
388 |
388 |
389 procedure SetPoints(var Template: TEdgeTemplate; var pa: TPixAr); |
389 procedure SetPoints(var Template: TEdgeTemplate; var pa: TPixAr); |
390 var i: LongInt; |
390 var i: LongInt; |
391 begin |
391 begin |
614 WriteLnToConsole('Selected template #'+inttostr(SelectTemplate)+' using filter #'+inttostr(cTemplateFilter)); |
614 WriteLnToConsole('Selected template #'+inttostr(SelectTemplate)+' using filter #'+inttostr(cTemplateFilter)); |
615 end; |
615 end; |
616 |
616 |
617 procedure LandSurface2LandPixels(Surface: PSDL_Surface); |
617 procedure LandSurface2LandPixels(Surface: PSDL_Surface); |
618 var x, y: LongInt; |
618 var x, y: LongInt; |
619 p: PLongwordArray; |
619 p: PLongwordArray; |
620 begin |
620 begin |
621 TryDo(Surface <> nil, 'Assert (LandSurface <> nil) failed', true); |
621 TryDo(Surface <> nil, 'Assert (LandSurface <> nil) failed', true); |
622 |
622 |
623 if SDL_MustLock(Surface) then |
623 if SDL_MustLock(Surface) then |
624 SDLTry(SDL_LockSurface(Surface) >= 0, true); |
624 SDLTry(SDL_LockSurface(Surface) >= 0, true); |
625 |
625 |
626 p:= Surface^.pixels; |
626 p:= Surface^.pixels; |
627 for y:= 0 to LAND_HEIGHT - 1 do |
627 for y:= 0 to LAND_HEIGHT - 1 do |
628 begin |
628 begin |
629 for x:= 0 to LAND_WIDTH - 1 do |
629 for x:= 0 to LAND_WIDTH - 1 do |
630 if Land[y, x] <> 0 then LandPixels[y, x]:= p^[x] or AMask; |
630 if Land[y, x] <> 0 then LandPixels[y, x]:= p^[x] or AMask; |
631 |
631 |
632 p:= @(p^[Surface^.pitch div 4]); |
632 p:= @(p^[Surface^.pitch div 4]); |
633 end; |
633 end; |
634 |
634 |
635 if SDL_MustLock(Surface) then |
635 if SDL_MustLock(Surface) then |
636 SDL_UnlockSurface(Surface); |
636 SDL_UnlockSurface(Surface); |
637 end; |
637 end; |
638 |
638 |
639 procedure GenLandSurface; |
639 procedure GenLandSurface; |
640 var tmpsurf: PSDL_Surface; |
640 var tmpsurf: PSDL_Surface; |
641 begin |
641 begin |
642 WriteLnToConsole('Generating land...'); |
642 WriteLnToConsole('Generating land...'); |
643 GenBlank(EdgeTemplates[SelectTemplate]); |
643 GenBlank(EdgeTemplates[SelectTemplate]); |
644 AddProgress(); |
644 AddProgress(); |
645 |
645 |
646 tmpsurf:= SDL_CreateRGBSurface(SDL_SWSURFACE, LAND_WIDTH, LAND_HEIGHT, 32, RMask, GMask, BMask, 0); |
646 tmpsurf:= SDL_CreateRGBSurface(SDL_SWSURFACE, LAND_WIDTH, LAND_HEIGHT, 32, RMask, GMask, BMask, 0); |
647 |
647 |
648 TryDo(tmpsurf <> nil, 'Error creating pre-land surface', true); |
648 TryDo(tmpsurf <> nil, 'Error creating pre-land surface', true); |
649 ColorizeLand(tmpsurf); |
649 ColorizeLand(tmpsurf); |
650 AddOnLandObjects(tmpsurf); |
650 AddOnLandObjects(tmpsurf); |
651 |
651 |
652 LandSurface2LandPixels(tmpsurf); |
652 LandSurface2LandPixels(tmpsurf); |
653 SDL_FreeSurface(tmpsurf); |
653 SDL_FreeSurface(tmpsurf); |
654 AddProgress(); |
654 AddProgress(); |
655 end; |
655 end; |
656 |
656 |
657 procedure MakeFortsMap; |
657 procedure MakeFortsMap; |
658 var tmpsurf: PSDL_Surface; |
658 var tmpsurf: PSDL_Surface; |
659 begin |
659 begin |
685 procedure LoadMask; |
685 procedure LoadMask; |
686 var tmpsurf: PSDL_Surface; |
686 var tmpsurf: PSDL_Surface; |
687 p: PLongwordArray; |
687 p: PLongwordArray; |
688 x, y, cpX, cpY: Longword; |
688 x, y, cpX, cpY: Longword; |
689 begin |
689 begin |
690 tmpsurf:= LoadImage(Pathz[ptMapCurrent] + '/mask', ifAlpha or ifTransparent or ifIgnoreCaps); |
690 tmpsurf:= LoadImage(Pathz[ptMapCurrent] + '/mask', ifAlpha or ifTransparent or ifIgnoreCaps); |
691 if (tmpsurf <> nil) and (tmpsurf^.w <= LAND_WIDTH) and (tmpsurf^.h <= LAND_HEIGHT) and (tmpsurf^.format^.BytesPerPixel = 4) then |
691 if (tmpsurf <> nil) and (tmpsurf^.w <= LAND_WIDTH) and (tmpsurf^.h <= LAND_HEIGHT) and (tmpsurf^.format^.BytesPerPixel = 4) then |
692 begin |
692 begin |
693 cpX:= (LAND_WIDTH - tmpsurf^.w) div 2; |
693 cpX:= (LAND_WIDTH - tmpsurf^.w) div 2; |
694 cpY:= LAND_HEIGHT - tmpsurf^.h; |
694 cpY:= LAND_HEIGHT - tmpsurf^.h; |
695 if SDL_MustLock(tmpsurf) then |
695 if SDL_MustLock(tmpsurf) then |
696 SDLTry(SDL_LockSurface(tmpsurf) >= 0, true); |
696 SDLTry(SDL_LockSurface(tmpsurf) >= 0, true); |
697 |
697 |
698 p:= tmpsurf^.pixels; |
698 p:= tmpsurf^.pixels; |
699 for y:= 0 to Pred(tmpsurf^.h) do |
699 for y:= 0 to Pred(tmpsurf^.h) do |
700 begin |
700 begin |
701 for x:= 0 to Pred(tmpsurf^.w) do |
701 for x:= 0 to Pred(tmpsurf^.w) do |
702 begin |
702 begin |
703 if ((AMask and p^[x]) = 0) then // Tiy was having trouble generating transparent black |
703 if ((AMask and p^[x]) = 0) then // Tiy was having trouble generating transparent black |
704 Land[cpY + y, cpX + x]:= 0 |
704 Land[cpY + y, cpX + x]:= 0 |
705 else if p^[x] = (AMask or RMask) then |
705 else if p^[x] = (AMask or RMask) then |
706 Land[cpY + y, cpX + x]:= COLOR_INDESTRUCTIBLE |
706 Land[cpY + y, cpX + x]:= COLOR_INDESTRUCTIBLE |
707 else if p^[x] = $FFFFFFFF then |
707 else if p^[x] = $FFFFFFFF then |
708 Land[cpY + y, cpX + x]:= COLOR_LAND; |
708 Land[cpY + y, cpX + x]:= COLOR_LAND; |
709 end; |
709 end; |
710 p:= @(p^[tmpsurf^.pitch div 4]); |
710 p:= @(p^[tmpsurf^.pitch div 4]); |
711 end; |
711 end; |
712 |
712 |
713 if SDL_MustLock(tmpsurf) then |
713 if SDL_MustLock(tmpsurf) then |
714 SDL_UnlockSurface(tmpsurf); |
714 SDL_UnlockSurface(tmpsurf); |
715 end; |
715 end; |
716 if (tmpsurf <> nil) then |
716 if (tmpsurf <> nil) then |
717 SDL_FreeSurface(tmpsurf); |
717 SDL_FreeSurface(tmpsurf); |
718 end; |
718 end; |
719 |
719 |
720 procedure LoadMap; |
720 procedure LoadMap; |
721 var tmpsurf: PSDL_Surface; |
721 var tmpsurf: PSDL_Surface; |
722 s: shortstring; |
722 s: shortstring; |
723 f: textfile; |
723 f: textfile; |
724 begin |
724 begin |
725 WriteLnToConsole('Loading land from file...'); |
725 WriteLnToConsole('Loading land from file...'); |
726 AddProgress; |
726 AddProgress; |
727 tmpsurf:= LoadImage(Pathz[ptMapCurrent] + '/map', ifAlpha or ifCritical or ifTransparent or ifIgnoreCaps); |
727 tmpsurf:= LoadImage(Pathz[ptMapCurrent] + '/map', ifAlpha or ifCritical or ifTransparent or ifIgnoreCaps); |
728 TryDo((tmpsurf^.w <= LAND_WIDTH) and (tmpsurf^.h <= LAND_HEIGHT), 'Map dimensions too big!', true); |
728 TryDo((tmpsurf^.w <= LAND_WIDTH) and (tmpsurf^.h <= LAND_HEIGHT), 'Map dimensions too big!', true); |
787 break; |
787 break; |
788 end; |
788 end; |
789 end; |
789 end; |
790 |
790 |
791 if hasBorder then |
791 if hasBorder then |
792 begin |
792 begin |
793 for y:= 0 to LAND_HEIGHT - 1 do |
793 for y:= 0 to LAND_HEIGHT - 1 do |
794 for x:= 0 to LAND_WIDTH - 1 do |
794 for x:= 0 to LAND_WIDTH - 1 do |
795 if (y < topY) or (x < leftX) or (x > rightX) then |
795 if (y < topY) or (x < leftX) or (x > rightX) then |
796 Land[y, x]:= COLOR_INDESTRUCTIBLE; |
796 Land[y, x]:= COLOR_INDESTRUCTIBLE; |
797 // experiment hardcoding cave |
797 // experiment hardcoding cave |
798 // also try basing cave dimensions on map/template dimensions, if they exist |
798 // also try basing cave dimensions on map/template dimensions, if they exist |
799 for w:= 0 to 5 do // width of 3 allowed hogs to be knocked through with grenade |
799 for w:= 0 to 5 do // width of 3 allowed hogs to be knocked through with grenade |
800 begin |
800 begin |
801 for y:= topY to LAND_HEIGHT - 1 do |
801 for y:= topY to LAND_HEIGHT - 1 do |
802 begin |
802 begin |
803 Land[y, leftX + w]:= COLOR_INDESTRUCTIBLE; |
803 Land[y, leftX + w]:= COLOR_INDESTRUCTIBLE; |
804 Land[y, rightX - w]:= COLOR_INDESTRUCTIBLE; |
804 Land[y, rightX - w]:= COLOR_INDESTRUCTIBLE; |
805 if (y + w) mod 32 < 16 then |
805 if (y + w) mod 32 < 16 then |
806 c:= AMask |
806 c:= AMask |
807 else |
807 else |
808 c:= AMask or RMask or GMask; // FF00FFFF |
808 c:= AMask or RMask or GMask; // FF00FFFF |
809 LandPixels[y, leftX + w]:= c; |
809 LandPixels[y, leftX + w]:= c; |
810 LandPixels[y, rightX - w]:= c; |
810 LandPixels[y, rightX - w]:= c; |
811 end; |
811 end; |
812 |
812 |
813 for x:= leftX to rightX do |
813 for x:= leftX to rightX do |
814 begin |
814 begin |
815 Land[topY + w, x]:= COLOR_INDESTRUCTIBLE; |
815 Land[topY + w, x]:= COLOR_INDESTRUCTIBLE; |
816 if (x + w) mod 32 < 16 then |
816 if (x + w) mod 32 < 16 then |
817 c:= AMask |
817 c:= AMask |
818 else |
818 else |
819 c:= AMask or RMask or GMask; // FF00FFFF |
819 c:= AMask or RMask or GMask; // FF00FFFF |
820 LandPixels[topY + w, x]:= c; |
820 LandPixels[topY + w, x]:= c; |
821 end; |
821 end; |
822 end; |
822 end; |
823 end; |
823 end; |
824 |
824 |
825 if (GameFlags and gfDisableGirders) <> 0 then hasGirders:= false; |
825 if (GameFlags and gfDisableGirders) <> 0 then hasGirders:= false; |
826 |
826 |
827 if ((GameFlags and gfForts) = 0) and (Pathz[ptMapCurrent] = '') then AddObjects; |
827 if ((GameFlags and gfForts) = 0) and (Pathz[ptMapCurrent] = '') then AddObjects; |
828 |
828 |