<commit_before>#include "UnrealEnginePythonPrivatePCH.h"

#include "Runtime/Engine/Classes/Kismet/KismetSystemLibrary.h"
#include "Runtime/Foliage/Public/FoliageType.h"
#include "Runtime/Foliage/Public/InstancedFoliageActor.h"

PyObject *py_ue_world_exec(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	char *command;
	if (!PyArg_ParseTuple(args, "s:world_exec", &command))
	{
		return NULL;
	}

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	if (world->Exec(world, UTF8_TO_TCHAR(command)))
		Py_RETURN_TRUE;
	Py_RETURN_FALSE;

}

PyObject *py_ue_quit_game(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	// no need to support multiple controllers
	APlayerController *controller = world->GetFirstPlayerController();
	if (!controller)
		return PyErr_Format(PyExc_Exception, "unable to retrieve the first controller");

	UKismetSystemLibrary::QuitGame(world, controller, EQuitPreference::Quit);

	Py_RETURN_NONE;
}

PyObject *py_ue_get_world_type(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	return PyLong_FromUnsignedLong(world->WorldType);
}

PyObject *py_ue_play(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	world->BeginPlay();

	Py_RETURN_NONE;
}

// mainly used for testing
PyObject *py_ue_world_tick(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	float delta_time;
	PyObject *py_increase_fc = nullptr;
	if (!PyArg_ParseTuple(args, "f|O:world_tick", &delta_time, &py_increase_fc))
	{
		return nullptr;
	}

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	world->Tick(LEVELTICK_All, delta_time);

	if (py_increase_fc && PyObject_IsTrue(py_increase_fc))
		GFrameCounter++;

	Py_RETURN_NONE;
}

PyObject *py_ue_all_objects(ue_PyUObject * self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	PyObject *ret = PyList_New(0);

	for (TObjectIterator<UObject> Itr; Itr; ++Itr)
	{
		UObject *u_obj = *Itr;
		if (u_obj->GetWorld() != world)
			continue;
		ue_PyUObject *py_obj = ue_get_python_wrapper(u_obj);
		if (!py_obj)
			continue;
		PyList_Append(ret, (PyObject *)py_obj);
	}
	return ret;
}

PyObject *py_ue_all_actors(ue_PyUObject * self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	PyObject *ret = PyList_New(0);

	for (TActorIterator<AActor> Itr(world); Itr; ++Itr)
	{
		UObject *u_obj = *Itr;
		ue_PyUObject *py_obj = ue_get_python_wrapper(u_obj);
		if (!py_obj)
			continue;
		PyList_Append(ret, (PyObject *)py_obj);

	}

	return ret;
}

PyObject *py_ue_find_object(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	char *name;
	if (!PyArg_ParseTuple(args, "s:find_object", &name))
	{
		return NULL;
	}

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	UObject *u_object = FindObject<UObject>(world->GetOutermost(), UTF8_TO_TCHAR(name));

	if (!u_object)
		return PyErr_Format(PyExc_Exception, "unable to find object %s", name);

	ue_PyUObject *ret = ue_get_python_wrapper(u_object);
	if (!ret)
		return PyErr_Format(PyExc_Exception, "uobject is in invalid state");
	Py_INCREF(ret);
	return (PyObject *)ret;
}

PyObject *py_ue_get_world(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	ue_PyUObject *ret = ue_get_python_wrapper(world);
	if (!ret)
		return PyErr_Format(PyExc_Exception, "PyUObject is in invalid state");
	Py_INCREF(ret);
	return (PyObject *)ret;

}

PyObject *py_ue_get_game_viewport(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	UGameViewportClient *viewport_client = world->GetGameViewport();
	if (!viewport_client)
		return PyErr_Format(PyExc_Exception, "world has no GameViewportClient");

	Py_RETURN_UOBJECT(viewport_client);
}

PyObject *py_ue_has_world(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	if (ue_get_uworld(self))
		Py_RETURN_TRUE;
	Py_RETURN_FALSE;
}

PyObject *py_ue_set_view_target(ue_PyUObject * self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	PyObject *py_obj;
	int controller_id = 0;
	if (!PyArg_ParseTuple(args, "O|i:set_view_target", &py_obj, &controller_id))
	{
		return NULL;
	}

	AActor *actor = ue_py_check_type<AActor>(py_obj);
	if (!actor)
	{
		return PyErr_Format(PyExc_Exception, "argument is not an actor");
	}

	APlayerController *controller = UGameplayStatics::GetPlayerController(world, controller_id);
	if (!controller)
		return PyErr_Format(PyExc_Exception, "unable to retrieve controller %d", controller_id);

	controller->SetViewTarget(actor);

	Py_RETURN_NONE;

}

PyObject *py_ue_get_world_delta_seconds(ue_PyUObject * self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	return Py_BuildValue("f", UGameplayStatics::GetWorldDeltaSeconds(world));
}

PyObject *py_ue_get_levels(ue_PyUObject * self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	PyObject *ret = PyList_New(0);

	for (ULevel *level : world->GetLevels())
	{
		ue_PyUObject *py_obj = ue_get_python_wrapper(level);
		if (!py_obj)
			continue;
		PyList_Append(ret, (PyObject *)py_obj);

	}
	return ret;
}

PyObject *py_ue_get_current_level(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	ULevel *level = world->GetCurrentLevel();
	if (!level)
		Py_RETURN_NONE;

	ue_PyUObject *ret = ue_get_python_wrapper(level);
	if (!ret)
		return PyErr_Format(PyExc_Exception, "PyUObject is in invalid state");
	Py_INCREF(ret);
	return (PyObject *)ret;
}

PyObject *py_ue_set_current_level(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	PyObject *py_level;

	if (!PyArg_ParseTuple(args, "O", &py_level))
		return nullptr;

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	ULevel *level = ue_py_check_type<ULevel>(py_level);
	if (!level)
		return PyErr_Format(PyExc_Exception, "argument is not a ULevel");

	if (world->SetCurrentLevel(level))
		Py_RETURN_TRUE;

	Py_RETURN_FALSE;
}

PyObject *py_ue_get_instanced_foliage_actor_for_current_level(ue_PyUObject *self, PyObject * args)
{
	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	Py_RETURN_UOBJECT(AInstancedFoliageActor::GetInstancedFoliageActorForCurrentLevel(world, true));
}

#if WITH_EDITOR
PyObject *py_ue_add_foliage_asset(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	PyObject *py_uobject;

	if (!PyArg_ParseTuple(args, "O:add_foliage_asset", &py_uobject))
	{
		return nullptr;
	}

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	UObject *u_object = ue_py_check_type<UObject>(py_uobject);
	if (!u_object)
		return PyErr_Format(PyExc_Exception, "argument is not a UObject");

	UFoliageType *foliage_type = nullptr;

	AInstancedFoliageActor *ifa = AInstancedFoliageActor::GetInstancedFoliageActorForCurrentLevel(world, true);
	if (u_object->IsA<UStaticMesh>())
	{
		foliage_type = ifa->GetLocalFoliageTypeForMesh((UStaticMesh *)u_object);
		if (!foliage_type)
		{
			ifa->AddMesh((UStaticMesh *)u_object, &foliage_type);
		}
	}
	else if (u_object->IsA<UFoliageType>())
	{
		ifa->AddFoliageType((UFoliageType *)u_object);
	}

	if (!foliage_type)
		return PyErr_Format(PyExc_Exception, "unable to add foliage asset");

	Py_RETURN_UOBJECT(foliage_type);

}
#endif

<commit_msg>fixed foliage api<commit_after>#include "UnrealEnginePythonPrivatePCH.h"

#include "Runtime/Engine/Classes/Kismet/KismetSystemLibrary.h"
#include "Runtime/Foliage/Public/FoliageType.h"
#include "Runtime/Foliage/Public/InstancedFoliageActor.h"

PyObject *py_ue_world_exec(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	char *command;
	if (!PyArg_ParseTuple(args, "s:world_exec", &command))
	{
		return NULL;
	}

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	if (world->Exec(world, UTF8_TO_TCHAR(command)))
		Py_RETURN_TRUE;
	Py_RETURN_FALSE;

}

PyObject *py_ue_quit_game(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	// no need to support multiple controllers
	APlayerController *controller = world->GetFirstPlayerController();
	if (!controller)
		return PyErr_Format(PyExc_Exception, "unable to retrieve the first controller");

	UKismetSystemLibrary::QuitGame(world, controller, EQuitPreference::Quit);

	Py_RETURN_NONE;
}

PyObject *py_ue_get_world_type(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	return PyLong_FromUnsignedLong(world->WorldType);
}

PyObject *py_ue_play(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	world->BeginPlay();

	Py_RETURN_NONE;
}

// mainly used for testing
PyObject *py_ue_world_tick(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	float delta_time;
	PyObject *py_increase_fc = nullptr;
	if (!PyArg_ParseTuple(args, "f|O:world_tick", &delta_time, &py_increase_fc))
	{
		return nullptr;
	}

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	world->Tick(LEVELTICK_All, delta_time);

	if (py_increase_fc && PyObject_IsTrue(py_increase_fc))
		GFrameCounter++;

	Py_RETURN_NONE;
}

PyObject *py_ue_all_objects(ue_PyUObject * self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	PyObject *ret = PyList_New(0);

	for (TObjectIterator<UObject> Itr; Itr; ++Itr)
	{
		UObject *u_obj = *Itr;
		if (u_obj->GetWorld() != world)
			continue;
		ue_PyUObject *py_obj = ue_get_python_wrapper(u_obj);
		if (!py_obj)
			continue;
		PyList_Append(ret, (PyObject *)py_obj);
	}
	return ret;
}

PyObject *py_ue_all_actors(ue_PyUObject * self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	PyObject *ret = PyList_New(0);

	for (TActorIterator<AActor> Itr(world); Itr; ++Itr)
	{
		UObject *u_obj = *Itr;
		ue_PyUObject *py_obj = ue_get_python_wrapper(u_obj);
		if (!py_obj)
			continue;
		PyList_Append(ret, (PyObject *)py_obj);

	}

	return ret;
}

PyObject *py_ue_find_object(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	char *name;
	if (!PyArg_ParseTuple(args, "s:find_object", &name))
	{
		return NULL;
	}

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	UObject *u_object = FindObject<UObject>(world->GetOutermost(), UTF8_TO_TCHAR(name));

	if (!u_object)
		return PyErr_Format(PyExc_Exception, "unable to find object %s", name);

	ue_PyUObject *ret = ue_get_python_wrapper(u_object);
	if (!ret)
		return PyErr_Format(PyExc_Exception, "uobject is in invalid state");
	Py_INCREF(ret);
	return (PyObject *)ret;
}

PyObject *py_ue_get_world(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	ue_PyUObject *ret = ue_get_python_wrapper(world);
	if (!ret)
		return PyErr_Format(PyExc_Exception, "PyUObject is in invalid state");
	Py_INCREF(ret);
	return (PyObject *)ret;

}

PyObject *py_ue_get_game_viewport(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	UGameViewportClient *viewport_client = world->GetGameViewport();
	if (!viewport_client)
		return PyErr_Format(PyExc_Exception, "world has no GameViewportClient");

	Py_RETURN_UOBJECT(viewport_client);
}

PyObject *py_ue_has_world(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	if (ue_get_uworld(self))
		Py_RETURN_TRUE;
	Py_RETURN_FALSE;
}

PyObject *py_ue_set_view_target(ue_PyUObject * self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	PyObject *py_obj;
	int controller_id = 0;
	if (!PyArg_ParseTuple(args, "O|i:set_view_target", &py_obj, &controller_id))
	{
		return NULL;
	}

	AActor *actor = ue_py_check_type<AActor>(py_obj);
	if (!actor)
	{
		return PyErr_Format(PyExc_Exception, "argument is not an actor");
	}

	APlayerController *controller = UGameplayStatics::GetPlayerController(world, controller_id);
	if (!controller)
		return PyErr_Format(PyExc_Exception, "unable to retrieve controller %d", controller_id);

	controller->SetViewTarget(actor);

	Py_RETURN_NONE;

}

