<commit_before>#include <cstdlib>
#include <cstdio>
#include "env.hpp"

#if PLATFORM == PLATFORM_LINUX
#	include <unistd.h>
#endif

namespace qm {

#if PLATFORM == PLATFORM_WINDOWS
bool Env::closeMessage;
bool Env::lbuttondownMessage;
#endif

Env envInit()
{
	const char* title= "QM Test";
	Vec2i reso(800, 800);

	Env env;
	env.cursorPos= Vec2f(0, 0);
	env.lmbDown= false;
	env.dt= 0.0;
	env.winSize= reso;
	env.quitRequested= false;

#if PLATFORM == PLATFORM_LINUX
	env.dpy= XOpenDisplay(NULL);
	if(env.dpy == NULL)
		std::abort();

	Window root= DefaultRootWindow(env.dpy);
	GLint att[]= { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None };
	XVisualInfo* vi= glXChooseVisual(env.dpy, 0, att);

	if(vi == NULL)
		std::abort();

	Colormap cmap;
	cmap= XCreateColormap(env.dpy, root, vi->visual, AllocNone);
	XSetWindowAttributes swa;
	swa.colormap= cmap;
	swa.event_mask= ExposureMask | KeyPressMask | ButtonPressMask | ButtonReleaseMask;
	env.win=
		XCreateWindow(	env.dpy,
						root,
						0, 0, reso.x, reso.y, 0,
						vi->depth,
						InputOutput,
						vi->visual,
						CWColormap | CWEventMask,
						&swa);
	XMapWindow(env.dpy, env.win);
	XStoreName(env.dpy, env.win, title);

	env.ctx= glXCreateContext(env.dpy, vi, NULL, GL_TRUE);
	glXMakeCurrent(env.dpy, env.win, env.ctx);

	clock_gettime(CLOCK_MONOTONIC, &env.ts);

#elif PLATFORM == PLATFORM_WINDOWS
	struct WndProc {
		static LRESULT CALLBACK call(
			HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
		{
			switch (message) {
				case WM_DESTROY:
					PostQuitMessage(0);
				break;
				case WM_CLOSE:
					Env::closeMessage= true;
				break;
				case WM_MOUSEMOVE:
					SetCursor(LoadCursor(NULL, IDC_ARROW));
				break;
				case WM_LBUTTONDOWN:
					Env::lbuttondownMessage= true;
				break;
				default:
					return DefWindowProc(hWnd, message, wParam, lParam);
			}
			return 0;
		}
	};

	WNDCLASS wc= WNDCLASS();
	wc.lpfnWndProc= WndProc::call;
	wc.hInstance= GetModuleHandle(0);
	wc.hbrBackground= (HBRUSH)(COLOR_BACKGROUND);
	wc.lpszClassName= title;
	wc.style = CS_OWNDC;
	if( !RegisterClass(&wc) ) {
			std::printf("RegisterClass failed\n");
			std::abort();
	}
	env.hWnd= CreateWindow(
		wc.lpszClassName,
		title,
		WS_OVERLAPPEDWINDOW|WS_VISIBLE,
		0, 0, reso.x, reso.y, 0, 0, wc.hInstance, 0);

	// Create OpenGL context
	PIXELFORMATDESCRIPTOR pfd= {
		sizeof(PIXELFORMATDESCRIPTOR), 1,
		PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
		PFD_TYPE_RGBA,
		32, // Framebuffer
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
		24, // Depth buffer
		8, // Stencil buffer
		0, PFD_MAIN_PLANE, 0, 0, 0, 0
	};

	env.hDC= GetDC(env.hWnd);
	int choose= ChoosePixelFormat(env.hDC, &pfd);
	SetPixelFormat(env.hDC, choose, &pfd);
	env.hGlrc= wglCreateContext(env.hDC);
	wglMakeCurrent(env.hDC, env.hGlrc);

	env.ticks= GetTickCount();

#elif PLATFORM == PLATFORM_SDL
	SDL_Init(SDL_INIT_VIDEO);
	env.win= SDL_CreateWindow(
		title,
		SDL_WINDOWPOS_UNDEFINED,
		SDL_WINDOWPOS_UNDEFINED,
		reso.x,
		reso.y,
		SDL_WINDOW_OPENGL);
	if (!env.win) {
		std::printf("SDL Error: %s\n", SDL_GetError());
		std::abort();
	}

	env.ctx= SDL_GL_CreateContext(env.win);
	env.ticks= SDL_GetTicks();
#endif

	return env;
}

void envQuit(Env& env)
{
#if PLATFORM == PLATFORM_LINUX
	glXMakeCurrent(env.dpy, None, NULL);
	glXDestroyContext(env.dpy, env.ctx);
	XDestroyWindow(env.dpy, env.win);
	XCloseDisplay(env.dpy);
#elif PLATFORM == PLATFORM_WINDOWS
	wglDeleteContext(env.hGlrc);
#elif PLATFORM == PLATFORM_SDL
	SDL_GL_DeleteContext(env.ctx);
	SDL_DestroyWindow(env.win);
	SDL_Quit();
#endif
}

void envUpdate(Env& env)
{
	Vec2f prev_cursor_pos= env.cursorPos;

#if PLATFORM == PLATFORM_LINUX
	usleep(1);
	glXSwapBuffers(env.dpy, env.win);

	while(XPending(env.dpy)) {
		XEvent xev;
        XNextEvent(env.dpy, &xev);
		if(xev.type == KeyPress) {
			int keys_ret;
			KeySym* keysym=
				XGetKeyboardMapping(env.dpy, xev.xkey.keycode, 1, &keys_ret);

			if (*keysym == XK_Escape)
				env.quitRequested= true;

			XFree(keysym);
		}

		if (xev.xbutton.type == ButtonPress)
			env.lmbDown= true;
		else if (xev.xbutton.type == ButtonRelease)
			env.lmbDown= false;
	}

	XWindowAttributes gwa;
	XGetWindowAttributes(env.dpy, env.win, &gwa);
	env.winSize.x= gwa.width;
	env.winSize.y= gwa.height;

	int root_x= 0, root_y= 0;
	Window w;
	int cursor_x, cursor_y;
	unsigned int mask;
	XQueryPointer(	env.dpy, env.win, &w,
					&w, &root_x, &root_y, &cursor_x, &cursor_y,
					&mask);

	env.cursorPos.x= 2.0*cursor_x/gwa.width - 1.0;
	env.cursorPos.y= 1.0 - 2.0*cursor_y/gwa.height;

	long old_us= env.ts.tv_nsec/1000 + env.ts.tv_sec*1000000;
	clock_gettime(CLOCK_MONOTONIC, &env.ts);
	long new_us= env.ts.tv_nsec/1000 + env.ts.tv_sec*1000000;
	env.dt= (new_us - old_us)/1000000.0;

#elif PLATFORM == PLATFORM_WINDOWS
	Sleep(1);
	SwapBuffers(env.hDC);

	env.lbuttondownMessage= false;

	MSG msg;
	while(PeekMessage(&msg, env.hWnd, 0, 0, PM_REMOVE) > 0) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	if (env.lbuttondownMessage)
		env.lmbDown= true;
	// Release can happen outside window
	if ((GetKeyState(VK_LBUTTON) & 0x8000) == 0)
		env.lmbDown= false;

	if (Env::closeMessage)
		env.quitRequested= true;

	RECT rect;
	if(GetClientRect(env.hWnd, &rect)) {
		env.winSize.x= rect.right - rect.left;
		env.winSize.y= rect.bottom - rect.top;
	}
	POINT cursor;
	GetCursorPos(&cursor);
	ScreenToClient(env.hWnd, &cursor);
	env.cursorPos.x= 2.0*cursor.x/(rect.right - rect.left) - 1.0;
	env.cursorPos.y= 1.0 - 2.0*cursor.y/(rect.bottom - rect.top);

	DWORD old_ticks= env.ticks;
	env.ticks= GetTickCount();
	DWORD new_ticks= env.ticks;
	env.dt= (new_ticks - old_ticks)/1000.0;

#elif PLATFORM == PLATFORM_SDL
	SDL_Delay(1);
	SDL_GL_SwapWindow(env.win);

	SDL_Event e;
	while(SDL_PollEvent(&e)) {
		if (e.type == SDL_QUIT)
			env.quitRequested= true;
	}

	int x, y;
	int state= SDL_GetMouseState(&x, &y);

	env.cursorPos.x= 2.0*x/env.winSize.x - 1.0;
	env.cursorPos.y= 1.0 - 2.0*y/env.winSize.y;

	bool was_down= env.lmbDown;
	env.lmbDown= state & SDL_BUTTON(SDL_BUTTON_LEFT);
	if (!was_down && env.lmbDown) {
		env.anchorPos= env.cursorPos;
	}

	unsigned int old_ticks= env.ticks;
	env.ticks= SDL_GetTicks();
	env.dt= (env.ticks - old_ticks)/1000.0;

#endif

	env.cursorDelta= env.cursorPos - prev_cursor_pos;
	if (!env.lmbDown)
		env.anchorPos= env.cursorPos;
}

typedef void (*voidFunc)();
voidFunc queryGlFunc(const char* name)
{
	voidFunc f= NULL;
#if PLATFORM == PLATFORM_LINUX
	f= glXGetProcAddressARB((const GLubyte*)name);
#elif PLATFORM == PLATFORM_WINDOWS
	f= (voidFunc)wglGetProcAddress(name);
#elif PLATFORM == PLATFORM_SDL
	f= (voidFunc)SDL_GL_GetProcAddress(name);
#endif
	if (!f) {
		std::printf("Failed to query gl function: %s\n", name);
		std::abort();
	}
	return f;
}

} // qm
<commit_msg>Changed title text<commit_after>#include <cstdlib>
#include <cstdio>
#include "env.hpp"

#if PLATFORM == PLATFORM_LINUX
#	include <unistd.h>
#endif

namespace qm {

#if PLATFORM == PLATFORM_WINDOWS
bool Env::closeMessage;
bool Env::lbuttondownMessage;
#endif

Env envInit()
{
	const char* title= "Hydrogen visualization";
	Vec2i reso(800, 800);

	Env env;
	env.cursorPos= Vec2f(0, 0);
	env.lmbDown= false;
	env.dt= 0.0;
	env.winSize= reso;
	env.quitRequested= false;

#if PLATFORM == PLATFORM_LINUX
	env.dpy= XOpenDisplay(NULL);
	if(env.dpy == NULL)
		std::abort();

	Window root= DefaultRootWindow(env.dpy);
	GLint att[]= { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None };
	XVisualInfo* vi= glXChooseVisual(env.dpy, 0, att);

	if(vi == NULL)
		std::abort();

	Colormap cmap;
	cmap= XCreateColormap(env.dpy, root, vi->visual, AllocNone);
	XSetWindowAttributes swa;
	swa.colormap= cmap;
	swa.event_mask= ExposureMask | KeyPressMask | ButtonPressMask | ButtonReleaseMask;
	env.win=
		XCreateWindow(	env.dpy,
						root,
						0, 0, reso.x, reso.y, 0,
						vi->depth,
						InputOutput,
						vi->visual,
						CWColormap | CWEventMask,
						&swa);
	XMapWindow(env.dpy, env.win);
	XStoreName(env.dpy, env.win, title);

	env.ctx= glXCreateContext(env.dpy, vi, NULL, GL_TRUE);
	glXMakeCurrent(env.dpy, env.win, env.ctx);

	clock_gettime(CLOCK_MONOTONIC, &env.ts);

#elif PLATFORM == PLATFORM_WINDOWS
	struct WndProc {
		static LRESULT CALLBACK call(
			HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
		{
			switch (message) {
				case WM_DESTROY:
					PostQuitMessage(0);
				break;
				case WM_CLOSE:
					Env::closeMessage= true;
				break;
				case WM_MOUSEMOVE:
					SetCursor(LoadCursor(NULL, IDC_ARROW));
				break;
				case WM_LBUTTONDOWN:
					Env::lbuttondownMessage= true;
				break;
				default:
					return DefWindowProc(hWnd, message, wParam, lParam);
			}
			return 0;
		}
	};

	WNDCLASS wc= WNDCLASS();
	wc.lpfnWndProc= WndProc::call;
	wc.hInstance= GetModuleHandle(0);
	wc.hbrBackground= (HBRUSH)(COLOR_BACKGROUND);
	wc.lpszClassName= title;
	wc.style = CS_OWNDC;
	if( !RegisterClass(&wc) ) {
			std::printf("RegisterClass failed\n");
			std::abort();
	}
	env.hWnd= CreateWindow(
		wc.lpszClassName,
		title,
		WS_OVERLAPPEDWINDOW|WS_VISIBLE,
		0, 0, reso.x, reso.y, 0, 0, wc.hInstance, 0);

	// Create OpenGL context
	PIXELFORMATDESCRIPTOR pfd= {
		sizeof(PIXELFORMATDESCRIPTOR), 1,
		PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
		PFD_TYPE_RGBA,
		32, // Framebuffer
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
		24, // Depth buffer
		8, // Stencil buffer
		0, PFD_MAIN_PLANE, 0, 0, 0, 0
	};

	env.hDC= GetDC(env.hWnd);
	int choose= ChoosePixelFormat(env.hDC, &pfd);
	SetPixelFormat(env.hDC, choose, &pfd);
	env.hGlrc= wglCreateContext(env.hDC);
	wglMakeCurrent(env.hDC, env.hGlrc);

	env.ticks= GetTickCount();

#elif PLATFORM == PLATFORM_SDL
	SDL_Init(SDL_INIT_VIDEO);
	env.win= SDL_CreateWindow(
		title,
		SDL_WINDOWPOS_UNDEFINED,
		SDL_WINDOWPOS_UNDEFINED,
		reso.x,
		reso.y,
		SDL_WINDOW_OPENGL);
	if (!env.win) {
		std::printf("SDL Error: %s\n", SDL_GetError());
		std::abort();
	}

	env.ctx= SDL_GL_CreateContext(env.win);
	env.ticks= SDL_GetTicks();
#endif

	return env;
}

void envQuit(Env& env)
{
#if PLATFORM == PLATFORM_LINUX
	glXMakeCurrent(env.dpy, None, NULL);
	glXDestroyContext(env.dpy, env.ctx);
	XDestroyWindow(env.dpy, env.win);
	XCloseDisplay(env.dpy);
#elif PLATFORM == PLATFORM_WINDOWS
	wglDeleteContext(env.hGlrc);
#elif PLATFORM == PLATFORM_SDL
	SDL_GL_DeleteContext(env.ctx);
	SDL_DestroyWindow(env.win);
	SDL_Quit();
#endif
}

void envUpdate(Env& env)
{
	Vec2f prev_cursor_pos= env.cursorPos;

#if PLATFORM == PLATFORM_LINUX
	usleep(1);
	glXSwapBuffers(env.dpy, env.win);

	while(XPending(env.dpy)) {
		XEvent xev;
        XNextEvent(env.dpy, &xev);
		if(xev.type == KeyPress) {
			int keys_ret;
			KeySym* keysym=
				XGetKeyboardMapping(env.dpy, xev.xkey.keycode, 1, &keys_ret);

			if (*keysym == XK_Escape)
				env.quitRequested= true;

			XFree(keysym);
		}

		if (xev.xbutton.type == ButtonPress)
			env.lmbDown= true;
		else if (xev.xbutton.type == ButtonRelease)
			env.lmbDown= false;
	}

	XWindowAttributes gwa;
	XGetWindowAttributes(env.dpy, env.win, &gwa);
	env.winSize.x= gwa.width;
	env.winSize.y= gwa.height;

	int root_x= 0, root_y= 0;
	Window w;
	int cursor_x, cursor_y;
	unsigned int mask;
	XQueryPointer(	env.dpy, env.win, &w,
					&w, &root_x, &root_y, &cursor_x, &cursor_y,
					&mask);

	env.cursorPos.x= 2.0*cursor_x/gwa.width - 1.0;
	env.cursorPos.y= 1.0 - 2.0*cursor_y/gwa.height;

	long old_us= env.ts.tv_nsec/1000 + env.ts.tv_sec*1000000;
	clock_gettime(CLOCK_MONOTONIC, &env.ts);
	long new_us= env.ts.tv_nsec/1000 + env.ts.tv_sec*1000000;
	env.dt= (new_us - old_us)/1000000.0;

#elif PLATFORM == PLATFORM_WINDOWS
	Sleep(1);
	SwapBuffers(env.hDC);

	env.lbuttondownMessage= false;

	MSG msg;
	while(PeekMessage(&msg, env.hWnd, 0, 0, PM_REMOVE) > 0) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	if (env.lbuttondownMessage)
		env.lmbDown= true;
	// Release can happen outside window
	if ((GetKeyState(VK_LBUTTON) & 0x8000) == 0)
		env.lmbDown= false;

	if (Env::closeMessage)
		env.quitRequested= true;

	RECT rect;
	if(GetClientRect(env.hWnd, &rect)) {
		env.winSize.x= rect.right - rect.left;
		env.winSize.y= rect.bottom - rect.top;
	}
	POINT cursor;
	GetCursorPos(&cursor);
	ScreenToClient(env.hWnd, &cursor);
	env.cursorPos.x= 2.0*cursor.x/(rect.right - rect.left) - 1.0;
	env.cursorPos.y= 1.0 - 2.0*cursor.y/(rect.bottom - rect.top);

	DWORD old_ticks= env.ticks;
	env.ticks= GetTickCount();
	DWORD new_ticks= env.ticks;
	env.dt= (new_ticks - old_ticks)/1000.0;

#elif PLATFORM == PLATFORM_SDL
	SDL_Delay(1);
	SDL_GL_SwapWindow(env.win);

	SDL_Event e;
	while(SDL_PollEvent(&e)) {
		if (e.type == SDL_QUIT)
			env.quitRequested= true;
	}

	int x, y;
	int state= SDL_GetMouseState(&x, &y);

	env.cursorPos.x= 2.0*x/env.winSize.x - 1.0;
	env.cursorPos.y= 1.0 - 2.0*y/env.winSize.y;

	bool was_down= env.lmbDown;
	env.lmbDown= state & SDL_BUTTON(SDL_BUTTON_LEFT);
	if (!was_down && env.lmbDown) {
		env.anchorPos= env.cursorPos;
	}

	unsigned int old_ticks= env.ticks;
	env.ticks= SDL_GetTicks();
	env.dt= (env.ticks - old_ticks)/1000.0;

#endif

	env.cursorDelta= env.cursorPos - prev_cursor_pos;
	if (!env.lmbDown)
		env.anchorPos= env.cursorPos;
}

typedef void (*voidFunc)();
voidFunc queryGlFunc(const char* name)
{
	voidFunc f= NULL;
#if PLATFORM == PLATFORM_LINUX
	f= glXGetProcAddressARB((const GLubyte*)name);
#elif PLATFORM == PLATFORM_WINDOWS
	f= (voidFunc)wglGetProcAddress(name);
#elif PLATFORM == PLATFORM_SDL
	f= (voidFunc)SDL_GL_GetProcAddress(name);
#endif
	if (!f) {
		std::printf("Failed to query gl function: %s\n", name);
		std::abort();
	}
	return f;
}

} // qm
<|endoftext|>


<commit_before>#include "gfx.h"

ds_Image * loadImage(std::string path){
	//loads a standard rgb bmp (not bmp custom format)
	//.3ds_Image
	//TODO: write a bmp to this shit convertor
	ds_image img;
	ifstream bmp(path.c_str(), ios::binary|ios::ate);
	int filelength = bmp.tellg();
	unsigned char fBuffer = new char[filelength];
	bmp.seekg(0, ios::beg);
	bmp.read(fBuffer, filelength); //read file bytes into char array

	//4 bytes = w
	//4 bytes = h
	//pixel array (r,g,b)

	//4*8 = 32 bits
	//32 - 8 = 24
	//24 - 8 = 16
	//16 - 8 = 8
	unsigned int imgW = (fBuffer[0] << 24) && (fBuffer[1] << 16) && (fBuffer[2] << 8) && (fBuffer[3]);
	unsigned int imgH = (fBuffer[4] << 24) && (fBuffer[5] << 16) && (fBuffer[6] << 8) && (fBuffer[7]);

	img.w = imgW;
	img.h = imgH;
	img.Buffer = new u8[imgW*imgH*3];
	for (int i = 0; i < imgW*imgH*3; i++){
		img.Buffer[i] = fBuffer[8+i];
	}
}

void ds_GFX::init(){
	gfxInitDefault();
	consoleInit(GFX_BOTTOM, NULL);
}

void ds_GFX::rectFill(ds_Rect rect, ds_Col col){
	for(int x = 0; x < rect.w; x++){
		for(int y = 0; y < rect.h; y++){
			putPixel((ds_Point){x+rect.x,y+rect.y},col);
		}
	}
}

void ds_GFX::beginFrame(gfxScreen_t scr){
	if(scr == GFX_TOP){
		top = true;

		w = 400;
		h = 240;
	}else{
		top = false;

		w = 320;
		h = 240;
	}
	fBuff = gfxGetFramebuffer(scr, GFX_LEFT, NULL/*W*/, NULL/*H*/);
}

void ds_GFX::pushFrame(){
	gfxFlushBuffers();
	gfxSwapBuffers();
	gspWaitForVBlank();
}

void circle(ds_Point p, ds_Col col, int r)
	unsigned int x= r0, y= 0;//local coords
	int cd2= 0;  //current distance squared - radius squared

