Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Messages - Scavenger

#201
This is a problem with engine scaling, I think. I resized it down from 1280x720 to 640x360 again and the text looked fine:

[imgzoom]https://dl.dropboxusercontent.com/u/50882197/art/GameStuff/unscaled.PNG[/imgzoom]

(Could you try looking at your game running at 1x scaling?)

I also made an empty project and imported the same font and text into a standard resolution - 640x400, and scaled that up to 1280x800:

[imgzoom]https://dl.dropboxusercontent.com/u/50882197/art/GameStuff/640x400_text.PNG[/imgzoom]
And it looks fine. I'm thinking it has to do with the scaler not playing well with custom resolutions.

Your entire screenshot looks like it's being unevenly scaled, with subpixels everywhere. I'm not sure why this would be, especially because 1280x720 is an even double of 640x360. But there is DEFINITELY a lot of uneven pixelation going on.
#203
Ags stores all sprites in the same format, and uses only rle compression if you compress the sprite file.

Jpgs imported as sprites would generally be larger if you have large areas of flat colour. Png is always preferable, though. It doesn't destroy a sprite.
#204
Khris : I've already implemented objects like that, but this is for fences, doors, and other wall types that the  player needs to see through. I'm just using the column texture because it's already on the texture map.

My biggest problem thus far is trying to get the ray caster to hit the back walls of a cube at all, I'm not sure how to do it. The method I tried just renders it to the front wall texture and that's definitely not what I need. How do I get the ray to hit the rear face at all?

EDIT: It's been solved, I needed to flip the signs on a lot of the math in case of drawing the opposite wall, and offset the floorcasting by one unit to compensate:



This'll be useful for all of my fence, door, and mysterious shaft of light needs!

Though now I have a new problem: Drawing the back face without first drawing the front face, like so:



The wall only gets drawn if the front face is drawn first (which triggers the Opposite flag), but I'm not sure how to make it so that the opposite wall is drawn when it's visible, rather than when the ray passes right through the block. You can see that the left block there makes the opposite side of the right block visible, but it doesn't draw the back face. What IS good is that fully solid blocks are drawn as well as the transparent blocks, with no z-fighting.

Code: C++

