/*---------------------------------------------------------------------------
  Shinobi2 Sample
  COPYRIGHT (C) SEGA ENTERPRISES, LTD.
---------------------------------------------------------------------------*/
#include	<shinobi.h>
#include	"Nj.h"
#include	"TexMain.h"
#include	"TexMalloc.h"

ALLOC_AREA head,tail;
ALLOC_AREA texblock[TEXMEM_BLOCK_NUM];
ALLOC_AREA *max_area;
ALLOC_AREA *space_area;




/*
	●head
	・next		ALLOC_AREAの先頭へ
	・before	NULL
	・flag		連続空き容量
	・addr		テクスチャ固定領域の先頭ポインタ
	・size		テクスチャ固定領域の合計サイズ
	
	●texblock
	・next		ALLOC_AREAの次の領域のポインタ
	・before	ALLOC_AREAの前の領域のポインタ
	・flag		領域の使用、未使用フラグ
	・addr		使用中のポインタ、未使用中のポインタ
	・size		使用中のサイズ。未使用中のサイズ
	
*/
Sint32 InitTexFixedArea(Uint32 size)
{
	Int i;
	
	if(njTexMallocFixedArea(size,&head.addr) < 0){
		return -1;
	}
	head.flag = size;
	head.size = size;
	head.next = &texblock[0];
	head.before = NULL;
	
	for(i = 0;i < TEXMEM_BLOCK_NUM;i++){
		texblock[i].next = &texblock[i+1];
		texblock[i].before = NULL;
		texblock[i].flag = FALSE;
		texblock[i].addr = NULL;
		texblock[i].size = 0;
	}
	texblock[TEXMEM_BLOCK_NUM - 1].next = NULL;

	max_area = &texblock[0];
	space_area = &texblock[1];

	return 1;
}

void SetTexFixedArea(void)
{
	texblock[0].addr = head.addr;
	texblock[0].size = head.size;
	texblock[0].next = &tail;
	tail.next = NULL;
}


/* 
	このTexMalloc関数は、取得したメモリの始めから
	順に割り当てるだけの簡単なものです。
	
	テクスチャをリリースするときは、割り当てたメモリを
	解放する

*/
Sint8* TexMalloc(Uint32 size)
{
	ALLOC_AREA *ptr;
	ALLOC_AREA *ptr2;
	ALLOC_AREA *space_ptr;
	
	if(size == 0) return NULL;
	
	/* 連続空き容量がすでにないとき*/
	if(head.flag < size) return NULL;
	
	ptr = head.next;
	/* 要求しているサイズとぴったりのサイズがあるか始めに探す */
	while(ptr->next != NULL){
		if((ptr->size == size) && (!ptr->flag)){
			ptr->flag = TRUE;/* フラグを使用中に変更する */
			if(head.flag == size){
				/* 次のMAX連続空き容量を探す */
				head.flag = 0;
				ptr2 = head.next;
				while(ptr2->next != NULL){
					if((head.flag < ptr2->size) && (!ptr2->flag)) {
						max_area = ptr2;
						head.flag = ptr2->size;
					}
					ptr2 = ptr2->next;
				}
			}
			return ptr->addr;
		}
		ptr = ptr->next;
	}
	
	/* ぴったりのサイズが存在しないときは大きいところから取得する */
	if(head.flag > size){
		/* 使用中の領域と残りの領域に分ける */
		/* 空いているtexblockを探す */
		space_ptr = space_area;
		/* 情報を入れる領域がない */
		if(space_ptr == NULL) return NULL;
		space_area = space_area->next;
	
		ptr = max_area;
		space_ptr->next = ptr->next;
		space_ptr->before = ptr;
		space_ptr->flag = FALSE;
		space_ptr->addr = ptr->addr + size;
		space_ptr->size = ptr->size - size;
		
		ptr->next = space_ptr;
		ptr->flag= TRUE;
		ptr->size = size;
	
		/* 次のMAX連続空き容量を探す */
		head.flag = 0;
		ptr2 = head.next;
		while(ptr2->next != NULL){
			if((head.flag < ptr2->size) && (!ptr2->flag)) {
				max_area = ptr2;
				head.flag = ptr2->size;
			}
			ptr2 = ptr2->next;
		}

		return ptr->addr;
	}
	
	return NULL;
}

void TexFree(Sint8 *addr)
{
	ALLOC_AREA *ptr;
	ALLOC_AREA *ptr2;

	ptr = head.next;

	while((ptr->next != NULL) && (ptr->addr != addr)){
		ptr=ptr->next;
	}
	
	if(ptr->addr == addr){

		ptr->flag = FALSE;

		if(ptr->before){
			while(!ptr->before->flag){
				/* 前が空きの場合はつなげる */
				ptr2 = ptr;
				ptr = ptr->before;
				ptr->size += ptr->next->size;
				ptr->next = ptr->next->next;
				ptr->next->before = ptr;
				
				
				ptr2->next = space_area->next;
				ptr2->flag = FALSE;
				ptr2->before = NULL;
				ptr2->addr = NULL;
				ptr2->size = 0;
				space_area = ptr2;

				if(max_area->size < ptr->size){
					max_area = ptr;
					head.flag = ptr->size;
					
				}
				if(!ptr->before){
					break;
				}
			}
		}
	
		if(ptr->next != &tail){
			while(!ptr->next->flag){
				/* 後ろが空きの場合もつなげる */
				if(max_area == ptr->next){
					max_area = ptr;
					head.flag = ptr->size;
				}

				ptr2 = ptr->next;
				ptr->size += ptr->next->size;
				ptr->next = ptr->next->next;
				ptr->next->before = ptr;
				
				ptr2->next = space_area->next;
				ptr2->flag = FALSE;
				ptr2->before = NULL;
				ptr2->addr = NULL;
				ptr2->size = 0;
				space_area = ptr2;

				if(max_area->size < ptr->size){
					max_area = ptr;
					head.flag = ptr->size;
				}

				if(ptr->next == &tail){
					break;
				}
			}
		}
	}
}