
//DANGER




#define _CRT_SECURE_NO_DEPRECATE

//#include <d3d9.h>

#include <d3dx9.h>
//for D3DXCreateTextureFromFile


#pragma warning( disable : 4996 ) // disable deprecated warning 
#include <strsafe.h>
#pragma warning( default : 4996 )


//LIBJPEG
#include <jpeglib.h>
#pragma comment(lib,"jpeg-static.lib")

#include <png.h>
#pragma comment(lib,"libpng16_staticd.lib")

#pragma warning (disable : 4010) //something about safe fopen_s

#pragma warning (disable : 4311) //pointer conversion
#pragma warning (disable : 4312)

#pragma warning (disable : 4995) //'wcscat': name was marked as #pragma deprecated


#include <windowsx.h> //for GET_X_LPARAM

#include <setjmp.h>

#include <Winnt.h> //for MemoryBarrier

//HEADERS

//SNIPPETS

	/*if (((intptr_t)cur & 0xFFF) == 0xFFC) {*/
	/*	DWORD next = (DWORD)memget();
		*(DWORD*)cur = next;
		cur = (whatever it actually is*)next;*/


	/*cur = (LPBYTE)g_thumb_start;
	chunkend = (LPBYTE)(((intptr_t)cur & ~0xFFF) + 0xFFC);*/


	/*img = *big_cursor;
	imgend = (intptr)img & ~0xFFF;
	if (imgend == (intptr)big_cursor & ~0xFFF) {
		imgend = big_cursor;
	} else {
		imgend = (DWORD*)((LPCHAR)imgend + 0xFFC);
	}*/



//big_sanitize
//big_next_read
//big_next_write



//FUNCAHEAD

VOID RenderBig();
void RenderIndex();
void LoadThumb(wchar_t* filename);
void* LoadBig(wchar_t* filename);
void* memget();
void memfree(void* in);


//VARS

//hm, i probably should list what functions use what...
//can't you just use search?
//this is exactly what I'm proposing!

LPDIRECT3D9             g_pD3D = NULL; // Used to create the D3DDevice
LPDIRECT3DDEVICE9       g_pd3dDevice = NULL; // Our rendering device

//libjpeg
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;



struct jpegErrorManager {
    /* "public" fields */
    struct jpeg_error_mgr pub;
    /* for return to caller */
    jmp_buf setjmp_buffer;
};
char jpegLastErrorMsg[JMSG_LENGTH_MAX];
void jpegErrorExit (j_common_ptr cinfo)
{
    /* cinfo->err actually points to a jpegErrorManager struct */
    jpegErrorManager* myerr = (jpegErrorManager*) cinfo->err;
    /* note : *(cinfo->err) is now equivalent to myerr->pub */

    /* output_message is a method to print an error message */
    /*(* (cinfo->err->output_message) ) (cinfo);*/      

    /* Create the message */
    ( *(cinfo->err->format_message) ) (cinfo, jpegLastErrorMsg);

    /* Jump to the setjmp point */
    longjmp(myerr->setjmp_buffer, 1);

}

struct jpegErrorManager myerror;

// A structure for our custom vertex type
struct CUSTOMVERTEX
{
    FLOAT x, y, z, rhw; // The transformed position for the vertex
	FLOAT tu, tv; //LATER: in what order it should be?
};

// Our custom FVF, which describes our custom vertex structure
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW | D3DFVF_TEX1)



LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL; // Buffer to hold tut2_Vertices

//w
//h
//texture
//texture
//texture
//texture
//w
//h
//texture
//texture
//w
//h
//texture
//texture
//texture
//texture

DWORD* g_big_start = 0;
DWORD* g_big = 0;

int g_big_chunks = 0;

LPDIRECT3DVERTEXBUFFER9 g_pVB_thumb = NULL; // Buffer to hold tut2_Vertices


//texture
//length
//x y w h
//x y w h
//texture
//length
//...
//...
//next  //LATER, right now it's at the beginning...

char* g_thumb_start = 0;
char* g_thumb = 0;
char* g_thumb_texture = 0;

unsigned short g_thumb_x = 0;
unsigned short g_thumb_y = 0;
unsigned short g_thumb_h = 0;

LPDIRECT3DTEXTURE9      g_texture_text;
LPDIRECT3DVERTEXBUFFER9 g_pVB_text = NULL; // Buffer to hold tut2_Vertices
int g_pVB_text_capacity = 512;

char* g_onscreen_text;

//gallery
//one of them. No need for this to be global.
//wchar_t* g_filenames_start;
//wchar_t* g_filenames;
//
//wchar_t** g_filenames_pointers_start;
//wchar_t** g_filenames_pointers;
//
//char* g_folder_texture_pointers_start;
//char* g_folder_texture_pointers;



//these _not are here so that the default state of everything is always 0.
struct display {

	bool need_redraw_not;
	
	int display_w;
	int display_h;

};

struct display g_display;

struct view {
	//int pos_y_img;
	int pos_y;
	int pos_x;
	float scale;
	bool need_scale_not;
};

struct view g_index_view;
int g_index_rows_skipped;

const int g_index_row_width = 7;
const int g_index_row_height = 6;
const float g_index_el_height = 180.0f;
const float g_index_el_width = 140.0f;
//later


struct gallery {
	struct view view;
	int images_skipped;

	wchar_t* pathbase; //one of g_index_filenames_stringbuf, and g_index
	int filenum;

	int files_total;
	int files_loaded;
	int files_loaded_first; //allows skipping first files

	wchar_t* filenames_stringbuf_start;
	wchar_t* filenames_stringbuf;

	wchar_t** filenames_start;
	wchar_t** filenames;

	DWORD** folder_texture_pointers_start;
	DWORD** folder_texture_pointers;

	struct gallery* next;

};

struct gallery* g_gallery_start; //all the loaded galleries...
struct gallery* g_gallery;

bool g_show_index_or_show_gallery = 0;
//and this is just for speed, cause oop is kewl
struct view* g_current_view;
void (*RenderCurrent)();

char g_scancodes[64] = {0}; //needs to store 9 bits of possible pressed keys
//seems to be all zero, at least in debug...


struct savestate {
	int index_rows_skipped;
	int gallery_filenum;
	int gallery_pos_y;
	int gallery_images_skipped;
};

struct savestate g_savestate; //let's make it constant size


//index
//this is where the galleries are
//NOW

//struct index_something_data {
//	wchar_t* path;
//	//some way to quickly find the last stop
//	//probably the oldest or youngest folder filenum.
//	DWORD num_of_elements;
//};
//
//struct index_something {
//	struct index_something* next;
//	//probably some wasted space here
//	struct index_something_data data[777];
//};

//overindex, where to look for them
wchar_t* g_index_filenames_stringbuf_start;
wchar_t* g_index_filenames_stringbuf;

struct index_body {

	wchar_t* path;
	int length;
	int* filenum_start;
	int* time_start;
	int* meta_start;

};

LPDWORD g_index_start;
struct index_body* g_index;
//const int g_index_byteswasted = (0x1000) % sizeof(struct index_body);
//i will only store 5 filepaths here, it will never overflow!



//next
//maybe, unused

//path
//length
//filenum_start
//time_start
//thumb_ranges_start //this will be expandable. Actually, no need for that, too small.
//meta_start

//wchar_t* g_index_filenames_start; //the sorted (by name) array of filenames
//wchar_t** g_index_filenames;
//wchar_t* g_index_filenames_end; //LATER //just use zero termination, lol
//void* g_index_loaded_start;
//void* g_index_loaded;
//these two will point to textures.

//if zero, nothing is loaded
//overwise, show in what direction to go

//probably should store write time for each, and reload if there is something new...

//probably can use bitmap here instead...


//probably should store how many files are in each
//and connect it with thumbs somehow...

//int g_index_thumbloaded_start;
int g_index_thumbloaded_end; //0 means nothing is loaded

//index, what is inside
//void* g_thumbranges_start;
//void* g_thumbranges;

//void* g_thumbranges_gaps; //for garbage collection later

//used by
//_ReadFiles() //not yet

//DWORD next
//probably some wasted space
//length
//filenum_start
//time_start
//meta_start

//will be split BOTH by texture and by chunks (and by folders!)
//chunks ain't forced to be properly filled

//filenum is 1 dword per gallery, and time is 2 dword per gallery
//not sure what to do with meta right now. But I'm sure it's measured in dwords as well.

//g_thumbranges ARE sorted, always. But the data they point to can go in any order. But maintain the order when you can.

//rendering will be done with ranges.

//the reason it's split like that, is because I'll may want to free some of it without affecting others, like, releasing time.

//g_thumbranges_start has "next", all the "_start" it points to DON'T have "next"

//you will memget all those _start at once, with a custom number






//struct renderable_interface {
//	int pos_y;
//	int pos_y_img;
//	void (*func_draw)();
//}
//
//struct renderable_interface g_renderable = {
//	pos_y = 0,
//	pos_y_img = 0,
//	func_draw = RenderThumb,
//};

//hm, i will need to store
//always, index pos_y pos_y_img
//if have one, gallery filenum pos_y pos_y_img








//used by:
//memget
//memfree
//main
void* g_alloc_base; //not sure why exactly i keep this around...
void* g_alloc_next;
DWORD* g_alloc_free;
//stack
//dword prev


//void* g_alloc_border;
//void* g_alloc_gaps = 0; //array

//memget100
void* g_alloc_next100;



//used by:
//int_to_wstring
wchar_t g_tempzero[12];
wchar_t* g_tempzero_almost_end = &g_tempzero[10];
char* g_tempzero_hexstart = (char*)g_tempzero_almost_end - 8;


//used once, temporarily, just to store one thing.

struct temp_surface_info {
	LPDIRECT3DSURFACE9 surface;
	int pitch;
	unsigned char* bits;
	unsigned int what_l;
	unsigned int what_r;
	unsigned int what_t;
	unsigned int what_b;
};



//FUNC


void FUCK() {
	DWORD error = GetLastError();

	LPVOID lpMsgBuf;
    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | 
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        error,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR) &lpMsgBuf,
        0, NULL );


	LPVOID lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, 
        (lstrlen((LPCTSTR)lpMsgBuf) + 40) * sizeof(TCHAR)); 

	StringCchPrintf((LPTSTR)lpDisplayBuf, 
        LocalSize(lpDisplayBuf) / sizeof(TCHAR),
		TEXT("FUCK: %d: %s"), 
        error, lpMsgBuf); 

	MessageBox(0, (LPCTSTR)lpDisplayBuf, TEXT("!!!!"), 0);

    LocalFree(lpMsgBuf);
    LocalFree(lpDisplayBuf);

	__debugbreak();
}


void _TestFenceSend(DWORD* p) {
	*(p+1) = 0x123456;
	//_WriteBarrier();
	//_ReadWriteBarrier();
	MemoryBarrier();
	*p = 1;
}

wchar_t* wcscpy_return_end(wchar_t* dst, wchar_t* src) {
	while(true) {
		wchar_t temp = *src++;
		*dst++ = temp;
		if (! temp) return dst-1;
	}
};

char* strcpy_return_end(char* dst, char* src) {
	while(true) {
		char temp = *src++;
		*dst++ = temp;
		if (! temp) return dst-1;
	}
};


wchar_t* int_to_wstring(int the_int) {
	//if (the_int > 9999999999)
	wchar_t* cur = g_tempzero_almost_end;
	int ostatok;
	while (the_int) {
		ostatok = the_int % 10;
		the_int = the_int / 10;

		*cur = L'0' + ostatok;
		cur--;
	}
	cur++;
	
	return cur;
}

char* int_to_string(int the_int) {
	//if (the_int > 9999999999)
	char* cur = (char*)g_tempzero_almost_end;
	int ostatok;
	while (the_int) {
		ostatok = the_int % 10;
		the_int = the_int / 10;

		*cur = '0' + ostatok;
		cur--;
	}
	cur++;
	
	return cur;
}