PyObject *py_ue_get_world_delta_seconds(ue_PyUObject * self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	return Py_BuildValue("f", UGameplayStatics::GetWorldDeltaSeconds(world));
}

PyObject *py_ue_get_levels(ue_PyUObject * self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	PyObject *ret = PyList_New(0);

	for (ULevel *level : world->GetLevels())
	{
		ue_PyUObject *py_obj = ue_get_python_wrapper(level);
		if (!py_obj)
			continue;
		PyList_Append(ret, (PyObject *)py_obj);

	}
	return ret;
}

PyObject *py_ue_get_current_level(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	ULevel *level = world->GetCurrentLevel();
	if (!level)
		Py_RETURN_NONE;

	ue_PyUObject *ret = ue_get_python_wrapper(level);
	if (!ret)
		return PyErr_Format(PyExc_Exception, "PyUObject is in invalid state");
	Py_INCREF(ret);
	return (PyObject *)ret;
}

PyObject *py_ue_set_current_level(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	PyObject *py_level;

	if (!PyArg_ParseTuple(args, "O", &py_level))
		return nullptr;

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	ULevel *level = ue_py_check_type<ULevel>(py_level);
	if (!level)
		return PyErr_Format(PyExc_Exception, "argument is not a ULevel");

	if (world->SetCurrentLevel(level))
		Py_RETURN_TRUE;

	Py_RETURN_FALSE;
}

PyObject *py_ue_get_instanced_foliage_actor_for_current_level(ue_PyUObject *self, PyObject * args)
{
	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	Py_RETURN_UOBJECT(AInstancedFoliageActor::GetInstancedFoliageActorForCurrentLevel(world, true));
}

#if WITH_EDITOR
PyObject *py_ue_add_foliage_asset(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	PyObject *py_uobject;

	if (!PyArg_ParseTuple(args, "O:add_foliage_asset", &py_uobject))
	{
		return nullptr;
	}

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	UObject *u_object = ue_py_check_type<UObject>(py_uobject);
	if (!u_object)
		return PyErr_Format(PyExc_Exception, "argument is not a UObject");

	UFoliageType *foliage_type = nullptr;

	AInstancedFoliageActor *ifa = AInstancedFoliageActor::GetInstancedFoliageActorForCurrentLevel(world, true);
	if (u_object->IsA<UStaticMesh>())
	{
		foliage_type = ifa->GetLocalFoliageTypeForMesh((UStaticMesh *)u_object);
		if (!foliage_type)
		{
			ifa->AddMesh((UStaticMesh *)u_object, &foliage_type);
		}
	}
	else if (u_object->IsA<UFoliageType>())
	{
		foliage_type = (UFoliageType *)u_object;
		ifa->AddFoliageType(foliage_type);

	}

	if (!foliage_type)
		return PyErr_Format(PyExc_Exception, "unable to add foliage asset");

	Py_RETURN_UOBJECT(foliage_type);

}
#endif

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2005, Peter Sommerlad and IFS Institute for Software at HSR Rapperswil, Switzerland
 * All rights reserved.
 *
 * This library/application is free software; you can redistribute and/or modify it under the terms of
 * the license that is included with this library/application in the file license.txt.
 */

//--- test modules used --------------------------------------------------------
#include "TestSuite.h"

//--- module under test --------------------------------------------------------
#include "DiffTimer.h"

//--- interface include --------------------------------------------------------
#include "DiffTimerTest.h"

//--- standard modules used ----------------------------------------------------
#include "Dbg.h"
#include "System.h"

//--- c-library modules used ---------------------------------------------------

//---- DiffTimerTest ----------------------------------------------------------------
DiffTimerTest::DiffTimerTest(TString tname) : TestCaseType(tname)
{
}

DiffTimerTest::~DiffTimerTest()
{
}

Test *DiffTimerTest::suite ()
{
	TestSuite *testSuite = new TestSuite;
	ADD_CASE(testSuite, DiffTimerTest, ConstructorTest);
	ADD_CASE(testSuite, DiffTimerTest, ScaleTest);
	ADD_CASE(testSuite, DiffTimerTest, DiffTest);
	ADD_CASE(testSuite, DiffTimerTest, SimulatedDiffTest);
	return testSuite;

}

void DiffTimerTest::ConstructorTest()
{
	StartTrace(DiffTimerTest.ConstructorTest);

	DiffTimer dt;

	assertEqual(1000L, dt.fResolution);
	t_assert(dt.TicksPerSecond() >= 100);

	dt = DiffTimer((DiffTimer::eResolution)100);
	assertEqual(100L, dt.fResolution);
}

void DiffTimerTest::ScaleTest()
{
	StartTrace(DiffTimerTest.ScaleTest);

	DiffTimer dt;
#if defined(__linux__)
	assertEqual(100L, dt.Scale(10, 1000));
#endif

#if defined(__sun)
	assertEqual(10000L, dt.Scale(10 * dt.TicksPerSecond(), DiffTimer::eMilliseconds));
	assertEqual(10L, dt.Scale(10 * 1000000, DiffTimer::eMilliseconds));
#endif

#if defined(WIN32)
	assertEqual(10, dt.Scale(10, 1000));
#endif
}

void DiffTimerTest::DiffTest()
{
	StartTrace(DiffTimerTest.DiffTest);

	DiffTimer::eResolution resolution( DiffTimer::eMilliseconds );
	DiffTimer dt(resolution); // milisecond resolution
	const HRTIME wait = 200L; //one fifth of a second, not only one twentieth
	t_assertm(System::MicroSleep(wait * resolution), "oops, interrupted"); // >= 50 miliseconds
	HRTIME result = dt.Diff() - wait;
	t_assertm( (result < 0 ? result * -1 : result) <= wait / 5 , (const char *)(String("assume (+-20%) accuracy but was ") << result));
	dt = DiffTimer(DiffTimer::eSeconds);
	t_assertm(System::MicroSleep(600 * resolution), "oops, interrupted"); // >= 50 miliseconds
	result = dt.Diff();
	t_assertm(result == 0L, "expected no round to take effect");
	dt = DiffTimer(DiffTimer::eSeconds);
	t_assertm(System::MicroSleep(1100 * resolution), "oops, interrupted"); // >= 50 miliseconds
	result = dt.Diff();
	t_assertm(result == 1L, "expected no round to take effect");
}

void DiffTimerTest::SimulatedDiffTest()
{
	StartTrace(DiffTimerTest.SimulatedDiffTest);

	DiffTimer dt;
	assertEqual(3000, dt.Diff(3000));
}
<commit_msg>changed to using enumerator to specify unit of timing<commit_after>/*
 * Copyright (c) 2005, Peter Sommerlad and IFS Institute for Software at HSR Rapperswil, Switzerland
 * All rights reserved.
 *
 * This library/application is free software; you can redistribute and/or modify it under the terms of
 * the license that is included with this library/application in the file license.txt.
 */

//--- test modules used --------------------------------------------------------
#include "TestSuite.h"

//--- module under test --------------------------------------------------------
#include "DiffTimer.h"

//--- interface include --------------------------------------------------------
#include "DiffTimerTest.h"

//--- standard modules used ----------------------------------------------------
#include "Dbg.h"
#include "System.h"

//--- c-library modules used ---------------------------------------------------

//---- DiffTimerTest ----------------------------------------------------------------
DiffTimerTest::DiffTimerTest(TString tname) : TestCaseType(tname)
{
}

DiffTimerTest::~DiffTimerTest()
{
}

Test *DiffTimerTest::suite ()
{
	TestSuite *testSuite = new TestSuite;
	ADD_CASE(testSuite, DiffTimerTest, ConstructorTest);
	ADD_CASE(testSuite, DiffTimerTest, ScaleTest);
	ADD_CASE(testSuite, DiffTimerTest, DiffTest);
	ADD_CASE(testSuite, DiffTimerTest, SimulatedDiffTest);
	return testSuite;

}

void DiffTimerTest::ConstructorTest()
{
	StartTrace(DiffTimerTest.ConstructorTest);

	DiffTimer dt;

	assertEqual(1000L, dt.fResolution);
	t_assert(dt.TicksPerSecond() >= 100);

	dt = DiffTimer((DiffTimer::eResolution)100);
	assertEqual(100L, dt.fResolution);
}

void DiffTimerTest::ScaleTest()
{
	StartTrace(DiffTimerTest.ScaleTest);

	DiffTimer dt;
#if defined(__linux__)
	assertEqual(100L, dt.Scale(10, DiffTimer::eMilliseconds));
#endif

#if defined(__sun)
	assertEqual(10000L, dt.Scale(10 * dt.TicksPerSecond(), DiffTimer::eMilliseconds));
	assertEqual(10L, dt.Scale(10 * 1000000, DiffTimer::eMilliseconds));
#endif

#if defined(WIN32)
	assertEqual(10, dt.Scale(10, DiffTimer::eMilliseconds));
#endif
}

void DiffTimerTest::DiffTest()
{
	StartTrace(DiffTimerTest.DiffTest);

	DiffTimer::eResolution resolution( DiffTimer::eMilliseconds );
	DiffTimer dt(resolution); // milisecond resolution
	const HRTIME wait = 200L; //one fifth of a second, not only one twentieth
	t_assertm(System::MicroSleep(wait * resolution), "oops, interrupted"); // >= 50 miliseconds
	HRTIME result = dt.Diff() - wait;
	t_assertm( (result < 0 ? result * -1 : result) <= wait / 5 , (const char *)(String("assume (+-20%) accuracy but was ") << result));
	dt = DiffTimer(DiffTimer::eSeconds);
	t_assertm(System::MicroSleep(600 * resolution), "oops, interrupted"); // >= 50 miliseconds
	result = dt.Diff();
	t_assertm(result == 0L, "expected no round to take effect");
	dt = DiffTimer(DiffTimer::eSeconds);
	t_assertm(System::MicroSleep(1100 * resolution), "oops, interrupted"); // >= 50 miliseconds
	result = dt.Diff();
	t_assertm(result == 1L, "expected no round to take effect");
}

void DiffTimerTest::SimulatedDiffTest()
{
	StartTrace(DiffTimerTest.SimulatedDiffTest);

	DiffTimer dt;
	assertEqual(3000, dt.Diff(3000));
}
<|endoftext|>


<commit_before>// Quantum Phase Estimation
// Source: ./examples/qpe.cpp

/*
A program to construct the following quantum phase estimator circuit and
execute simulation on the phase of U = diag(1, e^{2*pi*i*theta}).

|0> ---H----@--------------x----H----@----------@----------------|D--- [q0]
            |              |         |          |
|0> ---H----+----@---------+---------R2----H----+-----@----------|D--- [q1]
            |    |         |                    |     |
|0> ---H----+----+----@----x--------------------R3----R2----H----|D--- [q2]
            |    |    |
|0> ---X----U----U^2--U^4--------------------------------------------- [q3]

 */

#include <cmath>
#include <iostream>
#include <vector>

#include "qpp.h"