	int xc = p.x; int yc = p.y;

	if (!r0) return;
	putPixel((ds_Point){xc-r0, yc}, col);
	putPixel((ds_Point){xc+r0, yc}, col);
	putPixel((ds_Point){xc, yc-r0}, col);
	putPixel((ds_Point){xc, yc+r0}, col);

	while (x > y)    //only formulate 1/8 of circle
	{
		cd2-= (--x) - (++y);
		if (cd2 < 0) cd2+=x++;

		putPixel((ds_Point){xc-x, yc-y}, col);//upper left left
		putPixel((ds_Point){xc-y, yc-x}, col);//upper upper left
		putPixel((ds_Point){xc+y, yc-x}, col);//upper upper right
		putPixel((ds_Point){xc+x, yc-y}, col);//upper right right
		putPixel((ds_Point){xc-x, yc+y}, col);//lower left left
		putPixel((ds_Point){xc-y, yc+x}, col);//lower lower left
		putPixel((ds_Point){xc+y, yc+x}, col);//lower lower right
		putPixel((ds_Point){xc+x, yc+y}, col);//lower right right
	}
}

void ds_GFX::putPixel(ds_Point p, ds_Col col){
	if(!(p.y>=h || p.y<=-1 || p.x>=w || p.x<=-1)){
		int pitch =  h * (sizeof(u8) * 3);
		int pos = (p.x * pitch) + ((h-1-p.y) * sizeof(u8) * 3);
		fBuff[ pos ] = col.b;
		fBuff[ pos+1 ] = col.g;
		fBuff[ pos+2 ] = col.r;
	}
}

void ds_GFX::clear(ds_Col col){
	if (((col.r - col.g) - col.b) == -col.r){ //if all equal in astrange way for no paticular reason :)
		memset(fBuff, col.r, h*w*3);
	}else{
		for (int i = 0; i < w*h*3; i+=3){
			fBuff[i] = col.b;
			fBuff[i+1] = col.g;
			fBuff[i+2] = col.r;
		}
	}
}
<commit_msg>Update gfx.cpp<commit_after>#include "gfx.h"

ds_Image * loadImage(std::string path){
	//loads a standard rgb bmp (not bmp custom format)
	//.3ds_Image
	//TODO: write a bmp to this shit convertor
	ds_image img;
	ifstream bmp(path.c_str(), ios::binary|ios::ate);
	int filelength = bmp.tellg();
	unsigned char fBuffer = new char[filelength];
	bmp.seekg(0, ios::beg);
	bmp.read(fBuffer, filelength); //read file bytes into char array

	//4 bytes = w
	//4 bytes = h
	//pixel array (r,g,b)

	//4*8 = 32 bits
	//32 - 8 = 24
	//24 - 8 = 16
	//16 - 8 = 8
	unsigned int imgW = (fBuffer[0] << 24) && (fBuffer[1] << 16) && (fBuffer[2] << 8) && (fBuffer[3]);
	unsigned int imgH = (fBuffer[4] << 24) && (fBuffer[5] << 16) && (fBuffer[6] << 8) && (fBuffer[7]);

	img.w = imgW;
	img.h = imgH;
	img.Buffer = new u8[imgW*imgH*3];
	for (int i = 0; i < imgW*imgH*3; i++){
		img.Buffer[i] = fBuffer[8+i];
	}
}

void ds_GFX::drawImg(ds_Point p, ds_Image img){
	for(int x = 0; x < rect.w; x++){
		for(int y = 0; y < rect.h; y++){
			if(!((p.y+y)>=h || (p.y+y)<=-1 || (p.x+x)>=w || (p.x+x)<=-1)){
				int pitch =  h * (sizeof(u8) * 3);
				int pos = ((p.x+x) * pitch) + ((h-1-(p.y+y)) * sizeof(u8) * 3);
				int imgBuffPos = (x * pitch) + ((h-1-y) * sizeof(u8) * 3);
				fBuff[ pos ] = img.Buffer[imgBuffPos];
				fBuff[ pos+1 ] = img.Buffer[imgBuffPos+1];
				fBuff[ pos+2 ] = img.Buffer[imgBuffPos+2];
			}
		}
	}
}

void ds_GFX::init(){
	gfxInitDefault();
	consoleInit(GFX_BOTTOM, NULL);
}

void ds_GFX::rectFill(ds_Rect rect, ds_Col col){
	for(int x = 0; x < rect.w; x++){
		for(int y = 0; y < rect.h; y++){
			putPixel((ds_Point){x+rect.x,y+rect.y},col);
		}
	}
}

void ds_GFX::beginFrame(gfxScreen_t scr){
	if(scr == GFX_TOP){
		top = true;

		w = 400;
		h = 240;
	}else{
		top = false;

		w = 320;
		h = 240;
	}
	fBuff = gfxGetFramebuffer(scr, GFX_LEFT, NULL/*W*/, NULL/*H*/);
}

void ds_GFX::pushFrame(){
	gfxFlushBuffers();
	gfxSwapBuffers();
	gspWaitForVBlank();
}

void circle(ds_Point p, ds_Col col, int r)
	unsigned int x= r0, y= 0;//local coords
	int cd2= 0;  //current distance squared - radius squared