char* int_to_hexstring(UINT32 the_int) {
	//if (the_int > 9999999999)
	char* cur = (char*)g_tempzero_almost_end;
	int ostatok;
	while (the_int) {
		ostatok = the_int % 16;
		the_int = the_int / 16;

		if (ostatok < 10) {
			*cur = '0' + ostatok;
		} else {
			*cur = 'a' + ostatok - 10;
		}
		cur--;
	}
	while(cur != g_tempzero_hexstart) {
		*cur--=' ';
	}
	cur++;
	
	return cur;
}

int wstring_to_int(wchar_t* the_string) {
	wchar_t* cur = the_string;
	int the_int = 0;
	int x_num = 1;

	//find the zero
	while (*cur!=0) {
		cur++;
	}
	cur--;
	while (cur >= the_string) {
		the_int += (*cur - L'0')*x_num;
		x_num *= 10;
		cur--;
	}
	return the_int;
}

//void LoadThumb_int(int filenum) {
//
//	wchar_t* filename_no_path = int_to_wstring(filenum);
//
//	wchar_t* filename_end = L".jpg";
//	wchar_t* filename_start = g_filename + 36; //L"123412341234.jpg
//	//int filename_last_length = 12;
//
//	*filename_start = 0;
//	wcscat(filename_start, filename_no_path);
//	wcscat(filename_start, filename_end);
//	LoadThumb(g_filename);
//}

//void _LoadTexturesBigRest(struct gallery* gallery) {
//
//	//load everything else
//
//	if (gallery->files_loaded == gallery->files_total) return;
//	//LATER: make it so it only gets called once
//	//but that's when you'll make coroutines and "todo lists"
//
//	wchar_t* path = (wchar_t*)memget();
//	wchar_t* path1_1 = wcscpy_return_end(path, gallery->pathbase);
//	wchar_t* path2 = wcscpy_return_end(path1_1, L"\\");
//	wchar_t* path2_1 = int_to_wstring(gallery->filenum);
//	wchar_t* path3 = wcscpy_return_end(path2, path2_1);
//	wchar_t* path4 = wcscpy_return_end(path3, L"\\");
//
//	wchar_t** str = gallery->filenames_start + gallery->files_loaded;
//	DWORD* texture = gallery->folder_texture_pointers_start + gallery->files_loaded;
//
//	int files_to_load = gallery->files_total - gallery->files_loaded;
//
//	for (int i=0; i<files_to_load; i++) {
//		wcscpy(path4, *str++);
//		*texture++ = (DWORD)LoadBig(path);
//	}
//
//	gallery->files_loaded = gallery->files_total;
//
//	memfree(path);
//}

void LoadGallery(struct gallery* gallery) {



	//load first 3

	wchar_t* path = (wchar_t*)memget();
	wchar_t* path1_1 = wcscpy_return_end(path, gallery->pathbase);
	wchar_t* path2 = wcscpy_return_end(path1_1, L"\\");
	wchar_t* path2_1 = int_to_wstring(gallery->filenum);
	wchar_t* path3 = wcscpy_return_end(path2, path2_1);
	wchar_t* path4 = wcscpy_return_end(path3, L"\\");

	wchar_t** str = gallery->filenames_start;
	str += gallery->files_loaded;
	DWORD** texture = gallery->folder_texture_pointers_start;
	texture += gallery->files_loaded;

	
	int files_to_load = gallery->files_total - gallery->files_loaded;
	if (files_to_load > 1) files_to_load = 1;

	for (int i=0; i<files_to_load; i++) {
		wcscpy(path4, *str++);
		*texture = (DWORD*)LoadBig(path);
		if (*texture == 0) {
			//stopping loading
			gallery->files_total = gallery->files_loaded;
			memfree(path);
			return;
		}
		texture++;
	}

	gallery->files_loaded = gallery->files_loaded + files_to_load;

	memfree(path);
}

void ReadFilesBig(struct gallery* gallery) {

	wchar_t* path = (wchar_t*)memget();
	wchar_t* path1_1 = wcscpy_return_end(path, gallery->pathbase);
	wchar_t* path2 = wcscpy_return_end(path1_1, L"\\");
	wchar_t* path2_1 = int_to_wstring(gallery->filenum);
	wchar_t* path3 = wcscpy_return_end(path2, path2_1);
	wcscpy(path3, L"\\*");

	//wchar_t* path2 = wcscpy_return_end(path, L"C:\\shared\\f\\exhentai\\files\\exhentai-gen5-2017\\996612");

				//use this later: *((gallery->filenames)++) = temp;

	WIN32_FIND_DATA findData;
	BOOL res = 1;

	int files_total=0;

	HANDLE searchHandle = FindFirstFile(path, &findData);

	if (searchHandle == 0) goto notFound;
	res = FindNextFile(searchHandle, &findData);
	//"." and ".." are skipped

	wchar_t* src;
	wchar_t* dst = gallery->filenames_stringbuf;
	wchar_t* string_start;

	//for (int i=0; i<60; i++) {
	//	res = FindNextFile(searchHandle, &findData);
	//	if (res == 0) FUCK();
	//}

	while (true) {
		res = FindNextFile(searchHandle, &findData);
		if (res == 0) break;
		files_total++;


restart:
		src = findData.cFileName;
		string_start = dst;

		//copy strings, lol
		//copy a string into a 0x1000 memory chunk, allocate new one if run out of space
		while(true) {

			wchar_t temp = *src++;
			*dst++ = temp;
			if (temp==0) break;
			if (((intptr_t)dst & 0xFFF) == 0xFFC) {
				//out of space, alloc next chunk
				//wouldn't even clear the string, no need for that
				DWORD next = (DWORD)memget();
				*(DWORD*)dst = next;
				dst = (wchar_t*)next;
				goto restart;
			}
		}

		if (((intptr_t)dst & 0xFFF) == 0xFFC) {
			//out of space, alloc next chunk
			DWORD next = (DWORD)memget();
			*(DWORD*)dst = next;
			dst = (wchar_t*)next;
			//no restart here, we're done
		}

		*gallery->filenames++ = string_start;
		
		

		//*g_filenames_pointers++ = string_start;

		
	}

	gallery->filenames_stringbuf = dst;
	gallery->files_total = files_total;
	gallery->files_loaded = 0;

	memfree(path);

	return;

notFound:
	memfree(path);
	FUCK();

}

//void _ReadFilesBig(wchar_t* path, wchar_t* path2) {

				//use this later: *((gallery->filenames)++) = temp;

//	WIN32_FIND_DATA findData;
//	BOOL res = 1;
//
//	wcscpy(path2, L"\\*");
//
//	HANDLE searchHandle = FindFirstFile(path, &findData);
//
//	if (searchHandle == 0) goto notFound;
//	res = FindNextFile(searchHandle, &findData);
//	//"." and ".." are skipped
//
//	while (true) {
//		res = FindNextFile(searchHandle, &findData);
//		if (res == 0) break;
//
//
//restart:
//		wchar_t* src = findData.cFileName;
//		wchar_t* string_start = g_filenames;
//
//		//copy strings, lol
//		//copy a string into a 0x1000 memory chunk, allocate new one if run out of space
//		while(true) {
//
//			wchar_t temp = *src++;
//			*g_filenames++ = temp;
//			if (temp==0) break;
//			if (((intptr_t)g_filenames & 0xFFF) == 0) {
//				//out of space, alloc next chunk
//				//wouldn't even clear the string, no need for that
//				g_filenames = (wchar_t*)((LPBYTE)g_filenames - 0x1000);
//				DWORD next = (DWORD)memget();
//				*(DWORD*)g_filenames = next;
//				g_filenames = (wchar_t*)((LPBYTE)next + 4);
//				goto restart;
//			}
//		}
//
//		if (((intptr_t)g_filenames & 0xFFF) == 0) {
//			//out of space, alloc next chunk
//			g_filenames = (wchar_t*)((LPBYTE)g_filenames - 0x1000);
//			DWORD next = (DWORD)memget();
//			*(DWORD*)g_filenames = next;
//			g_filenames = (wchar_t*)((LPBYTE)next + 4);
//			//no restart here, we're done
//		}
//
//		*g_filenames_pointers++ = string_start;
//
//		
//	}
//
//	return;
//
//notFound:
//	FUCK();

//}

void ReadFilesThumb() {
	WIN32_FIND_DATA findData;
	BOOL res = 1;
	
    VirtualAlloc(
         (LPVOID)g_alloc_next,
         0x3000,
         MEM_COMMIT,
         PAGE_READWRITE);

	int* filenum_start = (int*)g_alloc_next;
	int* time_start = (int*)((LPBYTE)g_alloc_next + 0x2000);

	g_alloc_next = (char*) g_alloc_next + 0x3000;

	int* filenum = filenum_start;
	int* time = time_start;

	wchar_t* path = (wchar_t*)memget();
	wchar_t* path2 = wcscpy_return_end(path, g_index->path);
	wcscpy(path2, L"\\*");


	//\\exhentai-gen1-2015
	HANDLE searchHandle = FindFirstFile(path, &findData);
	if (searchHandle == 0) goto notFound;
	res = FindNextFile(searchHandle, &findData);
	//"." and ".." are skipped

	int length = 0;

	while (true) {
		res = FindNextFile(searchHandle, &findData);
		if (res == 0) break;

		length++;



		*filenum++ = _wtoi(findData.cFileName);
		*time++ = findData.ftCreationTime.dwLowDateTime;
		*time++ = findData.ftCreationTime.dwHighDateTime;

		//first you compare "high", then if necessary "low"

		int exchanges_needed = 0;

		int* time_current = time - 2;
		int* time_next = time_current-2;
		while(true) {

			//if (((intptr_t)time_next & 0xFFF) == 0) break;
			//if (((intptr_t)time_current & 0xFFF) == 0) break;
			//can instead add extra code before the loop
			//but i'm lazy

			if (time_next < time_start) break;

			if (*(time_next+1) < *(time_current+1)) goto confirmed;
			if (*(time_next+1) > *(time_current+1)) break;
			//if equal...
			if (*time_next < *time_current) goto confirmed;
			//if (*time_next > *time_current) break;
			break;
			

confirmed:
			time_next -= 2;
			exchanges_needed++;
		}

		time_current = time - 1;
		int* filenum_current = filenum - 1;
		int temp, tomp;

		while(exchanges_needed) {
			temp = *time_current;
			tomp = *(time_current-2);
			*(time_current-2) = temp;
			*time_current = tomp;
			time_current--;

			temp = *time_current;
			tomp = *(time_current-2);
			*(time_current-2) = temp;
			*time_current = tomp;
			time_current--;

			temp = *filenum_current;
			tomp = *(filenum_current-1);
			*(filenum_current-1) = temp;
			*filenum_current = tomp;
			filenum_current--;

			exchanges_needed--;
			
		}



		//maxfiles--;
		//if (!maxfiles) break;
		
	}
	
	FindClose(searchHandle);

	g_index->length = length;
	g_index->filenum_start = filenum_start;
	g_index->time_start = time_start;


	return;

notFound:
	FUCK();

}


#define BUFFER_SIZE 100

