Implement a more generic "rasters" mode for CPC
This is similar to mode 5, but with less constraints: - All inks can have split rasters - Split rasters have a min width of 32 pixels Note that this is nowhere near enough to make sure the image will be renderable (number of colors should be limited, unless there is a span without rasters allowing to reload registers with new colors, and moving from one pen to another also has a cost). The goal is to offer no over-restriction (everything that can be shown on the real machine is drawable). Additional constraints may be checked from a lua script that will generate the code and data for displaying the picture.
This commit is contained in:
		
							parent
							
								
									1d71a0759f
								
							
						
					
					
						commit
						9d46d1e90f
					
				
							
								
								
									
										143
									
								
								src/brush.c
									
									
									
									
									
								
							
							
						
						
									
										143
									
								
								src/brush.c
									
									
									
									
									
								
							@ -120,7 +120,8 @@ void Display_paintbrush(short x,short y,byte color)
 | 
			
		||||
  if (Mouse_K) // pas de curseur si on est en preview et 
 | 
			
		||||
    return;                  // en train de cliquer
 | 
			
		||||
    
 | 
			
		||||
  if (Main.backups->Pages->Image_mode == IMAGE_MODE_MODE5 && Main.current_layer < 4)
 | 
			
		||||
  if ((Main.backups->Pages->Image_mode == IMAGE_MODE_MODE5
 | 
			
		||||
  	|| Main.backups->Pages->Image_mode == IMAGE_MODE_RASTER) && Main.current_layer < 4)
 | 
			
		||||
  {
 | 
			
		||||
    goto single_pixel;
 | 
			
		||||
  }
 | 
			
		||||