int main() {
    using namespace qpp;

    // initial four qubit state
    // qubits 0, 1, 2 are counting qubits, qubit 3 is the ancilla
    std::vector<idx> qubits{0, 0, 0, 0};
    ket psi = mket(qubits);

    cmat U(2, 2); // initialize a unitary operator
    // use T-Gate as example; we expect estimated theta = 1/8.
    double theta = 1 / 8.;
    U << 1, 0, 0, std::exp(2 * pi * 1_i * theta);

    ket result = psi;
    idx n = qubits.size(); // number of qubits

    std::cout << ">> QPE on n = " << n << " qubits. ";
    std::cout << "The sequence of applied gates is:\n";

    result = apply(result, gt.X, {n - 1}); // apply X on the ancilla
    std::cout << "X" << (n - 1) << " ";

    for (idx i = 0; i < n - 1; ++i) {
        // apply Hadamard on counting qubits
        result = apply(result, gt.H, {i});
        std::cout << "H" << i << " ";
    }
    std::cout << '\n';

    // apply controlled unitary operations
    idx repetitions = 1;
    for (idx i = 0; i < n - 1; ++i) {
        for (idx r = 0; r < repetitions; ++r) {
            result = applyCTRL(result, U, {i}, {n - 1});
            std::cout << "CU"
                      << "(" << i << ", " << n - 1 << ") ";
        }
        repetitions *= 2;
        std::cout << '\n';
    }

    // apply inverse quantum Fourier transform to convert state of the counting
    // register
    for (idx i = 0; i < (n - 1) / 2; ++i) {
        std::cout << "SWAP(" << i << ", " << (n - 1) - i - 1 << ")\n";
        result = apply(result, gt.SWAP, {i, (n - 1) - i - 1});
    }

    for (idx j = 0; j < n - 1; ++j) {
        for (idx m = 0; m < j; ++m) {
            cmat Rj(2, 2);
            Rj << 1, 0, 0, std::exp(-1_i * pi / std::pow(2, j - m));
            result = applyCTRL(result, Rj, {m}, {j});
            std::cout << "R" << j << "(" << m << ", " << j << ") ";
        }
        result = apply(result, gt.H, {j});
        std::cout << "H" << j << "\n";
    }
    std::cout << '\n';

    // measure the counting register and readout probabilities
    double decimal = 0.0;
    for (idx i = 0; i < n - 1; ++i) {
        auto measured = measure(result, gt.Z, {i});
        auto res = std::get<RES>(measured);
        auto prob = std::get<PROB>(measured);
        std::cout << ">> Measurement result q" << i << ": " << res << '\n';
        std::cout << ">> Probabilities: ";
        std::cout << disp(prob, ", ") << '\n';
        if (prob[0] < prob[1]) {
            decimal += std::pow(2, i);
        }
    }
    std::cout << '\n';

    // readout phase estimate
    double theta_e = decimal / std::pow(2, n - 1);
    std::cout << ">> Input theta = " << theta << '\n';
    std::cout << ">> Estimated theta = " << theta_e << '\n';
    std::cout << ">> Norm difference: " << std::abs(theta_e - theta) << '\n';
}
<commit_msg>Updated qpe<commit_after>// Quantum Phase Estimation
// Source: ./examples/qpe.cpp

/*
A program to construct the following quantum phase estimator circuit and
execute simulation on the phase of U = diag(1, e^{2*pi*i*theta}).

|0> ---H----@--------------x----H----@----------@----------------|D--- [q0]
            |              |         |          |
|0> ---H----+----@---------+---------R2----H----+-----@----------|D--- [q1]
            |    |         |                    |     |
|0> ---H----+----+----@----x--------------------R3----R2----H----|D--- [q2]
            |    |    |
|0> ---X----U----U^2--U^4--------------------------------------------- [q3]

 */

#include <cmath>
#include <iostream>
#include <vector>

#include "qpp.h"

int main() {
    using namespace qpp;
    // initial four qubit state
    // qubits 0, 1, 2 are counting qubits, qubit 3 is the ancilla
    std::vector<idx> qubits{0, 0, 0, 0};
    ket psi = mket(qubits);

    cmat U(2, 2); // initialize a unitary operator
    // use T-Gate as example; we expect estimated theta = 1/8.
    double theta = 1 / 8.;
    U << 1, 0, 0, std::exp(2 * pi * 1_i * theta);

    ket result = psi;
    idx n = qubits.size(); // number of qubits

    std::cout << ">> QPE on n = " << n << " qubits. ";
    std::cout << "The sequence of applied gates is:\n";

    result = apply(result, gt.X, {n - 1}); // apply X on the ancilla
    std::cout << "X" << (n - 1) << " ";

    for (idx i = 0; i < n - 1; ++i) {
        // apply Hadamard on counting qubits
        result = apply(result, gt.H, {i});
        std::cout << "H" << i << " ";
    }
    std::cout << '\n';

    // apply controlled unitary operations
    idx repetitions = 1;
    for (idx i = 0; i < n - 1; ++i) {
        for (idx r = 0; r < repetitions; ++r) {
            result = applyCTRL(result, U, {i}, {n - 1});
            std::cout << "CU"
                      << "(" << i << ", " << n - 1 << ") ";
        }
        repetitions *= 2;
        std::cout << '\n';
    }

    // apply inverse quantum Fourier transform to convert state of the counting
    // register
    for (idx i = 0; i < (n - 1) / 2; ++i) {
        std::cout << "SWAP(" << i << ", " << (n - 1) - i - 1 << ")\n";
        result = apply(result, gt.SWAP, {i, (n - 1) - i - 1});
    }

    for (idx j = 0; j < n - 1; ++j) {
        for (idx m = 0; m < j; ++m) {
            cmat Rj(2, 2);
            Rj << 1, 0, 0, std::exp(-1_i * pi / std::pow(2, j - m));
            result = applyCTRL(result, Rj, {m}, {j});
            std::cout << "R" << j << "(" << m << ", " << j << ") ";
        }
        result = apply(result, gt.H, {j});
        std::cout << "H" << j << "\n";
    }
    std::cout << '\n';

    // measure the counting register and readout probabilities
    double decimal = 0.0;
    for (idx i = 0; i < n - 1; ++i) {
        auto measured = measure(result, gt.Z, {i});
        auto res = std::get<RES>(measured);
        auto prob = std::get<PROB>(measured);
        std::cout << ">> Measurement result q" << i << ": " << res << '\n';
        std::cout << ">> Probabilities: ";
        std::cout << disp(prob, ", ") << '\n';
        if (prob[0] < prob[1]) {
            decimal += std::pow(2, i);
        }
    }
    std::cout << '\n';

    // readout phase estimate
    double theta_e = decimal / std::pow(2, n - 1);
    std::cout << ">> Input theta = " << theta << '\n';
    std::cout << ">> Estimated theta = " << theta_e << '\n';
    std::cout << ">> Norm difference: " << std::abs(theta_e - theta) << '\n';
}
<|endoftext|>


<commit_before>/** \brief Utility for converting Dublin Core data downloaded from ICPSR to MARC.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2021 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <cstdlib>
#include "MARC.h"
#include "StringUtil.h"
#include "util.h"
#include "XMLParser.h"

bool IsCriminologyRecord(const MARC::Record &record) {
    for (const auto &field : record.getTagRange("653")) {
        if (StringUtil::StartsWith(field.getFirstSubfieldWithCode('a'), "crime"))
            return true;
    }

    return false;
}

// Mostly uses the mapping found at https://www.loc.gov/marc/dccross.html to map DC to MARC.
bool ParseRecord(XMLParser * const xml_parser, MARC::Writer * const marc_writer) {
    static unsigned record_number;
    ++record_number;
    MARC::Record new_record(MARC::Record::TypeOfRecord::LANGUAGE_MATERIAL, MARC::Record::BibliographicLevel::UNDEFINED,
                            "ICPSR" + StringUtil::ToString(record_number, /* radix = */10, /* width = */6,
                                                           /* padding_char = */'0'));
    new_record.insertField(MARC::Tag("935"), { { 'a', "icpsr" }, { '2', "LOK" } });

    XMLParser::XMLPart xml_part;
    std::string last_data;
    while (xml_parser->getNext(&xml_part)) {
        if (xml_part.type_ == XMLParser::XMLPart::CHARACTERS)
            xml_part.data_.swap(last_data);
        else if (xml_part.type_ == XMLParser::XMLPart::CLOSING_TAG and StringUtil::StartsWith(xml_part.data_, "dc:")) {
            const std::string tag(xml_part.data_.substr(3));
            if (tag == "title")
                new_record.insertField(MARC::Tag("245"), 'a', last_data);
            else if (tag == "contributor")
                new_record.insertField(MARC::Tag("720"), 'a', last_data);
            else if (tag == "creator")
                new_record.insertField(MARC::Tag("720"), { { 'a', last_data}, { 'e', "author" } });
            else if (tag == "description")
                new_record.insertField(MARC::Tag("520"), 'a', last_data);
            else if (tag == "identifier") {
                if (StringUtil::StartsWith(last_data, "http://doi.org/")) {
                    new_record.insertField(MARC::Tag("024"),
                                           { { 'a', last_data.substr(__builtin_strlen("http://doi.org/")) }, { '2', "doi" } });
                    new_record.insertField(MARC::Tag("856"), 'u', last_data);
                }
            } else if (tag == "date")
                new_record.insertField(MARC::Tag("260"), 'c', last_data);
            else if (tag == "type")
                new_record.insertField(MARC::Tag("655"), 'a', last_data, ' ', '7');
            else if (tag == "source")
                new_record.insertField(MARC::Tag("786"), 'n', last_data, '0', ' ');
            else if (tag == "coverage")
                new_record.insertField(MARC::Tag("500"), 'a', last_data);
            else if (tag == "subject")
                new_record.insertField(MARC::Tag("653"), 'a', last_data);
            else
                LOG_ERROR("Unhandled tag: \"" + xml_part.data_ + "\"!");
        } else if (not StringUtil::StartsWith(xml_part.data_, "dc:")) {
            if (IsCriminologyRecord(new_record)) {
                marc_writer->write(new_record);
                return true;
            } else
                return false;
        }
    }

    if (IsCriminologyRecord(new_record)) {
        marc_writer->write(new_record);
        return true;
    } else
        return false;
}