	int xc = p.x; int yc = p.y;

	if (!r0) return;
	putPixel((ds_Point){xc-r0, yc}, col);
	putPixel((ds_Point){xc+r0, yc}, col);
	putPixel((ds_Point){xc, yc-r0}, col);
	putPixel((ds_Point){xc, yc+r0}, col);

	while (x > y)    //only formulate 1/8 of circle
	{
		cd2-= (--x) - (++y);
		if (cd2 < 0) cd2+=x++;

		putPixel((ds_Point){xc-x, yc-y}, col);//upper left left
		putPixel((ds_Point){xc-y, yc-x}, col);//upper upper left
		putPixel((ds_Point){xc+y, yc-x}, col);//upper upper right
		putPixel((ds_Point){xc+x, yc-y}, col);//upper right right
		putPixel((ds_Point){xc-x, yc+y}, col);//lower left left
		putPixel((ds_Point){xc-y, yc+x}, col);//lower lower left
		putPixel((ds_Point){xc+y, yc+x}, col);//lower lower right
		putPixel((ds_Point){xc+x, yc+y}, col);//lower right right
	}
}

void ds_GFX::putPixel(ds_Point p, ds_Col col){
	if(!(p.y>=h || p.y<=-1 || p.x>=w || p.x<=-1)){
		int pitch =  h * (sizeof(u8) * 3);
		int pos = (p.x * pitch) + ((h-1-p.y) * sizeof(u8) * 3);
		fBuff[ pos ] = col.b;
		fBuff[ pos+1 ] = col.g;
		fBuff[ pos+2 ] = col.r;
	}
}

void ds_GFX::clear(ds_Col col){
	if (((col.r - col.g) - col.b) == -col.r){ //if all equal in astrange way for no paticular reason :)
		memset(fBuff, col.r, h*w*3);
	}else{
		for (int i = 0; i < w*h*3; i+=3){
			fBuff[i] = col.b;
			fBuff[i+1] = col.g;
			fBuff[i+2] = col.r;
		}
	}
}
<|endoftext|>


<commit_before><commit_msg>Added code to close proxy connection when content-length is unspecified.<commit_after><|endoftext|>


<commit_before>#include "interfaces/non_conservative/navier_stokes.h"
#include "pidomus.h"

#include <Teuchos_CommandLineProcessor.hpp>

#include "mpi.h"
#include <iostream>
#include <string>

void print_status(  std::string name,
                    std::string prm_file,
                    int dim,
                    int spacedim,
                    const MPI_Comm &comm);

int main (int argc, char *argv[])
{
  using namespace dealii;
  using namespace deal2lkit;

  Teuchos::CommandLineProcessor My_CLP;
  My_CLP.setDocString(
    ".__________        _______   ______   .___  ___.  __    __       _______. \n"
    "|_   __  __|      |       \\ /  __  \\  |   \\/   | |  |  |  |     /       | \n"
    "  | | | |   ______|  .--.  |  |  |  | |  \\  /  | |  |  |  |    |   (----` \n"
    "  | | | |  |______|  |  |  |  |  |  | |  |\\/|  | |  |  |  |     \\   \\     \n"
    "  | | | |         |  '--'  |  `--'  | |  |  |  | |  `--'  | .----)   |    \n"
    "  |_| |_|         |_______/ \\______/  |__|  |__|  \\______/  |_______/     \n"
    "\n\n"
    " PDE implemented: \n"
    " - Navier Stokes (navier_stokes): \n"
    "   - dim 2 \n"
    "     - default.prm     \n"
    "     - lid_cavity.prm  \n"
    "     - flow_past_a_cylinder.prm \n\n\n"
  );

  std::string pde_name="navier_stokes";
  My_CLP.setOption("pde", &pde_name, "name of the PDE (heat, stokes, dynamic_stokes, or navier_stokes)");

  int spacedim = 2;
  My_CLP.setOption("spacedim", &spacedim, "dimensione of the whole space");

  int dim = 2;
  My_CLP.setOption("dim", &dim, "dimension of the problem");

  std::string prm_file="default.prm";
  My_CLP.setOption("prm", &prm_file, "name of the parameter file");

  My_CLP.recogniseAllOptions(true);
  My_CLP.throwExceptions(false);

  Teuchos::CommandLineProcessor::EParseCommandLineReturn
  parseReturn= My_CLP.parse( argc, argv );
  if ( parseReturn == Teuchos::CommandLineProcessor::PARSE_HELP_PRINTED )
    {
      return 0;
    }
  if ( parseReturn != Teuchos::CommandLineProcessor::PARSE_SUCCESSFUL   )
    {
      return 1; // Error!
    }

  My_CLP.printHelpMessage(argv[0], std::cout);

  Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv,
                                                      numbers::invalid_unsigned_int);

  const MPI_Comm &comm = MPI_COMM_WORLD;
  deallog.depth_console (0);

  std::string parameter_file = "../utilities/prm/"+pde_name+"/"+prm_file;

  if (pde_name == "navier_stokes")
    {

      print_status(   "Navier-Stokes Equation",
                      prm_file,
                      dim,
                      spacedim,
                      comm);

      if (dim==2)
        {
          NavierStokes<2> energy;
          piDoMUS<2,2,3> navier_stokes_equation (energy);
          ParameterAcceptor::initialize(parameter_file, "used_parameters.prm");
          ParameterAcceptor::prm.log_parameters(deallog);
          navier_stokes_equation.run ();
        }
      else
        {
          NavierStokes<3> energy;
          piDoMUS<3,3,4> navier_stokes_equation (energy);
          ParameterAcceptor::initialize(parameter_file, "used_parameters.prm");
          ParameterAcceptor::prm.log_parameters(deallog);
          navier_stokes_equation.run ();
        }
    }
  else
    {
      std::cout << std::endl
                << "============================================================="
                << std::endl
                << " ERROR:"
                << std::endl
                << "  " << pde_name << " needs to be implemented or it is bad name."
                << std::endl
                << "=============================================================";
    }

  std::cout << std::endl;
  return 0;
}

void print_status(  std::string name,
                    std::string prm_file,
                    int dim,
                    int spacedim,
                    const MPI_Comm &comm)
{
  int numprocs = Utilities::MPI::n_mpi_processes(comm);
  int myid = Utilities::MPI::this_mpi_process(comm);

  if (myid == 0)
    {
      std::cout << std::endl
                << "============================================================="
                << std::endl
                << "    Name:   " << name
                // << std::endl
                // << "-------------------------------------------------------------"
                << std::endl
                << " Prm file:  " << prm_file
                << std::endl
                << " spacedim:  " << spacedim
                << std::endl
                << "      dim:  " << dim
                << std::endl
                << "    codim:  " << spacedim-dim
                << std::endl
                << "-------------------------------------------------------------"
                << std::endl;
    }
  std::cout << " Process " << getpid() << " is " << myid
            << "   of " << numprocs << " processes" << std::endl;

  if (myid == 0)
    {
      std::cout << "-------------------------------------------------------------"
                << std::endl;
      system("read -p \" Press [Enter] key to start...\"");
      std::cout << "============================================================="
                <<std::endl<<std::endl;
    }
}
<commit_msg>parallel<commit_after>#include "interfaces/non_conservative/navier_stokes.h"
#include "pidomus.h"

#include "deal.II/base/numbers.h"

#include "Teuchos_CommandLineProcessor.hpp"
#include "Teuchos_GlobalMPISession.hpp"
#include "Teuchos_oblackholestream.hpp"
#include "Teuchos_StandardCatchMacros.hpp"
#include "Teuchos_Version.hpp"

#include "mpi.h"
#include <iostream>
#include <string>

void print_status(  std::string name,
                    std::string prm_file,
                    int dim,
                    int spacedim,
                    const MPI_Comm &comm);

int main (int argc, char *argv[])
{
  using namespace dealii;
  using namespace deal2lkit;

  Teuchos::CommandLineProcessor My_CLP;
  My_CLP.setDocString(
    ".__________        _______   ______   .___  ___.  __    __       _______. \n"
    "|_   __  __|      |       \\ /  __  \\  |   \\/   | |  |  |  |     /       | \n"
    "  | | | |   ______|  .--.  |  |  |  | |  \\  /  | |  |  |  |    |   (----` \n"
    "  | | | |  |______|  |  |  |  |  |  | |  |\\/|  | |  |  |  |     \\   \\     \n"
    "  | | | |         |  '--'  |  `--'  | |  |  |  | |  `--'  | .----)   |    \n"
    "  |_| |_|         |_______/ \\______/  |__|  |__|  \\______/  |_______/     \n\n"
  );

  std::string pde_name="navier_stokes";
  My_CLP.setOption("pde", &pde_name, "name of the PDE (heat, stokes, dynamic_stokes, or navier_stokes)");

  int spacedim = 2;
  My_CLP.setOption("spacedim", &spacedim, "dimensione of the whole space");

  int dim = 2;
  My_CLP.setOption("dim", &dim, "dimension of the problem");

  int n_threads = 0;
  My_CLP.setOption("n_threads", &n_threads, "number of threads");

  std::string prm_file=pde_name+".prm";
  My_CLP.setOption("prm", &prm_file, "name of the parameter file");

  // My_CLP.recogniseAllOptions(true);
  My_CLP.throwExceptions(false);

  Teuchos::CommandLineProcessor::EParseCommandLineReturn
  parseReturn= My_CLP.parse( argc, argv );

  if ( parseReturn == Teuchos::CommandLineProcessor::PARSE_HELP_PRINTED )
    {
      return 0;
    }
  if ( parseReturn != Teuchos::CommandLineProcessor::PARSE_SUCCESSFUL   )
    {
      return 1; // Error!
    }

  Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv,
                                                      n_threads == 0 ? numbers::invalid_unsigned_int  : n_threads);

  const MPI_Comm &comm  = MPI_COMM_WORLD;

  Teuchos::oblackholestream blackhole;
  std::ostream &out = ( Utilities::MPI::this_mpi_process(comm) == 0 ? std::cout : blackhole );

  My_CLP.printHelpMessage(argv[0], out);

  deallog.depth_console (0);

  if (pde_name == "navier_stokes")
    {

      print_status(   "Navier-Stokes Equation",
                      prm_file,
                      dim,
                      spacedim,
                      comm);

      if (dim==2)
        {
          NavierStokes<2> energy;
          piDoMUS<2,2,3> navier_stokes_equation (energy);
          ParameterAcceptor::initialize(prm_file, pde_name+"_used.prm");
          ParameterAcceptor::prm.log_parameters(deallog);
          navier_stokes_equation.run ();
        }
      else
        {
          NavierStokes<3> energy;
          piDoMUS<3,3,4> navier_stokes_equation (energy);
          ParameterAcceptor::initialize(prm_file, pde_name+"_used.prm");
          ParameterAcceptor::prm.log_parameters(deallog);
          navier_stokes_equation.run ();
        }
    }
  else
    {
      out << std::endl
          << "============================================================="
          << std::endl
          << " ERROR:"
          << std::endl
          << "  " << pde_name << " needs to be implemented or it is bad name."
          << std::endl
          << "=============================================================";
    }

  out << std::endl;
  return 0;
}