//void _ReadFiles_old() {
//	WIN32_FIND_DATA findData;
//	BOOL res = 1;
//
//	char *pMBBuffer = (char *)malloc( BUFFER_SIZE );
//
//	wchar_t filename_orig[] = L"C:\\shared\\f\\exhentai\\exhentai-micro\\123412341234.jpg";
//	wchar_t* filename = (wchar_t*)malloc(sizeof(filename_orig));
//	memcpy(filename, filename_orig, sizeof(filename_orig));
//	wchar_t* filename_end = L".jpg";
//	wchar_t* filename_start = filename + 36; //L"123412341234.jpg
//	int filename_last_length = 12;
//
//	int maxfiles = 60;
//	
//	g_gallery_size = 411*sizeof(struct gallery);
//	g_gallery = (struct gallery*) malloc(g_gallery_size);
//	struct gallery* gallery_cursor = g_gallery;
//
//	//\\exhentai-gen1-2015
//	HANDLE searchHandle = FindFirstFile(L"C:\\shared\\f\\exhentai\\files\\exhentai-gen5-2017\\*", &findData);
//	if (searchHandle == 0) goto notFound;
//	res = FindNextFile(searchHandle, &findData);
//	//"." and ".." are skipped
//
//	while (true) {
//		res = FindNextFile(searchHandle, &findData);
//		if (res == 0) break;
//		gallery_cursor->id = _wtoi(findData.cFileName);
//
//		gallery_cursor->creation_time_low = findData.ftCreationTime.dwLowDateTime;
//		gallery_cursor->creation_time_high = findData.ftCreationTime.dwHighDateTime;
//		gallery_cursor->last_access_time_low = findData.ftLastAccessTime.dwLowDateTime;
//		gallery_cursor->last_access_time_high = findData.ftLastAccessTime.dwHighDateTime;
//		gallery_cursor->last_write_time_low = findData.ftLastWriteTime.dwLowDateTime;
//		gallery_cursor->last_write_time_high = findData.ftLastWriteTime.dwHighDateTime;
//
//		gallery_cursor++;
//
//		*filename_start = 0;
//		wcscat(filename_start, findData.cFileName);
//		wcscat(filename_start, filename_end);
//		LoadThumb(filename);
//
//		//wcstombs(pMBBuffer, findData.cFileName, BUFFER_SIZE );
//		//strcat(pMBBuffer, ".jpg");
//
//		//LoadThumb("1538.jpg");pMBBuffer
//		//LoadThumb(pMBBuffer);
//
//		//load the file, right here
//
//		maxfiles--;
//		if (!maxfiles) break;
//		
//	}
//	
//	FindClose(searchHandle);
//
//	//save to file
//
//	//FILE *infile = fopen("folders.bin", "wb");
//	//fwrite(g_gallery, 1, g_gallery_size, infile);
//	//fclose(infile);
//
//
//	return;
//
//notFound:
//	FUCK();
//
//}


void* memget_noreuse() {
	void* res;
	DWORD free = (DWORD)g_alloc_next;
	g_alloc_next = (char*) g_alloc_next + 0x1000;
    res = VirtualAlloc(
                 (void*)free,
                 0x1000,
                 MEM_COMMIT,
                 PAGE_READWRITE);

	return res;
}

void* memget() {

	void* res;
	DWORD free = *--g_alloc_free;
	if (((intptr_t) g_alloc_free & 0xFFF) == 0) {
		if (free == 0) {
			g_alloc_free++;
			free = (DWORD)g_alloc_next;
			g_alloc_next = (char*) g_alloc_next + 0x1000;
			//Nothing free, need to actually call VirtualAlloc.
		} else {
			g_alloc_free = (DWORD*)free - 1; //prev
			return (void*)free;
			FUCK();//rare
		}
	} else {
		return (void*)free;
		FUCK();//rare
	}


    res = VirtualAlloc(
                 (void*)free,
                 0x1000,
                 MEM_COMMIT,
                 PAGE_READWRITE);

	return res;
}

void memget_guard(char* string) {
	void* p = memget();
	strcpy((char*)p, string);
	PDWORD lpflOldProtect;
	VirtualProtect(p, 0x1000, PAGE_GUARD, lpflOldProtect);
}

void memfree(void* in) {
	//VirtualFree(in, 0x1000, MEM_DECOMMIT);

	*g_alloc_free++ = (DWORD)in;
	if (((intptr_t) g_alloc_free & 0xFFF) == 0) {
		FUCK(); //just to notify me, I need to check this works.
		//g_alloc_free = g_alloc_free; //wouldn't substract 0x1000.
		//hm, i can't call memget inside memfree, right?
		//I'll just reuse this exact chunk instead, lol.
		DWORD* next = (DWORD*)in;
		//VirtualAlloc(
  //               next,
  //               0x1000,
  //               MEM_COMMIT,
  //               PAGE_READWRITE);
		*next++ = (DWORD)g_alloc_free;
		g_alloc_free = next;

	}
	
}

void* memget100() {
	void* res = g_alloc_next100;
	
	g_alloc_next100 = (char*) g_alloc_next100 + 256;

	if (((intptr_t)g_alloc_next100 & 0xFFF) == 0) {
		g_alloc_next100 = memget();
	}

	return res;
}



//-----------------------------------------------------------------------------
// Name: InitD3D()
// Desc: Initializes Direct3D
//-----------------------------------------------------------------------------
HRESULT InitD3D( HWND hWnd )
{
    // Create the D3D object.
    if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
        return E_FAIL;

    // Set up the structure used to create the D3DDevice
    D3DPRESENT_PARAMETERS d3dpp;
    ZeroMemory( &d3dpp, sizeof( d3dpp ) );
    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;

    // Create the D3DDevice
    if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
                                      D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                                      &d3dpp, &g_pd3dDevice ) ) )
    {
        return E_FAIL;
    }

    // Device state would normally be set here

    return S_OK;
}





void LoadText() {

	FILE *infile;
	infile = fopen("C:/path/texture.raw", "rb");
	if (!infile) {
		FUCK();
	}

	//FILE *outfile;
	//outfile = fopen("texture_c.raw", "wb");

	//void* buffer = malloc(512/8);
	//char* inbuffer = (char*)malloc(512*512*4);

	//for (int i = 0; i < 8; i++) {
	//	//NOW
	//}

	//for (int i = 0; i<512; i++) {
	//	fseek(infile, (512 - 1 - i) * 512*4, SEEK_SET);
	//	fread(buffer, 1, 512*4, infile);
	//	fwrite(buffer, 1, 512*4, outfile);
	//}

	//fclose(outfile);

	g_pd3dDevice->CreateTexture(512, 512, 1, 0,
		D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &g_texture_text, 0);

	LPDIRECT3DSURFACE9 pSurface;
	g_texture_text->GetSurfaceLevel(0, &pSurface);

	D3DLOCKED_RECT lockedRect;
	pSurface->LockRect(&lockedRect, 0, 0);

	fread(lockedRect.pBits, 1, 512*512*4, infile);

	pSurface->UnlockRect();
	pSurface->Release();

	fclose(infile);
}



#define big_next_write(img, imgend)             \
	img++;                                \
	if (img == imgend) {                  \
		DWORD next = (DWORD)memget();        \
		*img = next;                      \
		img = (DWORD*)next;               \
		/*imgend = (DWORD*)(((intptr_t)img & ~0xFFF) + 0xFFC);*/    \
		imgend = (DWORD*)((intptr_t)img + 0xFFC);    \
	}                                                \




#define big_next_read(img, imgend)             \
	img++;                                \
	if (img == imgend) {                  \
		DWORD next = *(DWORD*)img;        \
		img = (DWORD*)next;               \
		/*imgend = (DWORD*)(((intptr_t)img & ~0xFFF) + 0xFFC);*/    \
		imgend = (DWORD*)((intptr_t)img + 0xFFC);    \
	}                                                \


#define big_sanitize(img, imgend)     \
	imgend = (DWORD*)(((intptr_t)img & ~0xFFF) + 0xFFC);        \


void UnloadBig() {
	//LATER
	//probably should also delete all galleries except current one here

	//FUCK(); //never seen this yet

	DWORD* cur;
	DWORD* curend;
	DWORD* curstart;
	//intptr_t curchunk = (intptr_t)cur >> 0xc; //&~0xFFF

	cur = g_big_start;
	big_sanitize(cur, curend);
	curstart = (DWORD*)((intptr_t)cur & ~0xFFF);

	bool stopflag = false;

	while(true) {

		int total_w = *cur;
		cur++;
		if (cur == curend) {
			DWORD next = *(DWORD*)cur;
			cur = (DWORD*)next;
			curend = (DWORD*)((intptr_t)cur + 0xFFC);
			stopflag = true;
			memfree((void*)curstart);
		}

		int total_h = *cur;
		cur++;
		if (cur == curend) {
			DWORD next = *(DWORD*)cur;
			cur = (DWORD*)next;
			curend = (DWORD*)((intptr_t)cur + 0xFFC);
			stopflag = true;
			memfree((void*)curstart);
		}

		int texture_w_tiles = total_w / 512;
		if (total_w & 0x1FF) texture_w_tiles++; //0x1FF is 512-1
		int texture_h_tiles = total_h / 512;
		if (total_h & 0x1FF) texture_h_tiles++; //0x1FF is 512-1

		int iterations = texture_w_tiles * texture_h_tiles;
		while(true) {
			LPDIRECT3DTEXTURE9 texture = *(LPDIRECT3DTEXTURE9*)cur;
			texture->Release();
			*cur = 0xf1f1f1f1; //debug

			//big_next_read(cur, curend);
			cur++;
			if (cur == curend) {
				DWORD next = *(DWORD*)cur;
				cur = (DWORD*)next;
				curend = (DWORD*)((intptr_t)cur + 0xFFC);
				stopflag = true;
				memfree((void*)curstart);
			}

			iterations--;
			if (!iterations) break;
		}

		if (stopflag) break;

	}

	g_big_start = cur;

	//LATER DEBUG
	DWORD* test = g_big_start;
	int testlength = 0;
	while(true) {
		if (((intptr_t)test & ~0xFFF) == ((intptr_t)g_big & ~0xFFF)) {
			testlength += (int)((intptr_t)test - (intptr_t)g_big);
			break;
		}
		test = *(DWORD**)(((intptr_t)test & ~0xFFF) + 0xFFC);
		testlength += 0xFFC;
	}

	//hm, let's remove unnecessary galleries while we're at it!
	//look at ShowGallery(int filenum)

	//struct gallery* curr = g_gallery_start;
	//struct gallery** prevaddr = &g_gallery_start;
	//while(true) {
	//	struct gallery* nextcurr = curr->next;
	//	if (curr != g_gallery) {
	//		free(curr); //also free everything inside it as well
	//		
	//	} else {
	//		prevaddr = curr
	//	}

	//	if (!nextcurr) break;
	//}


}


