Archive for November, 2008

h1

shadow town, it’s where shading of unlit areas goes down, doo de doo

November 30, 2008

I’m trying to implement them!  So, shadow volumes are kinda slow with any graphics hardware, because they have to be calculated on the CPU, then passed to a shader/fixed-pipeline.  Also, doing per light occlusion shadowing (the accurate per light shadow method) must be done in multiple passes.  This is why I want to do shadow maps.  Shadow samplers can be easily accessed from GLSL fragment programs.  I can do it in one rendering pass, as the shader can receive the information for each light and it’s shadow map all at once and simply add/clamp the results easy as pie.  Ultraaaa banananana creeeeeam piiiie!  Right.

Anyway, I have been looking for a good sample for quite some time now, and Imma like “whaaat, they nothin’ heah!”  I found some good ones on directional and spotlight mapping, but that’s easy because it fits in one simple perspective projection.  I really need an example for point lights: omnidirectional shadow mapping using cube maps specifically.  I’d like to use shadowCube samplers if possible, but it’s fine to pack depth info in some advanced way and do the comparisons manually in the shader.

Sooo, I’m a little frustrated right now, ’cause I can’t find the poop on it.  But I’m still looking, and I’ve ordered the OpenGL Orange Book, it should be arriving shortly.

Siiiiggghhhhh.  You should check out the Inhuman comic.  It’s made of awesome.  No, they’re not furries, they’re aliens.  And stop calling me gay already.  That was only for those of you who look at this and say “that’s gay.”  I’ve been informed that the supreme Overmind known as “Common Sense” wants you all lined up and shot.  If I only I could order someone to do that.  Oh well.

So, shadow maps anyone?  pleeezzz halp omg ur mom.

t3h b4lling3st f0h3v4r bitches

Bye.

Advertisements
h1

uncomfortable giving

November 28, 2008

THAT’S WHAT IT WAS DAMNIT!

gwuh.  Don’t even get me started man.  TOO LATE!  YOU ALREADY HAVE!  PREPARE FOR THE ANGST PUMMELING!

So, my dad’s had this fucking headache for the past two months, which isn’t seriously big news, since he’s a chronic migrane sufferer.  It’s bad man.  Imagine the pain of third degree burns, then imagine it’s still going as if you’ve done nothing about it even after you’ve emptied the entire painkiller section of the medicine cabinet in to your mouth.  And he takes some strong narcs for these things, so let me tell you: today, STONED OUT OF HIS FUCKING MIND.  And we actually took him along to some friends’ house to turkey day.  T_T *sob*

Fortunately he didn’t say anything throughout dinner, mainly because he realized with his last scrap of coherence that it would be a bad idea.  But I was like so sick from sitting through this I had to go to the bathroom and have a nervous breakdown like three times.  And there was also a one year old there.

Now, normally, we really like babies, we just do.  But she was tired.  And crying.  Forever.  Is it unhealthy to eventually want to throw said baby through a window?  YES!  BUT IT’S WHAT I FUCKING WANTED TO DO!  😡  Not to mention it was aggrivating dad’s headache making him more deranged, and mom was totally unsympathetic or oblivious to my uncomfortable situation.  YES, I know this is self centered, but I really don’t care.  It was making me sick.  Dad was so pale he had to eat early too.  It was a mish mash of feeling sorry for him, angry at mom and that baby, and also sorry for mom and the baby simultaniously.  And I just got done angsting about getting put down by a bunch of middleschool brats who I didn’t pummel out of decency, humiliating me in the eyes of others.

RAGE AND VENOM SPIT GRRRAAAAGGGGHHHHHFFFETTDTFTFTFTTDTDTTDFTYDTDSTRTEJHDSHG

Seriously man, what did I do to my fucking karma?  WHAT IS IT MAN?  Did I rape someone in my last life, is that it?

aaaahhhhhhhh

Now I will sleep.  But be warned.  Do NOT meet my family in person.  Seriously.

h1

interwebs are back! new laptop arrived! CAMERAS!

November 27, 2008