void print_status(  std::string name,
                    std::string prm_file,
                    int dim,
                    int spacedim,
                    const MPI_Comm &comm)
{
  int numprocs  = Utilities::MPI::n_mpi_processes(comm);
  int myid      = Utilities::MPI::this_mpi_process(comm);

  Teuchos::oblackholestream blackhole;
  std::ostream &out = ( Utilities::MPI::this_mpi_process(comm) == 0 ? std::cout : blackhole );

  if (myid == 0)
    {
      out << std::endl
          << "============================================================="
          << std::endl
          << "    Name:   " << name
          // << std::endl
          // << "-------------------------------------------------------------"
          << std::endl
          << " Prm file:  " << prm_file
          << std::endl
          << " spacedim:  " << spacedim
          << std::endl
          << "      dim:  " << dim
          << std::endl
          << "    codim:  " << spacedim-dim
          << std::endl
          << "-------------------------------------------------------------"
          << std::endl;
    }
  out << " Process " << getpid() << " is " << myid
      << "   of " << numprocs << " processes" << std::endl;

  if (myid == 0)
    {
      out << "-------------------------------------------------------------"
          << std::endl;
      system("read -p \" Press [Enter] key to start...\"");
      out << "============================================================="
          <<std::endl<<std::endl;
    }
}
<|endoftext|>


<commit_before>#include "executors_pool.h"

logxx::Log ExecutorsPool::cLog("ExecutorsPool");

ExecutorsPool::~ExecutorsPool() {
}

void ExecutorsPool::SetTasksPool(TasksPool* p) {
        for (ExecutorPtr &e : executors){
                e->SetTasksPool(p);
        }
}

bool ExecutorsPool::LaunchExecutors() {
        S_LOG("LaunchExecutors");
        auto begin = executors.begin();
        auto end = executors.end();
        for (auto it = begin; it != end; ++it){
                ExecutorPtr& e = *it;
                if (!e->Start()){
                        log(logxx::error) << "Can't launch an executor #" << e->id <<
                                "; interrupting and joining previously launched executors" << logxx::endl;
                        for (auto it2 = begin; it2 != it; ++it2){
                                ExecutorPtr& e = *it2;
                                e->Interrupt();
                                e->Join();
                        }
                        return false;
                }
        }
        log(logxx::notice) << "Launched " << executors.size() << " executors" << logxx::endl;
        return true;
}

void ExecutorsPool::Interrupt(bool andJoin) {
        for (ExecutorPtr &e : executors)
                e->Interrupt();
        if (andJoin){
                for (ExecutorPtr &e : executors)
                        e->Join();
        }
}

void ExecutorsPool::WaitForExecutors() {
        for (ExecutorPtr &e : executors)
                e->Join();
}

<commit_msg>Added cppcheck inline suppression<commit_after>#include "executors_pool.h"

logxx::Log ExecutorsPool::cLog("ExecutorsPool");

ExecutorsPool::~ExecutorsPool() {
}

void ExecutorsPool::SetTasksPool(TasksPool* p) {
        for (ExecutorPtr &e : executors){
                e->SetTasksPool(p);
        }
}

bool ExecutorsPool::LaunchExecutors() {
        S_LOG("LaunchExecutors");
        auto begin = executors.begin();
        auto end = executors.end();
        for (auto it = begin; it != end; ++it){
                ExecutorPtr& e = *it;
                if (!e->Start()){
                        log(logxx::error) << "Can't launch an executor #" << e->id <<
                                "; interrupting and joining previously launched executors" << logxx::endl;
                        for (auto it2 = begin; it2 != it; ++it2){
                                ExecutorPtr& e = *it2;
                                e->Interrupt();
                                e->Join();
                        }
                        return false;
                }
        }
	// cppcheck-suppress constStatement
        log(logxx::notice) << "Launched " << executors.size() << " executors" << logxx::endl;
        return true;
}

void ExecutorsPool::Interrupt(bool andJoin) {
        for (ExecutorPtr &e : executors)
                e->Interrupt();
        if (andJoin){
                for (ExecutorPtr &e : executors)
                        e->Join();
        }
}

void ExecutorsPool::WaitForExecutors() {
        for (ExecutorPtr &e : executors)
                e->Join();
}

<|endoftext|>


<commit_before>#include "SIO/LCIORandomAccessMgr.h"

#include "SIO/LCSIO.h"
#include "SIO/SIORandomAccessHandler.h"
#include "SIO/SIOIndexHandler.h"
#include "SIO/SIOEventHandler.h"
#include "SIO/SIORunHeaderHandler.h"
#include "IOIMPL/LCEventIOImpl.h"
#include "IOIMPL/LCRunHeaderIOImpl.h"
#include "Exceptions.h"

// -- std headers
#include <sstream>
#include <stdio.h>
#include <string.h>

// -- sio headers
#include <sio/api.h>
#include <sio/compression/zlib.h>

namespace SIO {

  void LCIORandomAccessMgr::clear() {
    _runEvtMap->clear() ;
    _list.clear() ;
    _fileRecord = nullptr ;
  }

  //----------------------------------------------------------------------------

  std::shared_ptr<LCIORandomAccess> LCIORandomAccessMgr::createFromEventMap() const {
    auto ra = std::make_shared<LCIORandomAccess>() ;
    ra->_minRunEvt =   _runEvtMap->minRunEvent() ;
    ra->_maxRunEvt =   _runEvtMap->maxRunEvent() ;
    ra->_nRunHeaders = _runEvtMap->getNumberOfRunRecords() ;
    ra->_nEvents =     _runEvtMap->getNumberOfEventRecords() ;
    ra->_recordsAreInOrder =  true ;  //  ???? how is this defined ????
    ra->_indexLocation = 0 ;
    ra->_prevLocation = 0 ;
    ra->_nextLocation = 0 ;
    ra->_firstRecordLocation = 0 ;
    return ra ;
  }

  //----------------------------------------------------------------------------

  void LCIORandomAccessMgr::createFileRecord() {
    if( nullptr == _fileRecord ) {
      _fileRecord = std::make_shared<LCIORandomAccess>() ;
      _fileRecord->_minRunEvt = RunEvent( 2147483647L, 2147483647L ) ; // 2**31-1  - largest 32 bit signed
      _fileRecord->_maxRunEvt = 0 ;
      _fileRecord->_nRunHeaders = 0 ;
      _fileRecord->_nEvents = 0 ;
      _fileRecord->_recordsAreInOrder = 1 ;
      _fileRecord->_indexLocation = 0 ; // defines file record
      _fileRecord->_prevLocation = 9223372036854775807LL ; // 2**63-1  - largest 64 bit signed
      _fileRecord->_nextLocation = 0 ;
      _fileRecord->_firstRecordLocation = 0 ;
    }

    for( auto i = _list.begin() ; i != _list.end() ; ++i ) {
      auto ra = *i ;
    	_fileRecord->_minRunEvt = ( ra->_minRunEvt < _fileRecord->_minRunEvt ?  ra->_minRunEvt : _fileRecord->_minRunEvt  ) ;
    	_fileRecord->_maxRunEvt = ( ra->_maxRunEvt > _fileRecord->_maxRunEvt ?  ra->_maxRunEvt : _fileRecord->_maxRunEvt  ) ;
    	_fileRecord->_nRunHeaders += ra->_nRunHeaders ;
    	_fileRecord->_nEvents += ra->_nEvents ;
    	_fileRecord->_recordsAreInOrder = ( _fileRecord->_recordsAreInOrder * ra->_recordsAreInOrder  ) ; // should be 0 if any record is 0
    	_fileRecord->_indexLocation = 0 ; // defines file record
    	if( ra->_nextLocation > _fileRecord->_nextLocation ) {
    	  _fileRecord->_nextLocation  =  ra->_nextLocation ;
      }
    	if( 0 < ra->_prevLocation  &&  ra->_prevLocation < _fileRecord->_prevLocation ) {
    	  _fileRecord->_prevLocation  =  ra->_prevLocation ;
      }
    }
  }

  //----------------------------------------------------------------------------

  void  LCIORandomAccessMgr::addLCIORandomAccess( std::shared_ptr<LCIORandomAccess> ra ) {
    _list.push_back( ra );
  }

  //----------------------------------------------------------------------------

  bool LCIORandomAccessMgr::readLCIORandomAccessAt( sio::ifstream& stream , long64 pos) {
    seekStream( stream, pos ) ;
    return readLCIORandomAccess( stream ) ;
  }

  //----------------------------------------------------------------------------

  bool LCIORandomAccessMgr::readLCIORandomAccess( sio::ifstream &stream ) {
    // first extract the record from the stream (header + data)
    sio::record_info recinfo ;
    try {
      sio::api::read_record( stream, recinfo, _rawBuffer ) ;
    }
    catch( sio::exception &e ) {
      return false ;
    }
    // we got a record but it's not an LCIORandomAccess record...
    if( recinfo._name != LCSIO::AccessRecordName ) {
      return false ;
    }
    // setup the rando access block
    sio::block_list blocks {} ;
    auto raBlock = std::make_shared<SIORandomAccessHandler>() ;
    blocks.push_back( raBlock ) ;
    // get a valid buffer span for reading
    auto recordData = _rawBuffer.span( recinfo._header_length, recinfo._data_length ) ;
    // read the record blocks
    sio::api::read_blocks( recordData, blocks ) ;
    // get our random access object and add it to our list
    addLCIORandomAccess( raBlock->randomAccess() ) ;
    return true ;
  }

  //----------------------------------------------------------------------------

  bool LCIORandomAccessMgr::readLCIOIndexAt( sio::ifstream &stream , long64 pos) {
    seekStream( stream, pos ) ;
    return readLCIOIndex( stream ) ;
  }

  //----------------------------------------------------------------------------

  bool LCIORandomAccessMgr::readLCIOIndex( sio::ifstream &stream ) {
    SIO_DEBUG( "LCIORandomAccessMgr::readLCIOIndex: Reading at " << stream.tellg() );
    // first extract the record from the stream (header + data)
    sio::record_info recinfo ;
    try {
      sio::api::read_record( stream, recinfo, _rawBuffer ) ;
    }
    catch( sio::exception &e ) {
      // no way to extract a record !
      return false ;
    }
    // we got a record but it's not an LCIOIndex record...
    if( recinfo._name != LCSIO::IndexRecordName ) {
      return false ;
    }
    // setup the rando access block
    sio::block_list blocks {} ;
    auto indexBlock = std::make_shared<SIOIndexHandler>() ;
    indexBlock->setRunEventMap( _runEvtMap ) ;
    blocks.push_back( indexBlock ) ;
    // get a valid buffer span for reading
    auto recordData = _rawBuffer.span( recinfo._header_length, recinfo._data_length ) ;
    // read the record blocks
    sio::api::read_blocks( recordData, blocks ) ;
    return true ;
  }

  //----------------------------------------------------------------------------

  bool LCIORandomAccessMgr::initAppend( sio::ifstream & stream ) {
    // check if the last record is LCIORandomAccess  (the file record )
    if( ! readLCIORandomAccessAt( stream , -LCSIO::RandomAccessSize ) ) {
      recreateEventMap( stream ) ;
      return false;
    }
    // store the file record separately
    _fileRecord = _list.back() ;
    _list.pop_back()  ;
    // now read first LCIORandomAccess record
    readLCIORandomAccessAt( stream , _fileRecord->_nextLocation ) ; // start of last LCIORandomAccessRecord
    return true ;
  }

  //----------------------------------------------------------------------------

