Animation now has correct visual display and input feedback. Loading GIF guesses it's an anim if it loops, layers otherwise : Some rare non-looping GIF anims (usaully broken) will be misunderstood as layered. Editing of anims and layers seems flawless and stable. Still requires an auto-switch to the best toolbar (anim/layers) when relevant, but you can already switch manually.

git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@1910 416bcca6-2ee7-4201-b75f-2eb2f807beb1
This commit is contained in:
Yves Rizoud 2012-03-02 23:19:47 +00:00
parent db50b4ebdc
commit e73eb2786a
8 changed files with 358 additions and 335 deletions

View File

@ -548,11 +548,23 @@ void Button_Toggle_toolbar(void)
case 0: // tools case 0: // tools
Set_bar_visibility(MENUBAR_TOOLS, !Menu_bars[MENUBAR_TOOLS].Visible); Set_bar_visibility(MENUBAR_TOOLS, !Menu_bars[MENUBAR_TOOLS].Visible);
break; break;
case 1: // anim case 1: // layers
if (Menu_bars[MENUBAR_ANIMATION].Visible && !Menu_bars[MENUBAR_LAYERS].Visible) if (Menu_bars[MENUBAR_ANIMATION].Visible && !Menu_bars[MENUBAR_LAYERS].Visible)
Set_bar_visibility(MENUBAR_ANIMATION, 0); Set_bar_visibility(MENUBAR_ANIMATION, 0);
Set_bar_visibility(MENUBAR_LAYERS, !Menu_bars[MENUBAR_LAYERS].Visible); Set_bar_visibility(MENUBAR_LAYERS, !Menu_bars[MENUBAR_LAYERS].Visible);
if (Main_backups->Pages->Image_mode == IMAGE_MODE_ANIMATION)
{
// Exceptionally, this doesn't require a backup because a single-layer
// image is the same as a single-frame animation.
Main_backups->Pages->Image_mode = IMAGE_MODE_LAYERED;
}
break;
case 2: // anim
if (Menu_bars[MENUBAR_LAYERS].Visible && !Menu_bars[MENUBAR_ANIMATION].Visible)
Set_bar_visibility(MENUBAR_LAYERS, 0);
Set_bar_visibility(MENUBAR_ANIMATION, !Menu_bars[MENUBAR_ANIMATION].Visible);
if (Main_backups->Pages->Image_mode == IMAGE_MODE_LAYERED) if (Main_backups->Pages->Image_mode == IMAGE_MODE_LAYERED)
{ {
// Exceptionally, this doesn't require a backup because a single-frame // Exceptionally, this doesn't require a backup because a single-frame
@ -560,18 +572,6 @@ void Button_Toggle_toolbar(void)
Main_backups->Pages->Image_mode = IMAGE_MODE_ANIMATION; Main_backups->Pages->Image_mode = IMAGE_MODE_ANIMATION;
} }
break;
case 2: // layers
if (Menu_bars[MENUBAR_LAYERS].Visible && !Menu_bars[MENUBAR_ANIMATION].Visible)
Set_bar_visibility(MENUBAR_LAYERS, 0);
Set_bar_visibility(MENUBAR_ANIMATION, !Menu_bars[MENUBAR_ANIMATION].Visible);
if (Main_backups->Pages->Image_mode == IMAGE_MODE_ANIMATION)
{
// Exceptionally, this doesn't require a backup because a single-layer
// image is the same as a single-frame animation.
Main_backups->Pages->Image_mode = IMAGE_MODE_LAYERED;
}
break; break;
} }
} }

View File

@ -70,11 +70,8 @@
/// Character to display in menus for an ellipsis. /// Character to display in menus for an ellipsis.
#define ELLIPSIS_CHARACTER '…' #define ELLIPSIS_CHARACTER '…'
#define NB_LAYERS 1 ///< Initial number of layers for a new image #define NB_LAYERS 1 ///< Initial number of layers for a new image
#ifdef NOLAYERS #define MAX_NB_FRAMES 999 ///< Maximum number of frames that can be used in a grafx2 animation.
#define MAX_NB_LAYERS 999 ///< Maximum number of layers that can be used in grafx2. Note that 32 is upper limit because of a few bit fields.
#else
#define MAX_NB_LAYERS 16 ///< Maximum number of layers that can be used in grafx2. Note that 32 is upper limit because of a few bit fields. #define MAX_NB_LAYERS 16 ///< Maximum number of layers that can be used in grafx2. Note that 32 is upper limit because of a few bit fields.
#endif
#define BRUSH_CONTAINER_PREVIEW_WIDTH 16 ///< Size for preview of a brush in Brush container #define BRUSH_CONTAINER_PREVIEW_WIDTH 16 ///< Size for preview of a brush in Brush container
#define BRUSH_CONTAINER_PREVIEW_HEIGHT 16 ///< Size for preview of a brush in Brush container #define BRUSH_CONTAINER_PREVIEW_HEIGHT 16 ///< Size for preview of a brush in Brush container
#define BRUSH_CONTAINER_COLUMNS 4 ///< Number of columns in the Brush container #define BRUSH_CONTAINER_COLUMNS 4 ///< Number of columns in the Brush container

View File