YYYAAAAAAAaHHHHHHHHH!  I’M FREE!  AFK FTW BBQ ROLFMAOCOPTERSAUCE

afk is a fairly disgusting statement.  It was coined by a friend who thought there should be texting abbreviation for anally fucking kittens.  He came up with it.  Not me.  Though it does make a great expletive.  gggrrrraaAAAHHH!  ANALLY FUCKING KITTENS, THIS SUCKS!  Packs a punch.

Now that I have full access to ye olde intarwebz0rz again, allow me to fill you in: my new laptop is here.  Yes here.  Not almost here, ACTUALLY HERE!  It runs Ubuntu 8.10 Intrepid perfectly, and Windows Vista because if I take it off I’ll lose the software license.  Microsoft bitches.

I have tested my stuff under Vista though, and I was pleasantly surprised that it ran!  My code has always been very raw and portable, something I am very proud of.  It also runs on Ubuntu Intrepid just fine.  Actually, better than anywhere else, because this is an AMD64 (Athlon64X2) machine.  It came with 32-bit Windows, which makes no sense to me, it’s like putting two toilets in an apartment with only one ass.  But the Ubuntu half is full on 64-bit, and I have to say it’s a big improvement, especially since this baby is dual core.  Multitasking!  Also, the physics engine has a build now just for 64-bit GNU/Linux, available through both GNU Make and C::B projects.  It’s really fast on this machine, and this build is always double precision too, because of the 64 bittage!

Here’s a screenshot of the pyramid example running on the laptop:

yoink!

yoink!

Yeah.  Now look at the zooming in on the frame rate:

pyramid_explosion_frameratesplosion

WHOA!  FFFFAAAASSSSSSSTTTTTT.

Okay, that’s about it.

But hey, webcam fun! 🙂  LOOOOKIIIT

T3H BAANNGGING OF T3H HEDZ M3TUHLZ

T3H BAANNGGING OF T3H HEDZ P0R M3TUHLZ!!!111!!1!1!!

Yes, the laptop has a webcam to.  Camgasm that’s awesome.

Oh, wait!  I’ve also just been messing around with shaders, because my laptop can actually handle this shit!  This is my phong lighting shader.  I have it split in to ambient and diffuse/specular passes, so that luminance occlusion multipass shadows can be easily integrated.  I’m working on a shadow mapper right now.  But anyway, last picture:

phong_perfrag_lighting

See all y’alls!

h1

other physics videos

November 17, 2008

For those too lazy to get the engine from the repository and build it, here are more videos of it in action.  Seriously though, I can understand if you aren’t a programmer.  But for those who are, I have a link on my site, accessible from here, that goes to a publicly checkout-able repository and a jillion ways to build it.  It builds on Visual Studio 2008 (VC9) with a project file, it builds in C::B 8.02 or higher on the MinGW toolset, it has a raw makefile MinGW build, it has a GNU/Linux make GCC build, a C::B 8.02 or highter Ubuntu Linux build, I MEAN HAVE I NOT GIVEN YOU ENOUGH OPTIONS!?  JESUS GOD OMFGROFLMAO NARNIA PANTALOON SCALLYWAG! SLDKJFKLSDJSOIEOWEJOOJ!!!1!1!!1!!11!!!1!  😮 😮 😮 😀 😡  I’ll do 64-bit build when my laptop gets here as it’s 64-bit, that should make it friendlier to 64-bit types.

yay, its crazy time forever lawlz XD.

Now that we’re done with me becoming mildly volatile for a brief period, let’s get back to the videos.

wooooooooo, happy town.

h1

pivot constraints == awesome chain physics!

November 17, 2008

In the past, I have had two different kinds of inelastic distance constraints: single distance constraints (rat_constraint_bar) and min/max distance constraints (rat_constraint_slider).  I add a new one called the pivot (rat_constraint_pivot).  Why, you ask?