  bool LCIORandomAccessMgr::createEventMap( sio::ifstream & stream ) {
    // check if the last record is LCIORandomAccess ( the file record )
    if( ! readLCIORandomAccessAt( stream , -LCSIO::RandomAccessSize) )  {
      return recreateEventMap( stream ) ;
    }
    // store the file record separately
    _fileRecord = _list.back() ;
    _list.pop_back()  ;

    auto raPos = _fileRecord->_nextLocation ;
    // start of last LCIORandomAccessRecord
    readLCIORandomAccessAt( stream ,  raPos  ) ;
    auto ra = lastLCIORandomAccess() ;
    // and then read all remaining LCIORandomAccess records
    raPos = ra->getPrevLocation() ;
    auto indexPos = ra->getIndexLocation() ;
    readLCIOIndexAt( stream , indexPos ) ;

    while( raPos != 0 ) {
      if( readLCIORandomAccessAt( stream , raPos) ) {
        ra = lastLCIORandomAccess() ;
      	raPos = ra->getPrevLocation() ;
      	auto idxPos = ra->getIndexLocation() ;
      	readLCIOIndexAt( stream , idxPos ) ;
      }
      else {
	       throw IO::IOException( std::string( "[LCIORandomAccessMgr::ReadEventMap()] Could not read previous LCIORandomAccess record" ) ) ;
      }
    }
    seekStream( stream, 0 ) ;// go to start of file
    return true ;
  }

  //----------------------------------------------------------------------------

  bool LCIORandomAccessMgr::recreateEventMap( sio::ifstream & stream ) {

    std::cout << " LCIORandomAccessMgr::getEventMap() recreating event map for direct access (old file)" << std::endl ;
    // read the next record from the stream
    if( not stream.is_open() ) {
      throw IO::IOException( "LCIORandomAccessMgr::recreateEventMap: stream is not open" ) ;
    }
    // go to start of file
    seekStream( stream, 0 ) ;
    std::set<std::string> recordlist = { LCSIO::HeaderRecordName, LCSIO::RunRecordName } ;
    while( true ) {
      sio::record_info recinfo {} ;
      try {
        sio::api::skip_records( stream, [&]( const sio::record_info &ri ){
          return ( recordlist.find(ri._name) == recordlist.end() ) ;
        }) ;
        // we read something valid here. Read the record from the stream
        sio::api::read_record( stream, recinfo, _rawBuffer ) ;
        // Get the record data
        auto recdata = _rawBuffer.span( recinfo._header_length, recinfo._data_length ) ;
        // deal with zlib uncompression
        const bool compressed = sio::api::is_compressed( recinfo._options ) ;
        if( compressed ) {
          sio::zlib_compression compressor ;
          _compressBuffer.resize( recinfo._uncompressed_length ) ;
          compressor.uncompress( recdata, _compressBuffer ) ;
        }
        // get the correct buffer depending of compression settings
        auto databuf = compressed ? _compressBuffer.span() : recdata ;
        // event case
        if( recinfo._name == LCSIO::HeaderRecordName ) {
          auto event = std::make_shared<IOIMPL::LCEventIOImpl>() ;
          // pass a dummy list of read collection with only '__dummy__' inside.
          // We only need the event and run numbers there, no need to settup all collections
          SIOEventHeaderRecord::readBlocks( databuf, event.get(), {"__dummy__"} ) ;
          _runEvtMap->add( RunEvent( event->getRunNumber() , event->getEventNumber() ) , static_cast<long64>(recinfo._file_start) ) ;
        }
        // run case
        else if( recinfo._name == LCSIO::RunRecordName ) {
          auto run = std::make_shared<IOIMPL::LCRunHeaderIOImpl>() ;
          SIORunHeaderRecord::readBlocks( recdata, run.get() ) ;
          _runEvtMap->add( RunEvent( run->getRunNumber() , -1 ) , static_cast<long64>(recinfo._file_start) ) ;
        }
      }
      catch( sio::exception &e ) {
        // reached end of file
        if( e.code() == sio::error_code::eof ) {
          break ;
        }
        SIO_RETHROW( e, e.code(), "Couldn't recreate event map !" ) ;
      }
    } // while
    // go to start of file
    seekStream( stream, 0 ) ;
    return true ;
  }

  //----------------------------------------------------------------------------

  void LCIORandomAccessMgr::writeRandomAccessRecords( sio::ofstream & stream ) {
    // nothing to write ?
    if( _runEvtMap->empty() ) {
      return ;
    }
    if( not stream.is_open() ) {
      throw IO::IOException( "[LCIORandomAccessMgr::writeRandomAccessRecords] stream not opened" ) ;
    }
    sio::block_list blocks {} ;

    // 1) write the first index in the file
    auto indexHandler = std::make_shared<SIOIndexHandler>() ;
    indexHandler->setRunEventMap( _runEvtMap ) ;
    blocks.push_back( indexHandler ) ;
    // write in the buffer first, then the buffer to the file
    auto recinfo = sio::api::write_record( LCSIO::IndexRecordName, _rawBuffer, blocks, 0 ) ;
    sio::api::write_record( stream, _rawBuffer.span(), recinfo ) ;

    // 2) create the LCIORandomAccess object ( linked list of records )
    auto ra = createFromEventMap() ;
    ra->setIndexLocation( recinfo._file_start ) ;
    long64 thisPos = stream.tellp() ;
    ra->setFirstRecordLocation(  thisPos  ) ;
    auto lRa  = lastLCIORandomAccess() ;
    SIO_DEBUG( "LCIORandomAccessMgr::writeRandomAccessRecords: lRa is " << lRa );
    long64 prevPos = (  lRa ? lRa->getFirstRecordLocation() : 0 ) ;
    ra->setPreviousLocation(  prevPos ) ;
    addLCIORandomAccess( ra ) ;

    // 3) Write the random access record
    blocks.clear() ;
    auto raHandler = std::make_shared<SIORandomAccessHandler>() ;
    raHandler->setRandomAccess( lastLCIORandomAccess() ) ;
    blocks.push_back( raHandler ) ;
    // write in the buffer first, then the buffer to the file
    recinfo = sio::api::write_record( LCSIO::AccessRecordName, _rawBuffer, blocks, 0 ) ;
    sio::api::write_record( stream, _rawBuffer.span(), recinfo ) ;

    // 4) Create the file record
    createFileRecord() ;
    if( thisPos > _fileRecord->_nextLocation ) {
      _fileRecord->_nextLocation  =  thisPos ;
    }
    if( _fileRecord->_prevLocation > thisPos ) {
      _fileRecord->_prevLocation  =  thisPos ;
    }

    // 5) Write the file random access record to stream
    raHandler->setRandomAccess( _fileRecord ) ;
    // write in the buffer first, then the buffer to the file
    recinfo = sio::api::write_record( LCSIO::AccessRecordName, _rawBuffer, blocks, 0 ) ;
    sio::api::write_record( stream, _rawBuffer.span(), recinfo ) ;

    SIO_DEBUG( "Random access manager: =====\n" << *this );
  }

  //----------------------------------------------------------------------------

  void LCIORandomAccessMgr::seekStream( sio::ifstream &stream, long64 pos ) {
    if( not stream.is_open() ) {
      throw IO::IOException( "[LCIORandomAccessMgr::seekStream] Stream not open") ;
    }
    if( pos < 0 ) {
      stream.seekg( 0 , std::ios_base::end ) ;
      auto endg = stream.tellg() ;
      if( endg < -pos ) {
        std::stringstream s ;  s << "[LCIORandomAccessMgr::seekStream] Can't seek stream to " << pos ;
        throw IO::IOException( s.str() ) ;
      }
      sio::ifstream::streampos tpos = -pos ;
      // pos is negative, so addition make sense here !
      stream.seekg( endg - tpos , std::ios_base::beg ) ;
    }
    else {
      stream.seekg( pos ) ;
    }
    if( not stream.good() ) {
      std::stringstream s ;  s << "[LCIORandomAccessMgr::seekStream] Can't seek stream to " << pos << ". rdstate is: " << stream.rdstate() ;
      throw IO::IOException( s.str() ) ;
    }
  }

  //----------------------------------------------------------------------------

  std::ostream& operator<<(std::ostream& os, const LCIORandomAccessMgr& ra ) {
    os << " LCIORandomAccessMgr:  ----------------------- " << std::endl   ;
    for( auto i = ra._list.begin() ; i != ra._list.end() ; ++i ) {
      os << **i ;
    }
    os  <<  ra._runEvtMap << std::endl ;
    return os ;
  }
}
<commit_msg>Fixed random access manager streaming operator<commit_after>#include "SIO/LCIORandomAccessMgr.h"

#include "SIO/LCSIO.h"
#include "SIO/SIORandomAccessHandler.h"
#include "SIO/SIOIndexHandler.h"
#include "SIO/SIOEventHandler.h"
#include "SIO/SIORunHeaderHandler.h"
#include "IOIMPL/LCEventIOImpl.h"
#include "IOIMPL/LCRunHeaderIOImpl.h"
#include "Exceptions.h"

// -- std headers
#include <sstream>
#include <stdio.h>
#include <string.h>

// -- sio headers
#include <sio/api.h>
#include <sio/compression/zlib.h>

namespace SIO {

  void LCIORandomAccessMgr::clear() {
    _runEvtMap->clear() ;
    _list.clear() ;
    _fileRecord = nullptr ;
  }

  //----------------------------------------------------------------------------

  std::shared_ptr<LCIORandomAccess> LCIORandomAccessMgr::createFromEventMap() const {
    auto ra = std::make_shared<LCIORandomAccess>() ;
    ra->_minRunEvt =   _runEvtMap->minRunEvent() ;
    ra->_maxRunEvt =   _runEvtMap->maxRunEvent() ;
    ra->_nRunHeaders = _runEvtMap->getNumberOfRunRecords() ;
    ra->_nEvents =     _runEvtMap->getNumberOfEventRecords() ;
    ra->_recordsAreInOrder =  true ;  //  ???? how is this defined ????
    ra->_indexLocation = 0 ;
    ra->_prevLocation = 0 ;
    ra->_nextLocation = 0 ;
    ra->_firstRecordLocation = 0 ;
    return ra ;
  }

  //----------------------------------------------------------------------------

  void LCIORandomAccessMgr::createFileRecord() {
    if( nullptr == _fileRecord ) {
      _fileRecord = std::make_shared<LCIORandomAccess>() ;
      _fileRecord->_minRunEvt = RunEvent( 2147483647L, 2147483647L ) ; // 2**31-1  - largest 32 bit signed
      _fileRecord->_maxRunEvt = 0 ;
      _fileRecord->_nRunHeaders = 0 ;
      _fileRecord->_nEvents = 0 ;
      _fileRecord->_recordsAreInOrder = 1 ;
      _fileRecord->_indexLocation = 0 ; // defines file record
      _fileRecord->_prevLocation = 9223372036854775807LL ; // 2**63-1  - largest 64 bit signed
      _fileRecord->_nextLocation = 0 ;
      _fileRecord->_firstRecordLocation = 0 ;
    }

    for( auto i = _list.begin() ; i != _list.end() ; ++i ) {
      auto ra = *i ;
    	_fileRecord->_minRunEvt = ( ra->_minRunEvt < _fileRecord->_minRunEvt ?  ra->_minRunEvt : _fileRecord->_minRunEvt  ) ;
    	_fileRecord->_maxRunEvt = ( ra->_maxRunEvt > _fileRecord->_maxRunEvt ?  ra->_maxRunEvt : _fileRecord->_maxRunEvt  ) ;
    	_fileRecord->_nRunHeaders += ra->_nRunHeaders ;
    	_fileRecord->_nEvents += ra->_nEvents ;
    	_fileRecord->_recordsAreInOrder = ( _fileRecord->_recordsAreInOrder * ra->_recordsAreInOrder  ) ; // should be 0 if any record is 0
    	_fileRecord->_indexLocation = 0 ; // defines file record
    	if( ra->_nextLocation > _fileRecord->_nextLocation ) {
    	  _fileRecord->_nextLocation  =  ra->_nextLocation ;
      }
    	if( 0 < ra->_prevLocation  &&  ra->_prevLocation < _fileRecord->_prevLocation ) {
    	  _fileRecord->_prevLocation  =  ra->_prevLocation ;
      }
    }
  }

  //----------------------------------------------------------------------------

  void  LCIORandomAccessMgr::addLCIORandomAccess( std::shared_ptr<LCIORandomAccess> ra ) {
    _list.push_back( ra );
  }

  //----------------------------------------------------------------------------

  bool LCIORandomAccessMgr::readLCIORandomAccessAt( sio::ifstream& stream , long64 pos) {
    seekStream( stream, pos ) ;
    return readLCIORandomAccess( stream ) ;
  }

  //----------------------------------------------------------------------------