int Main(int argc, char *argv[]) {
    if (argc != 3)
        ::Usage("dc_xml_imput marc_output");

    XMLParser xml_parser(argv[1], XMLParser::XML_FILE);
    const auto marc_writer(MARC::Writer::Factory(argv[2]));

    unsigned total_record_count(0), selected_record_count(0);
    while (xml_parser.skipTo(XMLParser::XMLPart::OPENING_TAG, "oai_dc:dc")) {
        ++total_record_count;
        if (ParseRecord(&xml_parser, marc_writer.get()))
            ++selected_record_count;
    }

    LOG_INFO("Processed " + std::to_string(total_record_count) + " record(s) of which "
             + std::to_string(selected_record_count) + " record(s) where selected and converted to MARC.");

    return EXIT_SUCCESS;
}
<commit_msg>Changes requested by the BSZ.<commit_after>/** \brief Utility for converting Dublin Core data downloaded from ICPSR to MARC.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2021 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <cstdlib>
#include "MARC.h"
#include "StringUtil.h"
#include "TimeUtil.h"
#include "util.h"
#include "XMLParser.h"

bool IsCriminologyRecord(const MARC::Record &record) {
    for (const auto &field : record.getTagRange("653")) {
        if (StringUtil::StartsWith(field.getFirstSubfieldWithCode('a'), "crime"))
            return true;
    }

    return false;
}

// "american_date" is expected to contain the pattern mm-dd-yyyy.
std::string AmericanDateToGermanDate(const std::string &american_date) {
    const auto month(StringUtil::ToUnsigned(american_date.substr(0, 2)));
    if (unlikely(month == 0 or month > 12))
        LOG_ERROR("bad month in \"" + american_date + "\"!");

    const auto day(StringUtil::ToUnsigned(american_date.substr(3, 2)));
    if (unlikely(day == 0 or day > 31))
        LOG_ERROR("bad day in \"" + american_date + "\"!");

    const auto year(StringUtil::ToUnsigned(american_date.substr(6)));
    if (unlikely(year < 1000 or year > 2099))
        LOG_ERROR("bad year in \"" + american_date + "\"!");

    return StringUtil::ToString(day) + "." + StringUtil::ToString(month) + "." + StringUtil::ToString(year);
}

// Mostly uses the mapping found at https://www.loc.gov/marc/dccross.html to map DC to MARC.
bool ParseRecord(XMLParser * const xml_parser, MARC::Writer * const marc_writer) {
    static unsigned record_number;
    ++record_number;
    MARC::Record new_record(MARC::Record::TypeOfRecord::LANGUAGE_MATERIAL, MARC::Record::BibliographicLevel::UNDEFINED,
                            "ICPSR" + StringUtil::ToString(record_number, /* radix = */10, /* width = */6,
                                                           /* padding_char = */'0'));
    static const std::string today(TimeUtil::GetCurrentDateAndTime("%y%m%d"));
    static const std::string current_year(TimeUtil::GetCurrentYear());
    static const std::string _008_contents(today + 's' + current_year);
    new_record.insertField(MARC::Tag("008"), _008_contents);
    new_record.insertField(MARC::Tag("935"), { { 'a', "icpsr" }, { '2', "LOK" } });

    XMLParser::XMLPart xml_part;
    std::string last_data;
    while (xml_parser->getNext(&xml_part)) {
        if (xml_part.type_ == XMLParser::XMLPart::CHARACTERS)
            xml_part.data_.swap(last_data);
        else if (xml_part.type_ == XMLParser::XMLPart::CLOSING_TAG and StringUtil::StartsWith(xml_part.data_, "dc:")) {
            const std::string tag(xml_part.data_.substr(3));
            if (tag == "title")
                new_record.insertField(MARC::Tag("245"), 'a', last_data);
            else if (tag == "contributor")
                new_record.insertField(MARC::Tag("720"), 'a', last_data);
            else if (tag == "creator")
                new_record.insertField(MARC::Tag("720"), { { 'a', last_data}, { 'e', "author" } });
            else if (tag == "description")
                new_record.insertField(MARC::Tag("520"), 'a', last_data);
            else if (tag == "identifier") {
                if (StringUtil::StartsWith(last_data, "http://doi.org/")) {
                    new_record.insertField(MARC::Tag("024"),
                                           { { 'a', last_data.substr(__builtin_strlen("http://doi.org/")) }, { '2', "doi" } });
                    new_record.insertField(MARC::Tag("856"), 'u', last_data);
                }
            } else if (tag == "date")
                new_record.insertField(MARC::Tag("260"), 'c', AmericanDateToGermanDate(last_data));
            else if (tag == "type")
                new_record.insertField(MARC::Tag("655"), 'a', last_data, ' ', '7');
            else if (tag == "source")
                new_record.insertField(MARC::Tag("786"), 'n', last_data, '0', ' ');
            else if (tag == "coverage")
                new_record.insertField(MARC::Tag("500"), 'a', last_data);
            else if (tag == "subject")
                new_record.insertField(MARC::Tag("653"), 'a', last_data);
            else
                LOG_ERROR("Unhandled tag: \"" + xml_part.data_ + "\"!");
        } else if (not StringUtil::StartsWith(xml_part.data_, "dc:")) {
            if (IsCriminologyRecord(new_record)) {
                marc_writer->write(new_record);
                return true;
            } else
                return false;
        }
    }

    if (IsCriminologyRecord(new_record)) {
        marc_writer->write(new_record);
        return true;
    } else
        return false;
}

