[C++] Keeping track of palette cycling / About AGSE_SPRITELOAD...

Started by Scavenger, Tue 10/11/2015 14:43:58

Previous topic - Next topic

Scavenger

The old question:
Spoiler
Hey, I'm just finishing off some functions in my translucency plugin, and I've come up with a problem that I can't solve easily. I'm trying to make sure that I can keep the translucency consistent with the real colours of a sprite while I cycle the palette (so I can have, for instance, a translucent waterfall that cycles while still being translucent or a magical rainbow that cycles). For this, I assume I need to create some way of creating an array of values that points the renderer to the right part of the LUT (if 22 cycles to 23, then entry 23 on the LUT needs to be rerouted to 22's entry, or any translucent sprite containing index 23 will still treat it as if it was the original colour)

I'm running into problems because I don't think I'm approaching this right. I have a function to remap an array in parallel to palette cycling, not sure if I'm doing it right:

Code: C++

unsigned char cycle_remap [256];

void ResetRemapping () //Called when a room is loaded, so that the array corresponds 1:1 with the palette.
{
	for (int j = 0; j < 256; ++j)
	{
		cycle_remap [j] = j;
	}
}

void CycleRemap (int start, int end)
{
	if (end > start)
	{
		int diff = end - start;
		int i = 0;
		int wraparound = cycle_remap [end];
		while (i < diff)
		{
			cycle_remap [end-i-1] = cycle_remap [end-i];
			i++;
		}
		cycle_remap [start] = wraparound;
	}
	else
	{
		int diff = start - end;
		int i = 0;
		int wraparound = cycle_remap [start];
		while (i < diff)
		{
			cycle_remap [end+i+1] = cycle_remap [end+i];
			i++;
		}
	}
}


It's meant to match what happens to the palette slots when called with CyclePalette, but it just seems to turn everything one colour. Is this code even right?
[close]

Just so I don't start like fifty different topics, I'll ask my new question here, it's related:

Does AGS only load a sprite once it's currently being used? I have an idea for tinting the colours of characters in 8-bit and I need to access their sprites as they're being used, and I need to know whether or not AGS keeps the sprites past the point they're being used.

Basically, I need to know if I can catch a character's current ViewFrame sprite as it's being loaded with AGSE_SPRITELOAD, run my image process on it, and then repeat for every frame of their animation. I don't want strange things like tinted sprites showing up when I've turned tinting off, or normal sprites showing up. Does the sprite get unloaded as soon as the view moves on to the next frame?

Crimson Wizard

#1
Regarding the code in question.

First, I would suggest to generally simplify it by reducing "entities".
1) You do not need two branches depending on whether "start" or "end" is larger. If "start" is larger, simply swap their values.
2) You do not really need "diff" and "i", you can use "start" to remember current index when cycling.

Code: cpp

void CycleRemap (int start, int end)
{
        if (end < start)
        {
                int temp = start;
                start = end;
                end = temp;
        }

        int wraparound = cycle_remap [start];
        for (; start < end; ++start)
        {
                cycle_remap [start] = cycle_remap [start + 1];
        }
        cycle_remap [end] = wraparound;
}


Hope this will work for you.


EDIT: I actually realized, that STL may not suit you if you are passing array to AGS in some way. So disregard that note.

Crimson Wizard

#2
Erm, wow! scrap that. I misunderstood the meaning of "start" and "end" differences.
The "start < end" case is for rotating left and "start > end" case is for rotating right, correct?


Code: cpp

void CycleRemap (int start, int end)
{
        int wraparound = cycle_remap [start];
        if (end > start)
        {
                // Rotate left
                for (; start < end; ++start)
                {
                        cycle_remap [start] = cycle_remap [start + 1];
                }
        }
        else if (end < start)
        {
                // Rotate right
                for (; start > end; --start)
                {
                        cycle_remap [start] = cycle_remap [start - 1];
                }
        }
        cycle_remap [end] = wraparound;
}



EDIT: Regarding the mistake in your code. The cycling to the right was done incorrectly:
Code: cpp

                while (i < diff)
                {
                        cycle_remap [end+i+1] = cycle_remap [end+i];
                        i++;
                }