Well, you might think a distance constraint with a length of zero is sufficient, but it isn’t.  Here’s why: a distance constraint uses the normal of the distance “bar” to decide how to pull or push the anchor points.  If you are a point, this value cannot exist unless the objects are separated, which means the constraint will never keep the anchors at zero distance from each other.  Furthermore, this means the pivot will never react like a revolute joint, because this behavior relies on a shared point.  So, the key is to compromise.  We use our old friend bias velocity (pseudo velocity) to keep the points together, regular distance constraint style.  But in order to get the correct pivot behavior out of it we have to calculate the impulse as if, like I said before, the anchors share a point even if they don’t.  This means instead of normals, we must create a mass matrix to get the correct torque, then apply the equal offset impulse to the anchors.  Think of it as unbreakable sticky friction.

The really cool looking result can be seen in the following video.  I can now have real segmented chains; solid segments, not distance constraints between particles!  🙂

h1

hard to blog in nirvana

November 14, 2008

So much good stuff has been happening to me at once.  I feel awesome!  I haven’t updated in a while for a coupla reasons that have been way too cool for me to care.

It looks like I’m actually going to CCIS this spring!  This is such a weight of uncertainly lifted off my mind.  For this reason, I will obtain a laptop.  Yes, a laptop.  My first new computer in ten years.  I’m all giddy!  I am such a performance and optimization wank; I wonder how crazy fast my code is going to run on there.  I’ll also have the power to implement one of my favorites, something I’ve never had the GPU to do before: GPU programs!  Fragment programs, vertex programs, even geometry programs!  This is really sweet.  Shader time.  My excuse for getting it was not empty, but in fact true: I will need a laptop in computer science.  This is very high end though, and will serve me for years to come.  Unless it breaks or gets stolen.  Let’s not even imagine that.  T_T

The other reason is that the whole CCIS talk thing is going forward!  I got a date set too.  Can’t remember it exactly now, this is why I have a schedule.  😛  It’s just before winter break, on Thursday.  December something.  This is when attendance will be highest for the talks in general, so I’ll get a very large crowd, all of them computer scientists or geeks in some way… wow.

When I got the first email on it, I seriously thought I was being fucking punk’d.  This is the first really good thing that’s happened to me in my whole life, aside from my meager group of friends who probably have no idea they are the reason I am not dead in the bathtub.  I thought I was luckier than usual when my mom let me go back to seeing my shrink after I left highschool in order to regroup.  My sanity hung by a thread then.  But now the funeral dirge is over, failed childhood fuck off, it’s time for a sweet-ass talk on physics!

Boy am I pumped.  I sure hope this goes well.  I feel it man, I feel the momentum building.  This could be the beginning of a much less hopeless and miserable chapter of my life!

Here also is Circus Maximus, the prog band I just discovered.  They are the definition of full-on prog wankery mixed with subtle and powerful meaning in real music.  They blend function with form almost as perfectly as Opeth themselves I daresay!

h1

ultra performance go!!!!!

November 3, 2008

This is awesome!!!  I just now implemented a memory block manager for all the stuff that gets allocated / deallocated hundreds if not thousands of times an iteration, which essentially recycles all blocks of that size’s cache deallocated until cleared.  There is a list of optimal sizes which all go evenly in to the chunks, which are propagated on out of free blocks.  It is basically just never deallocating anything ’till the end, but since we recycle everything, there are no leaks and it’s faster.  Twenty times faster, according to Monsieur Framerate, and we don’t argue with him.  If you want the full code for all my memory management used in Rat Physics, I’m going to put up articles about it.  But in the meantime, here’s the plain ol’ code.  But wait, credit where due: Erin Catto is responsible for his idea to use both stack allocators and block recyclers in Box2D.  That is where I directly ripped the idea off from.  The code, however, is my own.  Here it is now:

memory.h

#ifndef RAT_PHYSICS_MEMORY
#define RAT_PHYSICS_MEMORY

#include <stddef.h>