int Main(int argc, char *argv[]) {
    if (argc != 3)
        ::Usage("dc_xml_imput marc_output");

    XMLParser xml_parser(argv[1], XMLParser::XML_FILE);
    const auto marc_writer(MARC::Writer::Factory(argv[2]));

    unsigned total_record_count(0), selected_record_count(0);
    while (xml_parser.skipTo(XMLParser::XMLPart::OPENING_TAG, "oai_dc:dc")) {
        ++total_record_count;
        if (ParseRecord(&xml_parser, marc_writer.get()))
            ++selected_record_count;
    }

    LOG_INFO("Processed " + std::to_string(total_record_count) + " record(s) of which "
             + std::to_string(selected_record_count) + " record(s) where selected and converted to MARC.");

    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>#include "MathLibUtilities.h"
#include "MathLib_MatrixVectorOps.h"
#include "MathLib_QuaternionMatrixOps.h"

namespace MathLib
{

void GenerateTransformMatrix(matrix4x4& transform,
	const vector4& position,
	const vector4& rotation,
	const vector4& scale)
{
    // Generate the translation transform.
    matrix4x4 translationMatrix
    (
        1.0f, 0.0f, 0.0f, position.x,
        0.0f, 1.0f, 0.0f, position.y,
        0.0f, 0.0f, 1.0f, position.z,
        0.0f, 0.0f, 0.0f, 1.0f
    );

    // Generate the rotation transform.
    vector4 xAxis(1.0f, 0.0f, 0.0f, 0.0f);
    vector4 yAxis(0.0f, 1.0f, 0.0f, 0.0f);
    vector4 zAxis(0.0f, 0.0f, 1.0f, 0.0f);

    // Perform rotation around the x axis.
    {
        float angleRads = MATHLIB_DEG_TO_RAD(rotation.x);
        float sinAngle = sinf(angleRads);
        float cosAngle = cosf(angleRads);

        // Caclulate modified y axis.
        vector4 perpendicularContribution;
        vector4_scale(zAxis, sinAngle, perpendicularContribution);
        vector4_scale(yAxis, cosAngle, yAxis);
        vector4_add(yAxis, perpendicularContribution, yAxis);

        // Calculate modified z axis.
        vector4_crossProduct(xAxis, yAxis, zAxis);
    }

    // Perform rotation around the y axis.
    matrix4x4 rotateAroundY;
    rotateAroundY.loadRotationY(rotation.y);
    matrix4x4_vectorMul(rotateAroundY, xAxis, xAxis);
    matrix4x4_vectorMul(rotateAroundY, yAxis, yAxis);
    matrix4x4_vectorMul(rotateAroundY, zAxis, zAxis);

    // Perform rotaiton around the z axis.
    {
        float angleRads = MATHLIB_DEG_TO_RAD(rotation.z);
        float sinAngle = sinf(angleRads);
        float cosAngle = cosf(angleRads);

        // Calculate modified y axis.
        vector4 perpendicularContribution;
        vector4_scale(xAxis, sinAngle, perpendicularContribution);
        vector4_scale(yAxis, cosAngle, yAxis);
        vector4_sub(yAxis, perpendicularContribution, yAxis);

        // Calculate modified x axis.
        vector4_crossProduct(yAxis, zAxis, xAxis);
    }

    matrix4x4 rotationMatrix
    (
        xAxis.x, yAxis.x, zAxis.x, 0.0f,
        xAxis.y, yAxis.y, zAxis.y, 0.0f,
        xAxis.z, yAxis.z, zAxis.z, 0.0f,
        0.0f, 0.0f, 0.0f, 1.0f
    );

    // Generate the scale transform.
    matrix4x4 scaleMatrix
    (
        scale.x, 0.0f, 0.0f, 0.0f,
        0.0f, scale.y, 0.0f, 0.0f,
        0.0f, 0.0f, scale.z, 0.0f,
        0.0f, 0.0f, 0.0f, 1.0f
    );

    // Generate the final transform.
    matrix4x4 scaledRotationMatrix;
    matrix4x4_mul(rotationMatrix, scaleMatrix, scaledRotationMatrix);
    matrix4x4_mul(translationMatrix, scaledRotationMatrix, transform);
}

void GenerateTransformMatrix(matrix4x4& transform,
	const vector4& position,
	const quaternion& orientation,
	const vector4& scale)
{
	// Generation the translation transform.
	matrix4x4 translationTransform
	(
		1.0f, 0.0f, 0.0f, position.x,
		0.0f, 1.0f, 0.0f, position.y,
		0.0f, 0.0f, 1.0f, position.z,
		0.0f, 0.0f, 0.0f, 1.0f
	);

	// Generate the orientation transform.
	matrix4x4 orientationTransform;
	quaternion_toMatrix(orientation, orientationTransform);

	// Gemerate the scale transform.
	matrix4x4 scaleTransform
	(
		scale.x, 0.0f, 0.0f, 0.0f,
		0.0f, scale.y, 0.0f, 0.0f,
		0.0f, 0.0f, scale.z, 0.0f,
		0.0f, 0.0f, 0.0f, 1.0f
	);

	// Generate the final transform.
	matrix4x4 scaledOrientationTransform;
	matrix4x4_mul(orientationTransform, scaleTransform, scaledOrientationTransform);
	matrix4x4_mul(translationTransform, scaledOrientationTransform, transform);
}

void GenerateInverseTransformMatrix(matrix4x4& transform,
	const vector4& position,
	const quaternion& orientation,
	const vector4& scale)
{
	// Generate the inverse translation transform.
	matrix4x4 invTranslationTransform
	(
		1.0f, 0.0f, 0.0f, -position.x,
		0.0f, 1.0f, 0.0f, -position.y,
		0.0f, 0.0f, 1.0f, -position.z,
		0.0f, 0.0f, 0.0f, 1.0f
	);

	// Generate the inverse orientation transform.
	matrix4x4 invOrientationTransform;
	quaternion invOrientation;
	quaternion_inverse(orientation, invOrientation);
	quaternion_toMatrix(orientation, invOrientationTransform);

	// Generate the inverse scale transform.
	matrix4x4 invScaleTransform
	(
		1.0f / scale.x, 0.0f, 0.0f, 0.0f,
		0.0f, 1.0f / scale.y, 0.0f, 0.0f,
		0.0f, 0.0f, 1.0f / scale.z, 0.0f,
		0.0f, 0.0f, 0.0f, 1.0f
	);

	// Generate the final transform.
	matrix4x4 orientationTranslation;
	matrix4x4_mul(invOrientationTransform, invTranslationTransform, orientationTranslation);
	matrix4x4_mul(invScaleTransform, orientationTranslation, transform);
}

void GenerateInverseTransformMatrix(matrix4x4& transform,
	const vector4& position,
	const quaternion& orientation,
	float scale)
{
	GenerateInverseTransformMatrix(transform, position, orientation,
		MathLib::vector4(scale, scale, scale, 1.0f));
}

void GenerateTransformMatrix(matrix4x4& transform,
    const vector4& position,
    const quaternion& orientation,
    const float scale)
{
    // Generation the translation transform.
    matrix4x4 translationTransform
    (
        1.0f, 0.0f, 0.0f, position.x,
        0.0f, 1.0f, 0.0f, position.y,
        0.0f, 0.0f, 1.0f, position.z,
        0.0f, 0.0f, 0.0f, 1.0f
    );

    // Generate the orientation transform.
    matrix4x4 orientationTransform;
    quaternion_toMatrix(orientation, orientationTransform);

    // Gemerate the scale transform.
    matrix4x4 scaleTransform
    (
        scale, 0.0f, 0.0f, 0.0f,
        0.0f, scale, 0.0f, 0.0f,
        0.0f, 0.0f, scale, 0.0f,
        0.0f, 0.0f, 0.0f, 1.0f
    );

    // Generate the final transform.
    matrix4x4 scaledOrientationTransform;
    matrix4x4_mul(orientationTransform, scaleTransform, scaledOrientationTransform);
    matrix4x4_mul(translationTransform, scaledOrientationTransform, transform);
}

}
<commit_msg>Fixed incorrect inverse transform matrix generation in GenerateInverseTransformMatrix().<commit_after>#include "MathLibUtilities.h"
#include "MathLib_MatrixVectorOps.h"
#include "MathLib_QuaternionMatrixOps.h"

namespace MathLib
{

void GenerateTransformMatrix(matrix4x4& transform,
	const vector4& position,
	const vector4& rotation,
	const vector4& scale)
{
    // Generate the translation transform.
    matrix4x4 translationMatrix
    (
        1.0f, 0.0f, 0.0f, position.x,
        0.0f, 1.0f, 0.0f, position.y,
        0.0f, 0.0f, 1.0f, position.z,
        0.0f, 0.0f, 0.0f, 1.0f
    );

    // Generate the rotation transform.
    vector4 xAxis(1.0f, 0.0f, 0.0f, 0.0f);
    vector4 yAxis(0.0f, 1.0f, 0.0f, 0.0f);
    vector4 zAxis(0.0f, 0.0f, 1.0f, 0.0f);

    // Perform rotation around the x axis.
    {
        float angleRads = MATHLIB_DEG_TO_RAD(rotation.x);
        float sinAngle = sinf(angleRads);
        float cosAngle = cosf(angleRads);

        // Caclulate modified y axis.
        vector4 perpendicularContribution;
        vector4_scale(zAxis, sinAngle, perpendicularContribution);
        vector4_scale(yAxis, cosAngle, yAxis);
        vector4_add(yAxis, perpendicularContribution, yAxis);

        // Calculate modified z axis.
        vector4_crossProduct(xAxis, yAxis, zAxis);
    }

    // Perform rotation around the y axis.
    matrix4x4 rotateAroundY;
    rotateAroundY.loadRotationY(rotation.y);
    matrix4x4_vectorMul(rotateAroundY, xAxis, xAxis);
    matrix4x4_vectorMul(rotateAroundY, yAxis, yAxis);
    matrix4x4_vectorMul(rotateAroundY, zAxis, zAxis);

    // Perform rotaiton around the z axis.
    {
        float angleRads = MATHLIB_DEG_TO_RAD(rotation.z);
        float sinAngle = sinf(angleRads);
        float cosAngle = cosf(angleRads);

        // Calculate modified y axis.
        vector4 perpendicularContribution;
        vector4_scale(xAxis, sinAngle, perpendicularContribution);
        vector4_scale(yAxis, cosAngle, yAxis);
        vector4_sub(yAxis, perpendicularContribution, yAxis);

        // Calculate modified x axis.
        vector4_crossProduct(yAxis, zAxis, xAxis);
    }

    matrix4x4 rotationMatrix
    (
        xAxis.x, yAxis.x, zAxis.x, 0.0f,
        xAxis.y, yAxis.y, zAxis.y, 0.0f,
        xAxis.z, yAxis.z, zAxis.z, 0.0f,
        0.0f, 0.0f, 0.0f, 1.0f
    );

    // Generate the scale transform.
    matrix4x4 scaleMatrix
    (
        scale.x, 0.0f, 0.0f, 0.0f,
        0.0f, scale.y, 0.0f, 0.0f,
        0.0f, 0.0f, scale.z, 0.0f,
        0.0f, 0.0f, 0.0f, 1.0f
    );

    // Generate the final transform.
    matrix4x4 scaledRotationMatrix;
    matrix4x4_mul(rotationMatrix, scaleMatrix, scaledRotationMatrix);
    matrix4x4_mul(translationMatrix, scaledRotationMatrix, transform);
}

void GenerateTransformMatrix(matrix4x4& transform,
	const vector4& position,
	const quaternion& orientation,
	const vector4& scale)
{
	// Generation the translation transform.
	matrix4x4 translationTransform
	(
		1.0f, 0.0f, 0.0f, position.x,
		0.0f, 1.0f, 0.0f, position.y,
		0.0f, 0.0f, 1.0f, position.z,
		0.0f, 0.0f, 0.0f, 1.0f
	);

	// Generate the orientation transform.
	matrix4x4 orientationTransform;
	quaternion_toMatrix(orientation, orientationTransform);

	// Gemerate the scale transform.
	matrix4x4 scaleTransform
	(
		scale.x, 0.0f, 0.0f, 0.0f,
		0.0f, scale.y, 0.0f, 0.0f,
		0.0f, 0.0f, scale.z, 0.0f,
		0.0f, 0.0f, 0.0f, 1.0f
	);

	// Generate the final transform.
	matrix4x4 scaledOrientationTransform;
	matrix4x4_mul(orientationTransform, scaleTransform, scaledOrientationTransform);
	matrix4x4_mul(translationTransform, scaledOrientationTransform, transform);
}

void GenerateInverseTransformMatrix(matrix4x4& transform,
	const vector4& position,
	const quaternion& orientation,
	const vector4& scale)
{
	// Generate the inverse translation transform.
	matrix4x4 invTranslationTransform
	(
		1.0f, 0.0f, 0.0f, -position.x,
		0.0f, 1.0f, 0.0f, -position.y,
		0.0f, 0.0f, 1.0f, -position.z,
		0.0f, 0.0f, 0.0f, 1.0f
	);

	// Generate the inverse orientation transform.
	matrix4x4 invOrientationTransform;
	quaternion invOrientation;
	quaternion_inverse(orientation, invOrientation);
	quaternion_toMatrix(invOrientation, invOrientationTransform);

	// Generate the inverse scale transform.
	matrix4x4 invScaleTransform
	(
		1.0f / scale.x, 0.0f, 0.0f, 0.0f,
		0.0f, 1.0f / scale.y, 0.0f, 0.0f,
		0.0f, 0.0f, 1.0f / scale.z, 0.0f,
		0.0f, 0.0f, 0.0f, 1.0f
	);

	// Generate the final transform.
	matrix4x4 orientationTranslation;
	matrix4x4_mul(invOrientationTransform, invTranslationTransform, orientationTranslation);
	matrix4x4_mul(invScaleTransform, orientationTranslation, transform);
}

void GenerateInverseTransformMatrix(matrix4x4& transform,
	const vector4& position,
	const quaternion& orientation,
	float scale)
{
	GenerateInverseTransformMatrix(transform, position, orientation,
		MathLib::vector4(scale, scale, scale, 1.0f));
}

void GenerateTransformMatrix(matrix4x4& transform,
    const vector4& position,
    const quaternion& orientation,
    const float scale)
{
    // Generation the translation transform.
    matrix4x4 translationTransform
    (
        1.0f, 0.0f, 0.0f, position.x,
        0.0f, 1.0f, 0.0f, position.y,
        0.0f, 0.0f, 1.0f, position.z,
        0.0f, 0.0f, 0.0f, 1.0f
    );

    // Generate the orientation transform.
    matrix4x4 orientationTransform;
    quaternion_toMatrix(orientation, orientationTransform);

    // Gemerate the scale transform.
    matrix4x4 scaleTransform
    (
        scale, 0.0f, 0.0f, 0.0f,
        0.0f, scale, 0.0f, 0.0f,
        0.0f, 0.0f, scale, 0.0f,
        0.0f, 0.0f, 0.0f, 1.0f
    );

    // Generate the final transform.
    matrix4x4 scaledOrientationTransform;
    matrix4x4_mul(orientationTransform, scaleTransform, scaledOrientationTransform);
    matrix4x4_mul(translationTransform, scaledOrientationTransform, transform);
}

}
<|endoftext|>


<commit_before>//===- DLL.cpp ------------------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines various types of chunks for the DLL import
// descriptor table. They are inherently Windows-specific.
// You need to read Microsoft PE/COFF spec to understand details
// about the data structures.
//
// If you are not particularly interested in linking against Windows
// DLL, you can skip this file, and you should still be able to
// understand the rest of the linker.
//
//===----------------------------------------------------------------------===//

#include "Chunks.h"
#include "DLL.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/Endian.h"

using namespace llvm;
using namespace llvm::object;
using namespace llvm::support::endian;
using namespace llvm::COFF;
using llvm::RoundUpToAlignment;

const size_t LookupChunkSize = sizeof(uint64_t);
const size_t DirectoryChunkSize = sizeof(ImportDirectoryTableEntry);

namespace lld {
namespace coff {

// A chunk for the import descriptor table.
class HintNameChunk : public Chunk {
public:
  HintNameChunk(StringRef N, uint16_t H) : Name(N), Hint(H) {}

  size_t getSize() const override {
    // Starts with 2 byte Hint field, followed by a null-terminated string,
    // ends with 0 or 1 byte padding.
    return RoundUpToAlignment(Name.size() + 3, 2);
  }

  void writeTo(uint8_t *Buf) override {
    write16le(Buf + FileOff, Hint);
    memcpy(Buf + FileOff + 2, Name.data(), Name.size());
  }

private:
  StringRef Name;
  uint16_t Hint;
};

// A chunk for the import descriptor table.
class LookupChunk : public Chunk {
public:
  explicit LookupChunk(Chunk *C) : HintName(C) {}
  size_t getSize() const override { return LookupChunkSize; }

  void writeTo(uint8_t *Buf) override {
    write32le(Buf + FileOff, HintName->getRVA());
  }

  Chunk *HintName;
};

// A chunk for the import descriptor table.
// This chunk represent import-by-ordinal symbols.
// See Microsoft PE/COFF spec 7.1. Import Header for details.
class OrdinalOnlyChunk : public Chunk {
public:
  explicit OrdinalOnlyChunk(uint16_t V) : Ordinal(V) {}
  size_t getSize() const override { return sizeof(uint64_t); }

  void writeTo(uint8_t *Buf) override {
    // An import-by-ordinal slot has MSB 1 to indicate that
    // this is import-by-ordinal (and not import-by-name).
    write64le(Buf + FileOff, (uint64_t(1) << 63) | Ordinal);
  }

  uint16_t Ordinal;
};

// A chunk for the import descriptor table.
class DirectoryChunk : public Chunk {
public:
  explicit DirectoryChunk(Chunk *N) : DLLName(N) {}
  size_t getSize() const override { return DirectoryChunkSize; }

  void writeTo(uint8_t *Buf) override {
    auto *E = (coff_import_directory_table_entry *)(Buf + FileOff);
    E->ImportLookupTableRVA = LookupTab->getRVA();
    E->NameRVA = DLLName->getRVA();
    E->ImportAddressTableRVA = AddressTab->getRVA();
  }

  Chunk *DLLName;
  Chunk *LookupTab;
  Chunk *AddressTab;
};

// A chunk representing null terminator in the import table.
// Contents of this chunk is always null bytes.
class NullChunk : public Chunk {
public:
  explicit NullChunk(size_t N) : Size(N) {}
  bool hasData() const override { return false; }
  size_t getSize() const override { return Size; }

private:
  size_t Size;
};

uint64_t IdataContents::getDirSize() {
  return Dirs.size() * DirectoryChunkSize;
}

uint64_t IdataContents::getIATSize() {
  return Addresses.size() * LookupChunkSize;
}

// Returns a list of .idata contents.
// See Microsoft PE/COFF spec 5.4 for details.
std::vector<Chunk *> IdataContents::getChunks() {
  create();
  std::vector<Chunk *> V;
  // The loader assumes a specific order of data.
  // Add each type in the correct order.
  for (std::unique_ptr<Chunk> &C : Dirs)
    V.push_back(C.get());
  for (std::unique_ptr<Chunk> &C : Lookups)
    V.push_back(C.get());
  for (std::unique_ptr<Chunk> &C : Addresses)
    V.push_back(C.get());
  for (std::unique_ptr<Chunk> &C : Hints)
    V.push_back(C.get());
  for (auto &P : DLLNames) {
    std::unique_ptr<Chunk> &C = P.second;
    V.push_back(C.get());
  }
  return V;
}

void IdataContents::create() {
  // Group DLL-imported symbols by DLL name because that's how
  // symbols are layed out in the import descriptor table.
  std::map<StringRef, std::vector<DefinedImportData *>> Map;
  for (DefinedImportData *Sym : Imports)
    Map[Sym->getDLLName()].push_back(Sym);

  // Create .idata contents for each DLL.
  for (auto &P : Map) {
    StringRef Name = P.first;
    std::vector<DefinedImportData *> &Syms = P.second;

    // Sort symbols by name for each group.
    std::sort(Syms.begin(), Syms.end(),
              [](DefinedImportData *A, DefinedImportData *B) {
                return A->getName() < B->getName();
              });

    // Create lookup and address tables. If they have external names,
    // we need to create HintName chunks to store the names.
    // If they don't (if they are import-by-ordinals), we store only
    // ordinal values to the table.
    size_t Base = Lookups.size();
    for (DefinedImportData *S : Syms) {
      uint16_t Ord = S->getOrdinal();
      if (S->getExternalName().empty()) {
        Lookups.push_back(make_unique<OrdinalOnlyChunk>(Ord));
        Addresses.push_back(make_unique<OrdinalOnlyChunk>(Ord));
        continue;
      }
      auto C = make_unique<HintNameChunk>(S->getExternalName(), Ord);
      Lookups.push_back(make_unique<LookupChunk>(C.get()));
      Addresses.push_back(make_unique<LookupChunk>(C.get()));
      Hints.push_back(std::move(C));
    }
    // Terminate with null values.
    Lookups.push_back(make_unique<NullChunk>(sizeof(uint64_t)));
    Addresses.push_back(make_unique<NullChunk>(sizeof(uint64_t)));

    for (int I = 0, E = Syms.size(); I < E; ++I)
      Syms[I]->setLocation(Addresses[Base + I].get());

    // Create the import table header.
    if (!DLLNames.count(Name))
      DLLNames[Name] = make_unique<StringChunk>(Name);
    auto Dir = make_unique<DirectoryChunk>(DLLNames[Name].get());
    Dir->LookupTab = Lookups[Base].get();
    Dir->AddressTab = Addresses[Base].get();
    Dirs.push_back(std::move(Dir));
  }
  // Add null terminator.
  Dirs.push_back(make_unique<NullChunk>(DirectoryChunkSize));
}

} // namespace coff
} // namespace lld
<commit_msg>COFF: Make local variables local.<commit_after>//===- DLL.cpp ------------------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines various types of chunks for the DLL import
// descriptor table. They are inherently Windows-specific.
// You need to read Microsoft PE/COFF spec to understand details
// about the data structures.
//
// If you are not particularly interested in linking against Windows
// DLL, you can skip this file, and you should still be able to
// understand the rest of the linker.
//
//===----------------------------------------------------------------------===//

#include "Chunks.h"
#include "DLL.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/Endian.h"

using namespace llvm;
using namespace llvm::object;
using namespace llvm::support::endian;
using namespace llvm::COFF;
using llvm::RoundUpToAlignment;

static const size_t LookupChunkSize = sizeof(uint64_t);
static const size_t DirectoryChunkSize = sizeof(ImportDirectoryTableEntry);

namespace lld {
namespace coff {

// A chunk for the import descriptor table.
class HintNameChunk : public Chunk {
public:
  HintNameChunk(StringRef N, uint16_t H) : Name(N), Hint(H) {}

  size_t getSize() const override {
    // Starts with 2 byte Hint field, followed by a null-terminated string,
    // ends with 0 or 1 byte padding.
    return RoundUpToAlignment(Name.size() + 3, 2);
  }

  void writeTo(uint8_t *Buf) override {
    write16le(Buf + FileOff, Hint);
    memcpy(Buf + FileOff + 2, Name.data(), Name.size());
  }

private:
  StringRef Name;
  uint16_t Hint;
};

// A chunk for the import descriptor table.
class LookupChunk : public Chunk {
public:
  explicit LookupChunk(Chunk *C) : HintName(C) {}
  size_t getSize() const override { return LookupChunkSize; }

  void writeTo(uint8_t *Buf) override {
    write32le(Buf + FileOff, HintName->getRVA());
  }

  Chunk *HintName;
};

// A chunk for the import descriptor table.
// This chunk represent import-by-ordinal symbols.
// See Microsoft PE/COFF spec 7.1. Import Header for details.
class OrdinalOnlyChunk : public Chunk {
public:
  explicit OrdinalOnlyChunk(uint16_t V) : Ordinal(V) {}
  size_t getSize() const override { return sizeof(uint64_t); }

  void writeTo(uint8_t *Buf) override {
    // An import-by-ordinal slot has MSB 1 to indicate that
    // this is import-by-ordinal (and not import-by-name).
    write64le(Buf + FileOff, (uint64_t(1) << 63) | Ordinal);
  }

  uint16_t Ordinal;
};

// A chunk for the import descriptor table.
class DirectoryChunk : public Chunk {
public:
  explicit DirectoryChunk(Chunk *N) : DLLName(N) {}
  size_t getSize() const override { return DirectoryChunkSize; }

  void writeTo(uint8_t *Buf) override {
    auto *E = (coff_import_directory_table_entry *)(Buf + FileOff);
    E->ImportLookupTableRVA = LookupTab->getRVA();
    E->NameRVA = DLLName->getRVA();
    E->ImportAddressTableRVA = AddressTab->getRVA();
  }

  Chunk *DLLName;
  Chunk *LookupTab;
  Chunk *AddressTab;
};

// A chunk representing null terminator in the import table.
// Contents of this chunk is always null bytes.
class NullChunk : public Chunk {
public:
  explicit NullChunk(size_t N) : Size(N) {}
  bool hasData() const override { return false; }
  size_t getSize() const override { return Size; }

private:
  size_t Size;
};

uint64_t IdataContents::getDirSize() {
  return Dirs.size() * DirectoryChunkSize;
}

uint64_t IdataContents::getIATSize() {
  return Addresses.size() * LookupChunkSize;
}

// Returns a list of .idata contents.
// See Microsoft PE/COFF spec 5.4 for details.
std::vector<Chunk *> IdataContents::getChunks() {
  create();
  std::vector<Chunk *> V;
  // The loader assumes a specific order of data.
  // Add each type in the correct order.
  for (std::unique_ptr<Chunk> &C : Dirs)
    V.push_back(C.get());
  for (std::unique_ptr<Chunk> &C : Lookups)
    V.push_back(C.get());
  for (std::unique_ptr<Chunk> &C : Addresses)
    V.push_back(C.get());
  for (std::unique_ptr<Chunk> &C : Hints)
    V.push_back(C.get());
  for (auto &P : DLLNames) {
    std::unique_ptr<Chunk> &C = P.second;
    V.push_back(C.get());
  }
  return V;
}

void IdataContents::create() {
  // Group DLL-imported symbols by DLL name because that's how
  // symbols are layed out in the import descriptor table.
  std::map<StringRef, std::vector<DefinedImportData *>> Map;
  for (DefinedImportData *Sym : Imports)
    Map[Sym->getDLLName()].push_back(Sym);

  // Create .idata contents for each DLL.
  for (auto &P : Map) {
    StringRef Name = P.first;
    std::vector<DefinedImportData *> &Syms = P.second;

    // Sort symbols by name for each group.
    std::sort(Syms.begin(), Syms.end(),
              [](DefinedImportData *A, DefinedImportData *B) {
                return A->getName() < B->getName();
              });

    // Create lookup and address tables. If they have external names,
    // we need to create HintName chunks to store the names.
    // If they don't (if they are import-by-ordinals), we store only
    // ordinal values to the table.
    size_t Base = Lookups.size();
    for (DefinedImportData *S : Syms) {
      uint16_t Ord = S->getOrdinal();
      if (S->getExternalName().empty()) {
        Lookups.push_back(make_unique<OrdinalOnlyChunk>(Ord));
        Addresses.push_back(make_unique<OrdinalOnlyChunk>(Ord));
        continue;
      }
      auto C = make_unique<HintNameChunk>(S->getExternalName(), Ord);
      Lookups.push_back(make_unique<LookupChunk>(C.get()));
      Addresses.push_back(make_unique<LookupChunk>(C.get()));
      Hints.push_back(std::move(C));
    }
    // Terminate with null values.
    Lookups.push_back(make_unique<NullChunk>(sizeof(uint64_t)));
    Addresses.push_back(make_unique<NullChunk>(sizeof(uint64_t)));

    for (int I = 0, E = Syms.size(); I < E; ++I)
      Syms[I]->setLocation(Addresses[Base + I].get());

    // Create the import table header.
    if (!DLLNames.count(Name))
      DLLNames[Name] = make_unique<StringChunk>(Name);
    auto Dir = make_unique<DirectoryChunk>(DLLNames[Name].get());
    Dir->LookupTab = Lookups[Base].get();
    Dir->AddressTab = Addresses[Base].get();
    Dirs.push_back(std::move(Dir));
  }
  // Add null terminator.
  Dirs.push_back(make_unique<NullChunk>(DirectoryChunkSize));
}

} // namespace coff
} // namespace lld
<|endoftext|>


<commit_before>#include <OpenGLTexture.h>

#include <TextureRef.h>
#include <Image.h>
#include <Surface.h>

#define GL_GLEXT_PROTOTYPES

#if defined __APPLE__
#include <OpenGLES/ES3/gl.h>
#include <OpenGLES/ES3/glext.h>
#elif (defined GL_ES)
#include <GLES3/gl3.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#else
#define GL_GLEXT_PROTOTYPES

#ifdef _WIN32
#include <GL/glew.h>
#include <windows.h>
#endif

#ifdef ANDROID
#include <GLES3/gl3.h>
#include <GLES3/gl3ext.h>
#else
#include <GL/gl.h>

#ifdef _WIN32
#include "glext.h"
#else
#include <GL/glext.h>
#endif
#endif

#endif

#if defined __APPLE__ || defined ANDROID
#ifndef GL_COMPRESSED_RGB_S3TC_DXT1_EXT
#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0
#endif
#ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0
#endif
#ifndef GL_COMPRESSED_RED_RGTC1
#define GL_COMPRESSED_RED_RGTC1 0x8DBB
#endif
#ifndef GL_COMPRESSED_RG_RGTC2
#define GL_COMPRESSED_RG_RGTC2 0x8DBD
#endif
#endif

#include <cassert>
#include <iostream>

using namespace std;
using namespace canvas;

size_t OpenGLTexture::total_textures = 0;
vector<unsigned int> OpenGLTexture::freed_textures;
bool OpenGLTexture::global_init = false;

OpenGLTexture::OpenGLTexture(Surface & surface)
  : Texture(surface.getLogicalWidth(), surface.getLogicalHeight(), surface.getActualWidth(), surface.getActualHeight(), surface.getMinFilter(), surface.getMagFilter(), surface.getTargetFormat(), 1) {
  assert(getInternalFormat());
  auto image = surface.createImage();
  updateData(*image, 0, 0);
}

static GLenum getOpenGLInternalFormat(InternalFormat internal_format) {
  switch (internal_format) {
  case NO_FORMAT: return 0;
  case R8: return GL_R8;
  case RG8: return GL_RG8;
  case RGB565: return GL_RGB565;
  case RGBA4: return GL_RGBA4;
  case RGBA8: return GL_RGBA8;
  case RGB8: return GL_RGB8;
  case RGB8_24: return GL_RGBA8;
  case RED_RGTC1: return GL_COMPRESSED_RED_RGTC1;
  case RG_RGTC2: return GL_COMPRESSED_RG_RGTC2;
  case RGB_ETC1: return GL_COMPRESSED_RGB8_ETC2;
  case RGB_DXT1: return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
  case RGBA_DXT5: return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
  case LUMINANCE_ALPHA: return GL_RG8;
  case LA44: return GL_R8; // pack luminance and alpha to single byte
  case R32F: return GL_R32F;

  }
  assert(0);
  return 0;
}

static GLenum getOpenGLFilterType(FilterMode mode) {
  switch (mode) {
  case NEAREST: return GL_NEAREST;
  case LINEAR: return GL_LINEAR;
  case LINEAR_MIPMAP_LINEAR: return GL_LINEAR_MIPMAP_LINEAR;
  }
  return 0;
}

void
OpenGLTexture::updateCompressedData(const Image & image, unsigned int x, unsigned int y) {
  unsigned int offset = 0;
  unsigned int current_width = image.getWidth(), current_height = image.getHeight();
  GLenum format = getOpenGLInternalFormat(getInternalFormat());
  for (unsigned int level = 0; level < image.getLevels(); level++) {
    size_t size = image.calculateOffset(level + 1) - image.calculateOffset(level);
    // cerr << "compressed tex: x = " << x << ", y = " << y << ", l = " << (level+1) << "/" << image.getLevels() << ", w = " << current_width << ", h = " << current_height << ", offset = " << offset << ", size = " << size << endl;
    glCompressedTexSubImage2D(GL_TEXTURE_2D, level, x, y, current_width, current_height, format, (GLsizei)size, image.getData() + offset);
    offset += size;
    current_width /= 2;
    current_height /= 2;
    x /= 2;
    y /= 2;
  }
}

void
OpenGLTexture::updatePlainData(const Image & image, unsigned int x, unsigned int y) {
  unsigned int offset = 0;
  unsigned int current_width = image.getWidth(), current_height = image.getHeight();
  GLenum format = getOpenGLInternalFormat(getInternalFormat());

  for (unsigned int level = 0; level < image.getLevels(); level++) {
    size_t size = image.calculateOffset(level + 1) - image.calculateOffset(level);
    // cerr << "plain tex: x = " << x << ", y = " << y << ", l = " << (level+1) << "/" << image.getLevels() << ", w = " << current_width << ", h = " << current_height << ", size = " << size << ", offset = " << offset << endl;

    if (getInternalFormat() == RGBA8) {
      assert(image.getData());
#if defined __APPLE__ || defined ANDROID
      glTexSubImage2D(GL_TEXTURE_2D, level, x, y, current_width, current_height, GL_RGBA, GL_UNSIGNED_BYTE, image.getData() + offset);
#else
      glTexSubImage2D(GL_TEXTURE_2D, level, x, y, current_width, current_height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, image.getData() + offset);
      // glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, tmp_image.getWidth(), height, GL_BGRA_EXT, GL_UNSIGNED_BYTE, image.getData());
#endif
    } else if (getInternalFormat() == LA44) {
      glTexSubImage2D(GL_TEXTURE_2D, level, x, y, current_width, current_height, GL_RED, GL_UNSIGNED_BYTE, image.getData() + offset);
    } else if (getInternalFormat() == RGB565) {
      glTexSubImage2D(GL_TEXTURE_2D, level, x, y, current_width, current_height, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, image.getData() + offset);
    } else if (getInternalFormat() == R32F) {
      glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, current_width, current_height, GL_RED, GL_FLOAT, image.getData() + offset);
    } else {
      cerr << "unhandled format " << int(getInternalFormat()) << endl;
      assert(0);
    }

    // glTexSubImage2D(GL_TEXTURE_2D, level, x, y, current_width, current_height, getOpenGLInternalFormat(getInternalFormat()), size, image.getData() + offset);

    offset += size;
    current_width /= 2;
    current_height /= 2;
    x /= 2;
    y /= 2;
  }
}