void Raycast_Render (int slot)
{
	long w=0,h=0;
	BITMAP *screen = engine->GetSpriteGraphic (slot);
	engine->GetBitmapDimensions (screen,&w,&h,NULL);
	unsigned char** buffer = engine->GetRawBitmapSurface (screen);
	for (int x = 0;x<w;x++)
	{
		for (int y=0;y<h;y++)
		{
			ZBuffer[x][y] = 0;
		}
	}
  //start the main loop
    for(int x = 0; x < w; x++)
    {
      //calculate ray position and direction 
      double cameraX = 2 * x / double(w) - 1; //x-coordinate in camera space     
      double rayPosX = posX;
      double rayPosY = posY;
      double rayDirX = dirX + planeX * cameraX;
      double rayDirY = dirY + planeY * cameraX;
     
      //which box of the map we're in  
      int mapX = int(rayPosX);
      int mapY = int(rayPosY);
       
      //length of ray from current position to next x or y-side
      double sideDistX;
      double sideDistY;
       
      //length of ray from one x or y-side to next x or y-side
      double deltaDistX = sqrt(1 + (rayDirY * rayDirY) / (rayDirX * rayDirX));
      double deltaDistY = sqrt(1 + (rayDirX * rayDirX) / (rayDirY * rayDirY));
      double perpWallDist;
       
      //what direction to step in x or y-direction (either +1 or -1)
      int stepX;
      int stepY;
      int prevmapX=0;
	  int prevmapY=0;
      int hit = 0; //was there a wall hit?
      int side; //was a NS or a EW wall hit?
	  
      //calculate step and initial sideDist
      if (rayDirX < 0)
      {
        stepX = -1;
        sideDistX = (rayPosX - mapX) * deltaDistX;
      }
      else
      {
        stepX = 1;
        sideDistX = (mapX + 1.0 - rayPosX) * deltaDistX;
      }
      if (rayDirY < 0)
      {
        stepY = -1;
        sideDistY = (rayPosY - mapY) * deltaDistY;
      }
      else
      {
        stepY = 1;
        sideDistY = (mapY + 1.0 - rayPosY) * deltaDistY;
      }
      //perform DDA
	  bool deeper = true;
	  bool opposite = false;
	  bool oppositedrawn = false;
	  double wallX; //where exactly the wall was hit
	  int drawStart;
	  int drawEnd;
      while (hit == 0 && deeper == true)
	  {
		if (opposite)
		{
			  rayDirX = rayDirX * (-1);
			  rayDirY = rayDirY * (-1);
			  stepX = stepX * (-1);
			  stepY = stepY * (-1);
			  if (sideDistX < sideDistY) side = 0;
			  else side = 1;
		}
		else if (sideDistX < sideDistY) //jump to next map square, OR in x-direction, OR in y-direction
        {
          sideDistX += deltaDistX;
          mapX += stepX;
          side = 0;
        }
        else
        {
          sideDistY += deltaDistY;
          mapY += stepY;
          side = 1;
        }
        //Check if ray has hit a wall       
        if (worldMap[mapX][mapY] > 0)
		{
			hit = 1; //Set this to true so that by default, it's impossible to hang the engine.
			deeper = false; //Set this to false so that we don't go deeper than we need to.

			//Calculate distance of perpendicular ray (oblique distance will give fisheye effect!)    
			if (side == 0) perpWallDist = fabs((mapX - rayPosX + (1 - stepX) / 2) / rayDirX);
			else       perpWallDist = fabs((mapY - rayPosY + (1 - stepY) / 2) / rayDirY);
			 //Calculate height of line to draw on screen       
     		 int lineHeight = abs(int(h / perpWallDist));
     		 
     		 //calculate lowest and highest pixel to fill in current stripe
     		 drawStart = -lineHeight / 2 + h /2;
     		 if(drawStart < 0) drawStart = 0;
     		 drawEnd = lineHeight / 2 + h / 2;
     		 if(drawEnd >= h) drawEnd = h - 1;
     		 //texturing calculations
     		 int texNum = worldMap[mapX][mapY] - 1; //1 subtracted from it so that texture 0 can be used!
     		 if (!opposite)
			 {	 
     		 //calculate value of wallX
     		 if (side == 1) wallX = rayPosX + ((mapY - rayPosY + (1 - stepY) / 2) / rayDirY) * rayDirX;
     		 else       wallX = rayPosY + ((mapX - rayPosX + (1 - stepX) / 2) / rayDirX) * rayDirY;
			 }
			 else
			 {
				if (side == 1) wallX = rayPosX + ((mapY - rayPosY + (1 - stepY) / 2) / -rayDirY) * -rayDirX;
     			else       wallX = rayPosY + ((mapX - rayPosX + (1 - stepX) / 2) / -rayDirX) * -rayDirY;
			 }
     		 wallX -= floor((wallX));
     		  
     		 //x coordinate on the texture
	 		 int wall_light=0;
     		 int texX = int(wallX * double(texWidth));
     		 if(side == 0 && rayDirX > 0) texX = texWidth - texX - 1;
     		 if(side == 1 && rayDirY < 0) texX = texWidth - texX - 1;
			 if (!opposite)
			 {
	 		 if (rayDirX > 0 && side == 0) wall_light = 255 / (8-lightMap [(int)mapX-1][(int)mapY]);
	 		 if (rayDirX < 0 && side == 0) wall_light = 255 / (8-lightMap [(int)mapX+1][(int)mapY]);
	 		 if (rayDirY > 0 && side == 1) wall_light = 255 / (8-lightMap [(int)mapX][(int)mapY-1]);
	 		 if (rayDirY < 0 && side == 1) wall_light = 255 / (8-lightMap [(int)mapX][(int)mapY+1]);
			 }
			 else if (opposite) wall_light = 255 / (8-lightMap [(int)mapX][(int)mapY]);
     		 for(int y = drawStart; y < drawEnd; y++)
     			{
					if (ZBuffer[x][y] > perpWallDist || ZBuffer[x][y] == 0) //We can draw.
					{
     				int d = y * 256 - h * 128 + lineHeight * 128; //256 and 128 factors to avoid floats
     			 	int texY = ((d * texHeight) / lineHeight) / 256;
     				int color = texture[texNum][texWidth * texY + texX];
     				if (color > 0)
						{
							color = MixColorAlpha (color,GetColor565(0,0,10),wall_light);
							buffer[y][x] = color;
							//SET THE ZBUFFER FOR THE SPRITE CASTING
							ZBuffer[x][y] = perpWallDist; //perpendicular distance is used
						}
					else
						{
							//We found transparency, we have to draw deeper.
							deeper = true;
							hit = 0;
						}
					}
     			}
			 if (opposite)
			 {
				 oppositedrawn = true;
				 if (deeper) opposite = false;
				 rayDirX = rayDirX * (-1);
				 rayDirY = rayDirY * (-1);
				 stepX = stepX * (-1);
				 stepY = stepY * (-1);
			 }
			 else if (!opposite && deeper && (prevmapX != mapX && prevmapY != mapY))
			 {
				 opposite = true;
				 prevmapX = mapX;
				 prevmapY = mapY;
			 }
			//End of wall drawing functions.
			}
		//End of loop.
		}
      
      //FLOOR CASTING
      double floorXWall, floorYWall; //x, y position of the floor texel at the bottom of the wall
      //4 different wall directions possible
      if(side == 0 && rayDirX > 0)
      {
        floorXWall = mapX;
        floorYWall = mapY + wallX;
		if (opposite) floorXWall = floorXWall + 1.0;
      }
      else if(side == 0 && rayDirX < 0)
      {
        floorXWall = mapX + 1.0;
        floorYWall = mapY + wallX;
		if (opposite) floorXWall = floorXWall - 1.0;
      }
      else if(side == 1 && rayDirY > 0)
      {
        floorXWall = mapX + wallX;
        floorYWall = mapY;
		if (opposite) floorYWall = floorYWall + 1.0;
      }
      else
      {
        floorXWall = mapX + wallX;
        floorYWall = mapY + 1.0;
		if (opposite) floorYWall = floorYWall - 1.0;
      }
      
      double distWall, distPlayer, currentDist;

      distWall = perpWallDist;
      distPlayer = 0.0;
      if (drawEnd < 0) drawEnd = h; //becomes < 0 when the integer overflows
      //draw the floor from drawEnd to the bottom of the screen
      for(int y = drawEnd; y < h; y++)
      {
        currentDist = h / (2.0 * y - h); //you could make a small lookup table for this instead
		if (currentDist < ZBuffer[x][y] || ZBuffer[x][y] == 0)
		{
			double weight = (currentDist - distPlayer) / (distWall - distPlayer);
         
			double currentFloorX = weight * floorXWall + (1.0 - weight) * posX;
			double currentFloorY = weight * floorYWall + (1.0 - weight) * posY;
        
			int floorTexX, floorTexY;
			int lighting = 255 / (8-lightMap [(int)currentFloorX][(int)currentFloorY]);
			floorTexX = int(currentFloorX * texWidth) % texWidth;
			floorTexY = int(currentFloorY * texHeight) % texHeight; 
        
			//floor
			buffer[y][x] = MixColorAlpha(texture[3][texWidth * floorTexY + floorTexX],GetColor565(0,0,10),lighting);
			//ceiling (symmetrical!)
			buffer[h-y][x] = MixColorAlpha(texture[6][texWidth * floorTexY + floorTexX],GetColor565(0,0,10),lighting);
			//SET THE ZBUFFER FOR THE SPRITE CASTING
			ZBuffer[x][y] = currentDist; //perpendicular distance is used
			ZBuffer[x][h-y] = currentDist; //perpendicular distance is used
		}
      }
    }
    
	

    //SPRITE CASTING
    //sort sprites from far to close

    for(int i = 0; i < numSprites; i++)
    {
      spriteOrder[i] = i;
      spriteDistance[i] = ((posX - sprite[i].x) * (posX - sprite[i].x) + (posY - sprite[i].y) * (posY - sprite[i].y)); //sqrt not taken, unneeded
    }
    combSort(spriteOrder, spriteDistance, numSprites);
     
    //after sorting the sprites, do the projection and draw them
    for(int i = 0; i < numSprites; i++)
    {
      //translate sprite position to relative to camera
      double spriteX = sprite[spriteOrder[i]].x - posX;
      double spriteY = sprite[spriteOrder[i]].y - posY;
         
      //transform sprite with the inverse camera matrix
      // [ planeX   dirX ] -1                                       [ dirY      -dirX ]
      // [               ]       =  1/(planeX*dirY-dirX*planeY) *   [                 ]
      // [ planeY   dirY ]                                          [ -planeY  planeX ]
      
      double invDet = 1.0 / (planeX * dirY - dirX * planeY); //required for correct matrix multiplication
      
      double transformX = invDet * (dirY * spriteX - dirX * spriteY);
      double transformY = invDet * (-planeY * spriteX + planeX * spriteY); //this is actually the depth inside the screen, that what Z is in 3D       
            
      int spriteScreenX = int((w / 2) * (1 + transformX / transformY));
      
      //parameters for scaling and moving the sprites
      #define uDiv 1
      #define vDiv 1
      #define vMove 0.0
      int vMoveScreen = int(vMove / transformY);
      
      //calculate height of the sprite on screen
      int spriteHeight = abs(int(h / (transformY))) / vDiv; //using "transformY" instead of the real distance prevents fisheye
      //calculate lowest and highest pixel to fill in current stripe
      int drawStartY = -spriteHeight / 2 + h / 2 + vMoveScreen;
      if(drawStartY < 0) drawStartY = 0;
      int drawEndY = spriteHeight / 2 + h / 2 + vMoveScreen;
      if(drawEndY >= h) drawEndY = h - 1;
      
      //calculate width of the sprite
      int spriteWidth = abs( int (h / (transformY))) / uDiv;
      int drawStartX = -spriteWidth / 2 + spriteScreenX;
      if(drawStartX < 0) drawStartX = 0;
      int drawEndX = spriteWidth / 2 + spriteScreenX;
      if(drawEndX >= w) drawEndX = w - 1;
      int spr_light = 255 / (8-lightMap [(int)sprite[spriteOrder[i]].x][(int)sprite[spriteOrder[i]].y]);
      //loop through every vertical stripe of the sprite on screen
      for(int stripe = drawStartX; stripe < drawEndX; stripe++)
      {
        int texX = int(256 * (stripe - (-spriteWidth / 2 + spriteScreenX)) * texWidth / spriteWidth) / 256;
        //the conditions in the if are:
        //1) it's in front of camera plane so you don't see things behind you
        //2) it's on the screen (left)
        //3) it's on the screen (right)
        //4) ZBuffer, with perpendicular distance
        if(transformY > 0 && stripe > 0 && stripe < w) 
        for(int y = drawStartY; y < drawEndY; y++) //for every pixel of the current stripe
        {
		  if (transformY < ZBuffer[stripe][y])
		  {
			int d = (y-vMoveScreen) * 256 - h * 128 + spriteHeight * 128; //256 and 128 factors to avoid floats
			int texY = ((d * texHeight) / spriteHeight) / 256;
			unsigned char color = texture[sprite[spriteOrder[i]].texture][texWidth * texY + texX]; //get current color from the texture
			if (color !=0) 
			{
				  color = MixColorAlpha (color,GetColor565(0,0,10),spr_light);
				  buffer[y][stripe] = color; //paint pixel if it isn't black, black is the invisible color
		  }
		  }
        }
      }
	  
    }
	engine->ReleaseBitmapSurface (screen);
	engine->NotifySpriteUpdated (slot);
}