  bool LCIORandomAccessMgr::readLCIORandomAccess( sio::ifstream &stream ) {
    // first extract the record from the stream (header + data)
    sio::record_info recinfo ;
    try {
      sio::api::read_record( stream, recinfo, _rawBuffer ) ;
    }
    catch( sio::exception &e ) {
      return false ;
    }
    // we got a record but it's not an LCIORandomAccess record...
    if( recinfo._name != LCSIO::AccessRecordName ) {
      return false ;
    }
    // setup the rando access block
    sio::block_list blocks {} ;
    auto raBlock = std::make_shared<SIORandomAccessHandler>() ;
    blocks.push_back( raBlock ) ;
    // get a valid buffer span for reading
    auto recordData = _rawBuffer.span( recinfo._header_length, recinfo._data_length ) ;
    // read the record blocks
    sio::api::read_blocks( recordData, blocks ) ;
    // get our random access object and add it to our list
    addLCIORandomAccess( raBlock->randomAccess() ) ;
    return true ;
  }

  //----------------------------------------------------------------------------

  bool LCIORandomAccessMgr::readLCIOIndexAt( sio::ifstream &stream , long64 pos) {
    seekStream( stream, pos ) ;
    return readLCIOIndex( stream ) ;
  }

  //----------------------------------------------------------------------------

  bool LCIORandomAccessMgr::readLCIOIndex( sio::ifstream &stream ) {
    SIO_DEBUG( "LCIORandomAccessMgr::readLCIOIndex: Reading at " << stream.tellg() );
    // first extract the record from the stream (header + data)
    sio::record_info recinfo ;
    try {
      sio::api::read_record( stream, recinfo, _rawBuffer ) ;
    }
    catch( sio::exception &e ) {
      // no way to extract a record !
      return false ;
    }
    // we got a record but it's not an LCIOIndex record...
    if( recinfo._name != LCSIO::IndexRecordName ) {
      return false ;
    }
    // setup the rando access block
    sio::block_list blocks {} ;
    auto indexBlock = std::make_shared<SIOIndexHandler>() ;
    indexBlock->setRunEventMap( _runEvtMap ) ;
    blocks.push_back( indexBlock ) ;
    // get a valid buffer span for reading
    auto recordData = _rawBuffer.span( recinfo._header_length, recinfo._data_length ) ;
    // read the record blocks
    sio::api::read_blocks( recordData, blocks ) ;
    return true ;
  }

  //----------------------------------------------------------------------------

  bool LCIORandomAccessMgr::initAppend( sio::ifstream & stream ) {
    // check if the last record is LCIORandomAccess  (the file record )
    if( ! readLCIORandomAccessAt( stream , -LCSIO::RandomAccessSize ) ) {
      recreateEventMap( stream ) ;
      return false;
    }
    // store the file record separately
    _fileRecord = _list.back() ;
    _list.pop_back()  ;
    // now read first LCIORandomAccess record
    readLCIORandomAccessAt( stream , _fileRecord->_nextLocation ) ; // start of last LCIORandomAccessRecord
    return true ;
  }

  //----------------------------------------------------------------------------

  bool LCIORandomAccessMgr::createEventMap( sio::ifstream & stream ) {
    // check if the last record is LCIORandomAccess ( the file record )
    if( ! readLCIORandomAccessAt( stream , -LCSIO::RandomAccessSize) )  {
      return recreateEventMap( stream ) ;
    }
    // store the file record separately
    _fileRecord = _list.back() ;
    _list.pop_back()  ;

    auto raPos = _fileRecord->_nextLocation ;
    // start of last LCIORandomAccessRecord
    readLCIORandomAccessAt( stream ,  raPos  ) ;
    auto ra = lastLCIORandomAccess() ;
    // and then read all remaining LCIORandomAccess records
    raPos = ra->getPrevLocation() ;
    auto indexPos = ra->getIndexLocation() ;
    readLCIOIndexAt( stream , indexPos ) ;

    while( raPos != 0 ) {
      if( readLCIORandomAccessAt( stream , raPos) ) {
        ra = lastLCIORandomAccess() ;
      	raPos = ra->getPrevLocation() ;
      	auto idxPos = ra->getIndexLocation() ;
      	readLCIOIndexAt( stream , idxPos ) ;
      }
      else {
	       throw IO::IOException( std::string( "[LCIORandomAccessMgr::ReadEventMap()] Could not read previous LCIORandomAccess record" ) ) ;
      }
    }
    seekStream( stream, 0 ) ;// go to start of file
    return true ;
  }

  //----------------------------------------------------------------------------

  bool LCIORandomAccessMgr::recreateEventMap( sio::ifstream & stream ) {

    std::cout << " LCIORandomAccessMgr::getEventMap() recreating event map for direct access (old file)" << std::endl ;
    // read the next record from the stream
    if( not stream.is_open() ) {
      throw IO::IOException( "LCIORandomAccessMgr::recreateEventMap: stream is not open" ) ;
    }
    // go to start of file
    seekStream( stream, 0 ) ;
    std::set<std::string> recordlist = { LCSIO::HeaderRecordName, LCSIO::RunRecordName } ;
    while( true ) {
      sio::record_info recinfo {} ;
      try {
        sio::api::skip_records( stream, [&]( const sio::record_info &ri ){
          return ( recordlist.find(ri._name) == recordlist.end() ) ;
        }) ;
        // we read something valid here. Read the record from the stream
        sio::api::read_record( stream, recinfo, _rawBuffer ) ;
        // Get the record data
        auto recdata = _rawBuffer.span( recinfo._header_length, recinfo._data_length ) ;
        // deal with zlib uncompression
        const bool compressed = sio::api::is_compressed( recinfo._options ) ;
        if( compressed ) {
          sio::zlib_compression compressor ;
          _compressBuffer.resize( recinfo._uncompressed_length ) ;
          compressor.uncompress( recdata, _compressBuffer ) ;
        }
        // get the correct buffer depending of compression settings
        auto databuf = compressed ? _compressBuffer.span() : recdata ;
        // event case
        if( recinfo._name == LCSIO::HeaderRecordName ) {
          auto event = std::make_shared<IOIMPL::LCEventIOImpl>() ;
          // pass a dummy list of read collection with only '__dummy__' inside.
          // We only need the event and run numbers there, no need to settup all collections
          SIOEventHeaderRecord::readBlocks( databuf, event.get(), {"__dummy__"} ) ;
          _runEvtMap->add( RunEvent( event->getRunNumber() , event->getEventNumber() ) , static_cast<long64>(recinfo._file_start) ) ;
        }
        // run case
        else if( recinfo._name == LCSIO::RunRecordName ) {
          auto run = std::make_shared<IOIMPL::LCRunHeaderIOImpl>() ;
          SIORunHeaderRecord::readBlocks( recdata, run.get() ) ;
          _runEvtMap->add( RunEvent( run->getRunNumber() , -1 ) , static_cast<long64>(recinfo._file_start) ) ;
        }
      }
      catch( sio::exception &e ) {
        // reached end of file
        if( e.code() == sio::error_code::eof ) {
          break ;
        }
        SIO_RETHROW( e, e.code(), "Couldn't recreate event map !" ) ;
      }
    } // while
    // go to start of file
    seekStream( stream, 0 ) ;
    return true ;
  }

  //----------------------------------------------------------------------------

  void LCIORandomAccessMgr::writeRandomAccessRecords( sio::ofstream & stream ) {
    // nothing to write ?
    if( _runEvtMap->empty() ) {
      return ;
    }
    if( not stream.is_open() ) {
      throw IO::IOException( "[LCIORandomAccessMgr::writeRandomAccessRecords] stream not opened" ) ;
    }
    sio::block_list blocks {} ;

    // 1) write the first index in the file
    auto indexHandler = std::make_shared<SIOIndexHandler>() ;
    indexHandler->setRunEventMap( _runEvtMap ) ;
    blocks.push_back( indexHandler ) ;
    // write in the buffer first, then the buffer to the file
    auto recinfo = sio::api::write_record( LCSIO::IndexRecordName, _rawBuffer, blocks, 0 ) ;
    sio::api::write_record( stream, _rawBuffer.span(), recinfo ) ;

    // 2) create the LCIORandomAccess object ( linked list of records )
    auto ra = createFromEventMap() ;
    ra->setIndexLocation( recinfo._file_start ) ;
    long64 thisPos = stream.tellp() ;
    ra->setFirstRecordLocation(  thisPos  ) ;
    auto lRa  = lastLCIORandomAccess() ;
    SIO_DEBUG( "LCIORandomAccessMgr::writeRandomAccessRecords: lRa is " << lRa );
    long64 prevPos = (  lRa ? lRa->getFirstRecordLocation() : 0 ) ;
    ra->setPreviousLocation(  prevPos ) ;
    addLCIORandomAccess( ra ) ;

    // 3) Write the random access record
    blocks.clear() ;
    auto raHandler = std::make_shared<SIORandomAccessHandler>() ;
    raHandler->setRandomAccess( lastLCIORandomAccess() ) ;
    blocks.push_back( raHandler ) ;
    // write in the buffer first, then the buffer to the file
    recinfo = sio::api::write_record( LCSIO::AccessRecordName, _rawBuffer, blocks, 0 ) ;
    sio::api::write_record( stream, _rawBuffer.span(), recinfo ) ;

    // 4) Create the file record
    createFileRecord() ;
    if( thisPos > _fileRecord->_nextLocation ) {
      _fileRecord->_nextLocation  =  thisPos ;
    }
    if( _fileRecord->_prevLocation > thisPos ) {
      _fileRecord->_prevLocation  =  thisPos ;
    }

    // 5) Write the file random access record to stream
    raHandler->setRandomAccess( _fileRecord ) ;
    // write in the buffer first, then the buffer to the file
    recinfo = sio::api::write_record( LCSIO::AccessRecordName, _rawBuffer, blocks, 0 ) ;
    sio::api::write_record( stream, _rawBuffer.span(), recinfo ) ;

    SIO_DEBUG( "Random access manager: =====\n" << *this );
  }

  //----------------------------------------------------------------------------

  void LCIORandomAccessMgr::seekStream( sio::ifstream &stream, long64 pos ) {
    if( not stream.is_open() ) {
      throw IO::IOException( "[LCIORandomAccessMgr::seekStream] Stream not open") ;
    }
    if( pos < 0 ) {
      stream.seekg( 0 , std::ios_base::end ) ;
      auto endg = stream.tellg() ;
      if( endg < -pos ) {
        std::stringstream s ;  s << "[LCIORandomAccessMgr::seekStream] Can't seek stream to " << pos ;
        throw IO::IOException( s.str() ) ;
      }
      sio::ifstream::streampos tpos = -pos ;
      // pos is negative, so addition make sense here !
      stream.seekg( endg - tpos , std::ios_base::beg ) ;
    }
    else {
      stream.seekg( pos ) ;
    }
    if( not stream.good() ) {
      std::stringstream s ;  s << "[LCIORandomAccessMgr::seekStream] Can't seek stream to " << pos << ". rdstate is: " << stream.rdstate() ;
      throw IO::IOException( s.str() ) ;
    }
  }

  //----------------------------------------------------------------------------

  std::ostream& operator<<(std::ostream& os, const LCIORandomAccessMgr& ra ) {
    os << " LCIORandomAccessMgr:  ----------------------- " << std::endl   ;
    for( auto i = ra._list.begin() ; i != ra._list.end() ; ++i ) {
      os << **i ;
    }
    os  <<  *(ra._runEvtMap) << std::endl ;
    return os ;
  }
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtDeclarative module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qmleasefollow_p.h"
#include <qmlmetaproperty.h>
#include <math.h>
#include <QtCore/qdebug.h>
#include <private/qmlanimation_p_p.h>

QT_BEGIN_NAMESPACE

QML_DEFINE_TYPE(Qt,4,6,EaseFollow,QmlEaseFollow);

class QmlEaseFollowPrivate : public QObjectPrivate
{
    Q_DECLARE_PUBLIC(QmlEaseFollow)
public:
    QmlEaseFollowPrivate()
        : source(0), velocity(200), duration(-1), maximumEasingTime(-1),
          reversingMode(QmlEaseFollow::Eased), initialVelocity(0),
          initialValue(0), invert(false), enabled(true), trackVelocity(0), clockOffset(0),
          lastTick(0), clock(this)
    {}

    qreal source;
    qreal velocity;
    qreal duration;
    qreal maximumEasingTime;
    QmlEaseFollow::ReversingMode reversingMode;

    qreal initialVelocity;
    qreal initialValue;
    bool invert;
    bool enabled;

    qreal trackVelocity;

    QmlMetaProperty target;

