int main(int argc, const char *argv[])
{
    const char *string = "hello world~!";
    printf("strlen(string) = %d\n", strlen_asm(string));
    printf("strlen(string) = %d\n", strlen_asm_notl(string));
    printf("strlen(string) = %d\n", strlen_magic(string));
    printf("strlen(string) = %d\n", strlen_novariable(string));
    printf("strlen(string) = %d\n", strlen_strchar_com(string));
    printf("strlen(string) = %d\n", strlen(string));

    return 0;
}
void d3d_batch_string(int sx, int sy, char *s, int bw, int bh, float u_scale, float v_scale, uint color)
{
	int spacing = 0;
	int width;

	int x = sx;
	int y = sy;

	// centered
	x =(sx==0x8000) ? get_centered_x(s) : sx;

  	do
	{
	HRESULT hr;
	int magic_num, magic_num2;
	int len = strlen_magic(s, magic_num, magic_num2);
	int new_id = -1;

	if(len == 0) return;

	// Set to 0 to turn off batching to gfx card memory
#if 1
	// Check the string is of a valid size
	if(len > MIN_STRING_LEN && len < MAX_LG_STR_LEN)
	{
		bool long_str = (len >= MAX_SM_STR_LEN);

		int index = find_string(len, magic_num, magic_num2, sx, sy, color, long_str);
		
		// We have found the string, render and mark as rendered
		if(index != -1)
		{
			StringBatch *array = (long_str) ? long_str_array : small_str_array; 

			extern VertexTypeInfo vertex_types[D3DVT_MAX];

			d3d_SetVertexShader(FONT_VTYPE);
			hr = GlobalD3DVars::lpD3DDevice->SetStreamSource(
				0, array[index].vbuffer, vertex_types[FONT_VTYPE].size);
			
			Assert(SUCCEEDED(hr));
			hr = GlobalD3DVars::lpD3DDevice->DrawPrimitive(
				D3DPT_TRIANGLELIST, 0, array[index].char_count * 2);

   //			Assert(SUCCEEDED(hr));

			array[index].used_this_frame = true;
			return;

		// Prepare to enter the string
		} else {
			new_id = find_free_slot(long_str);
		}
	}
#endif

	IDirect3DVertexBuffer8 *vbuffer = NULL;	
	FONT_VERTEX *locked_buffer = NULL;
	StringBatch *array = NULL;

	if(new_id != -1) {

		array = (len > MAX_SM_STR_LEN) ? long_str_array : small_str_array; 
		vbuffer = array[new_id].vbuffer;
		hr = vbuffer->Lock(0, len * 6 * vertex_types[FONT_VTYPE].size, (BYTE **) &locked_buffer, 0);
		
		array[new_id].used_this_frame = true;
		// We can always bail out at this point
		if(FAILED(hr)) {
			Assert(0);
			new_id = -1;
		} 
	}

	int char_count = 0;

	while (*s)	{
		x += spacing;

		while (*s== '\n' )	{
			s++;
			y += Current_font->h;
			// centered
			x =(sx==0x8000) ? get_centered_x(s) : sx;
		}
		if (*s == 0 ) break;

		int letter = get_char_width(s[0],s[1],&width,&spacing);
		s++;

		//not in font, draw as space
		if (letter<0)	{
			continue;
		}

		int xd, yd, xc, yc;
		int wc, hc;

		// Check if this character is totally clipped
		if ( x + width < gr_screen.clip_left ) continue;
		if ( y + Current_font->h < gr_screen.clip_top ) continue;
		if ( x > gr_screen.clip_right ) continue;
		if ( y > gr_screen.clip_bottom ) continue;

		xd = yd = 0;
		if ( x < gr_screen.clip_left ) xd = gr_screen.clip_left - x;
		if ( y < gr_screen.clip_top ) yd = gr_screen.clip_top - y;
		xc = x+xd;
		yc = y+yd;

		wc = width - xd; hc = Current_font->h - yd;
		if ( xc + wc > gr_screen.clip_right ) wc = gr_screen.clip_right - xc;
		if ( yc + hc > gr_screen.clip_bottom ) hc = gr_screen.clip_bottom - yc;

		if ( wc < 1 ) continue;
		if ( hc < 1 ) continue;

		font_char *ch;
	
		ch = &Current_font->char_data[letter];

		int u = Current_font->bm_u[letter];
		int v = Current_font->bm_v[letter];

		if ( wc < 1 ) continue;
		if ( hc < 1 ) continue;

		FONT_VERTEX *src_v = NULL;

		if(new_id != -1) {
			src_v = &locked_buffer[char_count * 6];
		} else {
			src_v = &d3d_verts[char_count * 6];
		}

#if 0
		// Change the color this way to see which strings are being cached
	  	uint color2 = (new_id == -1) ? color : 0xff00ff00;

		// Marks the end of a batch blue
	  	if(char_count > (MAX_STRING_LEN - 10)) 
	  		color2 = 0xff0000ff;
#endif

	 	d3d_stuff_char(src_v, xc, yc, wc, hc, u+xd, v+yd, bw, bh, u_scale, v_scale, color);

		char_count++;
		if(char_count >= MAX_STRING_LEN) {
			// We've run out of space, we are going to have to go round again
			break;
		}
	}

	if(new_id != -1) {
		vbuffer->Unlock();

		if(char_count == 0) {
			array[new_id].free_slot		  = true;
			array[new_id].used_this_frame = false;
			continue;
		}

		hr = d3d_SetVertexShader(FONT_VTYPE);
		Assert(SUCCEEDED(hr));
		hr = GlobalD3DVars::lpD3DDevice->SetStreamSource(0, vbuffer, vertex_types[FONT_VTYPE].size); 
		Assert(SUCCEEDED(hr));

  		hr = GlobalD3DVars::lpD3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, char_count * 2);
//  		Assert(SUCCEEDED(hr));

		// Fill in details
		array[new_id].char_count   = char_count;
		array[new_id].color        = color;
		array[new_id].free_slot    = false;
		array[new_id].len		   = len;
		array[new_id].magic_number = magic_num;
		array[new_id].magic_number2 = magic_num2;
		array[new_id].x			   = sx;
		array[new_id].y			   = sy;
		array[new_id].offsetx      = gr_screen.offset_x; 
		array[new_id].offsety      = gr_screen.offset_y; 

		array[new_id].used_this_frame = true;

	} else if(char_count > 0) {
  	   	d3d_DrawPrimitive(FONT_VTYPE, D3DPT_TRIANGLELIST,(LPVOID)d3d_verts, char_count * 6);
	}

	} while (*s);
}