EDIT (again): Solved that. I should have this engine ready really soon!

#205
I'm trying to write a raycaster for AGS (that can be controlled from within AGS using sprites as maps and stuff), and it's going pretty well. I currently have a very very simple raycaster working, based on this tutorial, and I've added light levels and stuff to it, and am currently working on transparent walls. Unfortunately, I've run into a problem I can't solve myself, and I'm not sure where else to turn to. I know I'm asking a lot of non-AGSScript questions, but I really can't do this in AGSScript without it requiring a futuristic supercomputer.

My problem is that I can't seem to get the back face of a cube to render properly. This is what I got so far:


The cube has the pillar texture on all four faces, so in reality, it's got to look something like this, with the pillar texture visible at the back as well. But my attempts, well, they're not going well. I end up with an infinite line of "other walls", instead of just the one I wanted. You can see that the opposite wall of the cube just goes on forever when you look into it. I'm not even sure how it's doing that. And the adjacent wall isn't drawn at all, to be expected, but I'm not sure how to do that either.



My method is:
1) Cast ray
2) Continue until it hits a wall.
2) Start drawing that wall, using the ZBuffer to mask out anything already drawn in front of it.
3) If the wall has any transparent pixels, flag the thing to draw deeper.
4) On the next pass, draw the back face by flipping the ray direction and manually stepping to the next intersection.
5) Goto 2 afterwards to draw the wall behind it.