#ifdef __cplusplus
extern "C" {
#endif

// main alloc/dealloc functions, just calls dlmalloc|malloc/dlfree|free

void rat_set_alloc_fn(void *(*alloc_fn)(size_t));
void rat_set_realloc_fn(void *(*realloc_fn)(void *,size_t));
void rat_set_dealloc_fn(void (*dealloc_fn)(void *));

void *rat_alloc(size_t size);
void *rat_realloc(void *mem,size_t newsize);
void rat_dealloc(void *mem);

unsigned int rat_blocks_alloced();
unsigned int rat_mem_alloced();

void rat_mem_alloced_string(char *str);


// a simple stack allocator
// must push/pop memory allocations; faster than
// arbitrary malloc/free by a int shot.

struct rat_stack_allocator;
typedef struct rat_stack_allocator rat_stack_allocator;

extern const size_t rat_max_stack_cells;
extern const size_t rat_stack_size;

rat_stack_allocator *rat_stack_allocator_create();
void rat_stack_allocator_destroy(rat_stack_allocator *sal);

void *rat_stack_alloc(rat_stack_allocator *sal,size_t size);
void rat_stack_dealloc(rat_stack_allocator *sal,void *mem);

unsigned int rat_stack_most_alloced(rat_stack_allocator *sal);


// a simple small block allocator for objects of about
// the same size being alloced/dealloced on a regular
// basis.  it is very fast at recycling

struct rat_block_allocator;
typedef struct rat_block_allocator rat_block_allocator;

extern const unsigned int rat_chunk_size;
extern const unsigned int rat_max_block_size;
extern const unsigned int rat_block_sizes;
extern const unsigned int rat_chunk_arr_inc;

rat_block_allocator *rat_block_allocator_create();
void rat_block_allocator_destroy(rat_block_allocator *bal);
void rat_block_allocator_clear(rat_block_allocator *bal);

void *rat_block_alloc(rat_block_allocator *bal,size_t size);
void *rat_block_realloc(rat_block_allocator *bal,void *mem,size_t oldsize,size_t size);
void rat_block_dealloc(rat_block_allocator *bal,void *mem,size_t size);

#ifdef __cplusplus
}
#endif

#endif

memory.c

#include "common.h"

#define RAT_MEMORY_GUARD_WORD 0x52415453 // spells "RATS" in ascii 😛

#include "memory.h"
#ifndef RAT_PHYSICS_MSVC
#	include "dlmalloc.h"
#endif

static unsigned int blocksalloced=0;
static unsigned int amtmemalloced=0;
static unsigned int extrafootprint=0;

#ifdef RAT_PHYSICS_MSVC
	static void *(*rat_alloc_fn)(size_t)=malloc;
	static void *(*rat_realloc_fn)(void *,size_t)=realloc;
	static void (*rat_dealloc_fn)(void *)=free;
#else
	static void *(*rat_alloc_fn)(size_t)=dlmalloc;
	static void *(*rat_realloc_fn)(void *,size_t)=dlrealloc;
	static void (*rat_dealloc_fn)(void *)=dlfree;
#endif

void rat_set_alloc_fn(void *(*alloc_fn)(size_t))
{
	rat_alloc_fn=alloc_fn;
}

void rat_set_realloc_fn(void *(*realloc_fn)(void *,size_t))
{
	rat_realloc_fn=realloc_fn;
}

void rat_set_dealloc_fn(void (*dealloc_fn)(void *))
{
	rat_dealloc_fn=dealloc_fn;
}

void *rat_alloc(size_t size)
{
	size_t *ptr;
	void *mem=rat_alloc_fn(size+sizeof(size_t)*2);
	if (mem==NULL) return NULL;
	ptr=mem;

	ptr[0]=RAT_MEMORY_GUARD_WORD;
	ptr[1]=size;
	amtmemalloced+=size;

	blocksalloced++;
	extrafootprint=blocksalloced*sizeof(size_t)*2;
	return (void *)(ptr+2);
}

