Imagens

Com OSLib, você pode facilmente carregar imagens do Memory Stick, por enquanto apenas png, para manipular, remover, e deformar. O canal alpha também é suportado.
Vamos ver as funções necessária para isto:

Primeiro de tudo, é necessário criar uma imagem com a seguinte função:

OSL_IMAGE *oslCreateImage(int larg, int haut, short location, short pixelFormat);

Esta função cría uma imagem vazia do tamanho especificado. Vazia, não é muito útil, mas você é capaz de modificá-la mais tarde.

Em cada caso, quando OSLib não poder criar um objeto, o valor NULO é retornado. Assim, você tem que verificar qu e a imagem pode ser criada antes de ser usada, se não você será avisado por um ruído elétrico. No próximo exemplo, nós tentaremos primeiramente criar a imagem em VRAM, e se aquele falhar, nós tentamos na RAM, e se nenhum deles funcionar, mostraremos um erro e paramos então o jogo:

//Tentando criar a nova imagem
image = oslCreateImage(32, 32, OSL_IN_VRAM, OSL_PF_4444);
//A imagem é nula?
if (!image)         {
    //Impossível criar na VRAM... tentando na RAM
    image = oslCreateImage(32, 32, OSL_IN_RAM, OSL_PF_4444);
    //Está ok agora?
    if (!image)     {
        oslFatalError("Impossivel criar a imagem");
        return;
    }
}
//Partindo daqui, podemos utilizá-la
oslDrawImage(image);

Posição de Memória para Imagens

A maioria das funções de criação e de manipulação da imagem ajudam-lhe definir onde você pode alocar a imagem. No PSP, há dois lugares possíveis: a RAM (a memória principal, MB 20, lenta) e o VRAM (a memória video, MB 2, rápida). Para imagens normais, eu recomendo-o criá-las na RAM (porque há um espaço maior). E para as imagens que a velocidade é importante, criá-las na VRAM. Para criar uma imagem na RAM, colocar OSL_IN_RAM como o argumento em location e em OSL_IN_VRAM para o VRAM.

PixelFormats

PixelFormats é usado descrever o formato das cores de cada pixel. No PSP há 6 pixelformats principais, alguns deles são usados somente em determinadas circunstâncias:

- OSL_PF_8888: 32 bits por pixel, 8 bits para vermelho, verde, azul e alpha. O componente alpha é utilizado para definir a opacidade de um pixel (255=opaco, 0=transparente).
- OSL_PF_5650: 16 bits por pixel, 5 bits para vermelho, 6 bits para verde, 5 bits para azul e 0 alpha. Estas imagens não devem ser usadas para sprites ou mapas, porque não podem ter qualquer parte transparente, porque não possui canal alpha .
- OSL_PF_5551: 16 bits por pixel, 5 bits para vermelho, 5 bits para verde, 5 bits para azul, e 1 bit para o componente alpha, Mostra se o pixel é transparente ou se é mostrado. Util para sprites simples
- OSL_PF_4444: 16 bits por pixel, 4 bits para vermelho, verde, azul e alpha. Estas imagens têm uma quantidade limitada de cores (4096), mas podem definir 16 níveis da transparência para cada pixel.
- OSL_PF_8BIT: 8 bits por pixel, indexado em uma palette.
- OSL_PF_4BIT: 4 bits per pixel, indexado em uma palette.

OSL_IMAGE *oslLoadImageFile(char *filename, int location, int pixelFormat);

Esta função permite carregar uma imagem de um arquivo. Você pode voltar à raiz do Memory Stick digitando o trajeto, como este este: ms0: /path/file.png. Cuidado: Respeite maiúsculas e minúsculas, por exemplo se uma imagem tem o nome ?image.png? e está no ms, e no código é colocado ?Image.png?, o programa irá falhar!

void oslCopyImage(OSL_IMAGE *imgDst, OSL_IMAGE *imgSrc);

Permite a cópia de uma imagem para outra, mas ambas devem ter formatos idênticos, Exemplo:

myImage1 = oslCreateImage(32, 32, OSL_IN_RAM, OSL_PF_8888);
myImage2 = oslCreateImage(32, 32, OSL_IN_RAM, OSL_PF_8888);
//myImage2 <- myImage1
oslCopyImage(myImage2, myImage1);

OSL_IMAGE *oslCreateImageCopy(OSL_IMAGE *src, int newLocation);

Criar uma cópia de uma imagem, com a possibilidade de escolher onde a cópia ocorrerá. Exceto que, a imagem retornada terá exatamente o mesmo formato que a imagem passada como fonte no parâmetro. O exemplo da função oslCopyImage pode também ser feita como esta:

monImage1 = oslCreateImage(32, 32, OSL_IN_RAM, OSL_PF_8888);
monImage2 = oslCreateImageCopy(monImage1, OSL_IN_RAM);

void oslUncacheImage(OSL_IMAGE *img);

Retira a imagem colocada em cache. Se você quiser acessar os dados desta imagem, Você deve chamar esta função que passa a imagem antes que você possa removê-la. Para maiores informações volte ao capítulo CPU CACHE. Exemplo:

img = oslCreateImage(32, 32, OSL_IN_RAM, OSL_PF_8888);
unsigned long *ptr = oslGetImagePixelAdr(img, 15, 10);
//Colorizes 5 red pixels starting from (15,10).
for (i=0;i<5;i++)
    *ptr++ = RGB(255,0,0);
oslUncacheImage(img);
//Without the oslUncacheImage call, the GPU will draw the image incorrectly (Because it is still in the CPU cache and the GPU has no access to it).
oslDrawImage(img);

Uma vez terminado de utilizar a imagem, você pode apagá-la utilizando a função:

void oslDeleteImage(OSL_IMAGE *img);

Infelizmente, ainda não há nenhum controlador de heap na VRAM, sendo assim as imagens da VRAM podem ser apagadas somente se forem a ultima criada. Exemplo:

//Criação de Imagens
myImage1 = oslCreateImage(16, 16, OSL_IN_VRAM, OSL_PF_8888);
myImage2 = oslCreateImage(32, 32, OSL_IN_VRAM, OSL_PF_8888);
[...]
//Precisam ser deletadas na ordem da pilha
oslDeleteImage(myImage2);
oslDeleteImage(myImage1);

Se uma imagem for criada entre as duas imagens,você não pode apagar myImage1 antes da myImage2. Se você não fizer assim, o programa continuará, porém suas imagens podem corromper.
Abaixo um exemplo de imagem corrompida:

image1 = oslLoadImageFile("image1.png", OSL_IN_VRAM, OSL_PF_5551);
image2 = oslLoadImageFile("image2.png", OSL_IN_VRAM, OSL_PF_5551);
//Grande erro, você deve deletar a imagem2 antes da imagem1
oslDeleteImage(image1);
//Image2 corrompida pela imagem 3
image3 = oslLoadImageFile("image3.png", OSL_IN_VRAM, OSL_PF_5551);

Entretanto, não há nenhum problema se você criar suas imagens na RAM, que é porque você deve evitar de usar VRAM a menos que saiba exatamente o que está fazendo.

Manipulação de Imagens

Uma imagem contém uma estrutura que possui todas suas informações. Os primeiros elementos (public) são os que podem ser modificados, os outros (private) são internos e é recomendado não alterá-los. Exemplo:

myImage = oslCreateImage(16, 16, OSL_IN_VRAM, OSL_PF_8888);
myImage->angle = 20;
//Desenhando a imagem com rotação de aproximadamente 20°
oslDrawImage(myImage);

Aqui estão os elementos que falávamos aproximadamente :

typedef struct		{
	//public
	int x, y;							// Posições
	int stretchX, stretchY;					//tamanho final (stretched)
	//parte
	float offsetX0, offsetY0, offsetX1, offsetY1;
	//Rotação
	int centerX, centerY;					//Rotação Central
	float angle;						//Angulo (rotation)
	//Parameters
	bool autoStrip;						//Auto stripping (incompatible with rotation)
	bool bilinear;
	OSL_PALETTE *palette;					//Palette para 4 e 8 bits

	//private
	int sizeX, sizeY;						//tamanho Real
	int sysSizeX, sysSizeY;					//tamanho alinhado
	int realSizeX, realSizeY;					//tamanho se alinhado
	void *data;						//Dados da Imagem
	bool isCopy;						// uma cópia de uma outra imagem? 
	bool isSwizzled;						//É swizzled (otimizada)?
	int totalSize;						//tamanho em Bytes
	short location, pixelFormat;
} OSL_IMAGE;