I'm sure I'm doing this wrong, but I'm not sure how to fix it, I don't understand the code well enough to do anything constructive with it. Is there anything I can do to stop this? Is there a better way to be doing this?

My code for drawing walls is:
Code: C++
 while (hit == 0 && deeper == true)
{
	if (opposite)
	{
		rayDirX = rayDirX * (-1);
		rayDirY = rayDirY * (-1);
		stepX = stepX * (-1);
		stepY = stepY * (-1);
        }
	else if (sideDistX < sideDistY) //jump to next map square, OR in x-direction, OR in y-direction
        {
          sideDistX += deltaDistX;
          mapX += stepX;
          side = 0;
        }
        else
        {
          sideDistY += deltaDistY;
          mapY += stepY;
          side = 1;
        }
        //Check if ray has hit a wall       
        if (worldMap[mapX][mapY] > 0)
		{
			hit = 1; //Set this to true so that by default, it's impossible to hang the engine.
			deeper = false; //Set this to false so that we don't go deeper than we need to.

			//Calculate distance of perpendicular ray (oblique distance will give fisheye effect!)    
			if (side == 0) perpWallDist = fabs((mapX - rayPosX + (1 - stepX) / 2) / rayDirX);
			else       perpWallDist = fabs((mapY - rayPosY + (1 - stepY) / 2) / rayDirY);
      
			 //Calculate height of line to draw on screen       
     		 int lineHeight = abs(int(h / perpWallDist));
     		 
     		 //calculate lowest and highest pixel to fill in current stripe
     		 drawStart = -lineHeight / 2 + h /2;
     		 if(drawStart < 0) drawStart = 0;
     		 drawEnd = lineHeight / 2 + h / 2;
     		 if(drawEnd >= h) drawEnd = h - 1;
     		 //texturing calculations
     		 int texNum = worldMap[mapX][mapY] - 1; //1 subtracted from it so that texture 0 can be used!
     		 
     		 //calculate value of wallX
     		 if (side == 1) wallX = rayPosX + ((mapY - rayPosY + (1 - stepY) / 2) / rayDirY) * rayDirX;
     		 else       wallX = rayPosY + ((mapX - rayPosX + (1 - stepX) / 2) / rayDirX) * rayDirY;
     		 wallX -= floor((wallX));
     		  
     		 //x coordinate on the texture
	 		 int wall_light=0;
     		 int texX = int(wallX * double(texWidth));
     		 if(side == 0 && rayDirX > 0) texX = texWidth - texX - 1;
     		 if(side == 1 && rayDirY < 0) texX = texWidth - texX - 1;
	 	 if (rayDirX > 0 && side == 0) wall_light = 255 / (8-lightMap [(int)mapX-1][(int)mapY]);
	 	 if (rayDirX < 0 && side == 0) wall_light = 255 / (8-lightMap [(int)mapX+1][(int)mapY]);
	 	 if (rayDirY > 0 && side == 1) wall_light = 255 / (8-lightMap [(int)mapX][(int)mapY-1]);
	 	 if (rayDirY < 0 && side == 1) wall_light = 255 / (8-lightMap [(int)mapX][(int)mapY+1]);
     		 for(int y = drawStart; y < drawEnd; y++)
     			{
				if (ZBuffer[x][y] > perpWallDist || ZBuffer[x][y] == 0) //We can draw.
				{
     				    int d = y * 256 - h * 128 + lineHeight * 128; //256 and 128 factors to avoid floats
     			 	    int texY = ((d * texHeight) / lineHeight) / 256;
     				    int color = texture[texNum][texWidth * texY + texX];
     				    if (color > 0)
					{
					    color = MixColorAlpha (color,GetColor565(0,0,10),wall_light);
					    buffer[y][x] = color;
					    //SET THE ZBUFFER FOR THE SPRITE CASTING
					    ZBuffer[x][y] = perpWallDist; //perpendicular distance is used
					}
					else
					{
					    //We found transparency, we have to draw deeper.
					    deeper = true;
					    hit = 0;
					}
				}
     			}
			 if (opposite)
			 {
				 opposite = false;
				 rayDirX = rayDirX * (-1);
				 rayDirY = rayDirY * (-1);
				 stepX = stepX * (-1);
				 stepY = stepY * (-1);
			 }
			 else if (!opposite && deeper && (prevmapX != mapX && prevmapY != mapY))
			 {
				 opposite = true;
				 prevmapX = mapX;
				 prevmapY = mapY;
			 }
			//End of wall drawing functions.
			}
		//End of loop.
}



