Posted By: EpsiloN
bmap_scale and paint on terrain at position - 01/11/16 11:39
I'm using this in an isometric top-down shooter to paint blood on a terrain where my bullets hit the enemy, and I'll also use it to paint the trees on the terrain skin, for performance reasons...
I hope it helps you in some way...if not, at least bmap_scale is useful
bmap_scale() to scale a bitmap (receives pointer to bitmap, returns pointer of new scaled bitmap , OLD (original) bitmap is not destroyed!!! Also, make sure you destroy the new bitmap after you are done with it...
This uses basic bilinear interpolation)
paintSpriteOnTerrain() will paint a sprite you give it (as a bmap pointer) on a terrain entity, at a given skin-texture coordinates rotated by a given angle and scaled by a factor.
The way I'm calculating a position on the terrain to its skin coordinates is this:
This code calculates a size factor between the terrain skin and its quants size, adds bullet position to half of the terrain size in each axis (which means calculations will start at X=0 in Skin coordinats for X=-512 in quants coordinates, if that makes sense...) and multiplies the result by the factor of the size ratio (quants/skin)
For example, skin is 1024 quants, terrain whole size is 3200, player is at -1600.
(-1600 + 1600) * (1024 / 3200) = 0
(1600 + 1600) * (1024 / 3200) = 1024
Or if player is in center of terrain
(0 + 1600) * (1024 / 3200) = 512 (in skin coordinates)
Terrain orientation or position here is not considered, if you move or rotate the terrain, you'll have to correct the code a little...
Here's the syntax to call the two functions:
paintSpriteOnTerrain() uses bmap_scale().
Here's the two functions:
Have fun took me a while to make it...
PS.: I didn't needed it, but if you modify the loop in paintSpriteOnTerrain() you can get a separate function to just rotate a bitmap and return the rotated version as a pointer...
Oh, I almost forgot, after pixel rotation, interpolation has to be done too to get an accurate rotated image, but I'm using small sprites (32x32 or 64x64) so I didn't need additional complexity...
If you want to implement it, take as an example the interpolation done in bmap_scale.
*** EDIT *** The Engine crashes sometimes, and after looking at it for 20 seconds, my best guess is that it tries to access a NULL pointer.
Now, bmap_scale will return the source bitmap if it fails...
Here's the update with checks, but I deleted all comments in search for "Token too large" :
I hope it helps you in some way...if not, at least bmap_scale is useful
bmap_scale() to scale a bitmap (receives pointer to bitmap, returns pointer of new scaled bitmap , OLD (original) bitmap is not destroyed!!! Also, make sure you destroy the new bitmap after you are done with it...
This uses basic bilinear interpolation)
paintSpriteOnTerrain() will paint a sprite you give it (as a bmap pointer) on a terrain entity, at a given skin-texture coordinates rotated by a given angle and scaled by a factor.
The way I'm calculating a position on the terrain to its skin coordinates is this:
Code:
BMAP* terrBmp = bmap_for_entity(terrainEntity,0); VECTOR destPos; destPos.x = (my.x + ((terrainEntity.max_x + abs(terrainEntity.min_x)) / 2)) * (bmap_width(terrBmp) / (terrainEntity.max_x + abs(terrainEntity.min_x))); destPos.y = ((my.y * -1) + ((terrainEntity.max_y + abs(terrainEntity.min_y)) / 2)) * (bmap_height(terrBmp) / (terrainEntity.max_x + abs(terrainEntity.min_x))); destPos.z = 0; paintSpriteOnTerrain( terrainEntity , bloodSplatter1_tga , destPos , my.pan , 1 );
This code calculates a size factor between the terrain skin and its quants size, adds bullet position to half of the terrain size in each axis (which means calculations will start at X=0 in Skin coordinats for X=-512 in quants coordinates, if that makes sense...) and multiplies the result by the factor of the size ratio (quants/skin)
For example, skin is 1024 quants, terrain whole size is 3200, player is at -1600.
(-1600 + 1600) * (1024 / 3200) = 0
(1600 + 1600) * (1024 / 3200) = 1024
Or if player is in center of terrain
(0 + 1600) * (1024 / 3200) = 512 (in skin coordinates)
Terrain orientation or position here is not considered, if you move or rotate the terrain, you'll have to correct the code a little...
Here's the syntax to call the two functions:
Code:
bmap_scale( BMAP* sourceBmp , var scaleFactor ); paintSpriteOnTerrain( ENTITY* terrainEnt , BMAP* sourceSpriteBmap , VECTOR* posVec , var spriteAngle , var spriteScale );
paintSpriteOnTerrain() uses bmap_scale().
Here's the two functions:
Code:
// Takes pointer to BMAP and Scale factor (1 means no scaling... 2 means double size) // Returns pointer to scaled BMAP BMAP* bmap_scale( BMAP* sourceBmp , scaleFactor ) { if( !sourceBmp ) { return NULL; } if( scaleFactor == 0 || scaleFactor == 1 ) { return sourceBmp; } // If scale is ommited or 1 , return the same pointer // Get dimensions and lock the source bitmap var sWidth = bmap_width( sourceBmp ); var sHeight = bmap_height( sourceBmp ); var bmapFormat = bmap_lock( sourceBmp , 0 ); // Create a new bitmap with scaled dimensions and lock it for manipulation var dWidth = sWidth * scaleFactor; var dHeight = sHeight * scaleFactor; BMAP* destinationBmp = bmap_createblack( (int)dWidth , (int)dHeight , bmap_format(sourceBmp) ); if( !destinationBmp ) { return NULL; } var destBmapFormat = bmap_lock( destinationBmp , 0 ); int dx, dy, sx, sy; // Iterate over the destination pixels // (to avoid missing a destination pixel if we itterate over the source) for( dx = 0; dx < dWidth; dx++ ) { for( dy = 0; dy < dHeight; dy++ ) { sx = dx / scaleFactor; sy = dy / scaleFactor; if( sx == (int)sx && sy == (int)sy ) { // Pixel is the at correct pos, so write it pixel_to_bmap( destinationBmp , dx , dy , pixel_for_bmap( sourceBmp , sx , sy ) ); } else { if( sx == (int)sx && sy != (int)sy ) { // new pixel y is a middle between two source pixels var sy1 = integer(sy); // Get source closest lower pixel pos var sy2 = ceil(sy); // Get source closest upper pixel pos var pixel1 = pixel_for_bmap( sourceBmp , sx , sy1 ); // Get lower pixel value var pixel2 = pixel_for_bmap( sourceBmp , sx , sy2 ); // Get upper pixel value COLOR pixelColor[3]; var pixelAlpha[2]; pixel_to_vec( pixelColor[0] , pixelAlpha[0] , bmapFormat , pixel1 ); // Get the color of lower pixel pixel_to_vec( pixelColor[1] , pixelAlpha[1] , bmapFormat , pixel2 ); // Color of upper pixel var fact = sy - sy1; // Get a factor for interpolation between the two positions // (factor is if the destination is closer to lower or upper pixel) fact = minv(1 , (maxv(fact,0))); // Limit factor between 0 and 1 vec_lerp( pixelColor[2] , pixelColor[0] , pixelColor[1] , fact); // Calculate a new pixel based on the factor var alphaLerp = (1-fact)*pixelAlpha[0] + fact*pixelAlpha[1]; // Interpolate the alpha value too pixel_to_bmap( destinationBmp , dx , dy , pixel_for_vec( pixelColor[2] , alphaLerp , bmapFormat ) ); // Write the interpolated pixel } else { if( sx != (int)sx && sy == (int)sy ) { // new pixel x is middle var sx1 = integer(sx); // Get source closest lower pixel pos var sx2 = ceil(sx); // Get source closest higher pixel pos var pixel1 = pixel_for_bmap( sourceBmp , sx1 , sy ); // Get the two pixel values var pixel2 = pixel_for_bmap( sourceBmp , sx2 , sy ); COLOR pixelColor[3]; var pixelAlpha[2]; pixel_to_vec( pixelColor[0] , pixelAlpha[0] , bmapFormat , pixel1 ); // Convert pixel values pixel_to_vec( pixelColor[1] , pixelAlpha[1] , bmapFormat , pixel2 ); // to COLOR and ALPHA var fact = sx - sx1; // Calculate a factor for destination position fact = minv(1 , (maxv(fact,0))); // between the two source positions vec_lerp( pixelColor[2] , pixelColor[0] , pixelColor[1] , fact); // Interpolate the colors of the two source pixels var alphaLerp = (1-fact)*pixelAlpha[0] + fact*pixelAlpha[1]; // Interpolate the alpha between the two pixels pixel_to_bmap( destinationBmp , dx , dy , pixel_for_vec( pixelColor[2] , alphaLerp , bmapFormat ) ); // Write to destination } else { // cx and cy are middles // We'll have to deal with 4 pixels for interpolation var sx1 = integer(sx); // Get X lower position var sx2 = ceil(sx); // Get X higher position var sy1 = integer(sy); // Y lower var sy2 = ceil(sy); // Y higher var pixel1 = pixel_for_bmap( sourceBmp , sx1 , sy1 ); // Get pixel values var pixel2 = pixel_for_bmap( sourceBmp , sx2 , sy1 ); var pixel3 = pixel_for_bmap( sourceBmp , sx1 , sy2 ); var pixel4 = pixel_for_bmap( sourceBmp , sx2 , sy2 ); COLOR pixelColor[6]; var pixelAlpha[4]; pixel_to_vec( pixelColor[0] , pixelAlpha[0] , bmapFormat , pixel1 ); // Get COLOR and pixel_to_vec( pixelColor[1] , pixelAlpha[1] , bmapFormat , pixel2 ); // Alpha values pixel_to_vec( pixelColor[2] , pixelAlpha[2] , bmapFormat , pixel3 ); pixel_to_vec( pixelColor[3] , pixelAlpha[3] , bmapFormat , pixel4 ); var fact1 = (sx - sx1) / (sx2 - sx1); // Calculate a X factor for interpolation var fact2 = (sy - sy1) / (sy2 - sy1); // Y factor for interpolation fact1 = minv(1 , (maxv(fact1,0))); // Limit factors between 0 and 1 fact2 = minv(1 , (maxv(fact2,0))); // just in case... vec_lerp( pixelColor[4] , pixelColor[0] , pixelColor[1] , fact1); // Interpolate between two lowerY pixels vec_lerp( pixelColor[5] , pixelColor[2] , pixelColor[3] , fact1); // Interpolate between two higherY pixels vec_lerp( pixelColor[6] , pixelColor[4] , pixelColor[5] , fact2); // Interpolate between resulting two pixels(Y axis) with Y factor var alphaLerp1 = (1-fact1)*pixelAlpha[0] + fact1*pixelAlpha[1]; // Interpolate two lowerY alphas var alphaLerp2 = (1-fact1)*pixelAlpha[2] + fact1*pixelAlpha[3]; // Interpolate two higherY alphas var alphaLerp3 = (1-fact2)*alphaLerp1 + fact2*alphaLerp2; // Interpolate between resulting alphas with Y factor (the resulting are Y axis aligned pixels) pixel_to_bmap( destinationBmp , dx , dy , pixel_for_vec( pixelColor[6] , alphaLerp3 , bmapFormat ) ); // Write destination final pixel } } } } } // Unlock the source and destination bitmaps // And return the pointer to the new scaled bitmap bmap_unlock( sourceBmp ); bmap_unlock( destinationBmp ); return destinationBmp; } // Takes: // - Pointer to terrain entity // - BMAP pointer of sprite to be drawn // - Position of sprite in skin bitmap coordinates (0,0 to SkinSize.X,SkinSize.Y) // - Angle to rotate the sprite (0 - no rotation) // - Sprite scale factor (1 - no scaling, 2 - double size...) function paintSpriteOnTerrain( ENTITY* terrainEnt , BMAP* sourceSpriteBmap , VECTOR* posVec , var spriteAngle , spriteScale ) { // If scale is NULL, set scale default 1 if( spriteScale == 0 ) { spriteScale = 1; } // If a scale is given, scale the source sprite if( spriteScale != 1 ) { // Scale takes a bitmap and a scale and returns a pointer to the scaled version of the bitmap sourceSpriteBmap = bmap_scale( sourceSpriteBmap , spriteScale ); } // Inverse the angle and limit (-180,180) spriteAngle *= -1; if( spriteAngle < -180 ) { spriteAngle += 360; } if( spriteAngle > 180 ) { spriteAngle -= 360; } // Lock the sourceSprite and set dimensions var bmapHandle2 = bmap_lock(sourceSpriteBmap , 0); var sWidth = bmap_width(sourceSpriteBmap); var sHeight = bmap_height(sourceSpriteBmap); var spriteDimensions = sWidth * sHeight; // Get cosine and sine of angle var rotCosine = cosv( spriteAngle ); var rotSine = sinv( spriteAngle ); // Calculate the new border points VECTOR destPoint[4]; vec_zero( destPoint[0] ); destPoint[1].x = (-sHeight*rotSine); destPoint[1].y = (sHeight*rotCosine); destPoint[2].x = (sWidth*rotCosine-sHeight*rotSine); destPoint[2].y = (sHeight*rotCosine+sWidth*rotSine); destPoint[3].x = (sWidth*rotCosine); destPoint[3].y = (sWidth*rotSine); // Set min and max dimensions for X and Y (can be negative) var minx = minv(destPoint[0].x,minv(destPoint[1].x,minv(destPoint[2].x,destPoint[3].x))); var miny = minv(destPoint[0].y,minv(destPoint[1].y,minv(destPoint[2].y,destPoint[3].y))); var maxx = maxv(destPoint[0].x,maxv(destPoint[1].x,maxv(destPoint[2].x,destPoint[3].x))); var maxy = maxv(destPoint[0].y,maxv(destPoint[1].y,maxv(destPoint[2].y,destPoint[3].y))); // Get final dimensions int nWidth=(int)ceil(abs(maxx)-minx); int nHeight=(int)ceil(abs(maxy)-miny); // Lock the terrain skin and get its dimensions BMAP* terrainSkin = bmap_for_entity(terrainEnt,0); var dWidth = bmap_width( terrainSkin ); var dHeight = bmap_height( terrainSkin ); var bmapHandle = bmap_lock(terrainSkin , 0); // Make sure the sprite wont go outside of the terrain skin posVec.x -= integer(nWidth / 2); posVec.y -= integer(nHeight / 2); if( posVec.x < 0 ) { posVec.x = 0; } if( posVec.y < 0 ) { posVec.y = 0; } if( posVec.x > dWidth - nWidth ) { posVec.x = dWidth - nWidth; } if( posVec.y > dHeight - nHeight ) { posVec.y = dHeight - nHeight; } // Terrain pixel COLOR terrainColor; var terrainAlpha; COLOR finalColor; // Source pixel VECTOR sourcePixelPos; COLOR currentPixelColor; var currentPixelAlpha; var i , j; // Itterate over destination pixels for( j = 0; j < nHeight ; j++ ) { for( i = 0; i < nWidth; i++ ) { // Calculate a source pixel based on current destination pixel rotated by the angle sourcePixelPos.x = integer( (i + minx) * rotCosine + (j + miny) * rotSine); sourcePixelPos.y = integer( (j + miny) * rotCosine - (i + minx) * rotSine); // If the pixel lies on the source image if( sourcePixelPos.x >= 0 && sourcePixelPos.x < sWidth && sourcePixelPos.y >= 0 && sourcePixelPos.y < sHeight ) { // Get the source pixel as COLOR and ALPHA pixel_to_vec( currentPixelColor , currentPixelAlpha , bmapHandle2 , pixel_for_bmap( sourceSpriteBmap , sourcePixelPos.x , sourcePixelPos.y ) ); // Ignore invisible pixels if( currentPixelAlpha > 0 ) { // Get terrain destination pixel pixel_to_vec( terrainColor , terrainAlpha , bmapHandle , pixel_for_bmap( terrainSkin , posVec.x + i , posVec.y + j ) ); // Interpolate a color between the the terrain pixel and the unrotated source pixel vec_lerp ( finalColor, terrainColor, currentPixelColor , currentPixelAlpha/100 ); // Write the interpolated pixel on the new position pixel_to_bmap( terrainSkin , posVec.x + i , posVec.y + j , pixel_for_vec( finalColor , 100 , bmapHandle) ); } } } } // Unlock the sprite and terrain bitmaps bmap_unlock(terrainSkin); bmap_unlock(sourceSpriteBmap); if( spriteScale != 1) { bmap_remove( sourceSpriteBmap ); } }
Have fun took me a while to make it...
PS.: I didn't needed it, but if you modify the loop in paintSpriteOnTerrain() you can get a separate function to just rotate a bitmap and return the rotated version as a pointer...
Oh, I almost forgot, after pixel rotation, interpolation has to be done too to get an accurate rotated image, but I'm using small sprites (32x32 or 64x64) so I didn't need additional complexity...
If you want to implement it, take as an example the interpolation done in bmap_scale.
*** EDIT *** The Engine crashes sometimes, and after looking at it for 20 seconds, my best guess is that it tries to access a NULL pointer.
Now, bmap_scale will return the source bitmap if it fails...
Here's the update with checks, but I deleted all comments in search for "Token too large" :
Code:
BMAP* bmap_scale( BMAP* sourceBmp , scaleFactor ) { if( !sourceBmp ) { return NULL; } if( scaleFactor == 0 || scaleFactor == 1 ) { return sourceBmp; } var sWidth = bmap_width( sourceBmp ); var sHeight = bmap_height( sourceBmp ); var bmapFormat = bmap_lock( sourceBmp , 0 ); if( bmapFormat == 0 ) { return sourceBmp; } var dWidth = sWidth * scaleFactor; var dHeight = sHeight * scaleFactor; BMAP* destinationBmp = bmap_createblack( (int)dWidth , (int)dHeight , bmap_format(sourceBmp) ); if( !destinationBmp ) { return sourceBmp; } var destBmapFormat = bmap_lock( destinationBmp , 0 ); if( destBmapFormat == 0 ) { return sourceBmp; } int dx, dy, sx, sy; for( dx = 0; dx < dWidth; dx++ ) { for( dy = 0; dy < dHeight; dy++ ) { sx = dx / scaleFactor; sy = dy / scaleFactor; if( sx == (int)sx && sy == (int)sy ) { pixel_to_bmap( destinationBmp , dx , dy , pixel_for_bmap( sourceBmp , sx , sy ) ); } else { if( sx == (int)sx && sy != (int)sy ) { var sy1 = integer(sy); var sy2 = ceil(sy); var pixel1 = pixel_for_bmap( sourceBmp , sx , sy1 ); var pixel2 = pixel_for_bmap( sourceBmp , sx , sy2 ); COLOR pixelColor[3]; var pixelAlpha[2]; pixel_to_vec( pixelColor[0] , pixelAlpha[0] , bmapFormat , pixel1 ); pixel_to_vec( pixelColor[1] , pixelAlpha[1] , bmapFormat , pixel2 ); var fact = sy - sy1; fact = minv(1 , (maxv(fact,0))); vec_lerp( pixelColor[2] , pixelColor[0] , pixelColor[1] , fact); var alphaLerp = (1-fact)*pixelAlpha[0] + fact*pixelAlpha[1]; pixel_to_bmap( destinationBmp , dx , dy , pixel_for_vec( pixelColor[2] , alphaLerp , bmapFormat ) ); } else { if( sx != (int)sx && sy == (int)sy ) { var sx1 = integer(sx); var sx2 = ceil(sx); var pixel1 = pixel_for_bmap( sourceBmp , sx1 , sy ); var pixel2 = pixel_for_bmap( sourceBmp , sx2 , sy ); COLOR pixelColor[3]; var pixelAlpha[2]; pixel_to_vec( pixelColor[0] , pixelAlpha[0] , bmapFormat , pixel1 ); pixel_to_vec( pixelColor[1] , pixelAlpha[1] , bmapFormat , pixel2 ); var fact = sx - sx1; fact = minv(1 , (maxv(fact,0))); vec_lerp( pixelColor[2] , pixelColor[0] , pixelColor[1] , fact); var alphaLerp = (1-fact)*pixelAlpha[0] + fact*pixelAlpha[1]; pixel_to_bmap( destinationBmp , dx , dy , pixel_for_vec( pixelColor[2] , alphaLerp , bmapFormat ) ); } else { var sx1 = integer(sx); var sx2 = ceil(sx); var sy1 = integer(sy); var sy2 = ceil(sy); var pixel1 = pixel_for_bmap( sourceBmp , sx1 , sy1 ); var pixel2 = pixel_for_bmap( sourceBmp , sx2 , sy1 ); var pixel3 = pixel_for_bmap( sourceBmp , sx1 , sy2 ); var pixel4 = pixel_for_bmap( sourceBmp , sx2 , sy2 ); COLOR pixelColor[6]; var pixelAlpha[4]; pixel_to_vec( pixelColor[0] , pixelAlpha[0] , bmapFormat , pixel1 ); pixel_to_vec( pixelColor[1] , pixelAlpha[1] , bmapFormat , pixel2 ); pixel_to_vec( pixelColor[2] , pixelAlpha[2] , bmapFormat , pixel3 ); pixel_to_vec( pixelColor[3] , pixelAlpha[3] , bmapFormat , pixel4 ); var fact1 = (sx - sx1) / (sx2 - sx1); var fact2 = (sy - sy1) / (sy2 - sy1); fact1 = minv(1 , (maxv(fact1,0))); fact2 = minv(1 , (maxv(fact2,0))); vec_lerp( pixelColor[4] , pixelColor[0] , pixelColor[1] , fact1); vec_lerp( pixelColor[5] , pixelColor[2] , pixelColor[3] , fact1); vec_lerp( pixelColor[6] , pixelColor[4] , pixelColor[5] , fact2); var alphaLerp1 = (1-fact1)*pixelAlpha[0] + fact1*pixelAlpha[1]; var alphaLerp2 = (1-fact1)*pixelAlpha[2] + fact1*pixelAlpha[3]; var alphaLerp3 = (1-fact2)*alphaLerp1 + fact2*alphaLerp2; pixel_to_bmap( destinationBmp , dx , dy , pixel_for_vec( pixelColor[6] , alphaLerp3 , bmapFormat ) ); } } } } } bmap_unlock( sourceBmp ); bmap_unlock( destinationBmp ); return destinationBmp; } function paintSpriteOnTerrain( ENTITY* terrainEnt , BMAP* sourceSpriteBmap , VECTOR* posVec , var spriteAngle , spriteScale ) { if( spriteScale == 0 ) { spriteScale = 1; } if( spriteScale != 1 ) { BMAP* scaledBmap; scaledBmap = sourceSpriteBmap = bmap_scale( sourceSpriteBmap , spriteScale ); if( scaledBmap == NULL ) { scaledBmap = sourceSpriteBmap; } sourceSpriteBmap = scaledBmap; } spriteAngle *= -1; if( spriteAngle < -180 ) { spriteAngle += 360; } if( spriteAngle > 180 ) { spriteAngle -= 360; } var bmapHandle2 = bmap_lock(sourceSpriteBmap , 0); if( bmapHandle2 == 0 ) { return; } var sWidth = bmap_width(sourceSpriteBmap); var sHeight = bmap_height(sourceSpriteBmap); var spriteDimensions = sWidth * sHeight; var rotCosine = cosv( spriteAngle ); var rotSine = sinv( spriteAngle ); VECTOR destPoint[4]; vec_zero( destPoint[0] ); destPoint[1].x = (-sHeight*rotSine); destPoint[1].y = (sHeight*rotCosine); destPoint[2].x = (sWidth*rotCosine-sHeight*rotSine); destPoint[2].y = (sHeight*rotCosine+sWidth*rotSine); destPoint[3].x = (sWidth*rotCosine); destPoint[3].y = (sWidth*rotSine); var minx = minv(destPoint[0].x,minv(destPoint[1].x,minv(destPoint[2].x,destPoint[3].x))); var miny = minv(destPoint[0].y,minv(destPoint[1].y,minv(destPoint[2].y,destPoint[3].y))); var maxx = maxv(destPoint[0].x,maxv(destPoint[1].x,maxv(destPoint[2].x,destPoint[3].x))); var maxy = maxv(destPoint[0].y,maxv(destPoint[1].y,maxv(destPoint[2].y,destPoint[3].y))); int nWidth=(int)ceil(abs(maxx)-minx); int nHeight=(int)ceil(abs(maxy)-miny); BMAP* terrainSkin = bmap_for_entity(terrainEnt,0); if( terrainSkin == NULL ) { return; } var dWidth = bmap_width( terrainSkin ); var dHeight = bmap_height( terrainSkin ); var bmapHandle = bmap_lock(terrainSkin , 0); if( bmapHandle == 0 ) { return; } posVec.x -= integer(nWidth / 2); posVec.y -= integer(nHeight / 2); if( posVec.x < 0 ) { posVec.x = 0; } if( posVec.y < 0 ) { posVec.y = 0; } if( posVec.x > dWidth - nWidth ) { posVec.x = dWidth - nWidth; } if( posVec.y > dHeight - nHeight ) { posVec.y = dHeight - nHeight; } COLOR terrainColor; var terrainAlpha; COLOR finalColor; VECTOR sourcePixelPos; COLOR currentPixelColor; var currentPixelAlpha; var i , j; for( j = 0; j < nHeight ; j++ ) { for( i = 0; i < nWidth; i++ ) { sourcePixelPos.x = integer( (i + minx) * rotCosine + (j + miny) * rotSine); sourcePixelPos.y = integer( (j + miny) * rotCosine - (i + minx) * rotSine); if( sourcePixelPos.x >= 0 && sourcePixelPos.x < sWidth && sourcePixelPos.y >= 0 && sourcePixelPos.y < sHeight ) { pixel_to_vec( currentPixelColor , currentPixelAlpha , bmapHandle2 , pixel_for_bmap( sourceSpriteBmap , sourcePixelPos.x , sourcePixelPos.y ) ); if( currentPixelAlpha > 0 ) { pixel_to_vec( terrainColor , terrainAlpha , bmapHandle , pixel_for_bmap( terrainSkin , posVec.x + i , posVec.y + j ) ); vec_lerp ( finalColor, terrainColor, currentPixelColor , currentPixelAlpha/100 ); pixel_to_bmap( terrainSkin , posVec.x + i , posVec.y + j , pixel_for_vec( finalColor , 100 , bmapHandle) ); } } } } bmap_unlock(terrainSkin); bmap_unlock(sourceSpriteBmap); if( spriteScale != 1) { bmap_remove( sourceSpriteBmap ); } }