@ -284,7 +285,8 @@ void Draw_paintbrush(short x,short y,byte color)
 | 
			
		||||
  int position;
 | 
			
		||||
  byte old_color;
 | 
			
		||||
 | 
			
		||||
  if (Main.backups->Pages->Image_mode == IMAGE_MODE_MODE5 && Main.current_layer < 4)
 | 
			
		||||
  if ((Main.backups->Pages->Image_mode == IMAGE_MODE_MODE5
 | 
			
		||||
  	|| Main.backups->Pages->Image_mode == IMAGE_MODE_RASTER) && Main.current_layer < 4)
 | 
			
		||||
  {
 | 
			
		||||
    // Flood-fill the enclosing area
 | 
			
		||||
    if (x<Main.image_width && y<Main.image_height && x>= 0 && y >= 0
 | 
			
		||||
@ -296,40 +298,109 @@ void Draw_paintbrush(short x,short y,byte color)
 | 
			
		||||
      short min_x,width,min_y,height;
 | 
			
		||||
      short xx,yy;
 | 
			
		||||
 | 
			
		||||
      // determine area
 | 
			
		||||
      switch(Main.current_layer)
 | 
			
		||||
      {
 | 
			
		||||
        case 0:
 | 
			
		||||
        default:
 | 
			
		||||
          // Full layer
 | 
			
		||||
          min_x=0;
 | 
			
		||||
          min_y=0;
 | 
			
		||||
          width=Main.image_width;
 | 
			
		||||
          height=Main.image_height;
 | 
			
		||||
          break;
 | 
			
		||||
        case 1:
 | 
			
		||||
        case 2:
 | 
			
		||||
          // Line
 | 
			
		||||
          min_x=0;
 | 
			
		||||
          min_y=y;
 | 
			
		||||
          width=Main.image_width;
 | 
			
		||||
          height=1;
 | 
			
		||||
          break;
 | 
			
		||||
        case 3:
 | 
			
		||||
          // Segment
 | 
			
		||||
          min_x=x / 48 * 48;
 | 
			
		||||
          min_y=y;
 | 
			
		||||
          width=48;
 | 
			
		||||
          height=1;
 | 
			
		||||
          break;
 | 
			
		||||
        //case 4:
 | 
			
		||||
        //  // 8x8
 | 
			
		||||
        //  min_x=x / 8 * 8;
 | 
			
		||||
        //  min_y=y / 8 * 8;
 | 
			
		||||
        //  width=8;
 | 
			
		||||
        //  height=8;
 | 
			
		||||
        //  break;
 | 
			
		||||
      }
 | 
			
		||||
  	  if (Main.backups->Pages->Image_mode == IMAGE_MODE_MODE5)
 | 
			
		||||
	  {
 | 
			
		||||
		  // determine area
 | 
			
		||||
		  switch(Main.current_layer)
 | 
			
		||||
		  {
 | 
			
		||||
			  case 0:
 | 
			
		||||
			  default:
 | 
			
		||||
				  // Full layer
 | 
			
		||||
				  min_x=0;
 | 
			
		||||
				  min_y=0;
 | 
			
		||||
				  width=Main.image_width;
 | 
			
		||||
				  height=Main.image_height;
 | 
			
		||||
				  break;
 | 
			
		||||
			  case 1:
 | 
			
		||||
			  case 2:
 | 
			
		||||
				  // Line
 | 
			
		||||
				  min_x=0;
 | 
			
		||||
				  min_y=y;
 | 
			
		||||
				  width=Main.image_width;
 | 
			
		||||
				  height=1;
 | 
			
		||||
				  break;
 | 
			
		||||
			  case 3:
 | 
			
		||||
				  // Segment
 | 
			
		||||
				  min_x=x / 48 * 48;
 | 
			
		||||
				  min_y=y;
 | 
			
		||||
				  width=48;
 | 
			
		||||
				  height=1;
 | 
			
		||||
				  break;
 | 
			
		||||
		  }
 | 
			
		||||
	  } else {
 | 
			
		||||
		int prev_x;
 | 
			
		||||
		// Raster mode
 | 
			
		||||
		// No matter what, you can always edit only 1 line at a time here, and you will always
 | 
			
		||||
		// draw on "nops" boundaries (8 pixels in mode 1)
 | 
			
		||||
		height=1;
 | 
			
		||||
		min_y=y;
 | 
			
		||||
		min_x=x / 8 * 8;
 | 
			
		||||
		width = 8;
 | 
			
		||||
 | 
			
		||||
		// ????????
 | 
			
		||||
		//     ^
 | 
			
		||||
		//     A
 | 
			
		||||
 | 
			
		||||
		// First look for the previous span to see if it is the same color
 | 
			
		||||
		prev_x = min_x - 8;
 | 
			
		||||
 | 
			
		||||
		old_color = Read_pixel_from_current_screen(prev_x, y);
 | 
			
		||||
 | 
			
		||||
		if (old_color == color) {
 | 
			
		||||
			// aaaA????
 | 
			
		||||
			//     ^
 | 
			
		||||
			//     A
 | 
			
		||||
			// We are just making the previous span larger
 | 
			
		||||
			width = 8;
 | 
			
		||||
			while ((min_x >= 0) && (width < 32)
 | 
			
		||||
				&& (Read_pixel_from_current_screen(min_x, y) == color))
 | 
			
		||||
			{
 | 
			
		||||
				min_x -= 8;
 | 
			
		||||
				width += 8;
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			// ???B????
 | 
			
		||||
			//     ^
 | 
			
		||||
			//     A
 | 
			
		||||
			// We are creating a new span. We need to check if the previous span is still large
 | 
			
		||||
			// enough to be allowed. If it is less than 32 pixels, there is no way to render it
 | 
			
		||||
			// on the real hardware (this is the time the OUT instruction to change the palette
 | 
			
		||||
			// needs)
 | 
			
		||||
			while ((min_x - prev_x < 48)
 | 
			
		||||
				&& (prev_x <= 0 || old_color == Read_pixel_from_current_screen(prev_x, y)))
 | 
			
		||||
			{
 | 
			
		||||
				prev_x -= 8;
 | 
			
		||||
			}
 | 
			
		||||
			prev_x += 8;
 | 
			
		||||
 | 
			
		||||
			// CBBB????
 | 
			
		||||
			//  p  ^
 | 
			
		||||
			//     A
 | 
			
		||||
			// The previous span is too small, so eat it
 | 
			
		||||
			if (min_x - prev_x < 32) {
 | 
			
		||||
				width += min_x - prev_x;
 | 
			
		||||
				min_x = prev_x;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (width < 32)
 | 
			
		||||
				width = 32;
 | 
			
		||||
		}
 | 
			
		||||
		// Now, we also need to check if the next span is still large enough, as we are going to
 | 
			
		||||
		// remove 8 pixels from it. If it is not, we just replace it with the current color and
 | 
			
		||||
		// let the user figure out how to reinsert it without breaking everything.
 | 
			
		||||
		prev_x = min_x + width;
 | 
			
		||||
		old_color = Read_pixel_from_current_screen(prev_x, y);
 | 
			
		||||
		if (old_color != color) {
 | 
			
		||||
			while ((prev_x - (min_x + width) < 40)
 | 
			
		||||
				&& (prev_x > Main.image_width || old_color == Read_pixel_from_current_screen(prev_x, y)))
 | 
			
		||||
			{
 | 
			
		||||
				prev_x += 8;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (prev_x - (min_x + width) < 32)
 | 
			
		||||
				width = prev_x - min_x;
 | 
			
		||||
		}
 | 
			
		||||
	  }
 | 
			
		||||
      // Clip the bottom edge.
 | 
			
		||||
      // (Necessary if image height is not a multiple)
 | 
			
		||||
      if (min_y+height>=Main.image_height)
 | 
			
		||||
 | 
			
		||||
@ -180,19 +180,26 @@ void Button_Constraint_mode(void)
 | 
			
		||||
  if (Selected_Constraint_Mode <= IMAGE_MODE_ANIMATION)
 | 
			
		||||
    Selected_Constraint_Mode = IMAGE_MODE_EGX;
 | 
			
		||||
 | 
			
		||||
  if (Selected_Constraint_Mode == IMAGE_MODE_MODE5)
 | 
			
		||||
  if (Selected_Constraint_Mode == IMAGE_MODE_MODE5 && (Main.image_width%48))
 | 
			
		||||
  {
 | 
			
		||||
	  Verbose_message("Error!", "Emulation of Amstrad CPC's Mode5 can only be used on an image whose width is a multiple of 48.");
 | 
			
		||||
      return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (Selected_Constraint_Mode == IMAGE_MODE_MODE5 || Selected_Constraint_Mode == IMAGE_MODE_RASTER)
 | 
			
		||||
  {
 | 
			
		||||
	/* TODO it would be great to auto-create extra layers */
 | 
			
		||||
    if (Main.backups->Pages->Image_mode != IMAGE_MODE_LAYERED ||
 | 
			
		||||
        Main.backups->Pages->Nb_layers!=5 || (Main.image_width%48))
 | 
			
		||||
        Main.backups->Pages->Nb_layers!=5)
 | 
			
		||||
    {
 | 
			
		||||
      Verbose_message("Error!", "This emulation of Amstrad CPC's Mode5 can only be used on a 5-layer image whose width is a multiple of 48.");
 | 
			
		||||
      Verbose_message("Error!", "Emulation of Amstrad CPC's rasters requires a 5-layer image.");
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    for (pixel=0; pixel < Main.image_width*Main.image_height; pixel++)
 | 
			
		||||
    {
 | 
			
		||||
      if (Main.backups->Pages->Image[4].Pixels[pixel]>3)
 | 
			
		||||
      {
 | 
			
		||||
        Verbose_message("Error!", "This emulation of Amstrad CPC's Mode5 needs all pixels of layer 5 to use colors 0-3.");
 | 
			
		||||
        Verbose_message("Error!", "Emulation of Amstrad CPC's rasters needs all pixels of layer 5 to use colors 0-3.");
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
@ -220,6 +227,7 @@ void Button_Constraint_menu(void)
 | 
			
		||||
    {IMAGE_MODE_EGX,     "EGX (CPC)"},
 | 
			
		||||
    {IMAGE_MODE_EGX2,    "EGX2 (CPC)"},
 | 
			
		||||
    {IMAGE_MODE_MODE5,   "Mode 5 (CPC)"},
 | 
			
		||||
    {IMAGE_MODE_RASTER,  "Rasters (CPC)"},
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  Open_window(154,79,"8-bit constraints");
 | 
			
		||||
 | 
			
		||||
@ -614,6 +614,7 @@ enum IMAGE_MODES
 | 
			
		||||
  IMAGE_MODE_EGX,       ///< CPC EGX
 | 
			
		||||
  IMAGE_MODE_EGX2,      ///< CPC EGX2
 | 
			
		||||
  IMAGE_MODE_MODE5,     ///< CPC mode 5
 | 
			
		||||
  IMAGE_MODE_RASTER,    ///< CPC generic rasters
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// Circle / Ellipse Modes
 | 
			
		||||
 | 
			
		||||
@ -3213,7 +3213,8 @@ byte Read_pixel_from_current_screen  (word x,word y)
 | 
			
		||||
    return *((y)*Main.image_width+(x)+Main.backups->Pages->Image[Main.current_layer].Pixels);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (Main.backups->Pages->Image_mode == IMAGE_MODE_MODE5)
 | 
			
		||||
  if (Main.backups->Pages->Image_mode == IMAGE_MODE_MODE5
 | 
			
		||||
  	|| Main.backups->Pages->Image_mode == IMAGE_MODE_RASTER)
 | 
			
		||||
    if (Main.current_layer==4)
 | 
			
		||||
      return *(Main.backups->Pages->Image[Main.current_layer].Pixels + x+y*Main.image_width);
 | 
			
		||||
 | 
			
		||||
@ -3632,7 +3633,7 @@ void Update_pixel_renderer(void)
 | 
			
		||||
    Pixel_in_current_screen = Pixel_in_screen_zx;
 | 
			
		||||
    Pixel_in_current_screen_with_preview = Pixel_in_screen_zx_with_preview;
 | 
			
		||||
  }
 | 
			
		||||
  // Implicit else : Image_mode must be IMAGE_MODE_MODE5
 | 
			
		||||
  // Implicit else : Image_mode must be IMAGE_MODE_MODE5 or IMAGE_MODE_RASTER
 | 
			
		||||
  else if ( Main.current_layer == 4)
 | 
			
		||||
  {
 | 
			
		||||
    // overlay
 | 
			
		||||
@ -3647,7 +3648,7 @@ void Update_pixel_renderer(void)
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    // layered (again, for layers > 4 in MODE5)
 | 
			
		||||
    // layered (again, for layers > 4 in MODE5 and RASTER)
 | 
			
		||||
    Pixel_in_current_screen = Pixel_in_screen_layered;
 | 
			
		||||
    Pixel_in_current_screen_with_preview = Pixel_in_screen_layered_with_preview;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										17
									
								
								src/pages.c
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								src/pages.c
									
									
									
									
									
								
							@ -203,7 +203,8 @@ void Redraw_layered_image(void)
 | 
			
		||||
    // Re-construct the image with the visible layers
 | 
			
		||||
    byte layer=0;  
 | 
			
		||||
    // First layer
 | 
			
		||||
    if (Main.backups->Pages->Image_mode == IMAGE_MODE_MODE5 && Main.layers_visible & (1<<4))
 | 
			
		||||
    if ((Main.backups->Pages->Image_mode == IMAGE_MODE_MODE5
 | 
			
		||||
		|| Main.backups->Pages->Image_mode == IMAGE_MODE_RASTER) && Main.layers_visible & (1<<4))
 | 
			
		||||
    {
 | 
			
		||||
      // The raster result layer is visible: start there
 | 
			
		||||
      // Copy it in Main_visible_image
 | 
			
		||||
@ -1466,6 +1467,7 @@ byte Delete_layer(T_List_of_pages *list, int layer)
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// Merges the current layer onto the one below it.
 | 
			
		||||
byte Merge_layer()
 | 
			
		||||
{
 | 
			
		||||
@ -1479,6 +1481,7 @@ byte Merge_layer()
 | 
			
		||||
  return Delete_layer(Main.backups,Main.current_layer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void Switch_layer_mode(enum IMAGE_MODES new_mode)
 | 
			
		||||
{
 | 
			
		||||
  if (new_mode == Main.backups->Pages->Image_mode)
 | 
			
		||||
@ -1486,18 +1489,12 @@ void Switch_layer_mode(enum IMAGE_MODES new_mode)
 | 
			
		||||
 | 
			
		||||
  Main.backups->Pages->Image_mode = new_mode;
 | 
			
		||||
 | 
			
		||||
  switch (new_mode)
 | 
			
		||||
  if (new_mode != IMAGE_MODE_ANIMATION)
 | 
			
		||||
  {
 | 
			
		||||
    case IMAGE_MODE_MODE5:
 | 
			
		||||
    case IMAGE_MODE_LAYERED:
 | 
			
		||||
    default:
 | 
			
		||||
      Update_buffers(Main.image_width, Main.image_height);
 | 
			
		||||
      Redraw_layered_image();
 | 
			
		||||
      break;
 | 
			
		||||
    case IMAGE_MODE_ANIMATION:
 | 
			
		||||
      // nothing to do.
 | 
			
		||||
      // Eventually, we may clear the buffers to save a bit of memory...
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
  // TODO Eventually, in animation mode we may clear the buffers to save a bit of memory...
 | 
			
		||||
 | 
			
		||||
  Update_pixel_renderer();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -345,7 +345,8 @@ void Remap_image_highlevel(byte * conversion_table)
 | 
			
		||||
 | 
			
		||||
  // Remap the flatenned image view
 | 
			
		||||
  if (Main.backups->Pages->Image_mode != IMAGE_MODE_ANIMATION
 | 
			
		||||
      && Main.backups->Pages->Image_mode != IMAGE_MODE_MODE5)
 | 
			
		||||
      && Main.backups->Pages->Image_mode != IMAGE_MODE_MODE5
 | 
			
		||||
      && Main.backups->Pages->Image_mode != IMAGE_MODE_RASTER)
 | 
			
		||||
  {
 | 
			
		||||
    Remap_general_lowlevel(conversion_table,Main.visible_image.Image,Main.visible_image.Image,
 | 
			
		||||
                         Main.image_width,Main.image_height,Main.image_width);
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user