hedgewars/uLand.pas
changeset 12109 f61bd25b9f70
parent 12105 166725555e57
child 12597 00b539e6115d
--- a/hedgewars/uLand.pas	Tue Dec 06 01:05:46 2016 +0100
+++ b/hedgewars/uLand.pas	Tue Dec 06 02:18:38 2016 +0100
@@ -165,88 +165,90 @@
                 end
 end;
 
-procedure ColorizeLandFast(Surface: PSDL_Surface);
-var ltsurf: PSDL_Surface;
-    x, y, ltw, lth, c, modc, lastfull: LongInt;
-    srcp, dstp: Pointer;
+procedure ColorizeLandFast(mapsurf: PSDL_Surface);
+var ltexsurf: PSDL_Surface;
+    i: LongInt;
+    ltlnp, srcp, dstp, stopp: Pointer;
+    c: SizeInt;
 begin
-    ltsurf:= LoadDataImage(ptCurrTheme, 'LandTex', ifCritical or ifIgnoreCaps);
-    ltw:= ltsurf^.w;
-    lth:= ltsurf^.h;
+    ltexsurf:= LoadDataImage(ptCurrTheme, 'LandTex', ifCritical or ifIgnoreCaps);
 
-    // pointer to ltturf pixels. will be moved from line to line
-    srcp:= ltsurf^.pixels;
-    // pointer to Surface pixels. will be moved forward with every move()
-    dstp:= Surface^.pixels;
+    // pointer to current line of ltexsurf pixels. will be moved from line to line
+    ltlnp:= ltexsurf^.pixels;
+    // pointer to mapsurf pixels. will jump forward after every move()
+    dstp:= mapsurf^.pixels;
+
+    // time to get serious
+    SDL_LockSurface(mapsurf);
+    SDL_LockSurface(ltexsurf);
+
+    // for now only fill a row with the height of landtex. do vertical copies within mapsurf after
 
-    // amount of pixels to write per move()
-    c:= ltsurf^.pitch;
-    // amount of pixels to write for line's remainer move()
-    modc:= Surface^.pitch mod c;
+    // do this loop for each line of ltexsurf (unless we run out of map height first)
+    for i:= 1 to min(ltexsurf^.h, mapsurf^.h) do
+        begin
+        // amount of pixels to write in first move()
+        c:= ltexsurf^.pitch;
 
-    SDL_LockSurface(Surface);
-    SDL_LockSurface(ltsurf);
+        // protect from odd cases where landtex wider than map
+        if c > mapsurf^.pitch then
+            c:= mapsurf^.pitch;
+
+        // write line of landtex to mapsurf
+        move(ltlnp^, dstp^, c);
 
-    y:= 0;
-    // last x where a full line from src may be written to
-    lastfull:= Surface^.w - ltw;
-    // only copy in one row of landtex. do copies within Surface after
-    while (y < lth) and (y < Surface^.h) do
-        begin
-        x:= 0;
-        // fill dst line with src lines
-        while x <= lastfull do
+        // fill the rest of the line by copying left-to-right until full
+
+        // new src is start of line that we've just written to
+        srcp:= dstp;
+        // set stop pointer to start of next pixel line of mapsurf
+        stopp:= dstp + mapsurf^.pitch;
+        // move dst pointer to after what we've just written
+        inc(dstp, c);
+
+        // loop until dstp went past end of line
+        while dstp < stopp do
             begin
+            // copy all from left of dstp to right of it (or just fill the gap if smaller)
+            c:= min(dstp-srcp, stopp-dstp);
             move(srcp^, dstp^, c);
             inc(dstp, c);
-                inc(x, ltw);
             end;
 
-        // if it didn't fit perfectly, copy remainder
-        if modc > 0 then
-            begin
-            move(srcp^, dstp^, modc);
-            inc(dstp, modc);
-            end;
-
-        // move to next line in src surface
-        inc(srcp, ltsurf^.pitch);
-        inc(y);
+        // move to next line in ltexsurf
+        inc(ltlnp, ltexsurf^.pitch);
         end;
 
-    // we don't need ltsurf anymore -> cleanup
-    srcp:= nil;
-    SDL_UnlockSurface(ltsurf);
-    SDL_FreeSurface(ltsurf);
+    // we don't need ltexsurf itself anymore -> cleanup
+    ltlnp:= nil;
+    SDL_UnlockSurface(ltexsurf);
+    SDL_FreeSurface(ltexsurf);
+    ltexsurf:= nil;
 
-    // from now on only copy pixels within Surface
+    // from now on only copy pixels within mapsurf
 
-    // start reading from position 0, but continue writing at dstp
-    srcp:= Surface^.pixels;
     // copy all the already written lines at once for that get number of written bytes so far
-    c:= dstp - srcp; // effectively same as c:= lth * Surface^.pitch;
-    // also figure out the remainder again
-    modc:= (Surface^.h mod lth) * Surface^.pitch; // effectivle same as modc:= (Surface^.pitch * Surface^.h) mod c;
+    // already written pixels are between start and current dstp
+    srcp:= mapsurf^.pixels;
 
-    // last y where a full copy may be written to
-    lastfull:= Surface^.h - lth;
+    // first byte after end of pixels
+    stopp:= srcp + (mapsurf^.pitch * mapsurf^.h);
 
-    // copy filled area down
-    while y <= lastfull do
+    while dstp < stopp do
         begin
+        // copy all from before dstp to after (or just fill the gap if smaller)
+        c:= min(dstp-srcp, stopp-dstp);
+        // worried about size of c with humongous maps? don't be:
+        //  the OS wouldn't have allowed allocation of object with size > max of SizeInt anyway
         move(srcp^, dstp^, c);
-        inc(srcp, c);
         inc(dstp, c);
-        inc(y, lth);
         end;
 
-    // if it didn't fit perfectly, copy remainder
-    if modc > 0 then
-        begin
-        move(srcp^, dstp^, modc);
-        end;
-
-    SDL_UnlockSurface(Surface);
+    // cleanup
+    srcp:= nil;
+    dstp:= nil;
+    stopp:= nil;
+    SDL_UnlockSurface(mapsurf);
 
     // freed in freeModule() below
     LandBackSurface:= LoadDataImage(ptCurrTheme, 'LandBackTex', ifIgnoreCaps or ifTransparent);