@ -60,7 +60,6 @@
#include "struct.h" #include "struct.h"
#include "io.h" #include "io.h"
#include "windows.h" // Best_color() #include "windows.h" // Best_color()
#include "pages.h" // Add_layer()
//////////////////////////////////// IMG //////////////////////////////////// //////////////////////////////////// IMG ////////////////////////////////////
@ -2025,7 +2024,13 @@ void Load_GIF(T_IO_Context * context)
else if (!memcmp(aeb,"NETSCAPE2.0",0x0B)) else if (!memcmp(aeb,"NETSCAPE2.0",0x0B))
{ {
// The well-known Netscape extension. // The well-known Netscape extension.
// Nothing to do, just skip sub-block // Load as an animation
if (context->Type == CONTEXT_MAIN_IMAGE)
{
Main_backups->Pages->Image_mode = IMAGE_MODE_ANIMATION;
Update_screen_targets();
}
// Skip sub-block
do do
{ {
if (! Read_byte(GIF_file,&size_to_read)) if (! Read_byte(GIF_file,&size_to_read))
@ -2139,8 +2144,7 @@ void Load_GIF(T_IO_Context * context)
// Attempt to add a layer to current image // Attempt to add a layer to current image
current_layer++; current_layer++;
Set_loading_layer(context, current_layer); Set_loading_layer(context, current_layer);
#ifdef NOLAYERS if (context->Type == CONTEXT_MAIN_IMAGE && Main_backups->Pages->Image_mode == IMAGE_MODE_ANIMATION)
if (context->Type == CONTEXT_MAIN_IMAGE)
{ {
if (is_transparent) if (is_transparent)
// Copy the content of previous layer, in case of loading a GIF // Copy the content of previous layer, in case of loading a GIF
@ -2155,7 +2159,6 @@ void Load_GIF(T_IO_Context * context)
LSDB.Backcol, LSDB.Backcol,
Main_backups->Pages->Width*Main_backups->Pages->Height); Main_backups->Pages->Width*Main_backups->Pages->Height);
} }
#endif
} }
else else
{ {
@ -2165,7 +2168,6 @@ void Load_GIF(T_IO_Context * context)
LSDB.Backcol, LSDB.Backcol,
Main_backups->Pages->Width*Main_backups->Pages->Height); Main_backups->Pages->Width*Main_backups->Pages->Height);
} }
// Duration was set in the previously loaded GCE // Duration was set in the previously loaded GCE
Set_frame_duration(context, last_delay*10); Set_frame_duration(context, last_delay*10);
number_LID++; number_LID++;
@ -2497,10 +2499,9 @@ void Save_GIF(T_IO_Context * context)
// Write_bytes(GIF_file,"\x21\xFF\x0BNETSCAPE2.0\x03\xLL\xSS\xSS\x00",19); // Write_bytes(GIF_file,"\x21\xFF\x0BNETSCAPE2.0\x03\xLL\xSS\xSS\x00",19);
// LL : 01 to loop // LL : 01 to loop
// SSSS : number of loops // SSSS : number of loops
#ifdef NOLAYERS if (context->Type == CONTEXT_MAIN_IMAGE && Main_backups->Pages->Image_mode == IMAGE_MODE_ANIMATION)
if (context->Nb_layers>1) if (context->Nb_layers>1)
Write_bytes(GIF_file,"\x21\xFF\x0BNETSCAPE2.0\x03\x01\x00\x00\x00",19); Write_bytes(GIF_file,"\x21\xFF\x0BNETSCAPE2.0\x03\x01\x00\x00\x00",19);
#endif
// Ecriture du commentaire // Ecriture du commentaire
if (context->Comment[0]) if (context->Comment[0])
@ -2543,18 +2544,24 @@ void Save_GIF(T_IO_Context * context)
GCE.Block_identifier = 0x21; GCE.Block_identifier = 0x21;
GCE.Function = 0xF9; GCE.Function = 0xF9;
GCE.Block_size=4; GCE.Block_size=4;
#ifdef NOLAYERS
GCE.Packed_fields=(2<<2)|(context->Background_transparent); if (context->Type == CONTEXT_MAIN_IMAGE && Main_backups->Pages->Image_mode == IMAGE_MODE_ANIMATION)
GCE.Delay_time=Get_frame_duration(context)/10; {
#else // Animation frame
if (current_layer==0) GCE.Packed_fields=(2<<2)|(context->Background_transparent);
GCE.Packed_fields=(1<<2)|(context->Background_transparent); GCE.Delay_time=Get_frame_duration(context)/10;
}
else else
GCE.Packed_fields=(1<<2)|(1); {
GCE.Delay_time=5; // Duration 5/100s (minimum viable value for current web browsers) // Layered image
if (current_layer == context->Nb_layers -1) if (current_layer==0)
GCE.Delay_time=0xFFFF; // Infinity (10 minutes) GCE.Packed_fields=(1<<2)|(context->Background_transparent);
#endif else
GCE.Packed_fields=(1<<2)|(1);
GCE.Delay_time=5; // Duration 5/100s (minimum viable value for current web browsers)
if (current_layer == context->Nb_layers -1)
GCE.Delay_time=0xFFFF; // Infinity (10 minutes)
}
GCE.Transparent_color=context->Transparent_color; GCE.Transparent_color=context->Transparent_color;
GCE.Block_terminator=0x00; GCE.Block_terminator=0x00;

View File