void* LoadBig(wchar_t* filename) {

	DWORD* cur;
	DWORD* curend;

	cur = g_big;
	big_sanitize(cur, curend);

	DWORD* cur_oldbackup = cur; //LATER, this is just for debug
	intptr_t curchunk = (intptr_t)cur >> 0xc; //&~0xFFF

	FILE *infile;

	//LIBJPEG
	//cinfo.err = jpeg_std_error(&jerr);
	cinfo.err = jpeg_std_error(&myerror.pub);
	myerror.pub.error_exit = jpegErrorExit;

	if (setjmp(myerror.setjmp_buffer)) {
		//cerr << jpegLastErrorMsg << endl;
		jpeg_destroy_decompress(&cinfo);
		fclose(infile);
		return 0;
	}

	jpeg_create_decompress(&cinfo);

	

	//banana

	//DISPLAY
	//infile = _wfopen("Sequoiadendron_giganteum_at_Kenilworth_Castle.jpg", L"rb");
	infile = _wfopen(filename, L"rb");
	if (!infile) {
		FUCK();
	}
	jpeg_stdio_src(&cinfo, infile);

	jpeg_read_header(&cinfo, TRUE);

	
	unsigned int total_w = (unsigned int)cinfo.image_width;
	unsigned int total_h = (unsigned int)cinfo.image_height;
	unsigned int texture_w = total_w / 512;  //these are to count coordinates
	unsigned int texture_h = total_h / 512;
	//unsigned int w = total_w % 512;
	//unsigned int h = total_h % 512;

	//those are to count the actual surfaces
	unsigned int texture_w_tiles = texture_w;
	if (total_w & 0x1FF) texture_w_tiles++; //0x1FF is 512-1
	unsigned int texture_h_tiles = texture_h;
	if (total_h & 0x1FF) texture_h_tiles++;

	void* res = cur; //LATER
	
	*cur = total_w;
	big_next_write(cur, curend);
	*cur = total_h;
	big_next_write(cur, curend);

	bool is_rgb;
	if (cinfo.jpeg_color_space == JCS_YCbCr) {
		is_rgb = true;
	} else if (cinfo.jpeg_color_space == JCS_GRAYSCALE) {
		is_rgb = false;
	} else {
		FUCK();
	}

	if (is_rgb) {
		cinfo.out_color_space = JCS_EXT_BGRX;
	} else {
		cinfo.out_color_space = JCS_GRAYSCALE;
	}

	jpeg_start_decompress(&cinfo);


	//LATER: free every malloc
	struct temp_surface_info* temp_surface_info = (struct temp_surface_info*)malloc(sizeof(struct temp_surface_info)*(texture_w_tiles));


	for (unsigned int i_texture_h = 0; i_texture_h < texture_h_tiles; i_texture_h++) {
		//creating textures and surfaces
		for (unsigned int i_texture_w = 0; i_texture_w < texture_w_tiles; i_texture_w++) {

			temp_surface_info[i_texture_w].what_l = 0;
			temp_surface_info[i_texture_w].what_r = 512;
			if (i_texture_w*512+512 > total_w) temp_surface_info[i_texture_w].what_r = total_w % 512;

			temp_surface_info[i_texture_w].what_t = 0;
			temp_surface_info[i_texture_w].what_b = 512;
			if (i_texture_h*512+512 > total_h) temp_surface_info[i_texture_w].what_b = total_h % 512;

			LPDIRECT3DTEXTURE9 pTexture;

			HRESULT res;

			if (is_rgb) {
				res = g_pd3dDevice->CreateTexture(512, 512, 0, 0,
					D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &pTexture, 0);
			} else {
				res = g_pd3dDevice->CreateTexture(512, 512, 0, 0,
					D3DFMT_L8, D3DPOOL_MANAGED, &pTexture, 0);
			}

			if (res != D3D_OK) FUCK();  //usually out of memory

			//g_textureArray[g_textureArray_used++] = pTexture;
			*cur = (DWORD)pTexture;
			big_next_write(cur, curend);

			pTexture->GetSurfaceLevel(0, &temp_surface_info[i_texture_w].surface);

			//if (((intptr_t)(temp_surface_info[i_texture_w].surface) & 0xF) != 0) {
			//	FUCK();
			//}

			
			//store pTexture into that array, and forget about it
			//you will only work with pSurface

			D3DLOCKED_RECT lockedRect;
			RECT whatToLock;
			whatToLock.left = temp_surface_info[i_texture_w].what_l;
			whatToLock.right = temp_surface_info[i_texture_w].what_r;
			whatToLock.top = temp_surface_info[i_texture_w].what_t;
			whatToLock.bottom = temp_surface_info[i_texture_w].what_b;

			temp_surface_info[i_texture_w].surface->LockRect(&lockedRect, &whatToLock, 0);

			temp_surface_info[i_texture_w].pitch=lockedRect.Pitch;

			temp_surface_info[i_texture_w].bits=(unsigned char*)lockedRect.pBits;

			

		}

		JSAMPARRAY buffer = (JSAMPARRAY)malloc(sizeof(JSAMPROW));
		//JSAMPARRAY buffer = {0};
		if (is_rgb) {
			buffer[0] = (JSAMPROW)malloc(total_w * 4);
		} else {
			buffer[0] = (JSAMPROW)malloc(total_w);
		}

		//decompressing itself
		for (unsigned int i_scanline = 0; i_scanline < temp_surface_info[0].what_b; i_scanline++) {
			jpeg_read_scanlines(&cinfo, buffer, 1);

			unsigned char * in_cursor = (unsigned char*)buffer[0];

			for (unsigned int i_texture_w = 0; i_texture_w < texture_w_tiles; i_texture_w++) {

				unsigned char * out_cursor = temp_surface_info[i_texture_w].bits;
				
				if (is_rgb) {
				for (unsigned int pixel_num = 0; pixel_num < temp_surface_info[i_texture_w].what_r; pixel_num++) {
					
					*out_cursor++ = *in_cursor++;
					*out_cursor++ = *in_cursor++;
					*out_cursor++ = *in_cursor++;
					*out_cursor++ = *in_cursor++;
				}
				} else {
					for (unsigned int pixel_num = 0; pixel_num < temp_surface_info[i_texture_w].what_r; pixel_num++) {
						*out_cursor++ = *in_cursor++;
					}
				}

				int pitch_diff;
				if (is_rgb) {
					pitch_diff = temp_surface_info[i_texture_w].pitch - (temp_surface_info[i_texture_w].what_r * 4);
				} else {
					pitch_diff = temp_surface_info[i_texture_w].pitch - (temp_surface_info[i_texture_w].what_r);
				}

				out_cursor += pitch_diff;
				//for (int bytes_num = 0; bytes_num < pitch_diff; bytes_num++) {
				//	//MessageBoxA(0, "WOW", "!!!", 0);
				//	//have a chance of never happening, just in case
				//	*out_cursor++ = 0xFF;
				//}

				temp_surface_info[i_texture_w].bits = out_cursor;
			}
		}


		for (unsigned int i_texture_w = 0; i_texture_w < texture_w_tiles; i_texture_w++) {
			temp_surface_info[i_texture_w].surface->UnlockRect();
			temp_surface_info[i_texture_w].surface->Release();
		}
	}

	jpeg_finish_decompress(&cinfo);

	jpeg_destroy_decompress(&cinfo);

	fclose(infile);

	g_big = cur;

	if (((intptr_t)cur >> 0xc) != curchunk) {
		g_big_chunks++;
		if (g_big_chunks >= 2) { //set to 2 for an LATER bug
			g_big_chunks--;
			UnloadBig();
		}
	}

	return res;
	
}


void LoadIndex() {

	//int howmuchtoload = g_index_row_height*g_index_row_width;
	int howmuchtoload = 128;
	if (g_index_thumbloaded_end + howmuchtoload > g_index->length) {
		howmuchtoload = g_index->length - g_index_thumbloaded_end;
	}


	wchar_t* thumbpath = (wchar_t*)memget();
	wchar_t* path_end = wcscpy_return_end(thumbpath, L"C:\\shared\\f\\exhentai\\exhentai-micro\\");



	int i = howmuchtoload;
	int* filenum = g_index->filenum_start;
	filenum += g_index_thumbloaded_end;
	while(i) {
		//LoadThumb_int(*filenum);

		wchar_t* filename = int_to_wstring(*filenum);
		wchar_t* path_end_2 = wcscpy_return_end(path_end, filename);
		wcscpy(path_end_2, L".jpg");

		LoadThumb(thumbpath);

		filenum++;
		i--;
	}

	memfree((void*)thumbpath);

	g_index_thumbloaded_end += howmuchtoload;
}


void LoadThumb(wchar_t* filename) {

	char* cur;
	cur = g_thumb;

	char* curend;
	curend = (char*)(((intptr_t)cur & ~0xFFF) + 0xFFC);
	//LATER

	LPDIRECT3DTEXTURE9 pTexture = NULL;
	LPDIRECT3DSURFACE9 pSurface = NULL;

	//LIBJPEG
	cinfo.err = jpeg_std_error(&jerr);
	jpeg_create_decompress(&cinfo);

	FILE *infile;

	//banana2

	//DISPLAY
	infile = _wfopen(filename, L"rb");
	if (!infile) {
		FUCK();
	}
	jpeg_stdio_src(&cinfo, infile);

	jpeg_read_header(&cinfo, TRUE);

	unsigned short total_w = (unsigned short)cinfo.image_width;
	unsigned short total_h = (unsigned short)cinfo.image_height;

	if (g_thumb_x + total_w > 1028) goto add_below;
	//if (g_thumb_y + total_h > 1028) goto new_texture;

	// add_to_the_right:
	//g_thumb_y = g_thumb_y;
	if (g_thumb_y + total_h > g_thumb_h) g_thumb_h = g_thumb_y + total_h;
	if (g_thumb_h & 0xF) g_thumb_h = (g_thumb_h & ~0xF) + 16;

	goto decompress;

add_below:
	g_thumb_x = 0;
	g_thumb_y = g_thumb_h;
	g_thumb_h = g_thumb_y + total_h;
	if (g_thumb_h & 0xF) g_thumb_h = (g_thumb_h & ~0xF) + 16;
	
	if (g_thumb_y + total_h > 1028) goto new_texture;

	goto decompress;


new_texture:
	g_thumb_x = 0;
	g_thumb_y = 0;
	g_thumb_h = 0;

	g_pd3dDevice->CreateTexture(1028, 1028, 1, 0,
		D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &pTexture, 0);

	g_thumb_texture = cur;
	*(LPDIRECT3DTEXTURE9*)cur = pTexture;
	cur += 4;
	if (cur == curend) {
		DWORD next = (DWORD)memget();
		*cur = next;
		cur = (char*)next;
		/*imgend = (DWORD*)(((intptr_t)img & ~0xFFF) + 0xFFC);*/
		curend = (char*)((intptr_t)cur + 0xFFC);
	}  

	*(DWORD*)cur = 0; //length
	cur += 4;
	if (cur == curend) {
		DWORD next = (DWORD)memget();
		*cur = next;
		cur = (char*)next;
		/*imgend = (DWORD*)(((intptr_t)img & ~0xFFF) + 0xFFC);*/
		curend = (char*)((intptr_t)cur + 0xFFC);
	}  

	goto decompress;

decompress:

	if (!pTexture) {
		pTexture = *(LPDIRECT3DTEXTURE9*)g_thumb_texture;
	}
	pTexture->GetSurfaceLevel(0, &pSurface);

	char* thumb_length = g_thumb_texture + 4;
	*thumb_length += 1;

	//TODO-word2byte
	//*(WORD*)cur = g_thumb_x;
	//cur += 2;
	//*(WORD*)cur = g_thumb_y;
	//cur += 2;
	//*(WORD*)cur = total_w;
	//cur += 2;
	//*(WORD*)cur = total_h;
	//cur += 2;

	*(BYTE*)cur = g_thumb_x>>4;
	cur += 1;
	*(BYTE*)cur = g_thumb_y>>4;
	cur += 1;
	*(BYTE*)cur = total_w;
	cur += 1;
	*(BYTE*)cur = total_h;
	cur += 1;
	if (cur == curend) {
		DWORD next = (DWORD)memget();
		*cur = next;
		cur = (char*)next;
		/*imgend = (DWORD*)(((intptr_t)img & ~0xFFF) + 0xFFC);*/
		curend = (char*)((intptr_t)cur + 0xFFC);
	}


	//*((unsigned short*)g_texture_thumb_cursor)++ = g_thumb_x;
	//*(unsigned short*)g_texture_thumb_cursor++ = g_thumb_y;
	//*((unsigned short*)g_texture_thumb_cursor)++ = total_w;
	//*(unsigned short*)g_texture_thumb_cursor++ = total_h;
	//LATER (alloc memory as necessary)

	D3DLOCKED_RECT lockedRect;
	RECT whatToLock;
	whatToLock.left = g_thumb_x;
	whatToLock.right = g_thumb_x + total_w;
	whatToLock.top = g_thumb_y;
	whatToLock.bottom = g_thumb_y + total_h;

	g_thumb_x = g_thumb_x + total_w;
	if (g_thumb_x & 0xF) g_thumb_x = (g_thumb_x & ~0xF) + 16;

	pSurface->LockRect(&lockedRect, &whatToLock, 0);

	cinfo.out_color_space = JCS_EXT_BGRX;

	jpeg_start_decompress(&cinfo);

	int pitch_diff = lockedRect.Pitch - (cinfo.output_width * 4);
	
	//if (cinfo.out_color_space == JCS_GRAYSCALE) {


	JSAMPARRAY buffer = (JSAMPARRAY)malloc(sizeof(JSAMPROW));
	//JSAMPARRAY buffer = {0};
	buffer[0] = (JSAMPROW)malloc(cinfo.output_width * cinfo.output_components);

	char * out_cursor = (char*)lockedRect.pBits;
	char * in_cursor;

	while (cinfo.output_scanline < cinfo.output_height) {
		jpeg_read_scanlines(&cinfo, buffer, 1);
		in_cursor = (char*)buffer[0];
		for (unsigned int pixel_num = 0; pixel_num < cinfo.output_width; pixel_num++) {
			*out_cursor++ = *in_cursor++;
			*out_cursor++ = *in_cursor++;
			*out_cursor++ = *in_cursor++;
			*out_cursor++ = *in_cursor++;
		}
		out_cursor += pitch_diff;
		//for (int bytes_num = 0; bytes_num < pitch_diff; bytes_num++) {
		//	//have a chance of never happening, just in case
		//	*out_cursor++ = 0;
		//}
	}


	pSurface->UnlockRect();
	pSurface->Release();

	jpeg_finish_decompress(&cinfo);

	jpeg_destroy_decompress(&cinfo);

	fclose(infile);

	g_thumb = cur;
	
}