Full code is here in case I've missed anything out.

Thank you in advance, and sorry for filling the technical forum.
#206
You can do a really quick outline with:

Code: AGS

DynamicSprite *outlinespr;

function OutlineSprite (int slot,int color)
{
    DynamicSprite *sprol = DynamicSprite.CreateFromExistingSprite (slot);
    DrawingSurface *surf = sprol.GetDrawingSurface ();
    surf.Clear (color);
    surf.Release ();
    sprol.CopyTransparencyMask (slot);
    outlinespr = DynamicSprite.CreateFromExistingSprite (slot);
    surf = outlinespr.GetDrawingSurface ();
    surf.Clear (COLOR_TRANSPARENT);
    surf.DrawImage (sprol.Graphic,-1, 0);
    surf.DrawImage (sprol.Graphic, 1, 0);
    surf.DrawImage (sprol.Graphic, 0,-1);
    surf.DrawImage (sprol.Graphic, 0, 1);
    surf.DrawImage (slot,0,0);
    surf.Release ();
}


It's probably the easiest thing you can do without going into Get/DrawPixel, which are ungodly slow.
#207
Star Wars? At Christmastime? That can only mean one thing!

[imgzoom]https://dl.dropboxusercontent.com/u/50882197/art/starwarsholidayspecial.PNG[/imgzoom]