@ -3005,40 +3005,40 @@ void Redraw_grid(short x, short y, unsigned short w, unsigned short h)
byte Read_pixel_from_current_screen (word x,word y) byte Read_pixel_from_current_screen (word x,word y)
{ {
#ifndef NOLAYERS
byte depth; byte depth;
byte color; byte color;
if (Main_backups->Pages->Image_mode == IMAGE_MODE_ANIMATION)
{
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)
if (Main_current_layer==4) if (Main_current_layer==4)
return *(Main_backups->Pages->Image[Main_current_layer].Pixels + x+y*Main_image_width); return *(Main_backups->Pages->Image[Main_current_layer].Pixels + x+y*Main_image_width);
color = *(Main_screen+y*Main_image_width+x); color = *(Main_screen+y*Main_image_width+x);
if (color != Main_backups->Pages->Transparent_color) // transparent color if (color != Main_backups->Pages->Transparent_color) // transparent color
return color; return color;
depth = *(Main_visible_image_depth_buffer.Image+x+y*Main_image_width); depth = *(Main_visible_image_depth_buffer.Image+x+y*Main_image_width);
return *(Main_backups->Pages->Image[depth].Pixels + x+y*Main_image_width); return *(Main_backups->Pages->Image[depth].Pixels + x+y*Main_image_width);
#else
return *((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer].Pixels);
#endif
} }
/// Paint a a single pixel in image only : as-is. /// Paint a a single pixel in image only : as-is.
void Pixel_in_screen_direct(word x,word y,byte color) void Pixel_in_screen_direct(word x,word y,byte color)
{ {
*((y)*Main_image_width+(x)+/*Main_backups->Pages->Image[Main_current_layer].Pixels*/Main_screen)=color; *((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer].Pixels)=color;
} }
/// Paint a a single pixel in image and on screen: as-is. /// Paint a a single pixel in image and on screen: as-is.
void Pixel_in_screen_direct_with_preview(word x,word y,byte color) void Pixel_in_screen_direct_with_preview(word x,word y,byte color)
{ {
*((y)*Main_image_width+(x)+/*Main_backups->Pages->Image[Main_current_layer].Pixels*/Main_screen)=color; *((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer].Pixels)=color;
Pixel_preview(x,y,color); Pixel_preview(x,y,color);
} }
#ifndef NOLAYERS
/// Paint a a single pixel in image only : using layered display. /// Paint a a single pixel in image only : using layered display.
void Pixel_in_screen_layered(word x,word y,byte color) void Pixel_in_screen_layered(word x,word y,byte color)
{ {
@ -3140,7 +3140,6 @@ void Pixel_in_screen_overlay_with_preview(word x,word y,byte color)
Pixel_preview(x,y,color); Pixel_preview(x,y,color);
} }
} }
#endif
Func_pixel Pixel_in_current_screen=Pixel_in_screen_direct; Func_pixel Pixel_in_current_screen=Pixel_in_screen_direct;
Func_pixel Pixel_in_current_screen_with_preview=Pixel_in_screen_direct_with_preview; Func_pixel Pixel_in_current_screen_with_preview=Pixel_in_screen_direct_with_preview;
@ -3162,7 +3161,13 @@ byte Read_pixel_from_current_layer(word x,word y)
void Update_pixel_renderer(void) void Update_pixel_renderer(void)
{ {
#ifndef NOLAYERS if (Main_backups->Pages->Image_mode == IMAGE_MODE_ANIMATION)
{
// direct
Pixel_in_current_screen = Pixel_in_screen_direct;
Pixel_in_current_screen_with_preview = Pixel_in_screen_direct_with_preview;
}
else
if (Main_backups->Pages->Image_mode == IMAGE_MODE_LAYERED) if (Main_backups->Pages->Image_mode == IMAGE_MODE_LAYERED)
{ {
// layered // layered
@ -3188,9 +3193,4 @@ void Update_pixel_renderer(void)
Pixel_in_current_screen = Pixel_in_screen_layered; Pixel_in_current_screen = Pixel_in_screen_layered;
Pixel_in_current_screen_with_preview = Pixel_in_screen_layered_with_preview; Pixel_in_current_screen_with_preview = Pixel_in_screen_layered_with_preview;
} }
#else
// direct
Pixel_in_current_screen = Pixel_in_screen_direct;
Pixel_in_current_screen_with_preview = Pixel_in_screen_direct_with_preview;
#endif
} }

View File