void ShowGallery(int filenum) {
	RenderCurrent = RenderBig;
	g_show_index_or_show_gallery = 1; //probably don't need this...

	//iterate through all galleries, see if it's already loaded
	//if not, load it

	struct gallery* curr = g_gallery_start;
	if (!curr) {
		curr = (struct gallery*)malloc(sizeof(struct gallery));
		ZeroMemory(curr, sizeof(struct gallery));
		g_gallery_start = curr;
		goto now_load;
	} else {
		while(true) {
			if (curr->filenum == filenum) {
				//found
				goto show;
			}
			if (!curr->next) {
				struct gallery* nextcurr = (struct gallery*)malloc(sizeof(struct gallery));
				ZeroMemory(nextcurr, sizeof(struct gallery));
				curr->next = nextcurr;
				curr = nextcurr;
				goto now_load;
			}
			curr = curr->next;
		}
	}



now_load:
	//LATER
	//return;

	curr->filenum = filenum;
	curr->pathbase = g_index->path; //LATER

	curr->filenames_start = (wchar_t**)memget();
	curr->filenames = curr->filenames_start;
	memget_guard("ShowGallery, filenames_start");

	curr->filenames_stringbuf_start = (wchar_t*)memget();
	curr->filenames_stringbuf = curr->filenames_stringbuf_start;
	memget_guard("ShowGallery, filenames_stringbuf_start");

	curr->folder_texture_pointers_start = (DWORD**)memget();
	curr->folder_texture_pointers = curr->folder_texture_pointers_start;
	memget_guard("ShowGallery, folder_texture_pointers_start");

	curr->files_loaded = 0;

	ReadFilesBig(curr);

	//not now: sort files

	LoadGallery(curr);


show:
	//LATER
	g_gallery = curr;
	g_current_view = (struct view*)g_gallery;

	RenderCurrent = RenderBig;
	g_show_index_or_show_gallery = 1; //probably don't need this...

	g_current_view = (view*)curr;

	g_display.need_redraw_not = false;

	return;


}

void ShowIndex() {
	RenderCurrent = RenderIndex;
	g_show_index_or_show_gallery = 0; //probably don't need this...

	g_current_view = &g_index_view;

	g_display.need_redraw_not = false;
}



//-----------------------------------------------------------------------------
// Name: InitVB()
// Desc: Creates a vertex buffer and fills it with our tut2_Vertices. The vertex
//       buffer is basically just a chuck of memory that holds tut2_Vertices. After
//       creating it, we must Lock()/Unlock() it to fill it. For indices, D3D
//       also uses index buffers. The special thing about vertex and index
//       buffers is that they can be created in device memory, allowing some
//       cards to process them in hardware, resulting in a dramatic
//       performance gain.
//-----------------------------------------------------------------------------
HRESULT InitVB()
{



	//g_pd3dDevice->SetRenderState(D3DRS_WRAP0, D3DWRAPCOORD_0);

	//g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC);
	//g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MIPFILTER, D3DTEXF_ANISOTROPIC); //ugly



	//THIS WORKED!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	g_pd3dDevice->SetSamplerState( 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
	g_pd3dDevice->SetSamplerState( 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);

	g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
	//THIS WORKED!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!



	LoadText();

	//g_display.pos_x = 0;
	//g_display.pos_y = 0; //LATER
	//g_display.need_redraw_not = 0;
	//g_display.need_scale_not = 0;

	//g_display.current_folder = (struct folder*)malloc(sizeof(struct folder));
	//g_display.current_folder->filepath_slash = "c:/LATERLATERLATER";
	//g_display.current_folder->size = 2;
	//g_display.current_folder->filenames_array = (char**)malloc(sizeof(void*)*2);
	//g_display.current_folder->imgind_array = (int*)malloc(sizeof(void*)*2);

	//g_display.current_folder->filenames_array[0] = "Sequoiadendron_giganteum_at_Kenilworth_Castle.jpg";
	//g_display.current_folder->filenames_array[1] = "later2";



	
	//g_textureArray_size = 32;
	//g_textureArray_used = 0;
	//g_textureArray = (LPDIRECT3DTEXTURE9 *) malloc(sizeof(void*)*g_textureArray_size);

	//g_images_size = 16;
	//g_images_used = 0;


	//g_images = (  image (*)[]  ) malloc(sizeof(void*)*g_images_size);
	//hahahahaha!

	//and images should be loaded separately...
	//with a long, long function...

	//ListFiles(&g_display);


	//999908
	//L"C:\\shared\\f\\exhentai\\files\\exhentai-gen5-2017"
	//HANDLE hFile = CreateFileW(L"C:\\shared\\f\\exhentai\\files\\exhentai-gen5-2017\\", GENERIC_READ, FILE_SHARE_READ, NULL,
 //       OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);

	//if(hFile == INVALID_HANDLE_VALUE) {
	//	FUCK();
	//}





	g_big_start = (DWORD*)memget();
	g_big = g_big_start;
	memget_guard("g_big_start");



	g_index_start = (LPDWORD)memget();
	memget_guard("g_index_start");
	//g_index = (struct index_body*)((char*)g_index_start + g_index_byteswasted);
	g_index = (struct index_body*)g_index_start;

	g_index_filenames_stringbuf_start = (wchar_t*)memget();
	g_index_filenames_stringbuf = (wchar_t*)((LPBYTE)g_index_filenames_stringbuf_start + 4);
	g_index->path = (wchar_t*)g_index_filenames_stringbuf;
	g_index_filenames_stringbuf = wcscpy_return_end(g_index_filenames_stringbuf, 
		L"C:\\shared\\f\\exhentai\\files\\exhentai-gen5-2017");



	//preparing for ReadFilesThumb

	g_thumb_start = (char*)memget();
	g_thumb = g_thumb_start;


	LPDIRECT3DTEXTURE9 pTexture;
	g_pd3dDevice->CreateTexture(1028, 1028, 1, 0,
		D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &pTexture, 0);

	g_thumb_texture = g_thumb;
	*(LPDIRECT3DTEXTURE9*)g_thumb = pTexture;
	g_thumb += 4;

	*(DWORD*)g_thumb = 0; //length
	g_thumb += 4;

	ReadFilesThumb();

	//g_index_thumbloaded_start = 0;
	g_index_thumbloaded_end = 0;

	LoadIndex();



	ShowIndex();



	float where_l = 0.0f -0.5f;
	float where_r = (float)512 -0.5f;
	float where_t = 0.0f -0.5f;
	float where_b = (float)512 -0.5f;

	float what_l = 0.0f;
	float what_r = (float)512 / (float)512;
	float what_t = 0.0f;
	float what_b = (float)512 / (float)512;


	CUSTOMVERTEX vert_text[] =
    {
        { where_l,  where_t, 0.5f, 1.0f, what_l, what_t, },
		{ where_r,  where_t, 0.5f, 1.0f, what_r, what_t, },
		{ where_l,  where_b, 0.5f, 1.0f, what_l, what_b, },
		{ where_r,  where_b, 0.5f, 1.0f, what_r, what_b, },
    };

	
	//CUSTOMVERTEX vert_thumb[] =
 //   {
 //       { where_l*2,  where_t*2, 0.5f, 1.0f, what_l, what_t, },
	//	{ where_r*2,  where_t*2, 0.5f, 1.0f, what_r, what_t, },
	//	{ where_l*2,  where_b*2, 0.5f, 1.0f, what_l, what_b, },
	//	{ where_r*2,  where_b*2, 0.5f, 1.0f, what_r, what_b, },
 //   };

	CUSTOMVERTEX vert_thumb[] =
    {
        { where_l,  where_t, 0.5f, 1.0f, what_l, what_t, },
		{ where_r,  where_t, 0.5f, 1.0f, what_r, what_t, },
		{ where_l,  where_b, 0.5f, 1.0f, what_l, what_b, },
		{ where_r,  where_b, 0.5f, 1.0f, what_r, what_b, },
    };



	//128 tiles
    if( FAILED( g_pd3dDevice->CreateVertexBuffer( 128 * 4 * sizeof( CUSTOMVERTEX ),
                                                  D3DUSAGE_DYNAMIC, D3DFVF_CUSTOMVERTEX,
                                                  D3DPOOL_DEFAULT, &g_pVB, NULL ) ) )
    {
        FUCK();
    }


	if( FAILED( g_pd3dDevice->CreateVertexBuffer( g_pVB_text_capacity * 6 * sizeof( CUSTOMVERTEX ),
                                                  D3DUSAGE_DYNAMIC, D3DFVF_CUSTOMVERTEX,
                                                  D3DPOOL_DEFAULT, &g_pVB_text, NULL ) ) )
    {
        FUCK();
    }


    VOID* p_vert_text;
    if( FAILED( g_pVB_text->Lock( 0, sizeof(vert_text), ( void** )&p_vert_text, 0 ) ) )
        return E_FAIL;
    memcpy( p_vert_text, vert_text, sizeof(vert_text) );
    g_pVB_text->Unlock();



	
	if( FAILED( g_pd3dDevice->CreateVertexBuffer( 128 * 4 * sizeof( CUSTOMVERTEX ),
                                                  D3DUSAGE_DYNAMIC, D3DFVF_CUSTOMVERTEX,
                                                  D3DPOOL_DEFAULT, &g_pVB_thumb, NULL ) ) )
    {
        FUCK();
    }

	VOID* p_vert_thumb;
    if( FAILED( g_pVB_thumb->Lock( 0, sizeof(vert_thumb), ( void** )&p_vert_thumb, 0 ) ) )
        return E_FAIL;
    memcpy( p_vert_thumb, vert_thumb, sizeof(vert_thumb) );
    g_pVB_thumb->Unlock();


    return S_OK;
}




//-----------------------------------------------------------------------------
// Name: Cleanup()
// Desc: Releases all previously initialized objects
//-----------------------------------------------------------------------------
VOID Cleanup()
{
    if( g_pVB != NULL )
        g_pVB->Release();

    if( g_pd3dDevice != NULL )
        g_pd3dDevice->Release();

    if( g_pD3D != NULL )
        g_pD3D->Release();
}


#define fill_list(where_l, where_r, where_t, where_b, what_l, what_r, what_t, what_b)   \
                                     \
    /*lt*/                           \
    *p++ = where_l;                  \
    *p++ = where_t;                  \
    *p++ = 0.5f;                     \
    *p++ = 1.0f;                     \
    *p++ = what_l;                   \
    *p++ = what_t;                   \
                                     \
    /* rt */                         \
    *p++ = where_r;                  \
    *p++ = where_t;                  \
    *p++ = 0.5f;                     \
    *p++ = 1.0f;                     \
    *p++ = what_r;                   \
    *p++ = what_t;                   \
                                     \
    /*lb*/                           \
    *p++ = where_l;                  \
    *p++ = where_b;                  \
    *p++ = 0.5f;                     \
    *p++ = 1.0f;                     \
    *p++ = what_l;                   \
    *p++ = what_b;                   \
                                     \
     /*lb*/                          \
    *p++ = where_l;                  \
    *p++ = where_b;                  \
    *p++ = 0.5f;                     \
    *p++ = 1.0f;                     \
    *p++ = what_l;                   \
    *p++ = what_b;                   \
                                     \
    /*rt*/                           \
    *p++ = where_r;                  \
    *p++ = where_t;                  \
    *p++ = 0.5f;                     \
    *p++ = 1.0f;                     \
    *p++ = what_r;                   \
    *p++ = what_t;                   \
                                     \
    /*rb*/                           \
    *p++ = where_r;                  \
    *p++ = where_b;                  \
    *p++ = 0.5f;                     \
    *p++ = 1.0f;                     \
    *p++ = what_r;                   \
    *p++ = what_b;                   \