    int clockOffset;
    int lastTick;
    void tick(int);
    void clockStart();
    void clockStop();
    QTickAnimationProxy<QmlEaseFollowPrivate, &QmlEaseFollowPrivate::tick> clock;

    void restart();

    // Parameters for use in tick()
    qreal a;  // Acceleration
    qreal d;  // Deceleration
    qreal tf; // Total time
    qreal tp; // Time at which peak velocity occurs
    qreal td; // Time at which decelleration begins
    qreal vp; // Velocity at tp
    qreal sp; // Displacement at tp
    qreal sd; // Displacement at td
    qreal vi; // "Normalized" initialvelocity
    bool recalc();
};

bool QmlEaseFollowPrivate::recalc()
{
    qreal s = source - initialValue;
    vi = initialVelocity;

    s = (invert?-1.0:1.0) * s;
    vi = (invert?-1.0:1.0) * vi;

    if (duration > 0 && velocity > 0) {
        tf = s / velocity;
        if (tf > (duration / 1000.)) tf = (duration / 1000.);
    } else if (duration > 0) {
        tf = duration / 1000.;
    } else if (velocity > 0) {
        tf = s / velocity;
    } else {
        return false;
    }

    if (maximumEasingTime == 0) {
        a = 0;
        d = 0;
        tp = 0;
        td = tf;
        vp = velocity;
        sp = 0;
        sd = s;
    } else if (tf > (maximumEasingTime / 1000.)) {

        qreal met = maximumEasingTime / 1000.;
        td = tf - met;

        qreal c1 = td;
        qreal c2 = (tf - td) * vi - tf * velocity;
        qreal c3 = -0.5 * (tf - td) * vi * vi;

        qreal vp1 = (-c2 + sqrt(c2 * c2 - 4 * c1 * c3)) / (2. * c1);
        // qreal vp2 = (-c2 - sqrt(c2 * c2 - 4 * c1 * c3)) / (2. * c1);

        vp = vp1;
        a = vp / met;
        d = a;
        tp = (vp - vi) / a;
        sp = vi * tp + 0.5 * a * tp * tp;
        sd = sp + (td - tp) * vp;
    } else {

        qreal c1 = 0.25 * tf * tf;
        qreal c2 = 0.5 * vi * tf - s;
        qreal c3 = -0.25 * vi * vi;

        qreal a1 = (-c2 + sqrt(c2 * c2 - 4 * c1 * c3)) / (2. * c1);
        //qreal a2 = (-c2 - sqrt(c2 * c2 - 4 * c1 * c3)) / (2. * c1);

        qreal tp1 = 0.5 * tf - 0.5 * vi / a1;
        //qreal tp2 = 0.5 * tf - 0.5 * vi / a2;
        qreal vp1 = a1 * tp1 + vi;
        //qreal vp2 = a2 * tp2 + vi;

        qreal sp1 = 0.5 * a1 * tp1 * tp1 + vi * tp1;
        //qreal sp2 = 0.5 * a2 * tp2 * tp2 + vi * tp2;

        a = a1;
        d = a1;
        tp = tp1;
        td = tp1;
        vp = vp1;
        sp = sp1;
        sd = sp1;
    }

    /*
    qWarning() << "a:" << a << "tf:" << tf << "tp:" << tp << "vp:"
               << vp << "sp:" << sp << "vi:" << vi << "invert:" << invert;
    */
    return true;
}

void QmlEaseFollowPrivate::clockStart()
{
    if (clock.state() == QAbstractAnimation::Running) {
        clockOffset = lastTick;
        return;
    } else {
        clockOffset = 0;
        lastTick = 0;
        clock.start();
    }
}

void QmlEaseFollowPrivate::clockStop()
{
    clockOffset = 0;
    lastTick = 0;
    clock.stop();
}

void QmlEaseFollowPrivate::tick(int t)
{
    lastTick = t;
    t -= clockOffset;

    qreal time_seconds = qreal(t) / 1000.;

    qreal out = 0;
    if (time_seconds < tp) {

        trackVelocity = vi + time_seconds * a;
        trackVelocity = (invert?-1.0:1.0) * trackVelocity;

        qreal value = 0.5 * a * time_seconds * time_seconds + vi * time_seconds;
        value = (invert?-1.0:1.0) * value;
        target.write(initialValue + value);
        out = initialValue + value;
    } else if (time_seconds < td) {

        time_seconds -= tp;
        trackVelocity = (invert?-1.0:1.0) * vp;
        qreal value = sp + time_seconds * vp;
        value = (invert?-1.0:1.0) * value;

        target.write(initialValue + value);

        out = initialValue + value;
    } else if (time_seconds < tf) {

        time_seconds -= td;

        trackVelocity = vp - time_seconds * a;
        trackVelocity = (invert?-1.0:1.0) * trackVelocity;

        qreal value = sd - 0.5 * d * time_seconds * time_seconds + vp * time_seconds;
        value = (invert?-1.0:1.0) * value;

        target.write(initialValue + value);

        out = initialValue + value;
    } else {

        clock.stop();

        trackVelocity = 0;
        target.write(source);
    }

    //qWarning() << out << trackVelocity << t << a;
}

/*!
    \qmlclass EaseFollow QmlEaseFollow
    \brief The EaseFollow element allows a property to smoothly track a value.

    The EaseFollow smoothly animates a property's value to a set target value
    using an ease in/out quad easing curve.  If the target value changes while
    the animation is in progress, the easing curves used to animate to the old
    and the new target values are spliced together to avoid any obvious visual
    glitches.

    The property animation is configured by setting the velocity at which the
    animation should occur, or the duration that the animation should take.
    If both a velocity and a duration are specified, the one that results in
    the quickest animation is chosen for each change in the target value.

    For example, animating from 0 to 800 will take 4 seconds if a velocity
    of 200 is set, will take 8 seconds with a duration of 8000 set, and will
    take 4 seconds with both a velocity of 200 and a duration of 8000 set.
    Animating from 0 to 20000 will take 10 seconds if a velocity of 200 is set,
    will take 8 seconds with a duration of 8000 set, and will take 8 seconds
    with both a velocity of 200 and a duration of 8000 set.

    The follow example shows one rectangle tracking the position of another.
\code
import Qt 4.6

Rectangle {
    width: 800; height: 600; color: "blue"

    Rectangle {
        color: "green"
        width: 60; height: 60;
        x: -5; y: -5;
        x: EaseFollow { source: rect1.x - 5; velocity: 200 }
        y: EaseFollow { source: rect1.y - 5; velocity: 200 }
    }

    Rectangle {
        id: rect1
        color: "red"
        width: 50; height: 50;
    }

    focus: true
    Keys.onRightPressed: rect1.x = rect1.x + 100
    Keys.onLeftPressed: rect1.x = rect1.x - 100
    Keys.onUpPressed: rect1.y = rect1.y - 100
    Keys.onDownPressed: rect1.y = rect1.y + 100
}
\endcode

    \sa SpringFollow
*/

QmlEaseFollow::QmlEaseFollow(QObject *parent)
: QObject(*(new QmlEaseFollowPrivate), parent)
{
}

QmlEaseFollow::~QmlEaseFollow()
{
}

/*!
    \qmlproperty qreal EaseFollow::source
    This property holds the source value which will be tracked.

    Bind to a property in order to track its changes.
*/
qreal QmlEaseFollow::sourceValue() const
{
    Q_D(const QmlEaseFollow);
    return d->source;
}

/*!
    \qmlproperty enumeration EaseFollow::reversingMode

    Sets how the EaseFollow behaves if an animation direction is reversed.

    If reversing mode is \c Eased, the animation will smoothly decelerate, and
    then reverse direction.  If the reversing mode is \c Immediate, the
    animation will immediately begin accelerating in the reverse direction,
    begining with a velocity of 0.  If the reversing mode is \c Sync, the
    property is immediately set to the target value.
*/
QmlEaseFollow::ReversingMode QmlEaseFollow::reversingMode() const
{
    Q_D(const QmlEaseFollow);
    return d->reversingMode;
}

void QmlEaseFollow::setReversingMode(ReversingMode m)
{
    Q_D(QmlEaseFollow);
    if (d->reversingMode == m)
        return;

    d->reversingMode = m;
    emit reversingModeChanged();
}

void QmlEaseFollowPrivate::restart()
{
    if (!enabled || velocity == 0) {
        clockStop();
        return;
    }

    initialValue = target.read().toReal();

    if (source == initialValue) {
        clockStop();
        return;
    }

    bool hasReversed = trackVelocity != 0. &&
                      ((trackVelocity > 0) == ((initialValue - source) > 0));

    if (hasReversed) {
        switch (reversingMode) {
            default:
            case QmlEaseFollow::Eased:
                break;
            case QmlEaseFollow::Sync:
                target.write(source);
                return;
            case QmlEaseFollow::Immediate:
                initialVelocity = 0;
                clockStop();
                break;
        }
    }

    trackVelocity = initialVelocity;

    invert = (source < initialValue);

    if (!recalc()) {
        target.write(source);
        clockStop();
        return;
    }

    clockStart();
}

void QmlEaseFollow::setSourceValue(qreal s)
{
    Q_D(QmlEaseFollow);

    if (d->clock.state() == QAbstractAnimation::Running && d->source == s)
        return;

    d->source = s;
    d->initialVelocity = d->trackVelocity;
    d->restart();

    emit sourceChanged();
}

/*!
    \qmlproperty qreal EaseFollow::duration

    This property holds the animation duration used when tracking the source.

    Setting this to -1 disables the duration value.
*/
qreal QmlEaseFollow::duration() const
{
    Q_D(const QmlEaseFollow);
    return d->duration;
}

void QmlEaseFollow::setDuration(qreal v)
{
    Q_D(QmlEaseFollow);
    if (d->duration == v)
        return;

    d->duration = v;
    d->trackVelocity = 0;

    if (d->clock.state() == QAbstractAnimation::Running)
        d->restart();

    emit durationChanged();
}

qreal QmlEaseFollow::velocity() const
{
    Q_D(const QmlEaseFollow);
    return d->velocity;
}

/*!
    \qmlproperty qreal EaseFollow::velocity

    This property holds the average velocity allowed when tracking the source.

    Setting this to -1 disables the velocity value.
*/
void QmlEaseFollow::setVelocity(qreal v)
{
    Q_D(QmlEaseFollow);
    if (d->velocity == v)
        return;

    d->velocity = v;
    d->trackVelocity = 0;

    if (d->clock.state() == QAbstractAnimation::Running)
        d->restart();

    emit velocityChanged();
}

/*!
    \qmlproperty bool EaseFollow::enabled
    This property holds whether the target will track the source.
*/
bool QmlEaseFollow::enabled() const
{
    Q_D(const QmlEaseFollow);
    return d->enabled;
}

void QmlEaseFollow::setEnabled(bool enabled)
{
    Q_D(QmlEaseFollow);
    if (d->enabled == enabled)
        return;

    d->enabled = enabled;
    if (enabled)
        d->restart();
    else
        d->clockStop();

    emit enabledChanged();
}

void QmlEaseFollow::setTarget(const QmlMetaProperty &t)
{
    Q_D(QmlEaseFollow);
    d->target = t;
}

/*!
\qmlproperty qreal EaseFollow::maximumEasingTime

This property specifies the maximum time an "eases" during the follow should take.
Setting this property causes the velocity to "level out" after at a time.  Setting
a negative value reverts to the normal mode of easing over the entire animation
duration.

The default value is -1.
*/
qreal QmlEaseFollow::maximumEasingTime() const
{
    Q_D(const QmlEaseFollow);
    return d->maximumEasingTime;
}

void QmlEaseFollow::setMaximumEasingTime(qreal v)
{
    Q_D(QmlEaseFollow);
    d->maximumEasingTime = v;

    if (d->clock.state() == QAbstractAnimation::Running)
        d->restart();

    emit maximumEasingTimeChanged();
}

QT_END_NAMESPACE
<commit_msg>Fix jumpy EaseFollow animations<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtDeclarative module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qmleasefollow_p.h"
#include <qmlmetaproperty.h>
#include <math.h>
#include <QtCore/qdebug.h>
#include <private/qmlanimation_p_p.h>

QT_BEGIN_NAMESPACE

QML_DEFINE_TYPE(Qt,4,6,EaseFollow,QmlEaseFollow);

class QmlEaseFollowPrivate : public QObjectPrivate
{
    Q_DECLARE_PUBLIC(QmlEaseFollow)
public:
    QmlEaseFollowPrivate()
        : source(0), velocity(200), duration(-1), maximumEasingTime(-1),
          reversingMode(QmlEaseFollow::Eased), initialVelocity(0),
          initialValue(0), invert(false), enabled(true), trackVelocity(0), clockOffset(0),
          lastTick(0), clock(this)
    {}