void *rat_realloc(void *mem,size_t newsize)
{
	size_t *ptr=mem;
	if (mem==NULL) return rat_alloc(newsize);
	if (ptr[-2]!=RAT_MEMORY_GUARD_WORD) return NULL;

	amtmemalloced+=newsize-ptr[-1];
	ptr=(size_t *)rat_realloc_fn((void *)(ptr-2),newsize+sizeof(size_t)*2);

	ptr[0]=RAT_MEMORY_GUARD_WORD;
	ptr[1]=newsize;
	return (void *)(ptr+2);
}

void rat_dealloc(void *mem)
{
	size_t *ptr=mem;
	if (mem==NULL) return;
	if (ptr[-2]!=RAT_MEMORY_GUARD_WORD) return;
	amtmemalloced-=ptr[-1];
	blocksalloced--;
	extrafootprint=blocksalloced*sizeof(size_t)*2;
	rat_dealloc_fn((void *)(ptr-2));
}

unsigned int rat_blocks_alloced()	{return blocksalloced;}
unsigned int rat_mem_alloced()		{return amtmemalloced+extrafootprint;}

void rat_mem_alloced_string(char *str)
{
	size_t malc=amtmemalloced+extrafootprint;
	if (malc<1024)
		sprintf(str,"%04u Bytes",malc);
	else if (malc>=1024&&malc<1048576)
	{
		rat_real kb=(float)malc/1024.0f;
		sprintf(str,"%04.4f KB",kb);
	}
	else if (malc>=1048576&&malc<1073741824)
	{
		rat_real mb=(float)malc/1048576.0f;
		sprintf(str,"%04.4f MB",mb);
	}
	else
		sprintf(str,"overflowed");
}

// stack allocator...

const size_t rat_max_stack_cells=128;	// 128 stack cells
const size_t rat_stack_size=512*1024;	// 512KB total memory

typedef struct rat_stack_cell
{
	char *data;
	size_t size;
	int nonstackalloc;
} rat_stack_cell;

struct rat_stack_allocator
{
	unsigned int idx;
	char *data;

	unsigned int alloced;
	unsigned int most_alloced;

	unsigned int numcells;
	rat_stack_cell *cells;
};

rat_stack_allocator *rat_stack_allocator_create()
{
	rat_stack_allocator *sal=(rat_stack_allocator *)rat_alloc_fn(sizeof(rat_stack_allocator));
	memset(sal,0,sizeof(rat_stack_allocator));

	sal->alloced=0;
	sal->most_alloced=0;
	sal->idx=0;
	sal->numcells=0;

	sal->data=(char *)rat_alloc_fn(rat_stack_size);
	sal->cells=(rat_stack_cell *)rat_alloc_fn(sizeof(rat_stack_cell)*rat_max_stack_cells);

	return sal;
}

void rat_stack_allocator_destroy(rat_stack_allocator *sal)
{
	if (sal->idx||sal->numcells)
	{
		fprintf(stderr,"stack destroyed with memory still allocated!!!\n");
		fflush(stderr);
	}

	rat_dealloc_fn((void *)sal->data);
	rat_dealloc_fn((void *)sal->cells);
	rat_dealloc_fn((void *)sal);
}

void *rat_stack_alloc(rat_stack_allocator *sal,size_t size)
{
	rat_stack_cell *cell;

	if (sal->numcells>=rat_max_stack_cells)
	{
		fprintf(stderr,"stack allocator overflow!!! only %u cells allowed.\n",rat_max_stack_cells);
		fflush(stderr);
		return NULL;
	}

	cell=sal->cells+sal->numcells;
	cell->size=size;
	if (sal->idx+size>rat_stack_size)
	{
		cell->data=(char *)rat_alloc_fn(size);
		cell->nonstackalloc=1; // we did not use memory from the stack
	}
	else
	{
		cell->data=sal->data+sal->idx;
		cell->nonstackalloc=0; // we used memory from the stack
		sal->idx+=cell->size;
	}

	sal->alloced+=size;
	sal->most_alloced=sal->alloced>sal->most_alloced?sal->alloced:sal->most_alloced;
	sal->numcells++;

	amtmemalloced+=size;
	blocksalloced++;

	return (void *)cell->data;
}