void
OpenGLTexture::updateData(const Image & image, unsigned int x, unsigned int y) {
  if (!global_init) {
    global_init = true;
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  }

  bool initialize = false;
  if (!texture_id) {
    initialize = true;
    glGenTextures(1, &texture_id);
    // cerr << "created texture id " << texture_id << " (total = " << total_textures << ")" << endl;
    if (texture_id >= 1) total_textures++;
  }
  assert(texture_id >= 1);

  glBindTexture(GL_TEXTURE_2D, texture_id);

  bool has_mipmaps = getMinFilter() == LINEAR_MIPMAP_LINEAR;
  if (initialize) {
    glTexStorage2D(GL_TEXTURE_2D, has_mipmaps ? getMipmapLevels() : 1, getOpenGLInternalFormat(getInternalFormat()), getActualWidth(), getActualHeight());

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, getOpenGLFilterType(getMinFilter()));
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, getOpenGLFilterType(getMagFilter()));

    if (x != 0 || y != 0 || image.getWidth() != getActualWidth() || image.getHeight() != getActualHeight()) {
      int levels = has_mipmaps ? getMipmapLevels() : 1;
      if (getInternalFormat() == RGB_ETC1 || getInternalFormat() == RGB_DXT1 ||
	  getInternalFormat() == RED_RGTC1
	  ) {
	Image img(getInternalFormat(), getActualWidth(), getActualHeight(), levels);
	updateCompressedData(img, 0, 0);
      } else if (getInternalFormat() == RGBA8 || getInternalFormat() == LA44 ||
		 getInternalFormat() == RGB565 || getInternalFormat() == R32F) {
	Image img(getInternalFormat(), getActualWidth(), getActualHeight(), levels);
	updatePlainData(img, 0, 0);
      } else {
	assert(0);
      }
    }
  }

  if (getInternalFormat() == R32F) {
    glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, image.getWidth(), image.getHeight(), GL_RED, GL_FLOAT, image.getData());
  } else if (getInternalFormat() == R8) {
    glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, image.getWidth(), image.getHeight(), GL_RED, GL_UNSIGNED_BYTE, image.getData());
  } else if (getInternalFormat() == LA44) {
    auto tmp_image = image.convert(LA44);
    glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, tmp_image->getWidth(), tmp_image->getHeight(), GL_RED, GL_UNSIGNED_BYTE, tmp_image->getData());
  } else if (getInternalFormat() == LUMINANCE_ALPHA) {
    if (image.getInternalFormat() == LUMINANCE_ALPHA) {
      glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, image.getWidth(), image.getHeight(), GL_RG, GL_UNSIGNED_BYTE, image.getData());
    } else {
      auto tmp_image = image.convert(LUMINANCE_ALPHA);
      glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, tmp_image->getWidth(), tmp_image->getHeight(), GL_RG, GL_UNSIGNED_BYTE, tmp_image->getData());
    }
  } else if (getInternalFormat() == RGB565) {
    auto tmp_image = image.convert(RGB565);
    updatePlainData(*tmp_image, x, y);
    // glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, tmp_image->getWidth(), tmp_image->getHeight(), GL_RGB, GL_UNSIGNED_SHORT_5_6_5, tmp_image->getData());
  } else if (getInternalFormat() == RGBA4) {
    auto tmp_image = image.convert(RGBA4);
    glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, tmp_image->getWidth(), tmp_image->getHeight(), GL_RGBA4, GL_UNSIGNED_SHORT_4_4_4_4, tmp_image->getData());
  } else if (getInternalFormat() == RGB_ETC1) {
    if (image.getInternalFormat() == RGB_ETC1) {
      updateCompressedData(image, x, y);
    } else {
      auto fd = image.getImageFormat();
      cerr << "WARNING: compression should be done in thread (bpp = " << fd.getBytesPerPixel() << ", c = " << int(fd.getCompression()) << ", ch = " << fd.getNumChannels() << ")\n";
      auto tmp_image = image.convert(RGB_ETC1);
      updateCompressedData(*tmp_image, x, y);
    }
  } else if (getInternalFormat() == RGB_DXT1) {
    if (image.getInternalFormat() == RGB_DXT1) {
      updateCompressedData(image, x, y);
    } else {
      cerr << "WARNING: compression should be done in thread\n";
      auto tmp_image = image.convert(RGB_DXT1);
      updateCompressedData(*tmp_image, x, y);
    }
  } else if (getInternalFormat() == RED_RGTC1) {
    if (image.getInternalFormat() == RED_RGTC1) {
      updateCompressedData(image, x, y);
    } else {
      cerr << "WARNING: compression should be done in thread\n";
      auto tmp_image = image.convert(RED_RGTC1);
      updateCompressedData(*tmp_image, x, y);
    }
  } else if (getInternalFormat() == RG_RGTC2) {
    if (image.getInternalFormat() == RG_RGTC2) {
      updateCompressedData(image, x, y);
    } else {
      cerr << "WARNING: compression should be done in thread\n";
      auto tmp_image = image.convert(RG_RGTC2);
      updateCompressedData(*tmp_image, x, y);
    }
  } else {
    updatePlainData(image, x, y);
  }

  if (has_mipmaps && image.getLevels() == 1) {
    need_mipmaps = true;
  }

  glBindTexture(GL_TEXTURE_2D, 0);
}