As posições de x e de y são usadas controlar onde a imagem será desenhada na tela. O canto esquerdo acima é 0.0 e o direito abaixo é 479.271. A Primeira coordenada (x) é o componente horizontal e (y) vertical.
O stretchX e stretchY são propriedades que podem efetuar zoom. Informado o tamanho que você quer. Por exemplo uma imagem de 16x16 com um zoom 2x você precisa colocar 32 para stretchX e stretchY. Para este cálculo você pode utilizar as propriedades de sizeX e sizeY, ou offsetX1-offsetX0 e offsetY1-offsetY0 se for uma imagem do tipo tiles:

img->stretchX = 2 * img->sizeX;
img->stretchY = 2 * img->sizeY;
img->stretchX = 2 * abs(img->offsetX1-img->offsetX0);
img->stretchY = 2 * abs(img->offsetY1-img->offsetY0);

A propriedade offset tem quer usada para ajustar o frame da imagem que será mostrada na tela. Por Exemplo, se sua imagem possui tamanho 16x16 e você quiser mostrar apenas 8x8 da direita acima, você pode informar 8 em offsetX0 a offsetY0, 16 em offsetX1 e 8 em offsetY1, para definir estas propriedades, use isto: :

oslSetImageTile(image,x0,y0,x1,y1);
oslSetImageTileSize(image,x,y,width,height);

As propriedades centerX e centerY definem o centro da rotação da imagem, e o angle define o ângulo da rotação da imagem. Usar a rotação reduz desempenhos, principalmente para imagens grandes, faça testes antes de usar.

o autostrip otimiza a velocidade de exposição das imagens grandes (permitidas por default).

bilinear define um filtro bilinear à imagem.

palette define a paleta usada para desenhar uma imagem posicionada. Você pode criar uma e associá-lo à imagem como este:

const unsigned long myPalette[2] = {RGB(0,0,0), RGB(255,0,0)};			//vermelho e branco
myImage->palette = oslLoadPalette(myPalette, 2, OSL_PF_8888);

Desenhando em Imagens

With OSLib, you can redirect all drawing operations to an image. It is useful, because you can draw this image on the screen by applying it all the effects allowed to a standard image. For example you can draw the contents of a window then make it transparent or stretch it.

For that, we use the following function:

void oslSetDrawBuffer(OSL_IMAGE *img);

This function defines the drawbuffer, that means where you draw. You just have to pass the following parameters:
- OSL_DEFAULT_BUFFER: Default screen (resets to normal operation).
- OSL_SECONDARY_BUFFER: In double buffering mode, the displayed screen (unlike the drawing one).
- an image: Will draw on this image.

OSLib includes a global variable named osl_curBuf, which is a pointer to the current drawing image. So you can obtain the properties of the screen on which you are drawing, and adapt yourself to the resolution or the pixelformat. Here is an example of use of this function:

image = oslCreateImage(160, 100, OSL_IN_VRAM, OSL_PF_5650);
oslSetDrawBuffer(image);
oslDrawGradientRect(0,0,osl_curBuf->sizeX,osl_curBuf->sizeY, RGB(0,0,0), RGB(255,0,0), RGB(0,255,0), RGB(0,0,255));
oslSetDrawBuffer(OSL_DEFAULT_BUFFER);
//Dessine l'image centrée
image->angle = 35;
image->centerX = image->sizeX/2;
image->centerY = image->sizeY/2;
oslDrawImageXY(osl_curBuf->sizeX/2, osl_curBuf->sizeY/2, image);
oslDeleteImage(image);

Warning: The image on which you want to draw HAS TO be in VRAM, otherwise it won't work! Moreover it is why I erase it just after, because you should not stack too many images in VRAM for the enumerated reasons higher.