Lumpawaroo, Mallatobuck, Attichitcuk, and Gormaanda join us this Life Day for a Holiday Special!
#208
I got a faster sine function that I want to use in AGS (gotta keep up the speed wherever I can), that I've already used internally in my plugin elsewhere, but I don't seem to be able to get AGS to recognize the floating point number as a floating point number. Here's the relevant code:

Code: C++

const char *ourScriptHeader =
  "struct PALInternal {\r\n"
  "///Polynomial Sine Approximation.\r\n"
  "import static float FastSin (float x);// $AUTOCOMPLETESTATICONLY$\r\n"
  "///Polynomial Cosine Approximation.\r\n"
  "import static float FastCos (float x);// $AUTOCOMPLETESTATICONLY$\r\n"
  "int dummy; //$AUTOCOMPLETEIGNORE$\r\n"
  "};\r\n";

float FastSin(float x)
{
  // wrap x within [0, TWO_PI)
  const float a = x * twopi_inv;
  x -= static_cast<int>(a) * twopi;
  if (x < 0.0f)
    x += twopi;

  // 4 pieces of hills
  if (x < halfpi)
    return Hill(halfpi - x);
  else if (x < PI)
    return Hill(x - halfpi);
  else if (x < 3.0f * halfpi)
    return -Hill(3.0f * halfpi - x);
  else
    return -Hill(x - 3.0f * halfpi);
}

float FastCos(float x)
{
  return FastSin(x + halfpi);
}

//later on....
  engine->RegisterScriptFunction ("PALInternal::FastSin^1", FastSin);
  engine->RegisterScriptFunction ("PALInternal::FastCos^1", FastCos);


I dunno what I have to return to get AGS to recognize this float as a float. I read through AGS' source code a bit earlier, and it... looked like floats might not actually be literally floats? What do I have to cast the result as in order for AGS to recognize it as a float? I've seen a couple of other plugins returning floats (like the AGSSteam stub), so it's gotta be possible somehow, but I'm not sure how. The code for the AGS float type is a bit intimidating.

(Also I learned today that you can declare enums in a plugin, so that's amazing)

EDIT: Whoops, sorry, I delved further into the code and managed to come up with a solution. Hopefully this can help other people as well:

Code: ags

//Add this at the top
#define SCRIPT_FLOAT(x) signed int __script_float##x
#define INIT_SCRIPT_FLOAT(x) float x; memcpy(&x, &__script_float##x, sizeof(float))
#define FLOAT_RETURN_TYPE signed int
#define RETURN_FLOAT(x) signed int __ret##x; memcpy(&__ret##x, &x, sizeof(float)); return __ret##x


//Wrap functions so that they return a "float".
FLOAT_RETURN_TYPE AGSFastSin (SCRIPT_FLOAT(x))
{
	INIT_SCRIPT_FLOAT (x);
	x = FastSin (x);
	RETURN_FLOAT (x);
}

FLOAT_RETURN_TYPE AGSFastCos (SCRIPT_FLOAT(x))
{
	INIT_SCRIPT_FLOAT (x);
	x = FastSin (x+halfpi);
	RETURN_FLOAT (x);
}
#209
Aw man, I wasn't expecting to be in the running for winning! Everyone's entries were SO GOOD! You all did really well! I will wear my trophy with pride.

Tabata's entry really was stellar, they should have definitely done the art for the original Maniac Mansion. It looks too good to be using such a restrictive form!
#210
Like this:
Code: AGS

//Put these at the top of the script in question.
int counter=0;
int delay=5; //or however many game loops you want to wait for.

function repeatedly_execute () //or wherever you put the code.
{
    if (counter > delay)
    {
        cEgo.Tint(Random(255), Random(255), Random(255), 100, 100);
        counter=0;
    }
    else counter++;
}
#211
Thank you so much for the help!

So if I get it right, you'd type out that header like:
Code: C++

const char *ourScriptHeader =
"struct MyPlugin {                                                         \r\n"
"    /// Autocomplete text for Function 1                                  \r\n"
"    import static void Function1();            // $AUTOCOMPLETESTATICONLY$\r\n"
"    /// Autocomplete text for Function 2                                  \r\n"
"    import static int Function2(int a, int b); // $AUTOCOMPLETESTATICONLY$\r\n"
"    int dummy;                                 // $AUTOCOMPLETEIGNORE$    \r\n"
"}                                                                         \r\n";

,add "StructName::Function^[num. of arguments]" to RegisterScriptFunction, and I don't need to change the function declarations at all in the actual code? (Except for, I'm assuming, adding the static keyword?)