What you were doing there:
1) Take the color from current slot and write it into NEXT slot.
2) Go to NEXT slot
3) Repeat.
This actually copied same color everywhere.

Snarky

#3
Quote from: Scavenger on Tue 10/11/2015 14:43:58
Hey, I'm just finishing off some functions in my translucency plugin, and I've come up with a problem that I can't solve easily. I'm trying to make sure that I can keep the translucency consistent with the real colours of a sprite while I cycle the palette (so I can have, for instance, a translucent waterfall that cycles while still being translucent or a magical rainbow that cycles).

When you're composing arbitrary foreground and background layers, the number of possible different colors in the end composition = foreground_color_count * foreground_alpha_level_count * background_color_count (or maybe a better way to put it in a restricted-color scenario is foreground_color_count_rgba * background_color_count_rgb). This number will very quickly exceed the 256 different colors you have available. I therefore see two different possible approaches:

1. You stay very disciplined, limiting the number of colors (and alpha levels) of both the transparent object and the things behind to some small number, e.g. 8 each, and then use 8x8=64 slots in your palette to hold all the possible combinations. (You can also optimize this so you don't store unused combinations.) Keep track of the (constant) background palette, the foreground palette and the alpha for each of these slots, and then you can just cycle the foreground palette and calculate the mix with the background palette. (This would also allow you to e.g. adjust the alpha mix dynamically.)

2. You do the composition "virtually" (using essentially the same steps as in method 1), storing the color values of each final pixel in a table, and then use some color reduction algorithm to pick the 64 (or whatever) "best fit" colors for the whole composition (I'm assuming you want to keep the rest of the palette unaffected for the rest of the background and for other sprites). You set that palette and redraw every pixel with the closest matching color. I would expect this approach to exhibit visible "animation noise" artifacts.

I'm not sure about the overall approach your translucency plugin uses, so I guess it depends on that. I would have thought you'd need to solve the fundamental problem here irrespective of color cycling, so I'm a little confused.

Scavenger

Crimson Wizard: Thankyou! It works fine now. I've got the palette cycling and it looks great, with a couple of hiccups that I can work around when doing the final art for a game.

Snarky: I'm using a set of 8 LUTs, each 256x256 in size, for every palette I have translucency on. Each LUT is roughly 10% more translucent than the last. I'm currently using a single palette for many different backgrounds, so I don't have to generate that many of them. I just needed to figure out how to point the renderer towards the right part of the table. I tripped up on some simple math, I think.

Monsieur OUXX

 

Scavenger

Hey, I wanted to ask a question about AGS' sprite loading, but I didn't want to fill up the Technical forum with new topics, so if it's OK I'll ask it here?

Does AGS only load a sprite once it's currently being used? I have an idea for tinting the colours of characters in 8-bit and I need to access their sprites as they're being used, and I need to know whether or not AGS keeps the sprites past the point they're being used.

Basically, I need to know if I can catch a character's current ViewFrame sprite as it's being loaded with AGSE_SPRITELOAD, run my image process on it, and then repeat for every frame of their animation. I don't want strange things like tinted sprites showing up when I've turned tinting off, or normal sprites showing up. Does the sprite get unloaded as soon as the view moves on to the next frame, or does it stick around for the length of the view?

Cassiebsg

I'm in the "wow, I can answer this question!" state... 8-0

Anyway, CW just answer this recently on another thread:
Quote
AGS does not have sprite preload mechanism. The sprites only load when they are put into use (e.g. displayed on screen). You may have 1000 sprites in a view, but only current frame will load up at a time. This is also a reason why smooth hi-res animations can cause slowdowns (some people invented "preloading" techniques to fight this issue).
There are those who believe that life here began out there...

Crimson Wizard

Scavenger, actually I think that it is still better to create a new thread (or search for existing threads, if you are worried about cluttering forums), rather than modify the first post like you did, because that may be confusing for someone who just opened the thread.


Regarding sprite unloading: AGS has a sprite cache of particular size (can be set in config).
The sprite is only unloaded if sprite cache is full and new sprite is loading up.

Sprite cache keeps track of sprite uses, the sprites that were used long ago are deleted first, and sprites that were used recently are deleted last.

SMF spam blocked by CleanTalk