void rat_stack_dealloc(rat_stack_allocator *sal,void *mem)
{
	rat_stack_cell *cell;

	if (sal->numcells==0)
	{
		fprintf(stderr,"there's nothing left to deallocate!!!\n");
		fflush(stderr);
		return;
	}

	cell=sal->cells+sal->numcells-1;
	if (mem!=(void *)cell->data)
	{
		fprintf(stderr,
			"memory at 0x%08x is not at top of stack; deallocate fail! 0x%08x is next.\n",
			(unsigned int)mem,(unsigned int)cell->data);
		fflush(stderr);
		return;
	}

	if (cell->nonstackalloc)
		rat_dealloc_fn((void *)mem);
	else
		sal->idx-=cell->size;

	sal->alloced-=cell->size;
	sal->numcells--;

	amtmemalloced-=cell->size;
	blocksalloced--;
}

unsigned int rat_stack_most_alloced(rat_stack_allocator *sal)
{
	return sal->most_alloced;
}

// block allocator...

const unsigned int rat_chunk_size=32768;
const unsigned int rat_max_block_size=16384;
const unsigned int rat_block_sizes=20;
const unsigned int rat_chunk_arr_inc=128;

typedef struct rat_block
{
	struct rat_block *next;
} rat_block;

typedef struct rat_chunk
{
	unsigned int block_size;
	rat_block *blocks;
} rat_chunk;

static unsigned int block_sizes[]={16,32,64,96,128,160,192,224,256,320,384,448,512,640,1024,2048,4096,8192,16384};

static unsigned char *block_size_lookup;
static int is_block_size_lookup_init=0;

struct rat_block_allocator
{
	unsigned int numchunks;
	rat_chunk *chunks;

	unsigned int chunk_space;
	rat_block **recycling_lists;
};

void free_bsl(void)	// we use (void) to conform to that retarded standard
					// and get rid of the associated warning message
{
	free((void *)block_size_lookup);
}