Because there are a few functions I use internally I'd like to open up to the end user (Such as GetColor565, MixColorAlpha etc) and I'm not sure how I could handle a struct that isn't even technically declared in the plugin code itself. Unless I, like, make wrapper functions to put in the struct.

Also, there's quite a few things there I've not seen in the plugin documentation. You can make autocomplete text for plugin functions?? What does $AUTOCOMPLETESTATICONLY$ mean? There's so much I haven't ever seen before, and it feels like I've been working on this forever x3 Where do I get this information from?


EDIT: It ain't working. I'm not sure why, I followed your instructions? Do I need to make a copy of the struct in the script header in the code itself?

Code: C++

const char *ourScriptHeader =
  "struct TestStruct{\r\n"
  "import static void dummyfunction (); // $AUTOCOMPLETESTATICONLY$\r\n"
  "import int dummy; //$AUTOCOMPLETEIGNORE$\r\n"
  "}\r\n";

static void dummyfunction ()
{
}

//elsewhere in the AGS Engine startup code.
engine->RegisterScriptFunction ("TestStruct::dummyfunction^0", (void*)dummyfunction);


Am I missing anything? It just says:
__Plugin100.ash: 'import' not valid in this context
#212
Quote from: proximity on Sat 12/12/2015 21:43:04
Quote from: proximity on Sat 14/11/2015 02:38:35
I'm having difficulties when rendering sprites with semi-transparent alpha (like a character has shadow under him). Character movement and scaling is slower than non-transparent sprites (characters with no shadow). They are all PNG format so i wonder what causes this. The game engine ? The graphic card or CPU performance ? May be Direct X 9.0 ?

My system is : AMD FX 8120 3.1 GHZ, Geforce 640 GT, 24 GB Ram, Windows 7 64 bit, DirectX 11. AGS 3.4.0.6 Builder Patch and game resolution 960*540.

Any ideas please ?

Are you using DirectDraw or Direct3D? If I remember correctly, the D3D driver is faster at drawing alpha blended sprites, and the DD5 driver is better at raw image manipulation. If your setup says DirectDraw, change it, if it's D3D, then there's a problem.
#213
I have a lot of functions in my plugin, and I'd like to organize them a little so the interface to the end user isn't a complete mess. I've seen plugins use structs for their functions before (the Adplug plugin for instance), but I'm not sure how to do it myself. I'd assume it's similar to how you do it in AGS, but it's not documented and I'm not sure.

Also, the AGSObject* structure doesn't have IgnoreScaling and IgnoreLighting as flags - how do I check this from the plugin?
#214
DID SOMEONE MENTION ULTRA-RESTRICTED SPRITING?

I'm on like Donkey Kong for that!!

[imgzoom]https://dl.dropboxusercontent.com/u/50882197/art/MM_Dai_Nell.PNG[/imgzoom]

3 colors + transparency from the EGA palette, doublewide pixels, big heads, I think I can deal with that. Wow, compared to the MM style, AGI's native stuff is downright generous in it's form. The only thing that this style has going for it is the fact that the sprites are about 32x72 pixels in size, so nice and big.

For anyone who's interested, Maniac Mansion was originally programmed for the C64, and they wanted scrolling rooms, but you can't scroll the high-res (single width, monochrome) graphics without the engine slowing to a crawl. So they opted for the 160x200 mode, which is hella ugly, but fast.

I may do some more later, if I can work out how to eke more out of this style.
#215
Quote from: Monsieur OUXX on Wed 02/12/2015 10:12:38

Alright. But I hope it's lossless compression.

It's literally just RLE. It would be really useless if it was lossy, since AGS doesn't save the raw files seperately. You'd end up losing all your data after a couple of saves.
#216
Oh no, this is just to save space and allow me to use one lookup table instead of nine when I do translucency. After all, 65 kilobytes is smaller than 512k, and the less overhead I have, the better. Originally I had 256x256 LUTs that manually blended every possible pixel combination at different translucencies, but that approach is clunky and restrictive. I didn't like it, and it took half an hour to generate the LUTs.