    qreal source;
    qreal velocity;
    qreal duration;
    qreal maximumEasingTime;
    QmlEaseFollow::ReversingMode reversingMode;

    qreal initialVelocity;
    qreal initialValue;
    bool invert;
    bool enabled;

    qreal trackVelocity;

    QmlMetaProperty target;

    int clockOffset;
    int lastTick;
    void tick(int);
    void clockStart();
    void clockStop();
    QTickAnimationProxy<QmlEaseFollowPrivate, &QmlEaseFollowPrivate::tick> clock;

    void restart();

    // Parameters for use in tick()
    qreal a;  // Acceleration
    qreal d;  // Deceleration
    qreal tf; // Total time
    qreal tp; // Time at which peak velocity occurs
    qreal td; // Time at which decelleration begins
    qreal vp; // Velocity at tp
    qreal sp; // Displacement at tp
    qreal sd; // Displacement at td
    qreal vi; // "Normalized" initialvelocity
    bool recalc();
};

bool QmlEaseFollowPrivate::recalc()
{
    qreal s = source - initialValue;
    vi = initialVelocity;

    s = (invert?-1.0:1.0) * s;
    vi = (invert?-1.0:1.0) * vi;

    if (duration > 0 && velocity > 0) {
        tf = s / velocity;
        if (tf > (duration / 1000.)) tf = (duration / 1000.);
    } else if (duration > 0) {
        tf = duration / 1000.;
    } else if (velocity > 0) {
        tf = s / velocity;
    } else {
        return false;
    }

    if (maximumEasingTime == 0) {
        a = 0;
        d = 0;
        tp = 0;
        td = tf;
        vp = velocity;
        sp = 0;
        sd = s;
    } else if (maximumEasingTime != -1 && tf > (maximumEasingTime / 1000.)) {

        qreal met = maximumEasingTime / 1000.;
        td = tf - met;

        qreal c1 = td;
        qreal c2 = (tf - td) * vi - tf * velocity;
        qreal c3 = -0.5 * (tf - td) * vi * vi;

        qreal vp1 = (-c2 + sqrt(c2 * c2 - 4 * c1 * c3)) / (2. * c1);
        // qreal vp2 = (-c2 - sqrt(c2 * c2 - 4 * c1 * c3)) / (2. * c1);

        vp = vp1;
        a = vp / met;
        d = a;
        tp = (vp - vi) / a;
        sp = vi * tp + 0.5 * a * tp * tp;
        sd = sp + (td - tp) * vp;
    } else {

        qreal c1 = 0.25 * tf * tf;
        qreal c2 = 0.5 * vi * tf - s;
        qreal c3 = -0.25 * vi * vi;

        qreal a1 = (-c2 + sqrt(c2 * c2 - 4 * c1 * c3)) / (2. * c1);
        //qreal a2 = (-c2 - sqrt(c2 * c2 - 4 * c1 * c3)) / (2. * c1);

        qreal tp1 = 0.5 * tf - 0.5 * vi / a1;
        //qreal tp2 = 0.5 * tf - 0.5 * vi / a2;
        qreal vp1 = a1 * tp1 + vi;
        //qreal vp2 = a2 * tp2 + vi;

        qreal sp1 = 0.5 * a1 * tp1 * tp1 + vi * tp1;
        //qreal sp2 = 0.5 * a2 * tp2 * tp2 + vi * tp2;

        a = a1;
        d = a1;
        tp = tp1;
        td = tp1;
        vp = vp1;
        sp = sp1;
        sd = sp1;
    }

    /*
    qWarning() << "a:" << a << "tf:" << tf << "tp:" << tp << "vp:"
               << vp << "sp:" << sp << "vi:" << vi << "invert:" << invert;
    */
    return true;
}

void QmlEaseFollowPrivate::clockStart()
{
    if (clock.state() == QAbstractAnimation::Running) {
        clockOffset = lastTick;
        return;
    } else {
        clockOffset = 0;
        lastTick = 0;
        clock.start();
    }
}

void QmlEaseFollowPrivate::clockStop()
{
    clockOffset = 0;
    lastTick = 0;
    clock.stop();
}

void QmlEaseFollowPrivate::tick(int t)
{
    lastTick = t;
    t -= clockOffset;

    qreal time_seconds = qreal(t) / 1000.;

    qreal out = 0;
    if (time_seconds < tp) {

        trackVelocity = vi + time_seconds * a;
        trackVelocity = (invert?-1.0:1.0) * trackVelocity;

        qreal value = 0.5 * a * time_seconds * time_seconds + vi * time_seconds;
        value = (invert?-1.0:1.0) * value;
        target.write(initialValue + value);
        out = initialValue + value;
    } else if (time_seconds < td) {

        time_seconds -= tp;
        trackVelocity = (invert?-1.0:1.0) * vp;
        qreal value = sp + time_seconds * vp;
        value = (invert?-1.0:1.0) * value;

        target.write(initialValue + value);

        out = initialValue + value;
    } else if (time_seconds < tf) {

        time_seconds -= td;

        trackVelocity = vp - time_seconds * a;
        trackVelocity = (invert?-1.0:1.0) * trackVelocity;

        qreal value = sd - 0.5 * d * time_seconds * time_seconds + vp * time_seconds;
        value = (invert?-1.0:1.0) * value;

        target.write(initialValue + value);

        out = initialValue + value;
    } else {

        clock.stop();

        trackVelocity = 0;
        target.write(source);
    }

    //qWarning() << out << trackVelocity << t << a;
}

/*!
    \qmlclass EaseFollow QmlEaseFollow
    \brief The EaseFollow element allows a property to smoothly track a value.

    The EaseFollow smoothly animates a property's value to a set target value
    using an ease in/out quad easing curve.  If the target value changes while
    the animation is in progress, the easing curves used to animate to the old
    and the new target values are spliced together to avoid any obvious visual
    glitches.

    The property animation is configured by setting the velocity at which the
    animation should occur, or the duration that the animation should take.
    If both a velocity and a duration are specified, the one that results in
    the quickest animation is chosen for each change in the target value.

    For example, animating from 0 to 800 will take 4 seconds if a velocity
    of 200 is set, will take 8 seconds with a duration of 8000 set, and will
    take 4 seconds with both a velocity of 200 and a duration of 8000 set.
    Animating from 0 to 20000 will take 10 seconds if a velocity of 200 is set,
    will take 8 seconds with a duration of 8000 set, and will take 8 seconds
    with both a velocity of 200 and a duration of 8000 set.

    The follow example shows one rectangle tracking the position of another.
\code
import Qt 4.6

Rectangle {
    width: 800; height: 600; color: "blue"

    Rectangle {
        color: "green"
        width: 60; height: 60;
        x: -5; y: -5;
        x: EaseFollow { source: rect1.x - 5; velocity: 200 }
        y: EaseFollow { source: rect1.y - 5; velocity: 200 }
    }

    Rectangle {
        id: rect1
        color: "red"
        width: 50; height: 50;
    }

    focus: true
    Keys.onRightPressed: rect1.x = rect1.x + 100
    Keys.onLeftPressed: rect1.x = rect1.x - 100
    Keys.onUpPressed: rect1.y = rect1.y - 100
    Keys.onDownPressed: rect1.y = rect1.y + 100
}
\endcode

    \sa SpringFollow
*/

QmlEaseFollow::QmlEaseFollow(QObject *parent)
: QObject(*(new QmlEaseFollowPrivate), parent)
{
}

QmlEaseFollow::~QmlEaseFollow()
{
}

/*!
    \qmlproperty qreal EaseFollow::source
    This property holds the source value which will be tracked.

    Bind to a property in order to track its changes.
*/
qreal QmlEaseFollow::sourceValue() const
{
    Q_D(const QmlEaseFollow);
    return d->source;
}

/*!
    \qmlproperty enumeration EaseFollow::reversingMode

    Sets how the EaseFollow behaves if an animation direction is reversed.

    If reversing mode is \c Eased, the animation will smoothly decelerate, and
    then reverse direction.  If the reversing mode is \c Immediate, the
    animation will immediately begin accelerating in the reverse direction,
    begining with a velocity of 0.  If the reversing mode is \c Sync, the
    property is immediately set to the target value.
*/
QmlEaseFollow::ReversingMode QmlEaseFollow::reversingMode() const
{
    Q_D(const QmlEaseFollow);
    return d->reversingMode;
}

void QmlEaseFollow::setReversingMode(ReversingMode m)
{
    Q_D(QmlEaseFollow);
    if (d->reversingMode == m)
        return;

    d->reversingMode = m;
    emit reversingModeChanged();
}

void QmlEaseFollowPrivate::restart()
{
    if (!enabled || velocity == 0) {
        clockStop();
        return;
    }

    initialValue = target.read().toReal();

    if (source == initialValue) {
        clockStop();
        return;
    }

    bool hasReversed = trackVelocity != 0. &&
                      ((trackVelocity > 0) == ((initialValue - source) > 0));

    if (hasReversed) {
        switch (reversingMode) {
            default:
            case QmlEaseFollow::Eased:
                break;
            case QmlEaseFollow::Sync:
                target.write(source);
                return;
            case QmlEaseFollow::Immediate:
                initialVelocity = 0;
                clockStop();
                break;
        }
    }

    trackVelocity = initialVelocity;

    invert = (source < initialValue);

    if (!recalc()) {
        target.write(source);
        clockStop();
        return;
    }

    clockStart();
}

void QmlEaseFollow::setSourceValue(qreal s)
{
    Q_D(QmlEaseFollow);

    if (d->clock.state() == QAbstractAnimation::Running && d->source == s)
        return;

    d->source = s;
    d->initialVelocity = d->trackVelocity;
    d->restart();

    emit sourceChanged();
}

/*!
    \qmlproperty qreal EaseFollow::duration

    This property holds the animation duration used when tracking the source.

    Setting this to -1 disables the duration value.
*/
qreal QmlEaseFollow::duration() const
{
    Q_D(const QmlEaseFollow);
    return d->duration;
}

void QmlEaseFollow::setDuration(qreal v)
{
    Q_D(QmlEaseFollow);
    if (d->duration == v)
        return;

    d->duration = v;
    d->trackVelocity = 0;

    if (d->clock.state() == QAbstractAnimation::Running)
        d->restart();

    emit durationChanged();
}

qreal QmlEaseFollow::velocity() const
{
    Q_D(const QmlEaseFollow);
    return d->velocity;
}

/*!
    \qmlproperty qreal EaseFollow::velocity

    This property holds the average velocity allowed when tracking the source.

    Setting this to -1 disables the velocity value.
*/
void QmlEaseFollow::setVelocity(qreal v)
{
    Q_D(QmlEaseFollow);
    if (d->velocity == v)
        return;

    d->velocity = v;
    d->trackVelocity = 0;

    if (d->clock.state() == QAbstractAnimation::Running)
        d->restart();

    emit velocityChanged();
}

/*!
    \qmlproperty bool EaseFollow::enabled
    This property holds whether the target will track the source.
*/
bool QmlEaseFollow::enabled() const
{
    Q_D(const QmlEaseFollow);
    return d->enabled;
}

void QmlEaseFollow::setEnabled(bool enabled)
{
    Q_D(QmlEaseFollow);
    if (d->enabled == enabled)
        return;

    d->enabled = enabled;
    if (enabled)
        d->restart();
    else
        d->clockStop();

    emit enabledChanged();
}

void QmlEaseFollow::setTarget(const QmlMetaProperty &t)
{
    Q_D(QmlEaseFollow);
    d->target = t;
}

/*!
\qmlproperty qreal EaseFollow::maximumEasingTime

This property specifies the maximum time an "eases" during the follow should take.
Setting this property causes the velocity to "level out" after at a time.  Setting
a negative value reverts to the normal mode of easing over the entire animation
duration.

The default value is -1.
*/
qreal QmlEaseFollow::maximumEasingTime() const
{
    Q_D(const QmlEaseFollow);
    return d->maximumEasingTime;
}

void QmlEaseFollow::setMaximumEasingTime(qreal v)
{
    Q_D(QmlEaseFollow);
    d->maximumEasingTime = v;

    if (d->clock.state() == QAbstractAnimation::Running)
        d->restart();

    emit maximumEasingTimeChanged();
}

QT_END_NAMESPACE
<|endoftext|>