void
OpenGLTexture::generateMipmaps() {
  if (need_mipmaps) {
    if (getInternalFormat() != RGB_DXT1 && getInternalFormat() != RGB_ETC1 && getInternalFormat() != LA44 && getInternalFormat() != RED_RGTC1 && getInternalFormat() != RG_RGTC2) {
      glGenerateMipmap(GL_TEXTURE_2D);
    } else {
      cerr << "unable to generate mipmaps for compressed texture!\n";
    }
    need_mipmaps = false;
  }
}

void
OpenGLTexture::releaseTextures() {
  if (!freed_textures.empty()) {
    // cerr << "DELETING TEXTURES: " << OpenGLTexture::getFreedTextures().size() << "/" << OpenGLTexture::getNumTextures() << endl;

    for (vector<unsigned int>::const_iterator it = freed_textures.begin(); it != freed_textures.end(); it++) {
      GLuint texid = *it;
      glDeleteTextures(1, &texid);
    }
    freed_textures.clear();
  }
}

TextureRef
OpenGLTexture::createTexture(unsigned int _logical_width, unsigned int _logical_height, unsigned int _actual_width, unsigned int _actual_height, FilterMode min_filter, FilterMode mag_filter, InternalFormat _internal_format, unsigned int mipmap_levels) {
  assert(_internal_format);
  return TextureRef(_logical_width, _logical_height, _actual_width, _actual_height, new OpenGLTexture(_logical_width, _logical_height, _actual_width, _actual_height, min_filter, mag_filter, _internal_format, mipmap_levels));
}

TextureRef
OpenGLTexture::createTexture(Surface & surface) {
  return TextureRef( surface.getLogicalWidth(),
		     surface.getLogicalHeight(),
		     surface.getActualWidth(),
		     surface.getActualHeight(),
		     new OpenGLTexture(surface)
		     );
}
<commit_msg>use updatePlainData to update RGBA4 textures, convert RGBA4 and RGB565 only if necessary<commit_after>#include <OpenGLTexture.h>

#include <TextureRef.h>
#include <Image.h>
#include <Surface.h>

#define GL_GLEXT_PROTOTYPES

#if defined __APPLE__
#include <OpenGLES/ES3/gl.h>
#include <OpenGLES/ES3/glext.h>
#elif (defined GL_ES)
#include <GLES3/gl3.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#else
#define GL_GLEXT_PROTOTYPES

#ifdef _WIN32
#include <GL/glew.h>
#include <windows.h>
#endif

#ifdef ANDROID
#include <GLES3/gl3.h>
#include <GLES3/gl3ext.h>
#else
#include <GL/gl.h>

#ifdef _WIN32
#include "glext.h"
#else
#include <GL/glext.h>
#endif
#endif

#endif

#if defined __APPLE__ || defined ANDROID
#ifndef GL_COMPRESSED_RGB_S3TC_DXT1_EXT
#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0
#endif
#ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0
#endif
#ifndef GL_COMPRESSED_RED_RGTC1
#define GL_COMPRESSED_RED_RGTC1 0x8DBB
#endif
#ifndef GL_COMPRESSED_RG_RGTC2
#define GL_COMPRESSED_RG_RGTC2 0x8DBD
#endif
#endif

#include <cassert>
#include <iostream>

using namespace std;
using namespace canvas;

size_t OpenGLTexture::total_textures = 0;
vector<unsigned int> OpenGLTexture::freed_textures;
bool OpenGLTexture::global_init = false;

OpenGLTexture::OpenGLTexture(Surface & surface)
  : Texture(surface.getLogicalWidth(), surface.getLogicalHeight(), surface.getActualWidth(), surface.getActualHeight(), surface.getMinFilter(), surface.getMagFilter(), surface.getTargetFormat(), 1) {
  assert(getInternalFormat());
  auto image = surface.createImage();
  updateData(*image, 0, 0);
}