#define fill(where_l, where_r, where_t, where_b, what_l, what_r, what_t, what_b)   \
                                     \
    /*lt*/                           \
    *p++ = where_l;                  \
    *p++ = where_t;                  \
    *p++ = 0.5f;                     \
    *p++ = 1.0f;                     \
    *p++ = what_l;                   \
    *p++ = what_t;                   \
                                     \
    /* rt */                         \
    *p++ = where_r;                  \
    *p++ = where_t;                  \
    *p++ = 0.5f;                     \
    *p++ = 1.0f;                     \
    *p++ = what_r;                   \
    *p++ = what_t;                   \
                                     \
    /*lb*/                           \
    *p++ = where_l;                  \
    *p++ = where_b;                  \
    *p++ = 0.5f;                     \
    *p++ = 1.0f;                     \
    *p++ = what_l;                   \
    *p++ = what_b;                   \
                                     \
    /*rb*/                           \
    *p++ = where_r;                  \
    *p++ = where_b;                  \
    *p++ = 0.5f;                     \
    *p++ = 1.0f;                     \
    *p++ = what_r;                   \
    *p++ = what_b;                   \



VOID RenderText() {
	
	
	////int_to_string();
	//LPBYTE cur = (LPBYTE)g_index_start;
	//cur+=4; //next
	//cur+=4; //path
	//cur+=4; //length
	////filenum_start
	//DWORD* filenum = *(DWORD**)cur;

	//DWORD* filenum = (DWORD*)g_index->filenum_start;
	DWORD* filenum = (DWORD*)g_index->filenum_start + g_index_rows_skipped*g_index_row_width;

	int vertices_size = g_pVB_text_capacity * 6 * sizeof(CUSTOMVERTEX);

	VOID* pVertices;
	if( FAILED( g_pVB_text->Lock( 0, vertices_size, ( void** )&pVertices, D3DLOCK_DISCARD ) ) )
		FUCK();

	float* p = (float*)pVertices;

	int howmuchtodraw = g_index_row_width*g_index_row_height;

	float center_x = g_index_el_width/2.0f -0.5f;
	float center_y = (float)-g_index_view.pos_y + g_index_el_height - 20.0f -0.5f;

	int char_width = 9;
	int char_height = 16;

	int charstotal = 0;

	float where_x, where_y, where_w, where_h;
	float what_x, what_y, what_w, what_h;

	for (int i = 0; i<howmuchtodraw; i++) {
		char* renderthis = int_to_string(*filenum++);
		int renderlength = (char*)g_tempzero_almost_end - renderthis;

		float start_x = center_x - renderlength*16.0f/2.0f;
		float start_y = center_y;

		while(true) {

			char c = *renderthis++;
			if (!c) break;

			int whatchar_y = (int)c / 32;
			int whatchar_x = (int)c % 32;

			what_x = whatchar_x * 9.0f / 512.0f;
			what_y = whatchar_y * 16.0f / 512.0f;
			what_w = what_x + (9.0f / 512.0f);
			what_h = what_y + (16.0f / 512.0f);

			where_x = start_x;
			where_y = start_y;
			where_w = where_x + 9.0f;
			where_h = where_y + 16.0f;

			fill_list(where_x, where_w,
					where_y, where_h,
					what_x, what_w,		//should be something like what_x/1024.0f
					what_y, what_h);

			start_x+= 9.0f;

			charstotal++;

			if (charstotal > g_pVB_text_capacity) FUCK();

		}


		center_x += 140.0f;
		if (center_x > 1000.0f) {
			center_x = 70.0f -0.5f;
			center_y += 180.0f;
		}

	}

	where_x = 0.0f;
	where_y = 0.0f;
	
	//draw onscreen text
	char* cur_osd = g_onscreen_text;
	while(true) {
		char c = *cur_osd;
		if (!c) break;
		cur_osd++;


		int whatchar_y = (int)c / 32;
		int whatchar_x = (int)c % 32;

		what_x = whatchar_x * 9.0f / 512.0f;
		what_y = whatchar_y * 16.0f / 512.0f;
		what_w = what_x + (9.0f / 512.0f);
		what_h = what_y + (16.0f / 512.0f);

		where_w = where_x + 9.0f;
		where_h = where_y + 16.0f;

		fill_list(where_x, where_w,
				where_y, where_h,
				what_x, what_w,		//should be something like what_x/1024.0f
				what_y, what_h);

		where_x += 9.0f;

		charstotal++;

		if (charstotal > g_pVB_text_capacity) FUCK();


	}

	g_pVB_text->Unlock();

	g_pd3dDevice->SetStreamSource( 0, g_pVB_text, 0, sizeof( CUSTOMVERTEX ) );

	g_pd3dDevice->SetTexture( 0, g_texture_text);

	g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, charstotal*2 );


}


VOID RenderThumb() {

	LPBYTE cur;

	LPBYTE chunkend; //the point of the next "next"

	float where_x, where_y, where_w, where_h;
	float what_x, what_y, what_w, what_h;

	int needtoskip;
	needtoskip = g_index_rows_skipped*g_index_row_width;

	int howmuchtodraw = g_index_row_width*g_index_row_height;
	//int howmuchtodraw = 14;
	if (needtoskip + howmuchtodraw > g_index_thumbloaded_end) {
		howmuchtodraw = g_index_thumbloaded_end - needtoskip;
	}

	if (howmuchtodraw <= 0) return;

	int vertices_size = 128 * 4 * sizeof(CUSTOMVERTEX);

	VOID* pVertices;
	if( FAILED( g_pVB_thumb->Lock( 0, vertices_size, ( void** )&pVertices, D3DLOCK_DISCARD ) ) )
		FUCK();

	float* p = (float*)pVertices;

	float center_x = g_index_el_width / 2.0f - 10.0f -0.5f;
	float center_y = (float)-g_index_view.pos_y + 80.0f -0.5f;


	
	DWORD* texture;
	DWORD length;
	DWORD* size;
	

	//vertex-skip
	cur = (LPBYTE)g_thumb_start;
	chunkend = (LPBYTE)(((intptr_t)cur & ~0xFFF) + 0xFFC);
	//LATER: add those chunkend everywhere
	texture = (DWORD*)cur;
	cur+=4;
	if (cur == chunkend) {
		FUCK();
		DWORD next = (DWORD)memget();
		*(DWORD*)cur = next;
		cur = (LPBYTE)next;
		chunkend = (LPBYTE)((intptr_t)cur + 0xFFC);
	}
	length = *(DWORD*)cur;
	cur+=4;
	if (cur == chunkend) {
		FUCK();
		DWORD next = (DWORD)memget();
		*(DWORD*)cur = next;
		cur = (LPBYTE)next;
		chunkend = (LPBYTE)((intptr_t)cur + 0xFFC);
	}

	//vertex-skip-while
	while(true) {
		if (!needtoskip) break;
		if (needtoskip <= length) {
			cur+=4*needtoskip;
			if (cur > chunkend) {
				FUCK();
				DWORD next = (DWORD)memget();
				*(DWORD*)chunkend = next;
				cur = (LPBYTE)(next + (chunkend - cur));
				chunkend = (LPBYTE)(((intptr_t)cur & ~0xFFF) + 0xFFC);
			}

			length = length - needtoskip;

			break;
		} else {
			cur+=4*length;
			if (cur > chunkend) {
				FUCK();
				DWORD next = (DWORD)memget();
				*(DWORD*)chunkend = next;
				cur = (LPBYTE)(next + (chunkend - cur));
				chunkend = (LPBYTE)(((intptr_t)cur & ~0xFFF) + 0xFFC);
			}

			needtoskip -= length;
			if (!needtoskip) break;

			texture = (DWORD*)cur;
			cur+=4;
			if (cur == chunkend) {
				FUCK();
				DWORD next = (DWORD)memget();
				*(DWORD*)cur = next;
				cur = (LPBYTE)next;
				chunkend = (LPBYTE)((intptr_t)cur + 0xFFC);
			}
			length = *(DWORD*)cur;
			cur+=4;
			if (cur == chunkend) {
				FUCK();
				DWORD next = (DWORD)memget();
				*(DWORD*)cur = next;
				cur = (LPBYTE)next;
				chunkend = (LPBYTE)((intptr_t)cur + 0xFFC);
			}

		}
	}

	//vertex-iterate
	for (int i = 0; i<howmuchtodraw; i++) {
		//THIS
		//need to skip one texture and one length here
		//need to handle the case when the length ends too

		if (!length) {
			//texture = (DWORD*)cur;
			cur+=4;
			if (cur == chunkend) {
				FUCK();
				DWORD next = (DWORD)memget();
				*(DWORD*)cur = next;
				cur = (LPBYTE)next;
				chunkend = (LPBYTE)((intptr_t)cur + 0xFFC);
			}
			length = *(DWORD*)cur;
			cur+=4;
			if (cur == chunkend) {
				FUCK();
				DWORD next = (DWORD)memget();
				*(DWORD*)cur = next;
				cur = (LPBYTE)next;
				chunkend = (LPBYTE)((intptr_t)cur + 0xFFC);
			}
		}
		length--;


		//TODO-word2byte
		WORD texture_x = *(BYTE*)cur;
		texture_x = texture_x << 4;
		cur+=1;
		WORD texture_y = *(BYTE*)cur;
		texture_y = texture_y << 4;
		cur+=1;
		WORD total_w = *(BYTE*)cur;
		cur+=1;
		WORD total_h = *(BYTE*)cur;
		cur+=1;
		if (cur == chunkend) {
			FUCK();
			DWORD next = (DWORD)memget();
			*(DWORD*)cur = next;
			cur = (LPBYTE)next;
			chunkend = (LPBYTE)((intptr_t)cur + 0xFFC);
		}

		where_x = center_x - ((float)total_w / 2);
		where_w = where_x + ((float)total_w -1);

		where_y = center_y - ((float)total_h / 2);
		where_h = where_y + ((float)total_h -1);

		what_x = (float)texture_x / 1024.0f;
		what_w = what_x + (float)(total_w -1) / 1024.0f;

		what_y = (float)texture_y / 1024.0f;
		what_h = what_y + (float)(total_h -1) / 1024.0f;
		//what_h = (float)(texture_y + total_h) / 1024.0f;

		fill_list(where_x, where_w,
					where_y, where_h,
					what_x, what_w,
					what_y, what_h);

			//fill_list(where_x, where_w,
			//	where_y, where_h,
			//	0.0f, 1.0f,
			//	0.0f, 1.0f);


		center_x += g_index_el_width;
		if (center_x > 1000.0f) {
			center_x = g_index_el_width / 2.0f - 10.0f -0.5f;
			center_y += g_index_el_height;
		}

		

		

	}

	g_pVB_thumb->Unlock();

	g_pd3dDevice->SetStreamSource( 0, g_pVB_thumb, 0, sizeof( CUSTOMVERTEX ) );



	cur = (LPBYTE)g_thumb_start;
	

	//render-skip...
	needtoskip = g_index_rows_skipped*g_index_row_width;
	cur = (LPBYTE)g_thumb_start;
	chunkend = (LPBYTE)(((intptr_t)cur & ~0xFFF) + 0xFFC);
	texture = (DWORD*)cur;
	cur+=4;
	if (cur == chunkend) {
		FUCK();
		DWORD next = (DWORD)memget();
		*(DWORD*)cur = next;
		cur = (LPBYTE)next;
		chunkend = (LPBYTE)((intptr_t)cur + 0xFFC);
	}
	length = *(DWORD*)cur;
	cur+=4;
	if (cur == chunkend) {
		FUCK();
		DWORD next = (DWORD)memget();
		*(DWORD*)cur = next;
		cur = (LPBYTE)next;
		chunkend = (LPBYTE)((intptr_t)cur + 0xFFC);
	}

	//render-skip-while
	while(true) {
		if (!needtoskip) break;
		if (needtoskip <= length) {
			cur+=4*needtoskip;
			if (cur > chunkend) {
				FUCK();
				DWORD next = (DWORD)memget();
				*(DWORD*)chunkend = next;
				cur = (LPBYTE)(next + (chunkend - cur));
				chunkend = (LPBYTE)(((intptr_t)cur & ~0xFFF) + 0xFFC);
			}

			length = length - needtoskip;

			break;
		} else {
			cur+=4*length;
			if (cur > chunkend) {
				FUCK();
				DWORD next = (DWORD)memget();
				*(DWORD*)chunkend = next;
				cur = (LPBYTE)(next + (chunkend - cur));
				chunkend = (LPBYTE)(((intptr_t)cur & ~0xFFF) + 0xFFC);
			}

			needtoskip -= length;
			if (!needtoskip) break;

			texture = (DWORD*)cur;
			cur+=4;
			if (cur == chunkend) {
				FUCK();
				DWORD next = (DWORD)memget();
				*(DWORD*)cur = next;
				cur = (LPBYTE)next;
				chunkend = (LPBYTE)((intptr_t)cur + 0xFFC);
			}
			length = *(DWORD*)cur;
			cur+=4;
			if (cur == chunkend) {
				FUCK();
				DWORD next = (DWORD)memget();
				*(DWORD*)cur = next;
				cur = (LPBYTE)next;
				chunkend = (LPBYTE)((intptr_t)cur + 0xFFC);
			}

			
		}
	}

	//render-iterate
	int index = 0;
	while(howmuchtodraw) {

		//g_pd3dDevice->SetTexture( 0, *(LPDIRECT3DTEXTURE9*)g_thumb_start );
		////g_pd3dDevice->SetTexture( 0, *(LPDIRECT3DTEXTURE9*)texture );
		//g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, length*2 );
		//index+=4;


		if (!howmuchtodraw) break;
		if (howmuchtodraw <= length) {
			//TODO-word2byte
			cur+=4*howmuchtodraw;
			if (cur > chunkend) {
				FUCK();
				DWORD next = (DWORD)memget();
				*(DWORD*)chunkend = next;
				cur = (LPBYTE)(next + (chunkend - cur));
				chunkend = (LPBYTE)(((intptr_t)cur & ~0xFFF) + 0xFFC);
			}

			g_pd3dDevice->SetTexture( 0, *(LPDIRECT3DTEXTURE9*)texture );
			g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, index, howmuchtodraw*2 );

			break;
		} else { //howmuchtodraw > length
			if (length) {
				cur+=4*length;
				if (cur > chunkend) {
					FUCK();
					DWORD next = (DWORD)memget();
					*(DWORD*)chunkend = next;
					cur = (LPBYTE)(next + (chunkend - cur));
					chunkend = (LPBYTE)(((intptr_t)cur & ~0xFFF) + 0xFFC);
				}

			
				g_pd3dDevice->SetTexture( 0, *(LPDIRECT3DTEXTURE9*)texture );
				g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, index, 2*length );
				index += length*6;
			}

			howmuchtodraw -= length;
			if (!howmuchtodraw) break;

			texture = (DWORD*)cur;
			cur+=4;
			if (cur == chunkend) {
				FUCK();
				DWORD next = (DWORD)memget();
				*(DWORD*)cur = next;
				cur = (LPBYTE)next;
				chunkend = (LPBYTE)((intptr_t)cur + 0xFFC);
			}
			length = *(DWORD*)cur; //WHY LENGTH IS 0 HERE?
			//because you bypassed g_thumb, you idiot
			//you are at the end of the universe
			//but, why howmuchtodraw is 8? It should be 0.
			//also, this should be terminated a bit earlier, i'm afraid of going beyond available memory.
			cur+=4;
			if (cur == chunkend) {
				FUCK();
				DWORD next = (DWORD)memget();
				*(DWORD*)cur = next;
				cur = (LPBYTE)next;
				chunkend = (LPBYTE)((intptr_t)cur + 0xFFC);
			}

			
		}
	}



}