@ -41,46 +41,48 @@ void Layer_activate(int layer, short side)
// Keep a copy of which layers were visible // Keep a copy of which layers were visible
old_layers = Main_layers_visible; old_layers = Main_layers_visible;
#ifndef NOLAYERS if (Main_backups->Pages->Image_mode != IMAGE_MODE_ANIMATION)
if (side == RIGHT_SIDE)
{ {
// Right-click on current layer if (side == RIGHT_SIDE)
if (Main_current_layer == layer)
{ {
if (Main_layers_visible == (dword)(1<<layer)) // Right-click on current layer
if (Main_current_layer == layer)
{ {
// Set all layers visible if (Main_layers_visible == (dword)(1<<layer))
Main_layers_visible = 0xFFFFFFFF; {
// Set all layers visible
Main_layers_visible = 0xFFFFFFFF;
}
else
{
// Set only this one visible
Main_layers_visible = 1<<layer;
}
} }
else else
{ {
// Set only this one visible // Right-click on an other layer : toggle its visibility
Main_layers_visible = 1<<layer; Main_layers_visible ^= 1<<layer;
} }
} }
else else
{ {
// Right-click on an other layer : toggle its visibility // Left-click on any layer
Main_layers_visible ^= 1<<layer; Main_current_layer = layer;
Main_layers_visible |= 1<<layer;
} }
} }
else else
{ {
// Left-click on any layer // Only allow one visible at a time
Main_current_layer = layer; if (side == LEFT_SIDE)
Main_layers_visible |= 1<<layer; {
Main_current_layer = layer;
Main_layers_visible = 1<<layer;
Update_screen_targets();
}
} }
#else
// Handler for limited layers support: only allow one visible at a time
if (side == LEFT_SIDE)
{
Main_current_layer = layer;
Main_layers_visible = 1<<layer;
Update_screen_targets();
}
#endif
Hide_cursor(); Hide_cursor();
if (Main_layers_visible != old_layers) if (Main_layers_visible != old_layers)
@ -97,26 +99,31 @@ void Layer_activate(int layer, short side)
void Button_Layer_add(void) void Button_Layer_add(void)
{ {
int max[] = {MAX_NB_LAYERS, MAX_NB_FRAMES, 5};
Hide_cursor(); Hide_cursor();
if (Main_backups->Pages->Nb_layers < MAX_NB_LAYERS) if (Main_backups->Pages->Nb_layers < max[Main_backups->Pages->Image_mode])
{ {
// Backup with unchanged layers // Backup with unchanged layers
Backup_layers(0); Backup_layers(0);
if (!Add_layer(Main_backups,Main_current_layer+1)) if (!Add_layer(Main_backups,Main_current_layer+1))
{ {
#ifdef NOLAYERS if (Main_backups->Pages->Image_mode == IMAGE_MODE_ANIMATION)
// Make a copy of current image, so the display is unchanged {
memcpy( // Make a copy of current image, so the display is unchanged
Main_backups->Pages->Image[Main_current_layer].Pixels, memcpy(
Main_backups->Pages->Image[Main_current_layer-1].Pixels, Main_backups->Pages->Image[Main_current_layer].Pixels,
Main_backups->Pages->Width*Main_backups->Pages->Height); Main_backups->Pages->Image[Main_current_layer-1].Pixels,
#else Main_backups->Pages->Width*Main_backups->Pages->Height);
Update_depth_buffer(); }
// I just noticed this might be unneeded, since the new layer else
// is transparent, it shouldn't have any visible effect. {
Display_all_screen(); Update_depth_buffer();
#endif // I just noticed this might be unneeded, since the new layer
// is transparent, it shouldn't have any visible effect.
Display_all_screen();
}
Display_layerbar(); Display_layerbar();
End_of_modification(); End_of_modification();
} }

View File

@ -303,12 +303,14 @@ byte Read_pixel_from_spare_screen(word x,word y)
// (can be a bigger or smaller image) // (can be a bigger or smaller image)
if (x>=Spare_image_width || y>=Spare_image_height) if (x>=Spare_image_width || y>=Spare_image_height)
return Spare_backups->Pages->Transparent_color; return Spare_backups->Pages->Transparent_color;
#ifndef NOLAYERS if (Spare_backups->Pages->Image_mode == IMAGE_MODE_ANIMATION)
return *(Spare_visible_image.Image + y*Spare_image_width + x); {
#else return *(Spare_backups->Pages->Image[Spare_current_layer].Pixels + y*Spare_image_width + x);
return *(Spare_backups->Pages->Image[Spare_current_layer].Pixels + y*Spare_image_width + x); }
#endif else
{
return *(Spare_visible_image.Image + y*Spare_image_width + x);
}
} }
void Rotate_90_deg_lowlevel(byte * source, byte * dest, short width, short height) void Rotate_90_deg_lowlevel(byte * source, byte * dest, short width, short height)

View File

@ -2785,13 +2785,14 @@ void Scroll_12_0(void)
else else
{ {
Backup_layers(-1); // Main_layers_visible Backup_layers(-1); // Main_layers_visible
#ifndef NOLAYERS if (Main_backups->Pages->Image_mode != IMAGE_MODE_ANIMATION)
{
// Ensure the backup visible image is up-to-date // Ensure the backup visible image is up-to-date
// (after swapping some layers on/off, it gets outdated) // (after swapping some layers on/off, it gets outdated)
memcpy(Main_visible_image_backup.Image, memcpy(Main_visible_image_backup.Image,
Main_visible_image.Image, Main_visible_image.Image,
Main_image_width*Main_image_height); Main_image_width*Main_image_height);
#endif }
} }
Update_screen_targets(); Update_screen_targets();

View File

@ -38,12 +38,10 @@
// -- Layers data // -- Layers data
/// Array of two images, that contains the "flattened" version of the visible layers. /// Array of two images, that contains the "flattened" version of the visible layers.
#ifndef NOLAYERS
T_Bitmap Main_visible_image; T_Bitmap Main_visible_image;
T_Bitmap Main_visible_image_backup; T_Bitmap Main_visible_image_backup;
T_Bitmap Main_visible_image_depth_buffer; T_Bitmap Main_visible_image_depth_buffer;
T_Bitmap Spare_visible_image; T_Bitmap Spare_visible_image;
#endif
/// ///
/// GESTION DES PAGES /// GESTION DES PAGES
@ -200,40 +198,92 @@ void Download_infos_page_main(T_Page * page)
void Redraw_layered_image(void) void Redraw_layered_image(void)
{ {
#ifndef NOLAYERS if (Main_backups->Pages->Image_mode != IMAGE_MODE_ANIMATION)
// 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))
{ {
// The raster result layer is visible: start there // Re-construct the image with the visible layers
// Copy it in Main_visible_image byte layer=0;
int i; // First layer
for (i=0; i< Main_image_width*Main_image_height; i++) if (Main_backups->Pages->Image_mode == IMAGE_MODE_MODE5 && Main_layers_visible & (1<<4))
{ {
layer = *(Main_backups->Pages->Image[4].Pixels+i); // The raster result layer is visible: start there
Main_visible_image.Image[i]=*(Main_backups->Pages->Image[layer].Pixels+i); // Copy it in Main_visible_image
int i;
for (i=0; i< Main_image_width*Main_image_height; i++)
{
layer = *(Main_backups->Pages->Image[4].Pixels+i);
Main_visible_image.Image[i]=*(Main_backups->Pages->Image[layer].Pixels+i);
}
// Copy it to the depth buffer
memcpy(Main_visible_image_depth_buffer.Image,
Main_backups->Pages->Image[4].Pixels,
Main_image_width*Main_image_height);
// Next
layer= (1<<4)+1;
}
else
{
for (layer=0; layer<Main_backups->Pages->Nb_layers; layer++)
{
if ((1<<layer) & Main_layers_visible)
{
// Copy it in Main_visible_image
memcpy(Main_visible_image.Image,
Main_backups->Pages->Image[layer].Pixels,
Main_image_width*Main_image_height);
// Initialize the depth buffer
memset(Main_visible_image_depth_buffer.Image,
layer,
Main_image_width*Main_image_height);
// skip all other layers
layer++;
break;
}
}
}
// subsequent layer(s)
for (; layer<Main_backups->Pages->Nb_layers; layer++)
{
if ((1<<layer) & Main_layers_visible)
{
int i;
for (i=0; i<Main_image_width*Main_image_height; i++)
{
byte color = *(Main_backups->Pages->Image[layer].Pixels+i);
if (color != Main_backups->Pages->Transparent_color) // transparent color
{
*(Main_visible_image.Image+i) = color;
if (layer != Main_current_layer)
*(Main_visible_image_depth_buffer.Image+i) = layer;
}
}
}
} }
// Copy it to the depth buffer
memcpy(Main_visible_image_depth_buffer.Image,
Main_backups->Pages->Image[4].Pixels,
Main_image_width*Main_image_height);
// Next
layer= (1<<4)+1;
} }
else else
{ {
Update_screen_targets();
}
Update_FX_feedback(Config.FX_Feedback);
}
void Update_depth_buffer(void)
{
if (Main_backups->Pages->Image_mode != IMAGE_MODE_ANIMATION)
{
// Re-construct the depth buffer with the visible layers.
// This function doesn't touch the visible buffer, it assumes
// that it was already up-to-date. (Ex. user only changed active layer)
int layer;
// First layer
for (layer=0; layer<Main_backups->Pages->Nb_layers; layer++) for (layer=0; layer<Main_backups->Pages->Nb_layers; layer++)
{ {
if ((1<<layer) & Main_layers_visible) if ((1<<layer) & Main_layers_visible)
{ {
// Copy it in Main_visible_image
memcpy(Main_visible_image.Image,
Main_backups->Pages->Image[layer].Pixels,
Main_image_width*Main_image_height);
// Initialize the depth buffer // Initialize the depth buffer
memset(Main_visible_image_depth_buffer.Image, memset(Main_visible_image_depth_buffer.Image,
layer, layer,
@ -244,145 +294,99 @@ void Redraw_layered_image(void)
break; break;
} }
} }
} // subsequent layer(s)
// subsequent layer(s) for (; layer<Main_backups->Pages->Nb_layers; layer++)
for (; layer<Main_backups->Pages->Nb_layers; layer++)
{
if ((1<<layer) & Main_layers_visible)
{ {
int i; // skip the current layer, whenever we reach it
for (i=0; i<Main_image_width*Main_image_height; i++) if (layer == Main_current_layer)
continue;
if ((1<<layer) & Main_layers_visible)
{ {
byte color = *(Main_backups->Pages->Image[layer].Pixels+i); int i;
if (color != Main_backups->Pages->Transparent_color) // transparent color for (i=0; i<Main_image_width*Main_image_height; i++)
{ {
*(Main_visible_image.Image+i) = color; byte color = *(Main_backups->Pages->Image[layer].Pixels+i);
if (layer != Main_current_layer) if (color != Main_backups->Pages->Transparent_color) // transparent color
{
*(Main_visible_image_depth_buffer.Image+i) = layer; *(Main_visible_image_depth_buffer.Image+i) = layer;
}
} }
} }
} }
} }
#else
Update_screen_targets();
#endif
Update_FX_feedback(Config.FX_Feedback);
}
void Update_depth_buffer(void)
{
#ifndef NOLAYERS
// Re-construct the depth buffer with the visible layers.
// This function doesn't touch the visible buffer, it assumes
// that it was already up-to-date. (Ex. user only changed active layer)
int layer;
// First layer
for (layer=0; layer<Main_backups->Pages->Nb_layers; layer++)
{
if ((1<<layer) & Main_layers_visible)
{
// Initialize the depth buffer
memset(Main_visible_image_depth_buffer.Image,
layer,
Main_image_width*Main_image_height);
// skip all other layers
layer++;
break;
}
}
// subsequent layer(s)
for (; layer<Main_backups->Pages->Nb_layers; layer++)
{
// skip the current layer, whenever we reach it
if (layer == Main_current_layer)
continue;
if ((1<<layer) & Main_layers_visible)
{
int i;
for (i=0; i<Main_image_width*Main_image_height; i++)
{
byte color = *(Main_backups->Pages->Image[layer].Pixels+i);
if (color != Main_backups->Pages->Transparent_color) // transparent color
{
*(Main_visible_image_depth_buffer.Image+i) = layer;
}
}
}
}
#endif
Update_FX_feedback(Config.FX_Feedback); Update_FX_feedback(Config.FX_Feedback);
} }
void Redraw_spare_image(void) void Redraw_spare_image(void)
{ {
#ifndef NOLAYERS if (Spare_backups->Pages->Image_mode != IMAGE_MODE_ANIMATION)
// Re-construct the image with the visible layers
byte layer;
// First layer
for (layer=0; layer<Spare_backups->Pages->Nb_layers; layer++)
{ {
if ((1<<layer) & Spare_layers_visible) // Re-construct the image with the visible layers
byte layer;
// First layer
for (layer=0; layer<Spare_backups->Pages->Nb_layers; layer++)
{ {
// Copy it in Spare_visible_image if ((1<<layer) & Spare_layers_visible)
memcpy(Spare_visible_image.Image,
Spare_backups->Pages->Image[layer].Pixels,
Spare_image_width*Spare_image_height);
// No depth buffer in the spare
//memset(Spare_visible_image_depth_buffer.Image,
// layer,
// Spare_image_width*Spare_image_height);
// skip all other layers
layer++;
break;
}
}
// subsequent layer(s)
for (; layer<Spare_backups->Pages->Nb_layers; layer++)
{
if ((1<<layer) & Spare_layers_visible)
{
int i;
for (i=0; i<Spare_image_width*Spare_image_height; i++)
{ {
byte color = *(Spare_backups->Pages->Image[layer].Pixels+i); // Copy it in Spare_visible_image
if (color != Spare_backups->Pages->Transparent_color) // transparent color memcpy(Spare_visible_image.Image,
Spare_backups->Pages->Image[layer].Pixels,
Spare_image_width*Spare_image_height);
// No depth buffer in the spare
//memset(Spare_visible_image_depth_buffer.Image,
// layer,
// Spare_image_width*Spare_image_height);
// skip all other layers
layer++;
break;
}
}
// subsequent layer(s)
for (; layer<Spare_backups->Pages->Nb_layers; layer++)
{
if ((1<<layer) & Spare_layers_visible)
{
int i;
for (i=0; i<Spare_image_width*Spare_image_height; i++)
{ {
*(Spare_visible_image.Image+i) = color; byte color = *(Spare_backups->Pages->Image[layer].Pixels+i);
//if (layer != Spare_current_layer) if (color != Spare_backups->Pages->Transparent_color) // transparent color
// *(Spare_visible_image_depth_buffer.Image+i) = layer; {
*(Spare_visible_image.Image+i) = color;
//if (layer != Spare_current_layer)
// *(Spare_visible_image_depth_buffer.Image+i) = layer;
}
} }
} }
} }
} }
#endif
} }
void Redraw_current_layer(void) void Redraw_current_layer(void)
{ {
#ifndef NOLAYERS if (Main_backups->Pages->Image_mode != IMAGE_MODE_ANIMATION)
int i;
for (i=0; i<Main_image_width*Main_image_height; i++)
{ {
byte depth = *(Main_visible_image_depth_buffer.Image+i); int i;
if (depth<=Main_current_layer) for (i=0; i<Main_image_width*Main_image_height; i++)
{ {
byte color = *(Main_backups->Pages->Image[Main_current_layer].Pixels+i); byte depth = *(Main_visible_image_depth_buffer.Image+i);
if (color != Main_backups->Pages->Transparent_color) // transparent color if (depth<=Main_current_layer)
{ {
*(Main_visible_image.Image+i) = color; byte color = *(Main_backups->Pages->Image[Main_current_layer].Pixels+i);
} if (color != Main_backups->Pages->Transparent_color) // transparent color
else {
{ *(Main_visible_image.Image+i) = color;
*(Main_visible_image.Image+i) = *(Main_backups->Pages->Image[depth].Pixels+i); }
else
{
*(Main_visible_image.Image+i) = *(Main_backups->Pages->Image[depth].Pixels+i);
}
} }
} }
} }
#endif
} }
void Upload_infos_page_main(T_Page * page) void Upload_infos_page_main(T_Page * page)
@ -672,83 +676,79 @@ void Free_page_of_a_list(T_List_of_pages * list)
void Update_screen_targets(void) void Update_screen_targets(void)
{ {
#ifndef NOLAYERS if (Main_backups->Pages->Image_mode != IMAGE_MODE_ANIMATION)
{
Main_screen=Main_visible_image.Image; Main_screen=Main_visible_image.Image;
Screen_backup=Main_visible_image_backup.Image; Screen_backup=Main_visible_image_backup.Image;
#else }
else
{
Main_screen=Main_backups->Pages->Image[Main_current_layer].Pixels; Main_screen=Main_backups->Pages->Image[Main_current_layer].Pixels;
Screen_backup=Main_backups->Pages->Next->Image[Main_current_layer].Pixels; Screen_backup=Main_backups->Pages->Next->Image[Main_current_layer].Pixels;
#endif }
Update_pixel_renderer(); Update_pixel_renderer();
} }
/// Update all the special image buffers, if necessary. /// Update all the special image buffers, if necessary.
int Update_buffers(int width, int height) int Update_buffers(int width, int height)
{ {
#ifdef NOLAYERS if (Main_backups->Pages->Image_mode != IMAGE_MODE_ANIMATION)
// unused args
(void) width;
(void) height;
#else
// At least one dimension is different
if (Main_visible_image.Width*Main_visible_image.Height != width*height)
{ {
// Current image // At least one dimension is different
free(Main_visible_image.Image); if (Main_visible_image.Width*Main_visible_image.Height != width*height)
Main_visible_image.Image = (byte *)malloc(width * height); {
if (Main_visible_image.Image == NULL) // Current image
return 0; free(Main_visible_image.Image);
} Main_visible_image.Image = (byte *)malloc(width * height);
Main_visible_image.Width = width; if (Main_visible_image.Image == NULL)
Main_visible_image.Height = height; return 0;
}
if (Main_visible_image_backup.Width*Main_visible_image_backup.Height != width*height) Main_visible_image.Width = width;
{ Main_visible_image.Height = height;
// Previous image
free(Main_visible_image_backup.Image); if (Main_visible_image_backup.Width*Main_visible_image_backup.Height != width*height)
Main_visible_image_backup.Image = (byte *)malloc(width * height); {
if (Main_visible_image_backup.Image == NULL) // Previous image
return 0; free(Main_visible_image_backup.Image);
} Main_visible_image_backup.Image = (byte *)malloc(width * height);
Main_visible_image_backup.Width = width; if (Main_visible_image_backup.Image == NULL)
Main_visible_image_backup.Height = height; return 0;
}
if (Main_visible_image_depth_buffer.Width*Main_visible_image_depth_buffer.Height != width*height) Main_visible_image_backup.Width = width;
{ Main_visible_image_backup.Height = height;
// Depth buffer
free(Main_visible_image_depth_buffer.Image);
Main_visible_image_depth_buffer.Image = (byte *)malloc(width * height);
if (Main_visible_image_depth_buffer.Image == NULL)
return 0;
}
Main_visible_image_depth_buffer.Width = width;
Main_visible_image_depth_buffer.Height = height;
#endif if (Main_visible_image_depth_buffer.Width*Main_visible_image_depth_buffer.Height != width*height)
{
// Depth buffer
free(Main_visible_image_depth_buffer.Image);
Main_visible_image_depth_buffer.Image = (byte *)malloc(width * height);
if (Main_visible_image_depth_buffer.Image == NULL)
return 0;
}
Main_visible_image_depth_buffer.Width = width;
Main_visible_image_depth_buffer.Height = height;
}
Update_screen_targets(); Update_screen_targets();
return 1; return 1;
} }
/// Update all the special image buffers of the spare page, if necessary. /// Update all the special image buffers of the spare page, if necessary.
int Update_spare_buffers(int width, int height) int Update_spare_buffers(int width, int height)
{ {
#ifdef NOLAYERS if (Spare_backups->Pages->Image_mode != IMAGE_MODE_ANIMATION)
// unused args
(void) width;
(void) height;
#else
// At least one dimension is different
if (Spare_visible_image.Width*Spare_visible_image.Height != width*height)
{ {
// Current image // At least one dimension is different
free(Spare_visible_image.Image); if (Spare_visible_image.Width*Spare_visible_image.Height != width*height)
Spare_visible_image.Image = (byte *)malloc(width * height); {
if (Spare_visible_image.Image == NULL) // Current image
return 0; free(Spare_visible_image.Image);
Spare_visible_image.Image = (byte *)malloc(width * height);
if (Spare_visible_image.Image == NULL)
return 0;
}
Spare_visible_image.Width = width;
Spare_visible_image.Height = height;
} }
Spare_visible_image.Width = width;
Spare_visible_image.Height = height;
#endif
return 1; return 1;
} }
@ -783,7 +783,6 @@ int Init_all_backup_lists(int width,int height)
return 0; return 0;
memset(Main_backups->Pages->Image[i].Pixels, 0, width*height); memset(Main_backups->Pages->Image[i].Pixels, 0, width*height);
} }
#ifndef NOLAYERS
Main_visible_image.Width = 0; Main_visible_image.Width = 0;
Main_visible_image.Height = 0; Main_visible_image.Height = 0;
Main_visible_image.Image = NULL; Main_visible_image.Image = NULL;
@ -793,20 +792,17 @@ int Init_all_backup_lists(int width,int height)
Spare_visible_image.Height = 0; Spare_visible_image.Height = 0;
Spare_visible_image.Image = NULL; Spare_visible_image.Image = NULL;
#endif
if (!Update_buffers(width, height)) if (!Update_buffers(width, height))
return 0; return 0;
if (!Update_spare_buffers(width, height)) if (!Update_spare_buffers(width, height))
return 0; return 0;
#ifndef NOLAYERS
// For speed, instead of Redraw_layered_image() we'll directly set the buffers. // For speed, instead of Redraw_layered_image() we'll directly set the buffers.
memset(Main_visible_image.Image, 0, width*height); memset(Main_visible_image.Image, 0, width*height);
memset(Main_visible_image_backup.Image, 0, width*height); memset(Main_visible_image_backup.Image, 0, width*height);
memset(Main_visible_image_depth_buffer.Image, 0, width*height); memset(Main_visible_image_depth_buffer.Image, 0, width*height);
memset(Spare_visible_image.Image, 0, width*height); memset(Spare_visible_image.Image, 0, width*height);
#endif
Download_infos_page_main(Main_backups->Pages); Download_infos_page_main(Main_backups->Pages);
Update_FX_feedback(Config.FX_Feedback); Update_FX_feedback(Config.FX_Feedback);
@ -872,6 +868,7 @@ int Backup_new_image(int layers,int width,int height)
} }
Update_buffers(width, height); Update_buffers(width, height);
memset(Main_visible_image_depth_buffer.Image, 0, width*height);
Download_infos_page_main(Main_backups->Pages); Download_infos_page_main(Main_backups->Pages);
@ -926,13 +923,21 @@ int Backup_with_new_dimensions(int width,int height)
// Same code as in End_of_modification(), // Same code as in End_of_modification(),
// Without saving a safety backup: // Without saving a safety backup:
#ifndef NOLAYERS if (Main_backups->Pages->Image_mode != IMAGE_MODE_ANIMATION)
{
memcpy(Main_visible_image_backup.Image, memcpy(Main_visible_image_backup.Image,
Main_visible_image.Image, Main_visible_image.Image,
Main_image_width*Main_image_height); Main_image_width*Main_image_height);
#else }
else
{
// Clear the depth buffer anyway, because we may use it later
memset(Main_visible_image_depth_buffer.Image, 0,
Main_image_width*Main_image_height);
Update_screen_targets(); Update_screen_targets();
#endif }
Update_FX_feedback(Config.FX_Feedback); Update_FX_feedback(Config.FX_Feedback);
// -- // --
@ -989,31 +994,32 @@ int Backup_in_place(int width,int height)
// The following is part of Update_buffers() // The following is part of Update_buffers()
// (without changing the backup buffer) // (without changing the backup buffer)
#ifndef NOLAYERS if (Main_backups->Pages->Image_mode != IMAGE_MODE_ANIMATION)
// At least one dimension is different
if (Main_visible_image.Width*Main_visible_image.Height != width*height)
{ {
// Current image // At least one dimension is different
free(Main_visible_image.Image); if (Main_visible_image.Width*Main_visible_image.Height != width*height)
Main_visible_image.Image = (byte *)malloc(width * height); {
if (Main_visible_image.Image == NULL) // Current image
return 0; free(Main_visible_image.Image);
} Main_visible_image.Image = (byte *)malloc(width * height);
Main_visible_image.Width = width; if (Main_visible_image.Image == NULL)
Main_visible_image.Height = height; return 0;
}
if (Main_visible_image_depth_buffer.Width*Main_visible_image_depth_buffer.Height != width*height) Main_visible_image.Width = width;
{ Main_visible_image.Height = height;
// Depth buffer
free(Main_visible_image_depth_buffer.Image);
Main_visible_image_depth_buffer.Image = (byte *)malloc(width * height);
if (Main_visible_image_depth_buffer.Image == NULL)
return 0;
}
Main_visible_image_depth_buffer.Width = width;
Main_visible_image_depth_buffer.Height = height;
#endif if (Main_visible_image_depth_buffer.Width*Main_visible_image_depth_buffer.Height != width*height)
{
// Depth buffer
free(Main_visible_image_depth_buffer.Image);
Main_visible_image_depth_buffer.Image = (byte *)malloc(width * height);
if (Main_visible_image_depth_buffer.Image == NULL)
return 0;
}
Main_visible_image_depth_buffer.Width = width;
Main_visible_image_depth_buffer.Height = height;
}
Update_screen_targets(); Update_screen_targets();
return 1; return 1;
@ -1278,19 +1284,21 @@ void End_of_modification(void)
//Update_buffers(Main_image_width, Main_image_height); //Update_buffers(Main_image_width, Main_image_height);
#ifndef NOLAYERS if (Main_backups->Pages->Image_mode != IMAGE_MODE_ANIMATION)
// Backup buffer can have "wrong" size if a Lua script {
// performs a resize. // Backup buffer can have "wrong" size if a Lua script
Update_buffers(Main_image_width, Main_image_height); // performs a resize.
// Update_buffers(Main_image_width, Main_image_height);
//
memcpy(Main_visible_image_backup.Image,
Main_visible_image.Image,
Main_image_width*Main_image_height);
#else
Update_screen_targets();
#endif
memcpy(Main_visible_image_backup.Image,
Main_visible_image.Image,
Main_image_width*Main_image_height);
}
else
{
Update_screen_targets();
}
Update_FX_feedback(Config.FX_Feedback); Update_FX_feedback(Config.FX_Feedback);
/* /*
Last_backed_up_layers = 0; Last_backed_up_layers = 0;
@ -1306,6 +1314,7 @@ void End_of_modification(void)
/// Add a new layer to latest page of a list. Returns 0 on success. /// Add a new layer to latest page of a list. Returns 0 on success.
byte Add_layer(T_List_of_pages *list, int layer) byte Add_layer(T_List_of_pages *list, int layer)
{ {
int max[] = {MAX_NB_LAYERS, MAX_NB_FRAMES, 5};
T_Page * source_page; T_Page * source_page;
T_Page * new_page; T_Page * new_page;
byte * new_image; byte * new_image;
@ -1313,7 +1322,7 @@ byte Add_layer(T_List_of_pages *list, int layer)
source_page = list->Pages; source_page = list->Pages;
if (list->Pages->Nb_layers == MAX_NB_LAYERS) if (list->Pages->Nb_layers >= max[list->Pages->Image_mode]) // MAX_NB_LAYERS
return 1; return 1;
// Keep the position reasonable // Keep the position reasonable