static GLenum getOpenGLInternalFormat(InternalFormat internal_format) {
  switch (internal_format) {
  case NO_FORMAT: return 0;
  case R8: return GL_R8;
  case RG8: return GL_RG8;
  case RGB565: return GL_RGB565;
  case RGBA4: return GL_RGBA4;
  case RGBA8: return GL_RGBA8;
  case RGB8: return GL_RGB8;
  case RGB8_24: return GL_RGBA8;
  case RED_RGTC1: return GL_COMPRESSED_RED_RGTC1;
  case RG_RGTC2: return GL_COMPRESSED_RG_RGTC2;
  case RGB_ETC1: return GL_COMPRESSED_RGB8_ETC2;
  case RGB_DXT1: return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
  case RGBA_DXT5: return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
  case LUMINANCE_ALPHA: return GL_RG8;
  case LA44: return GL_R8; // pack luminance and alpha to single byte
  case R32F: return GL_R32F;

  }
  assert(0);
  return 0;
}

static GLenum getOpenGLFilterType(FilterMode mode) {
  switch (mode) {
  case NEAREST: return GL_NEAREST;
  case LINEAR: return GL_LINEAR;
  case LINEAR_MIPMAP_LINEAR: return GL_LINEAR_MIPMAP_LINEAR;
  }
  return 0;
}

void
OpenGLTexture::updateCompressedData(const Image & image, unsigned int x, unsigned int y) {
  unsigned int offset = 0;
  unsigned int current_width = image.getWidth(), current_height = image.getHeight();
  GLenum format = getOpenGLInternalFormat(getInternalFormat());
  for (unsigned int level = 0; level < image.getLevels(); level++) {
    size_t size = image.calculateOffset(level + 1) - image.calculateOffset(level);
    // cerr << "compressed tex: x = " << x << ", y = " << y << ", l = " << (level+1) << "/" << image.getLevels() << ", w = " << current_width << ", h = " << current_height << ", offset = " << offset << ", size = " << size << endl;
    glCompressedTexSubImage2D(GL_TEXTURE_2D, level, x, y, current_width, current_height, format, (GLsizei)size, image.getData() + offset);
    offset += size;
    current_width /= 2;
    current_height /= 2;
    x /= 2;
    y /= 2;
  }
}

void
OpenGLTexture::updatePlainData(const Image & image, unsigned int x, unsigned int y) {
  unsigned int offset = 0;
  unsigned int current_width = image.getWidth(), current_height = image.getHeight();
  GLenum format = getOpenGLInternalFormat(getInternalFormat());

  for (unsigned int level = 0; level < image.getLevels(); level++) {
    size_t size = image.calculateOffset(level + 1) - image.calculateOffset(level);
    // cerr << "plain tex: x = " << x << ", y = " << y << ", l = " << (level+1) << "/" << image.getLevels() << ", w = " << current_width << ", h = " << current_height << ", size = " << size << ", offset = " << offset << endl;

    if (getInternalFormat() == RGBA8) {
      assert(image.getData());
#if defined __APPLE__ || defined ANDROID
      glTexSubImage2D(GL_TEXTURE_2D, level, x, y, current_width, current_height, GL_RGBA, GL_UNSIGNED_BYTE, image.getData() + offset);
#else
      glTexSubImage2D(GL_TEXTURE_2D, level, x, y, current_width, current_height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, image.getData() + offset);
      // glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, tmp_image.getWidth(), height, GL_BGRA_EXT, GL_UNSIGNED_BYTE, image.getData());
#endif
    } else if (getInternalFormat() == RGBA4) {
      glTexSubImage2D(GL_TEXTURE_2D, level, x, y, current_width, current_height, GL_RGBA4, GL_UNSIGNED_SHORT_4_4_4_4, image.getData() + offset);
    } else if (getInternalFormat() == LA44) {
      glTexSubImage2D(GL_TEXTURE_2D, level, x, y, current_width, current_height, GL_RED, GL_UNSIGNED_BYTE, image.getData() + offset);
    } else if (getInternalFormat() == RGB565) {
      glTexSubImage2D(GL_TEXTURE_2D, level, x, y, current_width, current_height, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, image.getData() + offset);
    } else if (getInternalFormat() == R32F) {
      glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, current_width, current_height, GL_RED, GL_FLOAT, image.getData() + offset);
    } else {
      cerr << "unhandled format " << int(getInternalFormat()) << endl;
      assert(0);
    }

    // glTexSubImage2D(GL_TEXTURE_2D, level, x, y, current_width, current_height, getOpenGLInternalFormat(getInternalFormat()), size, image.getData() + offset);

    offset += size;
    current_width /= 2;
    current_height /= 2;
    x /= 2;
    y /= 2;
  }
}

void
OpenGLTexture::updateData(const Image & image, unsigned int x, unsigned int y) {
  if (!global_init) {
    global_init = true;
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  }

  bool initialize = false;
  if (!texture_id) {
    initialize = true;
    glGenTextures(1, &texture_id);
    // cerr << "created texture id " << texture_id << " (total = " << total_textures << ")" << endl;
    if (texture_id >= 1) total_textures++;
  }
  assert(texture_id >= 1);

  glBindTexture(GL_TEXTURE_2D, texture_id);

  bool has_mipmaps = getMinFilter() == LINEAR_MIPMAP_LINEAR;
  if (initialize) {
    glTexStorage2D(GL_TEXTURE_2D, has_mipmaps ? getMipmapLevels() : 1, getOpenGLInternalFormat(getInternalFormat()), getActualWidth(), getActualHeight());

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, getOpenGLFilterType(getMinFilter()));
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, getOpenGLFilterType(getMagFilter()));

    if (x != 0 || y != 0 || image.getWidth() != getActualWidth() || image.getHeight() != getActualHeight()) {
      int levels = has_mipmaps ? getMipmapLevels() : 1;
      if (getInternalFormat() == RGB_ETC1 || getInternalFormat() == RGB_DXT1 ||
	  getInternalFormat() == RED_RGTC1
	  ) {
	Image img(getInternalFormat(), getActualWidth(), getActualHeight(), levels);
	updateCompressedData(img, 0, 0);
      } else if (getInternalFormat() == RGBA8 || getInternalFormat() == LA44 ||
		 getInternalFormat() == RGB565 || getInternalFormat() == R32F) {
	Image img(getInternalFormat(), getActualWidth(), getActualHeight(), levels);
	updatePlainData(img, 0, 0);
      } else {
	assert(0);
      }
    }
  }

  if (getInternalFormat() == R32F) {
    glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, image.getWidth(), image.getHeight(), GL_RED, GL_FLOAT, image.getData());
  } else if (getInternalFormat() == R8) {
    glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, image.getWidth(), image.getHeight(), GL_RED, GL_UNSIGNED_BYTE, image.getData());
  } else if (getInternalFormat() == LA44) {
    auto tmp_image = image.convert(LA44);
    glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, tmp_image->getWidth(), tmp_image->getHeight(), GL_RED, GL_UNSIGNED_BYTE, tmp_image->getData());
  } else if (getInternalFormat() == LUMINANCE_ALPHA) {
    if (image.getInternalFormat() == LUMINANCE_ALPHA) {
      glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, image.getWidth(), image.getHeight(), GL_RG, GL_UNSIGNED_BYTE, image.getData());
    } else {
      auto tmp_image = image.convert(LUMINANCE_ALPHA);
      glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, tmp_image->getWidth(), tmp_image->getHeight(), GL_RG, GL_UNSIGNED_BYTE, tmp_image->getData());
    }
  } else if (getInternalFormat() == RGB565) {
    if (image.getInternalFormat() == RGB565) {
      updatePlainData(image, x, y);
    } else {
      cerr << "OpenGLTexture: doing online image conversion for RGB565 (SLOW)\n";
      auto tmp_image = image.convert(RGB565);
      updatePlainData(*tmp_image, x, y);
    }
  } else if (getInternalFormat() == RGBA4) {
    if (image.getInternalFormat() == RGBA4) {
      updatePlainData(image, x, y);
    } else {
      cerr << "OpenGLTexture: doing online image conversion for RGBA4 (SLOW)\n";
      auto tmp_image = image.convert(RGBA4);
      updatePlainData(*tmp_image, x, y);
      // glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, tmp_image->getWidth(), tmp_image->getHeight(), GL_RGBA4, GL_UNSIGNED_SHORT_4_4_4_4, tmp_image->getData());
    }
  } else if (getInternalFormat() == RGB_ETC1) {
    if (image.getInternalFormat() == RGB_ETC1) {
      updateCompressedData(image, x, y);
    } else {
      auto fd = image.getImageFormat();
      cerr << "WARNING: compression should be done in thread (bpp = " << fd.getBytesPerPixel() << ", c = " << int(fd.getCompression()) << ", ch = " << fd.getNumChannels() << ")\n";
      auto tmp_image = image.convert(RGB_ETC1);
      updateCompressedData(*tmp_image, x, y);
    }
  } else if (getInternalFormat() == RGB_DXT1) {
    if (image.getInternalFormat() == RGB_DXT1) {
      updateCompressedData(image, x, y);
    } else {
      cerr << "WARNING: compression should be done in thread\n";
      auto tmp_image = image.convert(RGB_DXT1);
      updateCompressedData(*tmp_image, x, y);
    }
  } else if (getInternalFormat() == RED_RGTC1) {
    if (image.getInternalFormat() == RED_RGTC1) {
      updateCompressedData(image, x, y);
    } else {
      cerr << "WARNING: compression should be done in thread\n";
      auto tmp_image = image.convert(RED_RGTC1);
      updateCompressedData(*tmp_image, x, y);
    }
  } else if (getInternalFormat() == RG_RGTC2) {
    if (image.getInternalFormat() == RG_RGTC2) {
      updateCompressedData(image, x, y);
    } else {
      cerr << "WARNING: compression should be done in thread\n";
      auto tmp_image = image.convert(RG_RGTC2);
      updateCompressedData(*tmp_image, x, y);
    }
  } else {
    updatePlainData(image, x, y);
  }

  if (has_mipmaps && image.getLevels() == 1) {
    need_mipmaps = true;
  }

  glBindTexture(GL_TEXTURE_2D, 0);
}

void
OpenGLTexture::generateMipmaps() {
  if (need_mipmaps) {
    if (getInternalFormat() != RGB_DXT1 && getInternalFormat() != RGB_ETC1 && getInternalFormat() != LA44 && getInternalFormat() != RED_RGTC1 && getInternalFormat() != RG_RGTC2) {
      glGenerateMipmap(GL_TEXTURE_2D);
    } else {
      cerr << "unable to generate mipmaps for compressed texture!\n";
    }
    need_mipmaps = false;
  }
}

void
OpenGLTexture::releaseTextures() {
  if (!freed_textures.empty()) {
    // cerr << "DELETING TEXTURES: " << OpenGLTexture::getFreedTextures().size() << "/" << OpenGLTexture::getNumTextures() << endl;

    for (vector<unsigned int>::const_iterator it = freed_textures.begin(); it != freed_textures.end(); it++) {
      GLuint texid = *it;
      glDeleteTextures(1, &texid);
    }
    freed_textures.clear();
  }
}

TextureRef
OpenGLTexture::createTexture(unsigned int _logical_width, unsigned int _logical_height, unsigned int _actual_width, unsigned int _actual_height, FilterMode min_filter, FilterMode mag_filter, InternalFormat _internal_format, unsigned int mipmap_levels) {
  assert(_internal_format);
  return TextureRef(_logical_width, _logical_height, _actual_width, _actual_height, new OpenGLTexture(_logical_width, _logical_height, _actual_width, _actual_height, min_filter, mag_filter, _internal_format, mipmap_levels));
}

TextureRef
OpenGLTexture::createTexture(Surface & surface) {
  return TextureRef( surface.getLogicalWidth(),
		     surface.getLogicalHeight(),
		     surface.getActualWidth(),
		     surface.getActualHeight(),
		     new OpenGLTexture(surface)
		     );
}
<|endoftext|>