Gamestudio Links
Zorro Links
Newest Posts
Blobsculptor tools and objects download here
by NeoDumont. 03/28/24 03:01
Issue with Multi-Core WFO Training
by aliswee. 03/24/24 20:20
Why Zorro supports up to 72 cores?
by Edgar_Herrera. 03/23/24 21:41
Zorro Trader GPT
by TipmyPip. 03/06/24 09:27
VSCode instead of SED
by 3run. 03/01/24 19:06
AUM Magazine
Latest Screens
The Bible Game
A psychological thriller game
SHADOW (2014)
DEAD TASTE
Who's Online Now
2 registered members (degenerate_762, Nymphodora), 1,012 guests, and 3 spiders.
Key: Admin, Global Mod, Mod
Newest Members
sakolin, rajesh7827, juergen_wue, NITRO_FOREVER, jack0roses
19043 Registered Users
Previous Thread
Next Thread
Print Thread
Rate Thread
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 Offline OP
User
EpsiloN  Offline 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 laugh

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 laugh 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" grin :
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 );
	}
}



Last edited by EpsiloN; 01/11/16 12:38.

Extensive Multiplayer tutorial:
http://mesetts.com/index.php?page=201
Re: bmap_scale and paint on terrain at position [Re: EpsiloN] #458689
03/25/16 10:39
03/25/16 10:39
Joined: Dec 2011
Posts: 1,823
Netherlands
Reconnoiter Offline
Serious User
Reconnoiter  Offline
Serious User

Joined: Dec 2011
Posts: 1,823
Netherlands
Sry for being the necro here; but I just noticed this and looks very handy (especially since I want to focus more on top-down/rts perspective too). Thanks for sharing EpsiloN!

Re: bmap_scale and paint on terrain at position [Re: Reconnoiter] #458693
03/25/16 11:46
03/25/16 11:46
Joined: Dec 2011
Posts: 1,823
Netherlands
Reconnoiter Offline
Serious User
Reconnoiter  Offline
Serious User

Joined: Dec 2011
Posts: 1,823
Netherlands
I get an error with "ceil" (not recognized), do I have to include a specific header or such? tnx

Re: bmap_scale and paint on terrain at position [Re: Reconnoiter] #458717
03/26/16 10:39
03/26/16 10:39
Joined: Jan 2006
Posts: 968
EpsiloN Offline OP
User
EpsiloN  Offline OP
User

Joined: Jan 2006
Posts: 968
Oh, sorry, I forgot about those laugh
Code:
function ceil( var x ) {
	if( x < integer(x) ) x++;
	return x;
}



Extensive Multiplayer tutorial:
http://mesetts.com/index.php?page=201
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 Offline OP
User
EpsiloN  Offline 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):

Code:
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 laugh (didn't win the contest) but, I remember it working the last time.


Extensive Multiplayer tutorial:
http://mesetts.com/index.php?page=201
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 Offline
Serious User
Reconnoiter  Offline
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.
Re: bmap_scale and paint on terrain at position [Re: Reconnoiter] #458724
03/26/16 19:26
03/26/16 19:26
Joined: Jan 2006
Posts: 968
EpsiloN Offline OP
User
EpsiloN  Offline OP
User

Joined: Jan 2006
Posts: 968
Yeah, let me know if there is something hiding.

By the way, I thought I clipped the image if it goes outside of the terrain, but for images bigger than the terrain I never checked, because I needed this for blood splashing laugh

I'm glad its useful laugh


Extensive Multiplayer tutorial:
http://mesetts.com/index.php?page=201

Moderated by  HeelX, Lukas, rayp, Rei_Ayanami, Superku, Tobias, TWO, VeT 

Gamestudio download | chip programmers | Zorro platform | shop | Data Protection Policy

oP group Germany GmbH | Birkenstr. 25-27 | 63549 Ronneburg / Germany | info (at) opgroup.de

Powered by UBB.threads™ PHP Forum Software 7.7.1