summaryrefslogtreecommitdiff
path: root/riscos
diff options
context:
space:
mode:
Diffstat (limited to 'riscos')
-rw-r--r--riscos/gif.c222
1 files changed, 171 insertions, 51 deletions
diff --git a/riscos/gif.c b/riscos/gif.c
index 5a829103d..cd63801f6 100644
--- a/riscos/gif.c
+++ b/riscos/gif.c
@@ -3,6 +3,8 @@
* Licensed under the GNU General Public License,
* http://www.opensource.org/licenses/gpl-license
* Copyright 2003 John M Bell <jmb202@ecs.soton.ac.uk>
+ * Copyright 2004 Richard Wilson <not_ginger_matt@sourceforge.net>
+ *
* Parts modified from IGviewer source by Peter Hartley
* http://utter.chaos.org/~pdh/software/intergif.htm
*/
@@ -25,18 +27,50 @@
#include "netsurf/utils/messages.h"
#include "netsurf/utils/utils.h"
+
+/* REVISED GIF FUNCTIONALITY
+ =========================
+
+ To improve the display quality of the GIFs, Tinct is used when plotting the
+ images. This provides a speed gain as the necessary translation tables are
+ cached, but comes at the expense that the current frame must be held as a
+ 32bpp sprite.
+
+ To overcome the problem of memory wastage, each frame of the GIF is held as
+ an 8bpp sprite with a 256 colour entry palette and is converted into a 32bpp
+ sprite suitable for plotting following a frame transition. This conversion is
+ performed by using Tinct_ConvertSprite.
+
+ By using this technique rather than dynamically decompressing the current
+ GIF frame we can skip over frames that we can't display and always keep
+ pace with the animation simply. If we were dynamically decompressing the
+ GIF then it would be necessary to also decompress any intermediate frames as
+ the GIF format dictates that each successive frame is plotted on top of any
+ previous one.
+
+ N.B. Future implementations may of store each frame at the lowest possible
+ colour depth to reduce memory usage. To ensure this forwards compatibility
+ nsgif_get_sprite_address should always be used to obtain the sprite for the
+ various animation frames.
+
+ [rjw] - Wed 17th March 2004
+*/
+
#ifdef WITH_GIF
static osspriteop_area *create_buffer_sprite(struct content *c, anim a);
-void nsgif_init(void)
-{
+void nsgif_init(void) {
}
-void nsgif_create(struct content *c, const char *params[])
-{
- c->data.gif.sprite_area = 0;
- c->data.gif.buffer_pos = 0;
+void nsgif_create(struct content *c, const char *params[]) {
+ c->data.gif.sprite_area = 0;
+ c->data.gif.buffer_pos = 0;
+ c->data.gif.total_frames = 0; // Paranoid
+
+ c->data.gif.current_frame = 0;
+ c->data.gif.expanded_frame = 0xffffffff; // ie invalid value
+ c->data.gif.remainder_time = 0;
}
@@ -48,6 +82,7 @@ int nsgif_convert(struct content *c, unsigned int iwidth, unsigned int iheight)
struct osspriteop_header *header;
struct osspriteop_area *area;
+
a = Anim_FromData(c->source_data, c->source_size, NULL, false, false, false);
if (!a) {
@@ -61,6 +96,10 @@ int nsgif_convert(struct content *c, unsigned int iwidth, unsigned int iheight)
Anim_Destroy(&a);
return 1;
}
+ /* Claim a buffer [temporary code]
+ */
+ struct osspriteop_header *temp_buf = xcalloc(1, a->nWidth * a->nHeight * 4 + 44);
+ c->data.gif.buffer_header = (osspriteop_header*)(temp_buf);
area = create_buffer_sprite(c, a);
if(!area) {
@@ -121,62 +160,143 @@ int nsgif_convert(struct content *c, unsigned int iwidth, unsigned int iheight)
void nsgif_redraw(struct content *c, long x, long y,
unsigned long width, unsigned long height,
long clip_x0, long clip_y0, long clip_x1, long clip_y1,
- float scale)
-{
+ float scale) {
+
+ /* Check if we need to expand the current frame to 32bpp
+ */
+ if (c->data.gif.current_frame != c->data.gif.expanded_frame) {
+
+ /* Convert the sprite
+ */
+ _swix(Tinct_ConvertSprite, _IN(2) | _IN(3),
+ ((char *) nsgif_get_sprite_address(c, c->data.gif.current_frame)),
+ ((char *) c->data.gif.buffer_header));
+
+ LOG(("Converted GIF frame %i.", c->data.gif.current_frame));
+
+ /* Remember we are expanded for future calls
+ */
+ c->data.gif.current_frame = c->data.gif.expanded_frame;
+ }
/* Tinct currently only handles 32bpp sprites that have an embedded alpha mask. Any
sprites not matching the required specifications are ignored. See the Tinct
documentation for further information.
*/
-/* _swix(Tinct_PlotScaledAlpha, _IN(2) | _IN(3) | _IN(4) | _IN(5) | _IN(6) | _IN(7),
- ((char *) c->data.gif.sprite_area + c->data.gif.sprite_area->first),
+ _swix(Tinct_PlotScaledAlpha, _IN(2) | _IN(3) | _IN(4) | _IN(5) | _IN(6) | _IN(7),
+ ((char *) c->data.gif.buffer_header),
x, (int)(y - height),
width, height,
(option_filter_sprites?(1<<1):0) | (option_dither_sprites?(1<<2):0));
+
+}
+
+
+
+void nsgif_destroy(struct content *c) {
+ /* Free all the associated memory buffers
+ */
+ xfree(c->title);
+ xfree(c->data.gif.sprite_area);
+ xfree(c->data.gif.buffer_header);
+ xfree(c->data.gif.frame_transitions);
+}
+
+
+
+/** Performs any necessary animation.
+
+ @param c The content to animate
+ @param advance_time The number of cs to move the animation forwards
+ @return 0 for no further scheduling as the animation has finished, or
+ >0 to indicate the number of cs until the next animation frame, or
+ <0 to indicate that an animation has occured. The absolute value
+ indicates the number of cs until the next animation frame.
*/
- unsigned int size;
- osspriteop_trans_tab *table;
- os_factors factors;
-
-
- xcolourtrans_generate_table_for_sprite(c->data.gif.sprite_area,
- (osspriteop_id) ((char*)c->data.gif.sprite_area +
- c->data.gif.sprite_area->first),
- colourtrans_CURRENT_MODE, colourtrans_CURRENT_PALETTE,
- 0, colourtrans_GIVEN_SPRITE, 0, 0, &size);
-
- table = xcalloc(size, 1);
-
- xcolourtrans_generate_table_for_sprite(c->data.gif.sprite_area,
- (osspriteop_id) ((char*)c->data.gif.sprite_area +
- c->data.gif.sprite_area->first),
- colourtrans_CURRENT_MODE, colourtrans_CURRENT_PALETTE,
- table, colourtrans_GIVEN_SPRITE, 0, 0, 0);
-
- factors.xmul = width;
- factors.ymul = height;
- factors.xdiv = c->width * 2;
- factors.ydiv = c->height * 2;
-
- xosspriteop_put_sprite_scaled(osspriteop_PTR,
- c->data.gif.sprite_area,
- (osspriteop_id) ((char*)c->data.gif.sprite_area +
- c->data.gif.sprite_area->first),
- x, (int)(y - height),
- /* osspriteop_USE_PALETTE is RO 3.5+ only.
- * behaviour on RO < 3.5 is unknown...
- */
- (osspriteop_action)(osspriteop_USE_MASK |
- osspriteop_USE_PALETTE),
- &factors, table);
-
- xfree(table);
+int nsgif_animate(struct content *c, unsigned int advance_time) {
+ unsigned int max_frame;
+ unsigned int cur_frame;
+ unsigned int old_frame;
+ unsigned int *delay_values;
+
+ /* Abort if we are not animated or cannot animate
+ */
+ max_frame = c->data.gif.total_frames;
+ if ((max_frame < 2) || (!c->data.gif.animate_gif)) return 0;
+
+ /* Add in the number of cs we had left over from the last animation
+ */
+ advance_time += c->data.gif.remainder_time;
+
+ /* Get our frame information locally
+ */
+ cur_frame = old_frame = c->data.gif.current_frame;
+ delay_values = c->data.gif.frame_transitions;
+
+ /* Move through the frames
+ */
+ while (advance_time >= delay_values[cur_frame]) {
+
+ /* Advance a frame
+ */
+ advance_time -= delay_values[cur_frame];
+ cur_frame++;
+
+ /* Handle looping
+ */
+ if (cur_frame >= max_frame) {
+ if (!c->data.gif.loop_gif) {
+ c->data.gif.current_frame = max_frame - 1;
+ c->data.gif.animate_gif = false;
+
+ /* We can't return 0 as it indicates no animation
+ has occured, so we return a small value so we
+ can be called back and then say that we're done.
+ */
+ return -1;
+ } else {
+ cur_frame -= max_frame;
+ }
+ }
+ }
+
+ /* Store the leftover time
+ */
+ c->data.gif.remainder_time = advance_time;
+
+ /* Return whether we've changed and when the next update should be
+ */
+ if (cur_frame == old_frame) {
+ return (delay_values[cur_frame] - advance_time);
+ } else {
+ c->data.gif.current_frame = cur_frame;
+ return (advance_time - delay_values[cur_frame]);
+ }
}
-void nsgif_destroy(struct content *c)
-{
- xfree(c->title);
- xfree(c->data.gif.sprite_area);
+
+
+/** Provides the address of a frame within the sprite area.
+
+ @param c The content to find the frame from
+ @param frame The desired frame [0...(max-1)]
+ @return The address of the sprite header
+*/
+osspriteop_header *nsgif_get_sprite_address(struct content *c, unsigned int frame) {
+ struct osspriteop_header *header;
+
+ /* Get the header for the first sprite
+ */
+ header = (osspriteop_header*)((char *)c->data.gif.sprite_area +
+ c->data.gif.sprite_area->first);
+
+ /* Keep advancing until we get our sprite
+ */
+ while (frame-- > 0) header += header->size;
+
+ /* Return our value
+ */
+ return header;
}