rat_block_allocator *rat_block_allocator_create()
{
	rat_block_allocator *bal=(rat_block_allocator *)rat_alloc(sizeof(rat_block_allocator));
	memset(bal,0,sizeof(rat_block_allocator));

	bal->chunk_space=rat_chunk_arr_inc;
	
	bal->numchunks=0;
	bal->chunks=(rat_chunk *)rat_alloc(sizeof(rat_chunk)*bal->chunk_space);
	bal->recycling_lists=(rat_block **)rat_alloc(sizeof(rat_block *)*rat_block_sizes);
	
	memset(bal->chunks,0,sizeof(rat_chunk)*bal->chunk_space);
	memset(bal->recycling_lists,0,sizeof(rat_block *)*rat_block_sizes);

	if (!is_block_size_lookup_init)
	{
		register unsigned int i,j=0;
		block_size_lookup=(char *)malloc(rat_max_block_size+1);
		atexit(free_bsl);
		
		for (i=1; i<rat_max_block_size+1; i++)
		{
			if (j>=rat_block_sizes)
			{
				fprintf(stderr,"blocks size list exceeds block sizes!\n");
				fflush(stderr);
			}
			if (i<=block_sizes&#91;j&#93;)
				block_size_lookup&#91;i&#93;=(unsigned char)j;
			else
				block_size_lookup&#91;i&#93;=(unsigned char)++j;
		}
		is_block_size_lookup_init=1;
	}

	return bal;
}

void rat_block_allocator_destroy(rat_block_allocator *bal)
{
	register unsigned int i;

	for (i=0; i<bal->numchunks; i++)
		rat_dealloc((void *)bal->chunks[i].blocks);
	
	rat_dealloc((void *)bal->chunks);
	rat_dealloc((void *)bal->recycling_lists);
	rat_dealloc((void *)bal);
}

void rat_block_allocator_clear(rat_block_allocator *bal)
{
	register unsigned int i;

	for (i=0; i<bal->numchunks; i++)
		rat_dealloc((void *)bal->chunks[i].blocks);
	bal->numchunks=0;

	memset(bal->chunks,0,sizeof(rat_chunk)*bal->chunk_space);
	memset(bal->recycling_lists,0,sizeof(rat_block *)*rat_block_sizes);
}

void *rat_block_alloc(rat_block_allocator *bal,size_t size)
{
	register unsigned int i,idx;

	if (size==0) return NULL;
	if (size>rat_max_block_size)
	{
		fprintf(stderr,"this block is too fucking big! you can't allocate more than %u bytes!\n",rat_max_block_size);
		fflush(stderr);
		return NULL;
	}

	idx=block_size_lookup[size];
	if (idx<0||rat_block_sizes<idx)
	{
		fprintf(stderr,"block size lookup failed!\n");
		fflush(stderr);
		return NULL;
	}

	if (bal->recycling_lists[idx]) // this is our fast memory recycler!!! look at that ultra speed!!!
	{
		rat_block *block=bal->recycling_lists[idx];
		bal->recycling_lists[idx]=block->next;

		return block;
	}
	else
	{
		register unsigned int block_size,numblocks;
		rat_chunk *chunk;
		rat_block *last;

		if (bal->numchunks==bal->chunk_space)
		{
			rat_chunk *old_chunks=bal->chunks;

			bal->chunk_space+=rat_chunk_arr_inc;
			bal->chunks=(rat_chunk *)rat_alloc(sizeof(rat_chunk)*bal->chunk_space);

			memcpy(bal->chunks,old_chunks,sizeof(rat_chunk)*bal->numchunks);
			memset(bal->chunks+bal->numchunks,0,sizeof(rat_chunk)*rat_chunk_arr_inc);
			rat_dealloc((void *)old_chunks);
		}

		chunk=bal->chunks+bal->numchunks;
		chunk->blocks=(rat_block *)rat_alloc(rat_chunk_size);

		block_size=block_sizes[idx];
		chunk->block_size=block_size;
		numblocks=rat_chunk_size/block_size;

		if (numblocks*block_size>rat_chunk_size)
		{
			fprintf(stderr,"internal memory block listing error!\n");
			fflush(stderr);
			return NULL;
		}

		for (i=0; i<numblocks-1; i++)
		{
			rat_block *thisblock=(rat_block *)((char *)chunk->blocks+block_size*i);
			rat_block *nextblock=(rat_block *)((char *)chunk->blocks+block_size*(i+1));
			thisblock->next=nextblock;
		}
		last=(rat_block *)((char *)chunk->blocks+block_size*(numblocks-1));
		last->next=NULL;

		bal->recycling_lists[idx]=chunk->blocks->next;
		bal->numchunks++;

		return chunk->blocks;
	}
}

void *rat_block_realloc(rat_block_allocator *bal,void *mem,size_t oldsize,size_t size)
{
	void *newmem;
	size_t roldsize=block_sizes[block_size_lookup[oldsize]];
	size_t rsize=block_sizes[block_size_lookup[size]];

	if (rsize==roldsize)
		return mem;
	else if (rsize>roldsize)
	{
		newmem=rat_block_alloc(bal,size);
		memcpy(newmem,mem,roldsize);
		rat_block_dealloc(bal,mem,oldsize);
	}
	else
	{
		newmem=rat_block_alloc(bal,size);
		memcpy(newmem,mem,rsize);
		rat_block_dealloc(bal,mem,oldsize);
	}

	return newmem;
}

void rat_block_dealloc(rat_block_allocator *bal,void *mem,size_t size)
{
	register unsigned int idx;
	rat_block *block;

	if (size==0||mem==NULL) return;
	if (size<0||size>rat_max_block_size)
	{
		fprintf(stderr,"block size out of range; impossible dealloc size!\n");
		fflush(stderr);
		return;
	}

	idx=block_size_lookup[size];
	if (idx<0||rat_block_sizes<idx)
	{
		fprintf(stderr,"block size lookup failed!\n");
		fflush(stderr);
		return;
	}

	block=(rat_block *)mem;
	block->next=bal->recycling_lists[idx];
	bal->recycling_lists[idx]=block;
}