void RenderIndex() {
	RenderThumb();
	RenderText();
}




VOID RenderBig() {

	struct gallery* gallery = g_gallery;

	DWORD** big_cursor = gallery->folder_texture_pointers_start;

	DWORD* img;
	DWORD* imgend;



	int howmuchtodraw = gallery->files_loaded - gallery->images_skipped;
	if (howmuchtodraw > 3) howmuchtodraw = 3;
	if (!howmuchtodraw) return;

	float start_im_x = (float)-gallery->view.pos_x, start_im_y = (float)-gallery->view.pos_y;

	//int vertices_size = texture_w_tiles * texture_h_tiles * 4 * sizeof(CUSTOMVERTEX); //LATER
	int vertices_size = 128 * 4 * sizeof(CUSTOMVERTEX); //LATER

	VOID* pVertices;
	if( FAILED( g_pVB->Lock( 0, vertices_size, ( void** )&pVertices, D3DLOCK_DISCARD ) ) )
		FUCK();

	float* p = (float*)pVertices;

	img = *big_cursor;
	big_sanitize(img, imgend);

	int first_picture_w = *img;
	big_next_read(img, imgend);

	int first_picture_h = *img;
	big_next_read(img, imgend);

	gallery->view.scale = (float)g_display.display_w / (float)(first_picture_w);
	if (gallery->view.scale > 1.0f) gallery->view.scale = 1.0f;
	if (gallery->view.need_scale_not) gallery->view.scale = 1.0f;


	int img_i = gallery->images_skipped;
	
	for (int i_images=0; i_images < howmuchtodraw; i_images++) {

		img = *(big_cursor + img_i);
		big_sanitize(img, imgend);
		img_i++;

		int total_w = *img;
		big_next_read(img, imgend);
		int total_h = *img;
		big_next_read(img, imgend);

		int texture_w_tiles = total_w / 512;
		if (total_w & 0x1FF) texture_w_tiles++; //0x1FF is 512-1
		int texture_h_tiles = total_h / 512;
		if (total_h & 0x1FF) texture_h_tiles++; //0x1FF is 512-1

		/*img += texture_w_tiles*texture_h_tiles;*/

		int texture_h = total_h / 512;
		int texture_w = total_w / 512;

		float squaresize = 512.0f * gallery->view.scale;
		float edgeh = (float) (total_h & 0x1FF);
		float edgew = (float) (total_w & 0x1FF);

		float ix, iy, ir, ib;

		iy = start_im_y -0.5f;
		ib = iy + squaresize;
		for (int i_im_h = 0; i_im_h < texture_h; i_im_h++) {
			ix = start_im_x -0.5f;
			//circle almost everything
			for (int i_im_w = 0; i_im_w < texture_w; i_im_w++) {
				ir = ix + squaresize;

				fill(ix, ir,
					iy, ib,
					0.0f, 1.0f,
					0.0f, 1.0f);

				ix = ir;
			}
			
			////cicle right border
			if (edgew) {
				ir = ix + edgew * gallery->view.scale;
				
				fill(ix, ir,
					iy, ib,
					0.0f, edgew / 512.0f,
					0.0f, 1.0f);
			}
			iy = ib;
			ib = iy + squaresize;
		}
		

		////circle bottom border
		if (edgeh) {
			ix = start_im_x -0.5f;
			ib = iy + edgeh * gallery->view.scale;
			for (int i_im_w = 0; i_im_w < texture_w; i_im_w++) {
				ir = ix + squaresize;

				fill(ix, ir,
					iy, ib,
					0.0f, 1.0f,
					0.0f, edgeh / 512.0f);

				ix = ir;
			}
			

			////circle bottom-right courner
			if (edgew) {
				ir = ix + edgew * gallery->view.scale;

				fill(ix, ir,
					iy, ib,
					0.0f, edgew / 512.0f,
					0.0f, edgeh / 512.0f);
			}
		}

		//decide next start_im_x/y

		start_im_x = start_im_x;
		start_im_y = start_im_y + (int)(float)(total_h * gallery->view.scale) + 6;

	}


	//memcpy( pVertices, vertices, vertices_size );
	g_pVB->Unlock();

	//D3DXMATRIXA16 matWorld;
	//D3DXMatrixRotationY( &matWorld, 34.0f );
	//D3DXMatrixTranslation(&matWorld, 1.0f, 1.0f, 1.0f);
	//g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );



	g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof( CUSTOMVERTEX ) );

	img_i = gallery->images_skipped;
	img = *(big_cursor + img_i);
	big_sanitize(img, imgend);
	int index = 0;

	for (int i_images=0; i_images < howmuchtodraw; i_images++) {

		int total_w = *img;
		big_next_read(img, imgend);
		int total_h = *img;
		big_next_read(img, imgend);

		int texture_w_tiles = total_w / 512;
		if (total_w & 0x1FF) texture_w_tiles++; //0x1FF is 512-1
		int texture_h_tiles = total_h / 512;
		if (total_h & 0x1FF) texture_h_tiles++; //0x1FF is 512-1

		int i_end = texture_w_tiles * texture_h_tiles;
		
		for (int i=0; i < i_end; i++) {
			g_pd3dDevice->SetTexture( 0, (LPDIRECT3DTEXTURE9)*img );
			big_next_read(img, imgend);

			g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, index, 2 );
			index+=4;
			img_i++;
		}

	}
}


//-----------------------------------------------------------------------------
// Name: Render()
// Desc: Draws the scene
//-----------------------------------------------------------------------------
VOID Render()
{

    // Clear the backbuffer to a blue (nope, BLACK) color
    g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB( 0, 255, 0 ), 1.0f, 0 );

    // Begin the scene
	g_pd3dDevice->BeginScene();

	g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );

	//if (g_show_index_or_show_gallery) {

	//	RenderBig();

	//} else {

	//	RenderIndex();

	//}

	RenderCurrent();

	



	//g_pd3dDevice->SetStreamSource( 0, g_pVB_text, 0, sizeof( CUSTOMVERTEX ) );
	//g_pd3dDevice->SetTexture( 0, g_texture_text );
	//g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );



	//g_pd3dDevice->SetStreamSource( 0, g_pVB_thumb, 0, sizeof( CUSTOMVERTEX ) );
	//g_pd3dDevice->SetTexture( 0, *(LPDIRECT3DTEXTURE9*)(g_thumb_start+4) );
	//g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );




    // End the scene
    g_pd3dDevice->EndScene();

    // Present the backbuffer contents to the display
    g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}





