5 registered members (AndrewAMD, SBGuy, Petra, flink, 1 invisible),
699
guests, and 6
spiders. |
Key:
Admin,
Global Mod,
Mod
|
|
|
bmap_scale and paint on terrain at position
#457270
01/11/16 11:39
01/11/16 11:39
|
Joined: Jan 2006
Posts: 968
EpsiloN
OP
User
|
OP
User
Joined: Jan 2006
Posts: 968
|
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:
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:
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:
// 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" :
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 );
}
}
Last edited by EpsiloN; 01/11/16 12:38.
|
|
|
Re: bmap_scale and paint on terrain at position
[Re: EpsiloN]
#458718
03/26/16 10:47
03/26/16 10:47
|
Joined: Jan 2006
Posts: 968
EpsiloN
OP
User
|
OP
User
Joined: Jan 2006
Posts: 968
|
And, since you're gonna use this, here's the final function I used, because bmap_scale gave some wrong results and errors (probably bad memory management):
function paintSpriteOnTerrain( ENTITY* terrainEnt , BMAP* sourceSpriteBmap , VECTOR* posVec , spriteAngle , spriteScale ) {
if( !terrainEnt || !sourceSpriteBmap ) { return; }
if( spriteScale == 0 ) { spriteScale = 1; }
var sWidth = bmap_width(sourceSpriteBmap) * spriteScale;
var sHeight = bmap_height(sourceSpriteBmap) * spriteScale;
// Create the spriteBmap pointer global and create a bitmap for it one time only
// Blit each time the sprite is used
// to save some run-time...
BMAP* spriteBmap = bmap_createblack( sWidth, sHeight, bmap_format(sourceSpriteBmap) );
bmap_blit( spriteBmap, sourceSpriteBmap, NULL , vector(sWidth, sHeight, 0) );
spriteAngle *= -1;
if( spriteAngle < -180 ) { spriteAngle += 360; }
if( spriteAngle > 180 ) { spriteAngle -= 360; }
var bmapHandle2 = bmap_lock(spriteBmap , 0);
if( bmapHandle2 == 0 ) { return; }
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( spriteBmap , 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(spriteBmap);
bmap_remove( spriteBmap );
}
I cant say this is bug-free, because I dropped the project 3 months ago (didn't win the contest) but, I remember it working the last time.
|
|
|
Re: bmap_scale and paint on terrain at position
[Re: EpsiloN]
#458719
03/26/16 11:21
03/26/16 11:21
|
Joined: Dec 2011
Posts: 1,823 Netherlands
Reconnoiter
Serious User
|
Serious User
Joined: Dec 2011
Posts: 1,823
Netherlands
|
Thanks man, it works now. I will keep an eye on the bugs, if you want I could let you know later after a few weeks if it is fully safe to us.
For others who use this: - so far found 1 bug: if the image becomes to big (either has to do with going beyond the terrain or perhaps bigger than the terrain's texture), you will get a crash. Easy to workaround though.
Last edited by Reconnoiter; 03/26/16 11:25.
|
|
|
|