I'm fully aware of what else I can do in 8-bit colour mode, like palette cycling and stuff, and I fully intend to keep doing all I can do with it. This is just a way of not having to deal with three billion different tables for different effects. My plugin also takes palette cycling into account anyway, so there's no problem there.
#217
Ah, I'm not actually using 16-bit colour mode, I'm trying to fill out the colour space using Game.GetColorFromRGB in 8-bit mode. It's too slow for realtime stuff, but it seems fast enough to populate a lookup table. I won't actually be running afoul of AGS' remapping problems. I just need to know how to draw it using RGB values. Then, using C++, I'll read the values from it and use it to draw colour effects to the screen. It seemed like a better idea than having static lookup tables that took up a load of memory.


Hmm, if I can't do simple math with the resulting number, that means I'll need to just use the palette entry's values instead:

Code: AGS

function GetClosestMixedColour (char x,char y)
{
//average of two colours, add additional /2 to the red and blue channels, because 256 colour mode uses 666 and 16bit uses 565
int result;
int r = (palette[x].r + palette[y].r)>>2;
int b = (palette[x].b + palette[y].b)>>2;
int g = (palette[x].g + palette[x].g)>>1;
result = (r<<11) + (g<<5) + b; //shift bits into place. Not sure if these are the right numbers for shifting, will check later
return result;
}

Though I'm not sure how I'd model 10% transparent, 20% transparent and so on from this.

EDIT:
Looking good! It isn't losing too much in the way of precision, except at the darker end where it doesn't matter too much.
#218
I'm trying to draw this colour space:

with AGS using Game.GetColorFromRGB and DrawPixel. it's the standard 565 16 bit colour space, but I'm having trouble coming up with the formula just looking at it. I tried a couple of things but it looks really off. Can someone point me in the right direction? My current code is:

Code: AGS

DynamicSprite *CLUT256;
int x = 0;
int y = 0;
int r = 0;
int g = 0;
int b = 0;
int maxr = 0;
int maxb = 31;
int maxg = 0;

function room_AfterFadeIn()
{
CLUT256 = DynamicSprite.Create (256, 256);
SetGameSpeed (60);
}
function room_RepExec()
{
  DrawingSurface *surf = CLUT256.GetDrawingSurface ();
  if (y < 256)
  {
    while (x < 256)
      {
        surf.DrawingColor = Game.GetColorFromRGB (r*8, g*4, b*8);
        //surf.DrawingColor = 21;
        surf.DrawPixel (x, y);
        /* //Clearly wrong colour code.
        if (b < maxb) b++;
        else
          {
            if (maxb > 0) maxb --;
            b = 0;
            if (r < maxr) r++;
            else 
            {
              if (maxr < 31) maxr++;
              r = 0;
              if (g < maxg) g++;
              else
              {
                g=0;
                if (maxg < 63) maxg++;
              }
            }
          }
           */
          x++;
      }
      x=0;
      y++;
  }
  surf.Release ();
  oClut.Graphic = CLUT256.Graphic;


And on a related note, colour mixing in the 16bit colour space is done simply by doing math on the index number, right? EG the colour that is 50% between color 3000 and color 6000 is (6000+3000)/2? I tested it out with AGS' 16bit colour mixer tab, it seemed to check out, but I need some confirmation.

I'm not too familiar with pure RGB mixing. I'm just trying to create something more memory efficient than a 256*2048 array for my colour mixing, and something more extensible.
#219
File-->Preferences...->In the lower left corner, 8-bit background import.
Uncheck the remap option.

Check if it still remaps:
Code: AGS

DynamicSprite *test;
test = DynamicSprite.Create (16, 16);
int x = 0;
int y = 0;
DrawingSurface *surf = test.GetDrawingSurface ();
int i = 0;
while (y < 16)
{
  while (x < 16)
  {
    surf.DrawingColor = i;
    surf.DrawPixel (x, y);
    x++;
    i++;
  }
  y++;
  x=0;
}
surf.Release ();
test.Resize (128, 128);
//Then display test by any means you want.

The above code will create a palette image for you to look at.

Make sure that your background palette either has a copy of the gamewide palette, or blank spaces where the gamewide palette is, or you'll run into the picture just being garbage.
#220
Your background got it's palette slots rearranged:



AGS will remap slots bottom up unless you specifically tell it to not remap the slots.
SMF spam blocked by CleanTalk