//-----------------------------------------------------------------------------
// Name: MsgProc()
// Desc: The window's message handler
//-----------------------------------------------------------------------------
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
	

	bool down;

	char* text;

	int is_repeat;
	UINT32 scancode;

    switch( msg )
    {
	case WM_LBUTTONDOWN:
		{
			//g_display.view_gallery = ! g_display.view_gallery;
			//need to do the actual loading somehow as well...
			//ShowGallery(1141564);

			short xPos = GET_X_LPARAM(lParam);
			short yPos = GET_Y_LPARAM(lParam);

			int rownumber = (g_index_view.pos_y + yPos) / g_index_el_height;
			rownumber += g_index_rows_skipped;

			int columnnumber = -1;
			int columnstart = 0;
			for (int i = 0; i< g_index_row_width; i++) {
				
				if (columnstart <= xPos && xPos <= columnstart + g_index_el_width) {
					columnnumber = i;
					break;
				}

				columnstart += g_index_el_width;
			}

			if (columnnumber == -1) return 0;

			int filenum_offset;
			filenum_offset = rownumber*g_index_row_width + columnnumber;
			

			if (g_index->length < filenum_offset) return 0;
			int filenum = *(g_index->filenum_start + filenum_offset);

			//text = int_to_string(filenum);
			//strcpy(g_onscreen_text, text);
			//g_display.need_redraw_not = 0;

			ShowGallery(filenum);

			return 0;
		}

	case WM_RBUTTONDOWN:
		if (g_show_index_or_show_gallery == 0) {
			DestroyWindow(hWnd);
			return 0;
		}

		if (g_show_index_or_show_gallery == 1) {
			ShowIndex();
			return 0;
		}
		
		////this is just disabling of zoom...
		////LATER
		//if (g_show_index_or_show_gallery == 1) {
		//	//LATER
		//	//make it so that,
		//	//if zoomed, stop zoom
		//	//if not zoomed, go to index
		//	//if in index, exit
		//	if (g_current_view->need_scale_not) {
		//		g_current_view->need_scale_not = ! g_current_view->need_scale_not;
		//		g_current_view->pos_y = g_current_view->pos_y / g_current_view->scale;
		//	} else {
		//		g_current_view->need_scale_not = ! g_current_view->need_scale_not;
		//		g_current_view->pos_y = g_current_view->pos_y * g_current_view->scale;
		//		//eh, will figure it out later
		//		//LATER
		//	}
		//	g_display.need_redraw_not = 0;
		//	return 0;
		//}

	case WM_MOUSEWHEEL:
		{
		int zDelta;
		zDelta = GET_WHEEL_DELTA_WPARAM(wParam)/WHEEL_DELTA;
		int pos_y = g_current_view->pos_y;
		int last_pos_y = pos_y;
		

		if (g_show_index_or_show_gallery == 1) {
			pos_y -= zDelta * 100*4;

			struct gallery* gallery = g_gallery;

			if (gallery->images_skipped==0 && pos_y < 0) pos_y = 0;
			if (pos_y != last_pos_y) {
				//LATER: decide if images_skipped needs to be changed.
				
				//if (g_show_index_or_show_gallery == 1) {
					//gallery
					
					DWORD** big_cursor = gallery->folder_texture_pointers_start;
					DWORD* img;
					DWORD* imgend;

recheck:
					//decide if currently visible image is no longer visible
					if (pos_y > last_pos_y && gallery->images_skipped!=gallery->files_loaded) { //scrolled down
						img = *(big_cursor + gallery->images_skipped);
						big_sanitize(img, imgend);
						int image_w = *img;
						big_next_read(img, imgend);
						int image_h = *img;
						//big_next(img, imgend);
						float scaled_h = image_h * gallery->view.scale;
						if ((- pos_y) + scaled_h < 0) {
							gallery->images_skipped++;
							pos_y -= scaled_h + 6;
							//goto recheck;
						}
					}
					//decide if recently invisible image became visible
					else if (pos_y < last_pos_y && gallery->images_skipped!=0) { //scrolled up
						img = *(big_cursor + gallery->images_skipped-1);
						int image_w = *img++;
						int image_h = *img++;
						float scaled_h = image_h * gallery->view.scale;
						//if ((- pos_y) + scaled_h > 0) {
						if ((- pos_y) > 0) {
							gallery->images_skipped--;
							pos_y += scaled_h + 6;
							//goto recheck;
						}
					}
				//}
				g_current_view->pos_y = pos_y;
				g_display.need_redraw_not = 0;
			}

		} else { //if (g_show_index_or_show_gallery == 1) {
			//index

			pos_y -= zDelta * 100;

			if (g_index_rows_skipped==0 && pos_y < 0) pos_y = 0;
			if (pos_y > last_pos_y) { //scrolled down
				if ((- pos_y) + g_index_el_height < 0) {
					g_index_rows_skipped++;
					pos_y -= g_index_el_height;
				}
			} else if (pos_y < last_pos_y) { //scrolled up
				if ((- pos_y) > 0) {
					g_index_rows_skipped--;
					pos_y += g_index_el_height;
				}
			}
			g_current_view->pos_y = pos_y;
			g_display.need_redraw_not = 0;
		}

		return 0;
		}

	case WM_KEYDOWN:
	case WM_SYSKEYDOWN:
		down = true;
	//case WM_KEYUP:
	//case WM_SYSKEYUP:
		//is_repeat = lParam & (1 << 26);
		//is_keyup  = lParam & (1 << 30);
		scancode = ((lParam >> 16) & 0x1ff);
		text = int_to_hexstring(scancode);
		strcpy(g_onscreen_text, text);
		g_display.need_redraw_not = 0;

		if (wParam == VK_ESCAPE || wParam == 'Q' || wParam == VK_NUMPAD0) {
			/* ExitProcess(0); */
			DestroyWindow(hWnd);
		}
		if (wParam == VK_UP || wParam == 'I') {
			g_current_view->pos_y -= 100;
			g_display.need_redraw_not = 0;
		}
		if (wParam == VK_DOWN || wParam == 'K') {
			g_current_view->pos_y += 100;
			g_display.need_redraw_not = 0;
		}

		if (wParam == VK_LEFT || wParam == 'J') {
			g_current_view->pos_x -= 100;
			g_display.need_redraw_not = 0;
		}
		if (wParam == VK_RIGHT || wParam == 'L') {
			g_current_view->pos_x += 100;
			g_display.need_redraw_not = 0;
		}
		return 0;


	case WM_CLOSE:
		//you may just comment this out
		DestroyWindow(hWnd);
		//PostQuitMessage(0);
		return 0;

    case WM_DESTROY:
		{
			//int howmuchtowrite;
			g_savestate.index_rows_skipped = g_index_rows_skipped;
			if (!g_gallery) {
				g_savestate.gallery_filenum = 0;
				//howmuchtowrite = 4*2;
			} else {
				g_savestate.gallery_filenum = g_gallery->filenum;
				g_savestate.gallery_images_skipped = g_gallery->images_skipped;
				g_savestate.gallery_pos_y = g_gallery->view.pos_y;
				//howmuchtowrite = 4*2 + 4*2;
			}

			//and now save savestate

			FILE* file = fopen("savestat.bin", "wb");
			//LATER, don't like this global path...
			//actually done, probably
			//C:\\_src\\DirectXSamples\\ex_tut2_ShowJPG\\
			//let's... make it so the viewer_debug.exe and viewer_release.exe are in the same folder
			fwrite(&g_savestate, sizeof(char), 4*2+4*2, file);
			fclose(file);


			Cleanup();
			PostQuitMessage( 0 );
			return 0;
		}
    }

    return DefWindowProc( hWnd, msg, wParam, lParam );
}




INT WINAPI wWinMain( HINSTANCE hInst, HINSTANCE, LPWSTR, INT )
{
	//g_index_view.pos_y = 80;
	//g_index_rows_skipped = 14;

	g_index_rows_skipped = 24;


	//FILE* file = fopen("savestat.bin", "rb");

	//fread(&g_savestate, sizeof(char), 4*2+4*2, file);

	//g_index_rows_skipped = g_savestate.index_rows_skipped;

	//and do the rest later
	//LATER: uncomment it once the "loading out of order" will actually work!



	//_ReadFiles();

	//wchar_t filename_orig[] = L"C:\\shared\\f\\exhentai\\exhentai-micro\\123412341234.jpg";
	//g_filename = (wchar_t*)malloc(sizeof(filename_orig));
	//memcpy(g_filename, filename_orig, sizeof(filename_orig));

	g_tempzero[12]=0;

	//int_to_wstring(123);
	//wstring_to_int(L"456");

    g_alloc_base = VirtualAlloc(
             NULL,                 // System selects address
             4096*256, // Size of allocation
             MEM_RESERVE,          // Allocate reserved pages
             PAGE_NOACCESS);       // Protection = no access

	g_alloc_next = g_alloc_base;
	g_alloc_free = (DWORD*)memget_noreuse() + 1;
	memget_guard("g_alloc_free");

	//g_alloc_border = (char*) g_alloc_base + 4096*256;

	g_alloc_next100 = memget();


	//DWORD* fencetest = (DWORD*)memget();
	//_TestFenceSend(fencetest);




	//void* test1 = memget();
	//void* test2 = memget();
	//void* test3 = memget();
	//memfree(test3);
	//memfree(test2);
	//memfree(test1);
	//test1 = memget();
	//test2 = memget();
	//test3 = memget();

	//g_filenames_start = (wchar_t*)memget();
	//g_filenames = (wchar_t*)((char*)g_filenames_start + 4);

	//g_filenames_pointers_start = (wchar_t**)memget();
	//g_filenames_pointers = g_filenames_pointers_start;

	//g_folder_texture_pointers_start = (char*)memget();
	//g_folder_texture_pointers = g_folder_texture_pointers_start;


	g_onscreen_text = (char*)memget();
	strcpy(g_onscreen_text, "xxxxxx");

	

	//g_display = (struct display*)malloc(sizeof(struct display));
	//lol, it's not a pointer


    // Register the window class
    WNDCLASSEX wc =
    {
        sizeof( WNDCLASSEX ), CS_CLASSDC, MsgProc, 0L, 0L,
        GetModuleHandle( NULL ), NULL, LoadCursor(NULL, IDC_ARROW), NULL, NULL,
        L"showjpg", NULL
    };
    RegisterClassEx( &wc );

	int g_window_w = GetSystemMetrics(SM_CXSCREEN);
	int g_window_h = GetSystemMetrics(SM_CYSCREEN);

	RECT rc = {0, 0, 0, 0};
	AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, false);

	g_display.display_w = g_window_w + rc.left - rc.right;
	g_display.display_h = g_window_h + rc.top - rc.bottom;

    // Create the application's window
    //HWND hWnd = CreateWindow( L"D3D Tutorial", L"ex_tut2_ShowJPG.sln",
    //                          WS_OVERLAPPEDWINDOW, 0, 0, g_window_w, g_window_h,
    //                          NULL, NULL, wc.hInstance, NULL );

	//winapi borderless window fullscreen
	//https://stackoverflow.com/questions/34462445/fullscreen-vs-borderless-window

    HWND hWnd = CreateWindow( L"showjpg", L"showjpg",
                              WS_POPUP, 0, 0, g_window_w, g_window_h,
                              NULL, NULL, wc.hInstance, NULL );

	//HWND hWnd = CreateWindow( L"showjpg", L"showjpg",
 //                             WS_OVERLAPPED, 0, 0, g_window_w, g_window_h,
 //                             NULL, NULL, wc.hInstance, NULL );

	//ShowWindow(hWnd, SW_SHOW);

    // Initialize Direct3D
    //if( SUCCEEDED( InitD3D( hWnd ) ) )
	if( FAILED( InitD3D( hWnd ) ) )
    {
		FUCK();
	}

    // Create the vertex buffer
    if( FAILED( InitVB() ) )
    {
		FUCK();
	}

    // Show the window
    ShowWindow( hWnd, SW_SHOWDEFAULT );
	//ShowWindow( hWnd, SW_MAXIMIZE );
    UpdateWindow( hWnd );

    // Enter the message loop
    MSG msg;
    ZeroMemory( &msg, sizeof( msg ) );
    while( msg.message != WM_QUIT )
    {
        if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
        {
            //TranslateMessage( &msg );
            DispatchMessage( &msg );
        }
        else
		{
			bool bisy = false;

			if (! g_display.need_redraw_not) {
				g_display.need_redraw_not = true;
				Render();
				bisy = true;
				//_LoadTexturesBigRest(g_gallery);
			}
			if (g_show_index_or_show_gallery == 1) {
				if (g_gallery->files_loaded < g_gallery->files_total && 
					g_gallery->files_loaded - g_gallery->images_skipped < 4) {

					LoadGallery(g_gallery);
					bisy = true;
				}
			} else { //load index thumbs
				//load it by chunks of 128 thumbs.

				int needtoload;
				needtoload = (g_index_rows_skipped+g_index_row_height*2)*g_index_row_width;
				//extra screen, even two
				if (needtoload > g_index->length) needtoload = g_index->length;

				if (needtoload > g_index_thumbloaded_end) {
					LoadIndex(); //MAYBE: same calculations outside and inside a function...
					//could use a return value, maybe...
					bisy = true;
				}
			}
			if (!bisy) {
				Sleep(1);
			}
		}
    }


    //UnregisterClass( L"showjpg", wc.hInstance );
    return 0;
}


//DWORD WINAPI ThreadProc(LPVOID lpParameter) {
//	
//}
