<commit_before>#include "UnrealCVPrivate.h"
#include "ObjectPainter.h"
#include "StaticMeshResources.h"
#include "UE4CVServer.h"
#include "SceneViewport.h"

static TMap<uint8, uint8> DecodeColorValue; // Convert Encoded Color to Display Color, for numerical issue

// Do Gamma correction
void BuildDecodeColorValue(float InvGamma)
{
	DecodeColorValue.Empty();
	for (int32 DisplayIter = 0; DisplayIter < 256; DisplayIter++) // if use uint8, this loop will go forever
	{
		int32 EncodeVal = FMath::FloorToInt(FMath::Pow((float)DisplayIter / 255.0, InvGamma) * 255.0);
		check(EncodeVal >= 0);
		check(EncodeVal <= 255);
		if (!DecodeColorValue.Find(EncodeVal))
		{
			DecodeColorValue.Emplace(EncodeVal, DisplayIter);
		}
	}
	check(DecodeColorValue.Num() < 256); // Not all of them can find a correspondence due to numerical issue
}

bool GetDisplayValue(uint8 InEncodedValue, uint8& OutDisplayValue, float InvGamma)
{
	static float CachedInvGamma;
	if (DecodeColorValue.Num() == 0 || CachedInvGamma != InvGamma)
	{
		BuildDecodeColorValue(InvGamma);
		CachedInvGamma = InvGamma;
	}

	if (DecodeColorValue.Find(InEncodedValue))
	{
		OutDisplayValue = DecodeColorValue[InEncodedValue];
		return true;
	}
	else
	{
		return false;
	}
}

FObjectPainter& FObjectPainter::Get()
{
	static FObjectPainter Singleton(NULL);
	return Singleton;
}

FObjectPainter::FObjectPainter(ULevel* InLevel)
{
	this->Level = InLevel;
}

FExecStatus FObjectPainter::SetActorColor(FString ObjectName, FColor Color)
{
	auto ObjectsMapping = GetObjectsMapping();
	if (ObjectsMapping.Contains(ObjectName))
	{
		AActor* Actor = ObjectsMapping[ObjectName];
		if (PaintObject(Actor, Color))
		{
			ObjectsColorMapping.Emplace(ObjectName, Color);
			return FExecStatus::OK();
		}
		else
		{
			return FExecStatus::Error(FString::Printf(TEXT("Failed to paint object %s"), *ObjectName));
		}
	}
	else
	{
		return FExecStatus::Error(FString::Printf(TEXT("Object %s not exist"), *ObjectName));
	}
}

FExecStatus FObjectPainter::GetActorColor(FString ObjectName)
{
	if (ObjectsColorMapping.Contains(ObjectName))
	{
		FColor ObjectColor = ObjectsColorMapping[ObjectName]; // Make sure the object exist
		FString Message = ObjectColor.ToString();
		// FString Message = "%.3f %.3f %.3f %.3f";
		return FExecStatus::OK(Message);
	}
	else
	{
		return FExecStatus::Error(FString::Printf(TEXT("Object %s not exist"), *ObjectName));
	}
}

FExecStatus FObjectPainter::GetObjectList()
{
	TArray<FString> Keys;
	GetObjectsMapping().GetKeys(Keys);
	FString Message = "";
	for (auto ObjectName : Keys)
	{
		Message += ObjectName + " ";
	}
	Message = Message.LeftChop(1);
	return FExecStatus::OK(Message);
}

TMap<FString, AActor*>& FObjectPainter::GetObjectsMapping()
{
	static TMap<FString, AActor*> ObjectsMapping;
	if (!this->Level) return ObjectsMapping;
	check(Level);
	if (ObjectsMapping.Num() == 0)
	{
		for (AActor* Actor : Level->Actors)
		{
			if (Actor && Actor->IsA(AStaticMeshActor::StaticClass())) // Only StaticMeshActor is interesting
			{
				FString ActorLabel = Actor->GetActorLabel();
				ObjectsMapping.Emplace(ActorLabel, Actor);
			}
		}
	}
	return ObjectsMapping;
}

bool FObjectPainter::PaintRandomColors()
{
	FSceneViewport* SceneViewport = FUE4CVServer::Get().GetPawn()->GetWorld()->GetGameViewport()->GetGameViewport();
	float Gamma = SceneViewport->GetDisplayGamma();
	check(Gamma != 0);
	if (Gamma == 0) Gamma = 1;
	float InvGamma = 1 / Gamma;
	BuildDecodeColorValue(InvGamma);
	// Iterate over all actors
	// ULevel* Level = GetLevel();

	// Get a random color
	check(Level);
	for (auto Actor : Level->Actors)
	{
		if (Actor && Actor->IsA(AStaticMeshActor::StaticClass())) // Only StaticMeshActor is interesting
		{
			FString ActorLabel = Actor->GetActorLabel();
			// FString ActorLabel = Actor->GetHumanReadableName();
			// FColor NewColor = FColor(FMath::RandRange(0, 255), FMath::RandRange(0, 255), FMath::RandRange(0, 255), 255);
			// FColor NewColor = FColor(1, 1, 1, 255);
			FColor NewColor;
			TArray<uint8> ValidVals;
			DecodeColorValue.GenerateKeyArray(ValidVals);

			NewColor.R = ValidVals[FMath::RandRange(0, ValidVals.Num()-1)];
			NewColor.G = ValidVals[FMath::RandRange(0, ValidVals.Num()-1)];
			NewColor.B = ValidVals[FMath::RandRange(0, ValidVals.Num()-1)];
			NewColor.A = 255;
			// FColor NewColor = FColor(128, 128, 128, 255);

			ObjectsColorMapping.Emplace(ActorLabel, NewColor);
			// if (Actor->GetActorLabel() == FString("SM_Door43"))
			{
				check(PaintObject(Actor, NewColor));
			}
		}
	}

	// Paint actor using floodfill.
	// return FExecStatus::OK();
	return true;
}

/** DisplayColor is the color that the screen will show
	If DisplayColor.R = 128, the display will show 0.5 voltage
	To achieve this, UnrealEngine will do gamma correction.
	The value on image will be 187.
	https://en.wikipedia.org/wiki/Gamma_correction#Methods_to_perform_display_gamma_correction_in_computing
*/
bool FObjectPainter::PaintObject(AActor* Actor, const FColor& Color, bool IsColorGammaEncoded)
{
	if (!Actor) return false;

	FColor NewColor;
	if (IsColorGammaEncoded)
	{
		FSceneViewport* SceneViewport = FUE4CVServer::Get().GetPawn()->GetWorld()->GetGameViewport()->GetGameViewport();
		float Gamma = SceneViewport->GetDisplayGamma();
		check(Gamma != 0);
		if (Gamma == 0) Gamma = 1;
		float InvGamma = 1 / Gamma;

		bool Converted = true;
		Converted &= GetDisplayValue(Color.R, NewColor.R, InvGamma);
		Converted &= GetDisplayValue(Color.G, NewColor.G, InvGamma);
		Converted &= GetDisplayValue(Color.B, NewColor.B, InvGamma);
		if (!Converted)
		{
			UE_LOG(LogTemp, Error, TEXT("Can not convert encoded color %d %d %d"), Color.R, Color.G, Color.B);
			return false;
		}

		// See UnrealEngine/Engine/Shaders/GammaCorrection.usf
		/* This is the real calculation, but due to numerical issue, we need to use table lookup
		NewColor.R = FMath::RoundToInt(FMath::Pow(Color.R / 255.0, Gamma) * 255.0);
		NewColor.G = FMath::RoundToInt(FMath::Pow(Color.G / 255.0, Gamma) * 255.0);
		NewColor.B = FMath::RoundToInt(FMath::Pow(Color.B / 255.0, Gamma) * 255.0);
		*/
	}
	else
	{
		NewColor = Color;
	}

	TArray<UMeshComponent*> PaintableComponents;
	// TInlineComponentArray<UMeshComponent*> MeshComponents;
	// Actor->GetComponents<UMeshComponent>(MeshComponents);
	Actor->GetComponents<UMeshComponent>(PaintableComponents);

	for (auto MeshComponent : PaintableComponents)
	{
		if (UStaticMeshComponent* StaticMeshComponent = Cast<UStaticMeshComponent>(MeshComponent))
		{
			if (UStaticMesh* StaticMesh = StaticMeshComponent->StaticMesh)
			{
				uint32 PaintingMeshLODIndex = 0;
				uint32 NumLODLevel = StaticMeshComponent->StaticMesh->RenderData->LODResources.Num();
				check(NumLODLevel == 1);
				FStaticMeshLODResources& LODModel = StaticMeshComponent->StaticMesh->RenderData->LODResources[PaintingMeshLODIndex];
				FStaticMeshComponentLODInfo* InstanceMeshLODInfo = NULL;

				// PaintingMeshLODIndex + 1 is the minimum requirement, enlarge if not satisfied
				StaticMeshComponent->SetLODDataCount(PaintingMeshLODIndex + 1, StaticMeshComponent->LODData.Num());
				InstanceMeshLODInfo = &StaticMeshComponent->LODData[PaintingMeshLODIndex];

				// Setup OverrideVertexColors
				// if (!InstanceMeshLODInfo->OverrideVertexColors) // TODO: Check this
				{
					InstanceMeshLODInfo->OverrideVertexColors = new FColorVertexBuffer;

					FColor FillColor = FColor(255, 255, 255, 255);
					InstanceMeshLODInfo->OverrideVertexColors->InitFromSingleColor(FColor::White, LODModel.GetNumVertices());
				}

				uint32 NumVertices = LODModel.GetNumVertices();
				check(InstanceMeshLODInfo->OverrideVertexColors);
				check(NumVertices <= InstanceMeshLODInfo->OverrideVertexColors->GetNumVertices());
				// StaticMeshComponent->CachePaintedDataIfNecessary();

				for (uint32 ColorIndex = 0; ColorIndex < NumVertices; ++ColorIndex)
				{
					// FColor NewColor = FColor(FMath::RandRange(0, 255), FMath::RandRange(0, 255), FMath::RandRange(0, 255), 255);
					// LODModel.ColorVertexBuffer.VertexColor(ColorIndex) = NewColor;  // This is vertex level
					// Need to initialize the vertex buffer first
					uint32 NumOverrideVertexColors = InstanceMeshLODInfo->OverrideVertexColors->GetNumVertices();
					uint32 NumPaintedVertices = InstanceMeshLODInfo->PaintedVertices.Num();
					// check(NumOverrideVertexColors == NumPaintedVertices);
					InstanceMeshLODInfo->OverrideVertexColors->VertexColor(ColorIndex) = NewColor;
					// InstanceMeshLODInfo->PaintedVertices[ColorIndex].Color = NewColor;
				}
				BeginInitResource(InstanceMeshLODInfo->OverrideVertexColors);
				StaticMeshComponent->MarkRenderStateDirty();
				// BeginUpdateResourceRHI(InstanceMeshLODInfo->OverrideVertexColors);

				/*
				// TODO: Need to check other LOD levels
				// Use flood fill to paint mesh vertices
				UE_LOG(LogTemp, Warning, TEXT("%s:%s has %d vertices"), *Actor->GetActorLabel(), *StaticMeshComponent->GetName(), NumVertices);

				if (LODModel.ColorVertexBuffer.GetNumVertices() == 0)
				{
					// Mesh doesn't have a color vertex buffer yet!  We'll create one now.
					LODModel.ColorVertexBuffer.InitFromSingleColor(FColor(255, 255, 255, 255), LODModel.GetNumVertices());
				}

				*/
			}
		}
	}
	return true;
}

void FObjectPainter::SetLevel(ULevel* InLevel)
{
	Level = InLevel;
}
<commit_msg>Add color map.<commit_after>#include "UnrealCVPrivate.h"
#include "ObjectPainter.h"
#include "StaticMeshResources.h"
#include "UE4CVServer.h"
#include "SceneViewport.h"

static TMap<uint8, uint8> DecodeColorValue; // Convert Encoded Color to Display Color, for numerical issue

// Do Gamma correction
void BuildDecodeColorValue(float InvGamma)
{
	DecodeColorValue.Empty();
	for (int32 DisplayIter = 0; DisplayIter < 256; DisplayIter++) // if use uint8, this loop will go forever
	{
		int32 EncodeVal = FMath::FloorToInt(FMath::Pow((float)DisplayIter / 255.0, InvGamma) * 255.0);
		check(EncodeVal >= 0);
		check(EncodeVal <= 255);
		if (!DecodeColorValue.Find(EncodeVal))
		{
			DecodeColorValue.Emplace(EncodeVal, DisplayIter);
		}
	}
	check(DecodeColorValue.Num() < 256); // Not all of them can find a correspondence due to numerical issue
}

bool GetDisplayValue(uint8 InEncodedValue, uint8& OutDisplayValue, float InvGamma)
{
	static float CachedInvGamma;
	if (DecodeColorValue.Num() == 0 || CachedInvGamma != InvGamma)
	{
		BuildDecodeColorValue(InvGamma);
		CachedInvGamma = InvGamma;
	}

	if (DecodeColorValue.Find(InEncodedValue))
	{
		OutDisplayValue = DecodeColorValue[InEncodedValue];
		return true;
	}
	else
	{
		return false;
	}
}

int32 GetChannelValue(uint32 Index)
{
	static int32 Values[256] = { 0 };
	static bool Init = false;
	if (!Init)
	{
		float Step = 256;
		uint32 Iter = 0;
		Values[0] = 0;
		while (Step >= 1)
		{
			for (uint32 Value = Step-1; Value <= 256; Value += Step * 2)
			{
				Iter++;
				Values[Iter] = Value;
			}
			Step /= 2;
		}
		Init = true;
	}
	if (Index >= 0 && Index <= 255)
	{
		return Values[Index];
	}
	else
	{
		UE_LOG(LogTemp, Error, TEXT("Invalid channel index"));
		check(false);
		return -1;
	}
}

void GetColors(int32 MaxVal, bool Fix1, bool Fix2, bool Fix3, TArray<FColor>& ColorMap)
{
	for (int32 I = 0; I <= (Fix1 ? 0 : MaxVal-1); I++)
	{
		for (int32 J = 0; J <= (Fix2 ? 0 : MaxVal-1); J++)
		{
			for (int32 K = 0; K <= (Fix3 ? 0 : MaxVal-1); K++)
			{
				uint8 R = GetChannelValue(Fix1 ? MaxVal : I);
				uint8 G = GetChannelValue(Fix2 ? MaxVal : J);
				uint8 B = GetChannelValue(Fix3 ? MaxVal : K);
				FColor Color(R, G, B, 255);
				ColorMap.Add(Color);
			}
		}
	}
}

FColor GetColorFromColorMap(int32 ObjectIndex)
{
	static TArray<FColor> ColorMap;
	if (ColorMap.Num() == 0)
	{
		for (int32 MaxChannelIndex = 0; MaxChannelIndex < 10; MaxChannelIndex++) // Get color map for 1000 objects
		{
			// GetColors(MaxChannelIndex, false, false, false, ColorMap);
			GetColors(MaxChannelIndex, false, false, true , ColorMap);
			GetColors(MaxChannelIndex, false, true , false, ColorMap);
			GetColors(MaxChannelIndex, false, true , true , ColorMap);
			GetColors(MaxChannelIndex, true , false, false, ColorMap);
			GetColors(MaxChannelIndex, true , false, true , ColorMap);
			GetColors(MaxChannelIndex, true , true , false, ColorMap);
			GetColors(MaxChannelIndex, true , true , true , ColorMap);
		}
	}
	check(ColorMap.Num() == 1000);
	check(ObjectIndex >= 0 && ObjectIndex <= 1000);
	return ColorMap[ObjectIndex];
}

FObjectPainter& FObjectPainter::Get()
{
	static FObjectPainter Singleton(NULL);
	return Singleton;
}

FObjectPainter::FObjectPainter(ULevel* InLevel)
{
	this->Level = InLevel;
}

FExecStatus FObjectPainter::SetActorColor(FString ObjectName, FColor Color)
{
	auto ObjectsMapping = GetObjectsMapping();
	if (ObjectsMapping.Contains(ObjectName))
	{
		AActor* Actor = ObjectsMapping[ObjectName];
		if (PaintObject(Actor, Color))
		{
			ObjectsColorMapping.Emplace(ObjectName, Color);
			return FExecStatus::OK();
		}
		else
		{
			return FExecStatus::Error(FString::Printf(TEXT("Failed to paint object %s"), *ObjectName));
		}
	}
	else
	{
		return FExecStatus::Error(FString::Printf(TEXT("Object %s not exist"), *ObjectName));
	}
}

FExecStatus FObjectPainter::GetActorColor(FString ObjectName)
{
	if (ObjectsColorMapping.Contains(ObjectName))
	{
		FColor ObjectColor = ObjectsColorMapping[ObjectName]; // Make sure the object exist
		FString Message = ObjectColor.ToString();
		// FString Message = "%.3f %.3f %.3f %.3f";
		return FExecStatus::OK(Message);
	}
	else
	{
		return FExecStatus::Error(FString::Printf(TEXT("Object %s not exist"), *ObjectName));
	}
}

FExecStatus FObjectPainter::GetObjectList()
{
	TArray<FString> Keys;
	GetObjectsMapping().GetKeys(Keys);
	FString Message = "";
	for (auto ObjectName : Keys)
	{
		Message += ObjectName + " ";
	}
	Message = Message.LeftChop(1);
	return FExecStatus::OK(Message);
}

TMap<FString, AActor*>& FObjectPainter::GetObjectsMapping()
{
	static TMap<FString, AActor*> ObjectsMapping;
	if (!this->Level) return ObjectsMapping;
	check(Level);
	if (ObjectsMapping.Num() == 0)
	{
		for (AActor* Actor : Level->Actors)
		{
			if (Actor && Actor->IsA(AStaticMeshActor::StaticClass())) // Only StaticMeshActor is interesting
			{
				FString ActorLabel = Actor->GetActorLabel();
				ObjectsMapping.Emplace(ActorLabel, Actor);
			}
		}
	}
	return ObjectsMapping;
}

bool FObjectPainter::PaintRandomColors()
{
	FSceneViewport* SceneViewport = FUE4CVServer::Get().GetPawn()->GetWorld()->GetGameViewport()->GetGameViewport();
	float Gamma = SceneViewport->GetDisplayGamma();
	check(Gamma != 0);
	if (Gamma == 0) Gamma = 1;
	float InvGamma = 1 / Gamma;
	BuildDecodeColorValue(InvGamma);
	// Iterate over all actors
	// ULevel* Level = GetLevel();

	// Get a random color
	check(Level);
	uint32 ObjectIndex = 0;
	for (auto Actor : Level->Actors)
	{
		if (Actor && Actor->IsA(AStaticMeshActor::StaticClass())) // Only StaticMeshActor is interesting
		{
			FString ActorLabel = Actor->GetActorLabel();
			// FString ActorLabel = Actor->GetHumanReadableName();
			// FColor NewColor = FColor(FMath::RandRange(0, 255), FMath::RandRange(0, 255), FMath::RandRange(0, 255), 255);
			// FColor NewColor = FColor(1, 1, 1, 255);
			/*
			FColor NewColor;
			TArray<uint8> ValidVals;
			DecodeColorValue.GenerateKeyArray(ValidVals);

			NewColor.R = ValidVals[FMath::RandRange(0, ValidVals.Num()-1)];
			NewColor.G = ValidVals[FMath::RandRange(0, ValidVals.Num()-1)];
			NewColor.B = ValidVals[FMath::RandRange(0, ValidVals.Num()-1)];
			NewColor.A = 255;
			*/
			// FColor NewColor = FColor(128, 128, 128, 255);
			// FColor NewColor = FColor::MakeRandomColor();
			FColor NewColor = GetColorFromColorMap(ObjectIndex);

			ObjectsColorMapping.Emplace(ActorLabel, NewColor);
			check(PaintObject(Actor, NewColor));
			ObjectIndex++;
		}
	}

	// Paint actor using floodfill.
	// return FExecStatus::OK();
	return true;
}

/** DisplayColor is the color that the screen will show
	If DisplayColor.R = 128, the display will show 0.5 voltage
	To achieve this, UnrealEngine will do gamma correction.
	The value on image will be 187.
	https://en.wikipedia.org/wiki/Gamma_correction#Methods_to_perform_display_gamma_correction_in_computing
*/
bool FObjectPainter::PaintObject(AActor* Actor, const FColor& Color, bool IsColorGammaEncoded)
{
	if (!Actor) return false;

	FColor NewColor;
	if (IsColorGammaEncoded)
	{
		/*
		FSceneViewport* SceneViewport = FUE4CVServer::Get().GetPawn()->GetWorld()->GetGameViewport()->GetGameViewport();
		float Gamma = SceneViewport->GetDisplayGamma();
		check(Gamma != 0);
		if (Gamma == 0) Gamma = 1;
		float InvGamma = 1 / Gamma;

		bool Converted = true;
		Converted &= GetDisplayValue(Color.R, NewColor.R, InvGamma);
		Converted &= GetDisplayValue(Color.G, NewColor.G, InvGamma);
		Converted &= GetDisplayValue(Color.B, NewColor.B, InvGamma);
		if (!Converted)
		{
			UE_LOG(LogTemp, Error, TEXT("Can not convert encoded color %d %d %d"), Color.R, Color.G, Color.B);
			return false;
		}

		// See UnrealEngine/Engine/Shaders/GammaCorrection.usf
		// This is the real calculation, but due to numerical issue, we need to use table lookup
		// NewColor.R = FMath::RoundToInt(FMath::Pow(Color.R / 255.0, Gamma) * 255.0);
		// NewColor.G = FMath::RoundToInt(FMath::Pow(Color.G / 255.0, Gamma) * 255.0);
		// NewColor.B = FMath::RoundToInt(FMath::Pow(Color.B / 255.0, Gamma) * 255.0);
		*/
		FLinearColor LinearColor = FLinearColor::FromPow22Color(Color);
		NewColor = LinearColor.ToFColor(false);
		// NewColor = LinearColor.ToFColor(true); // this is incorrect, not sRGB, just pow22
	}
	else
	{
		NewColor = Color;
	}

	TArray<UMeshComponent*> PaintableComponents;
	// TInlineComponentArray<UMeshComponent*> MeshComponents;
	// Actor->GetComponents<UMeshComponent>(MeshComponents);
	Actor->GetComponents<UMeshComponent>(PaintableComponents);

	for (auto MeshComponent : PaintableComponents)
	{
		if (UStaticMeshComponent* StaticMeshComponent = Cast<UStaticMeshComponent>(MeshComponent))
		{
			if (UStaticMesh* StaticMesh = StaticMeshComponent->StaticMesh)
			{
				uint32 PaintingMeshLODIndex = 0;
				uint32 NumLODLevel = StaticMeshComponent->StaticMesh->RenderData->LODResources.Num();
				check(NumLODLevel == 1);
				FStaticMeshLODResources& LODModel = StaticMeshComponent->StaticMesh->RenderData->LODResources[PaintingMeshLODIndex];
				FStaticMeshComponentLODInfo* InstanceMeshLODInfo = NULL;

				// PaintingMeshLODIndex + 1 is the minimum requirement, enlarge if not satisfied
				StaticMeshComponent->SetLODDataCount(PaintingMeshLODIndex + 1, StaticMeshComponent->LODData.Num());
				InstanceMeshLODInfo = &StaticMeshComponent->LODData[PaintingMeshLODIndex];

				// Setup OverrideVertexColors
				// if (!InstanceMeshLODInfo->OverrideVertexColors) // TODO: Check this
				{
					InstanceMeshLODInfo->OverrideVertexColors = new FColorVertexBuffer;

					FColor FillColor = FColor(255, 255, 255, 255);
					InstanceMeshLODInfo->OverrideVertexColors->InitFromSingleColor(FColor::White, LODModel.GetNumVertices());
				}

				uint32 NumVertices = LODModel.GetNumVertices();
				check(InstanceMeshLODInfo->OverrideVertexColors);
				check(NumVertices <= InstanceMeshLODInfo->OverrideVertexColors->GetNumVertices());
				// StaticMeshComponent->CachePaintedDataIfNecessary();

				for (uint32 ColorIndex = 0; ColorIndex < NumVertices; ++ColorIndex)
				{
					// FColor NewColor = FColor(FMath::RandRange(0, 255), FMath::RandRange(0, 255), FMath::RandRange(0, 255), 255);
					// LODModel.ColorVertexBuffer.VertexColor(ColorIndex) = NewColor;  // This is vertex level
					// Need to initialize the vertex buffer first
					uint32 NumOverrideVertexColors = InstanceMeshLODInfo->OverrideVertexColors->GetNumVertices();
					uint32 NumPaintedVertices = InstanceMeshLODInfo->PaintedVertices.Num();
					// check(NumOverrideVertexColors == NumPaintedVertices);
					InstanceMeshLODInfo->OverrideVertexColors->VertexColor(ColorIndex) = NewColor;
					// InstanceMeshLODInfo->PaintedVertices[ColorIndex].Color = NewColor;
				}
				BeginInitResource(InstanceMeshLODInfo->OverrideVertexColors);
				StaticMeshComponent->MarkRenderStateDirty();
				// BeginUpdateResourceRHI(InstanceMeshLODInfo->OverrideVertexColors);

				/*
				// TODO: Need to check other LOD levels
				// Use flood fill to paint mesh vertices
				UE_LOG(LogTemp, Warning, TEXT("%s:%s has %d vertices"), *Actor->GetActorLabel(), *StaticMeshComponent->GetName(), NumVertices);

				if (LODModel.ColorVertexBuffer.GetNumVertices() == 0)
				{
					// Mesh doesn't have a color vertex buffer yet!  We'll create one now.
					LODModel.ColorVertexBuffer.InitFromSingleColor(FColor(255, 255, 255, 255), LODModel.GetNumVertices());
				}

				*/
			}
		}
	}
	return true;
}

void FObjectPainter::SetLevel(ULevel* InLevel)
{
	Level = InLevel;
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <windows.h>
#include <shlwapi.h>

#include "base/command_line.h"
#include "base/environment.h"
#include "base/file_util.h"
#include "base/trace_event.h"
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "base/utf_string_conversions.h"
#include "chrome/app/breakpad_win.h"
#include "chrome/app/client_util.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/result_codes.h"
#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/install_util.h"
#include "chrome/installer/util/google_update_constants.h"
#include "chrome/installer/util/util_constants.h"

namespace {
// The entry point signature of chrome.dll.
typedef int (*DLL_MAIN)(HINSTANCE, sandbox::SandboxInterfaceInfo*, wchar_t*);

typedef void (*RelaunchChromeBrowserWithNewCommandLineIfNeededFunc)();

// Not generic, we only handle strings up to 128 chars.
bool ReadRegistryStr(HKEY key, const wchar_t* name, std::wstring* value) {
  BYTE out[128 * sizeof(wchar_t)];
  DWORD size = sizeof(out);
  DWORD type = 0;
  if (ERROR_SUCCESS != ::RegQueryValueExW(key, name, NULL, &type, out, &size))
    return false;
  if (type != REG_SZ)
    return false;
  value->assign(reinterpret_cast<wchar_t*>(out));
  return true;
}

// Gets chrome version according to the load path. |exe_path| must be the
// backslash terminated directory of the current chrome.exe.
bool GetVersion(const wchar_t* exe_path, const wchar_t* key_path,
                std::wstring* version) {
  HKEY reg_root = InstallUtil::IsPerUserInstall(exe_path) ? HKEY_CURRENT_USER :
                                                            HKEY_LOCAL_MACHINE;
  HKEY key;
  if (::RegOpenKeyEx(reg_root, key_path, 0, KEY_READ, &key) != ERROR_SUCCESS)
    return false;

  // If 'new_chrome.exe' is present it means chrome was auto-updated while
  // running. We need to consult the opv value so we can load the old dll.
  // TODO(cpu) : This is solving the same problem as the environment variable
  // so one of them will eventually be deprecated.
  std::wstring new_chrome_exe(exe_path);
  new_chrome_exe.append(installer_util::kChromeNewExe);
  if (::PathFileExistsW(new_chrome_exe.c_str()) &&
      ReadRegistryStr(key, google_update::kRegOldVersionField, version)) {
    ::RegCloseKey(key);
    return true;
  }

  bool ret = ReadRegistryStr(key, google_update::kRegVersionField, version);
  ::RegCloseKey(key);
  return ret;
}

// Gets the path of the current exe with a trailing backslash.
std::wstring GetExecutablePath() {
  wchar_t path[MAX_PATH];
  ::GetModuleFileNameW(NULL, path, MAX_PATH);
  if (!::PathRemoveFileSpecW(path))
    return std::wstring();
  std::wstring exe_path(path);
  return exe_path.append(L"\\");
}

// Not generic, we only handle strings up to 128 chars.
bool EnvQueryStr(const wchar_t* key_name, std::wstring* value) {
  wchar_t out[128];
  DWORD count = sizeof(out)/sizeof(out[0]);
  DWORD rv = ::GetEnvironmentVariableW(key_name, out, count);
  if ((rv == 0) || (rv >= count))
    return false;
  *value = out;
  return true;
}

// Expects that |dir| has a trailing backslash. |dir| is modified so it
// contains the full path that was tried. Caller must check for the return
// value not being null to dermine if this path contains a valid dll.
HMODULE LoadChromeWithDirectory(std::wstring* dir) {
  ::SetCurrentDirectoryW(dir->c_str());
  const CommandLine& cmd_line = *CommandLine::ForCurrentProcess();
#ifdef _WIN64
  if ((cmd_line.GetSwitchValueASCII(switches::kProcessType) ==
      switches::kNaClBrokerProcess) ||
      (cmd_line.GetSwitchValueASCII(switches::kProcessType) ==
      switches::kNaClLoaderProcess)) {
    // Load the 64-bit DLL when running in a 64-bit process.
    dir->append(installer_util::kChromeNaCl64Dll);
  } else {
    // Only NaCl broker and loader can be launched as Win64 processes.
    NOTREACHED();
    return NULL;
  }
#else
  dir->append(installer_util::kChromeDll);
#endif

#ifdef NDEBUG
  // Experimental pre-reading optimization
  // The idea is to pre read significant portion of chrome.dll in advance
  // so that subsequent hard page faults are avoided.
  if (!cmd_line.HasSwitch(switches::kProcessType)) {
    // The kernel brings in 8 pages for the code section at a time and 4 pages
    // for other sections. We can skip over these pages to avoid a soft page
    // fault which may not occur during code execution. However skipping 4K at
    // a time still has better performance over 32K and 16K according to data.
    // TODO(ananta)
    // Investigate this and tune.
    const size_t kStepSize = 4 * 1024;

    DWORD pre_read_size = 0;
    DWORD pre_read_step_size = kStepSize;
    DWORD pre_read = 1;

    HKEY key = NULL;
    if (::RegOpenKeyEx(HKEY_CURRENT_USER, L"Software\\Google\\ChromeFrame",
                       0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) {
      DWORD unused = sizeof(pre_read_size);
      RegQueryValueEx(key, L"PreReadSize", NULL, NULL,
                      reinterpret_cast<LPBYTE>(&pre_read_size), &unused);
      RegQueryValueEx(key, L"PreReadStepSize", NULL, NULL,
                      reinterpret_cast<LPBYTE>(&pre_read_step_size), &unused);
      RegQueryValueEx(key, L"PreRead", NULL, NULL,
                      reinterpret_cast<LPBYTE>(&pre_read), &unused);
      RegCloseKey(key);
      key = NULL;
    }
    if (pre_read) {
      TRACE_EVENT_BEGIN("PreReadImage", 0, "");
      file_util::PreReadImage(dir->c_str(), pre_read_size, pre_read_step_size);
      TRACE_EVENT_END("PreReadImage", 0, "");
    }
  }
#endif  // NDEBUG

  return ::LoadLibraryExW(dir->c_str(), NULL,
                          LOAD_WITH_ALTERED_SEARCH_PATH);
}

// Set did_run "dr" in omaha's client state for this product.
bool SetDidRunState(const wchar_t* guid, const wchar_t* value) {
  std::wstring key_path(google_update::kRegPathClientState);
  key_path.append(L"\\").append(guid);
  HKEY reg_key;
  if (::RegCreateKeyExW(HKEY_CURRENT_USER, key_path.c_str(), 0, NULL,
                        REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL,
                        &reg_key, NULL) == ERROR_SUCCESS) {
    // Note that the length here must be in bytes and must account for the
    // terminating null char.
    ::RegSetValueExW(reg_key, google_update::kRegDidRunField, 0, REG_SZ,
                     reinterpret_cast<const BYTE *>(value),
                     (::lstrlenW(value) + 1) * sizeof(wchar_t));
    ::RegCloseKey(reg_key);
    return true;
  }
  return false;
}

bool RecordDidRun(const wchar_t* guid) {
  return SetDidRunState(guid, L"1");
}

bool ClearDidRun(const wchar_t* guid) {
  return SetDidRunState(guid, L"0");
}

}
//=============================================================================

MainDllLoader::MainDllLoader() : dll_(NULL) {
}

MainDllLoader::~MainDllLoader() {
#ifdef PURIFY
  // We should never unload the dll. There is only risk and no gain from
  // doing so. The singleton dtors have been already run by AtExitManager.
  ::FreeLibrary(dll_);
#endif
}

// Loading chrome is an interesting afair. First we try loading from the current
// directory to support run-what-you-compile and other development scenarios.
// If that fails then we look at the 'CHROME_VERSION' env variable to determine
// if we should stick with an older dll version even if a new one is available
// to support upgrade-in-place scenarios, and if that fails we finally we look
// at the registry which should point us to the latest version.
HMODULE MainDllLoader::Load(std::wstring* version, std::wstring* file) {
  std::wstring dir(GetExecutablePath());
  *file = dir;
  HMODULE dll = LoadChromeWithDirectory(file);
  if (dll)
    return dll;

  if (!EnvQueryStr(
          BrowserDistribution::GetDistribution()->GetEnvVersionKey().c_str(),
          version)) {
    std::wstring reg_path(GetRegistryPath());
    // Look into the registry to find the latest version.
    if (!GetVersion(dir.c_str(), reg_path.c_str(), version))
      return NULL;
  }

  *file = dir;
  file->append(*version).append(L"\\");
  return LoadChromeWithDirectory(file);
}

// Launching is a matter of loading the right dll, setting the CHROME_VERSION
// environment variable and just calling the entry point. Derived classes can
// add custom code in the OnBeforeLaunch callback.
int MainDllLoader::Launch(HINSTANCE instance,
                          sandbox::SandboxInterfaceInfo* sbox_info) {
  std::wstring version;
  std::wstring file;
  dll_ = Load(&version, &file);
  if (!dll_)
    return ResultCodes::MISSING_DATA;

  scoped_ptr<base::Environment> env(base::Environment::Create());
  env->SetVar(WideToUTF8(
      BrowserDistribution::GetDistribution()->GetEnvVersionKey()).c_str(),
      WideToUTF8(version));

  InitCrashReporterWithDllPath(file);
  OnBeforeLaunch(version);

  DLL_MAIN entry_point =
      reinterpret_cast<DLL_MAIN>(::GetProcAddress(dll_, "ChromeMain"));
  if (!entry_point)
    return ResultCodes::BAD_PROCESS_TYPE;

  int rc = entry_point(instance, sbox_info, ::GetCommandLineW());
  return OnBeforeExit(rc);
}

void MainDllLoader::RelaunchChromeBrowserWithNewCommandLineIfNeeded() {
  RelaunchChromeBrowserWithNewCommandLineIfNeededFunc relaunch_function =
      reinterpret_cast<RelaunchChromeBrowserWithNewCommandLineIfNeededFunc>(
          ::GetProcAddress(dll_,
                           "RelaunchChromeBrowserWithNewCommandLineIfNeeded"));
  if (!relaunch_function) {
    LOG(ERROR) << "Could not find exported function "
               << "RelaunchChromeBrowserWithNewCommandLineIfNeeded";
  } else {
    relaunch_function();
  }
}

//=============================================================================

class ChromeDllLoader : public MainDllLoader {
 public:
  virtual std::wstring GetRegistryPath() {
    std::wstring key(google_update::kRegPathClients);
    BrowserDistribution* dist = BrowserDistribution::GetDistribution();
    key.append(L"\\").append(dist->GetAppGuid());
    return key;
  }

  virtual void OnBeforeLaunch(const std::wstring& version) {
    BrowserDistribution* dist = BrowserDistribution::GetDistribution();
    RecordDidRun(dist->GetAppGuid().c_str());
  }

  virtual int OnBeforeExit(int return_code) {
    // NORMAL_EXIT_CANCEL is used for experiments when the user cancels
    // so we need to reset the did_run signal so omaha does not count
    // this run as active usage.
    if (ResultCodes::NORMAL_EXIT_CANCEL == return_code) {
      BrowserDistribution* dist = BrowserDistribution::GetDistribution();
      ClearDidRun(dist->GetAppGuid().c_str());
    }
    return return_code;
  }
};

//=============================================================================

class ChromiumDllLoader : public MainDllLoader {
 public:
  virtual std::wstring GetRegistryPath() {
    BrowserDistribution* dist = BrowserDistribution::GetDistribution();
    return dist->GetVersionKey();
  }
};

MainDllLoader* MakeMainDllLoader() {
#if defined(GOOGLE_CHROME_BUILD)
  return new ChromeDllLoader();
#else
  return new ChromiumDllLoader();
#endif
}
<commit_msg>Use Environment::GetVar instead of the obscure EnvQueryStr function.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <windows.h>
#include <shlwapi.h>

#include "base/command_line.h"
#include "base/environment.h"
#include "base/file_util.h"
#include "base/trace_event.h"
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "base/utf_string_conversions.h"
#include "chrome/app/breakpad_win.h"
#include "chrome/app/client_util.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/result_codes.h"
#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/install_util.h"
#include "chrome/installer/util/google_update_constants.h"
#include "chrome/installer/util/util_constants.h"

namespace {
// The entry point signature of chrome.dll.
typedef int (*DLL_MAIN)(HINSTANCE, sandbox::SandboxInterfaceInfo*, wchar_t*);

typedef void (*RelaunchChromeBrowserWithNewCommandLineIfNeededFunc)();

// Not generic, we only handle strings up to 128 chars.
bool ReadRegistryStr(HKEY key, const wchar_t* name, std::wstring* value) {
  BYTE out[128 * sizeof(wchar_t)];
  DWORD size = sizeof(out);
  DWORD type = 0;
  if (ERROR_SUCCESS != ::RegQueryValueExW(key, name, NULL, &type, out, &size))
    return false;
  if (type != REG_SZ)
    return false;
  value->assign(reinterpret_cast<wchar_t*>(out));
  return true;
}

// Gets chrome version according to the load path. |exe_path| must be the
// backslash terminated directory of the current chrome.exe.
bool GetVersion(const wchar_t* exe_path, const wchar_t* key_path,
                std::wstring* version) {
  HKEY reg_root = InstallUtil::IsPerUserInstall(exe_path) ? HKEY_CURRENT_USER :
                                                            HKEY_LOCAL_MACHINE;
  HKEY key;
  if (::RegOpenKeyEx(reg_root, key_path, 0, KEY_READ, &key) != ERROR_SUCCESS)
    return false;

  // If 'new_chrome.exe' is present it means chrome was auto-updated while
  // running. We need to consult the opv value so we can load the old dll.
  // TODO(cpu) : This is solving the same problem as the environment variable
  // so one of them will eventually be deprecated.
  std::wstring new_chrome_exe(exe_path);
  new_chrome_exe.append(installer_util::kChromeNewExe);
  if (::PathFileExistsW(new_chrome_exe.c_str()) &&
      ReadRegistryStr(key, google_update::kRegOldVersionField, version)) {
    ::RegCloseKey(key);
    return true;
  }

  bool ret = ReadRegistryStr(key, google_update::kRegVersionField, version);
  ::RegCloseKey(key);
  return ret;
}

// Gets the path of the current exe with a trailing backslash.
std::wstring GetExecutablePath() {
  wchar_t path[MAX_PATH];
  ::GetModuleFileNameW(NULL, path, MAX_PATH);
  if (!::PathRemoveFileSpecW(path))
    return std::wstring();
  std::wstring exe_path(path);
  return exe_path.append(L"\\");
}

// Expects that |dir| has a trailing backslash. |dir| is modified so it
// contains the full path that was tried. Caller must check for the return
// value not being null to dermine if this path contains a valid dll.
HMODULE LoadChromeWithDirectory(std::wstring* dir) {
  ::SetCurrentDirectoryW(dir->c_str());
  const CommandLine& cmd_line = *CommandLine::ForCurrentProcess();
#ifdef _WIN64
  if ((cmd_line.GetSwitchValueASCII(switches::kProcessType) ==
      switches::kNaClBrokerProcess) ||
      (cmd_line.GetSwitchValueASCII(switches::kProcessType) ==
      switches::kNaClLoaderProcess)) {
    // Load the 64-bit DLL when running in a 64-bit process.
    dir->append(installer_util::kChromeNaCl64Dll);
  } else {
    // Only NaCl broker and loader can be launched as Win64 processes.
    NOTREACHED();
    return NULL;
  }
#else
  dir->append(installer_util::kChromeDll);
#endif

#ifdef NDEBUG
  // Experimental pre-reading optimization
  // The idea is to pre read significant portion of chrome.dll in advance
  // so that subsequent hard page faults are avoided.
  if (!cmd_line.HasSwitch(switches::kProcessType)) {
    // The kernel brings in 8 pages for the code section at a time and 4 pages
    // for other sections. We can skip over these pages to avoid a soft page
    // fault which may not occur during code execution. However skipping 4K at
    // a time still has better performance over 32K and 16K according to data.
    // TODO(ananta)
    // Investigate this and tune.
    const size_t kStepSize = 4 * 1024;

    DWORD pre_read_size = 0;
    DWORD pre_read_step_size = kStepSize;
    DWORD pre_read = 1;

    HKEY key = NULL;
    if (::RegOpenKeyEx(HKEY_CURRENT_USER, L"Software\\Google\\ChromeFrame",
                       0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) {
      DWORD unused = sizeof(pre_read_size);
      RegQueryValueEx(key, L"PreReadSize", NULL, NULL,
                      reinterpret_cast<LPBYTE>(&pre_read_size), &unused);
      RegQueryValueEx(key, L"PreReadStepSize", NULL, NULL,
                      reinterpret_cast<LPBYTE>(&pre_read_step_size), &unused);
      RegQueryValueEx(key, L"PreRead", NULL, NULL,
                      reinterpret_cast<LPBYTE>(&pre_read), &unused);
      RegCloseKey(key);
      key = NULL;
    }
    if (pre_read) {
      TRACE_EVENT_BEGIN("PreReadImage", 0, "");
      file_util::PreReadImage(dir->c_str(), pre_read_size, pre_read_step_size);
      TRACE_EVENT_END("PreReadImage", 0, "");
    }
  }
#endif  // NDEBUG

  return ::LoadLibraryExW(dir->c_str(), NULL,
                          LOAD_WITH_ALTERED_SEARCH_PATH);
}

// Set did_run "dr" in omaha's client state for this product.
bool SetDidRunState(const wchar_t* guid, const wchar_t* value) {
  std::wstring key_path(google_update::kRegPathClientState);
  key_path.append(L"\\").append(guid);
  HKEY reg_key;
  if (::RegCreateKeyExW(HKEY_CURRENT_USER, key_path.c_str(), 0, NULL,
                        REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL,
                        &reg_key, NULL) == ERROR_SUCCESS) {
    // Note that the length here must be in bytes and must account for the
    // terminating null char.
    ::RegSetValueExW(reg_key, google_update::kRegDidRunField, 0, REG_SZ,
                     reinterpret_cast<const BYTE *>(value),
                     (::lstrlenW(value) + 1) * sizeof(wchar_t));
    ::RegCloseKey(reg_key);
    return true;
  }
  return false;
}

bool RecordDidRun(const wchar_t* guid) {
  return SetDidRunState(guid, L"1");
}

bool ClearDidRun(const wchar_t* guid) {
  return SetDidRunState(guid, L"0");
}

}
//=============================================================================

MainDllLoader::MainDllLoader() : dll_(NULL) {
}

MainDllLoader::~MainDllLoader() {
#ifdef PURIFY
  // We should never unload the dll. There is only risk and no gain from
  // doing so. The singleton dtors have been already run by AtExitManager.
  ::FreeLibrary(dll_);
#endif
}

// Loading chrome is an interesting afair. First we try loading from the current
// directory to support run-what-you-compile and other development scenarios.
// If that fails then we look at the 'CHROME_VERSION' env variable to determine
// if we should stick with an older dll version even if a new one is available
// to support upgrade-in-place scenarios, and if that fails we finally we look
// at the registry which should point us to the latest version.
HMODULE MainDllLoader::Load(std::wstring* version, std::wstring* file) {
  std::wstring dir(GetExecutablePath());
  *file = dir;
  HMODULE dll = LoadChromeWithDirectory(file);
  if (dll)
    return dll;

  scoped_ptr<base::Environment> env(base::Environment::Create());

  std::string version_value;
  if (!env->GetVar(WideToUTF8(
          BrowserDistribution::GetDistribution()->GetEnvVersionKey()).c_str(),
          &version_value)) {
    std::wstring reg_path(GetRegistryPath());

    *version = UTF8ToWide(version_value);
    // Look into the registry to find the latest version.
    if (!GetVersion(dir.c_str(), reg_path.c_str(), version))
      return NULL;
  }

  *file = dir;
  file->append(*version).append(L"\\");
  return LoadChromeWithDirectory(file);
}

// Launching is a matter of loading the right dll, setting the CHROME_VERSION
// environment variable and just calling the entry point. Derived classes can
// add custom code in the OnBeforeLaunch callback.
int MainDllLoader::Launch(HINSTANCE instance,
                          sandbox::SandboxInterfaceInfo* sbox_info) {
  std::wstring version;
  std::wstring file;
  dll_ = Load(&version, &file);
  if (!dll_)
    return ResultCodes::MISSING_DATA;

  scoped_ptr<base::Environment> env(base::Environment::Create());
  env->SetVar(WideToUTF8(
      BrowserDistribution::GetDistribution()->GetEnvVersionKey()).c_str(),
      WideToUTF8(version));

  InitCrashReporterWithDllPath(file);
  OnBeforeLaunch(version);

  DLL_MAIN entry_point =
      reinterpret_cast<DLL_MAIN>(::GetProcAddress(dll_, "ChromeMain"));
  if (!entry_point)
    return ResultCodes::BAD_PROCESS_TYPE;

  int rc = entry_point(instance, sbox_info, ::GetCommandLineW());
  return OnBeforeExit(rc);
}

void MainDllLoader::RelaunchChromeBrowserWithNewCommandLineIfNeeded() {
  RelaunchChromeBrowserWithNewCommandLineIfNeededFunc relaunch_function =
      reinterpret_cast<RelaunchChromeBrowserWithNewCommandLineIfNeededFunc>(
          ::GetProcAddress(dll_,
                           "RelaunchChromeBrowserWithNewCommandLineIfNeeded"));
  if (!relaunch_function) {
    LOG(ERROR) << "Could not find exported function "
               << "RelaunchChromeBrowserWithNewCommandLineIfNeeded";
  } else {
    relaunch_function();
  }
}

//=============================================================================

class ChromeDllLoader : public MainDllLoader {
 public:
  virtual std::wstring GetRegistryPath() {
    std::wstring key(google_update::kRegPathClients);
    BrowserDistribution* dist = BrowserDistribution::GetDistribution();
    key.append(L"\\").append(dist->GetAppGuid());
    return key;
  }

  virtual void OnBeforeLaunch(const std::wstring& version) {
    BrowserDistribution* dist = BrowserDistribution::GetDistribution();
    RecordDidRun(dist->GetAppGuid().c_str());
  }

  virtual int OnBeforeExit(int return_code) {
    // NORMAL_EXIT_CANCEL is used for experiments when the user cancels
    // so we need to reset the did_run signal so omaha does not count
    // this run as active usage.
    if (ResultCodes::NORMAL_EXIT_CANCEL == return_code) {
      BrowserDistribution* dist = BrowserDistribution::GetDistribution();
      ClearDidRun(dist->GetAppGuid().c_str());
    }
    return return_code;
  }
};

//=============================================================================

class ChromiumDllLoader : public MainDllLoader {
 public:
  virtual std::wstring GetRegistryPath() {
    BrowserDistribution* dist = BrowserDistribution::GetDistribution();
    return dist->GetVersionKey();
  }
};

MainDllLoader* MakeMainDllLoader() {
#if defined(GOOGLE_CHROME_BUILD)
  return new ChromeDllLoader();
#else
  return new ChromiumDllLoader();
#endif
}
<|endoftext|>


<commit_before><commit_msg>File missing from previous recommit.<commit_after><|endoftext|>


<commit_before>#include "sncc_disparitywise_calculator.h"

#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <omp.h>

#include "disparitywise_calculator.h"

sncc_disparitywise_calculator::sncc_disparitywise_calculator(const cv::Mat& pbase, const cv::Mat& pmatch)
{
	long long start = cv::getCPUTickCount();
	cv::Size box_size(3,3);

	cv::Mat_<float> base_float_org;
	pbase.convertTo(base_float_org, CV_32F);
	cv::copyMakeBorder(base_float_org, base_float, 1,1,1,1, cv::BORDER_DEFAULT);
	cv::Mat base_square;
	cv::pow(base_float_org, 2, base_square);
	cv::boxFilter(base_float_org, mu_base, -1, box_size);
	cv::Mat mu_base_sq;
	cv::pow(mu_base, 2, mu_base_sq);
	cv::Mat sq_base_box;
	cv::boxFilter(base_square, sq_base_box, -1, box_size);
	cv::sqrt(sq_base_box - mu_base_sq, sigma_base_inv);
	cv::pow(sigma_base_inv, -1, sigma_base_inv);

	cv::Mat match_float_org;
	pmatch.convertTo(match_float_org, CV_32F);
	cv::copyMakeBorder(match_float_org, match_float, 1,1,1,1, cv::BORDER_DEFAULT);
	cv::Mat match_square;
	cv::pow(match_float_org, 2, match_square);
	cv::boxFilter(match_float_org, mu_match, -1, box_size);
	cv::Mat mu_match_sq;
	cv::pow(mu_match, 2, mu_match_sq);
	cv::Mat sq_match_box;
	cv::boxFilter(match_square, sq_match_box, -1, box_size);
	cv::sqrt(sq_match_box - mu_match_sq, sigma_match_inv);
	cv::pow(sigma_match_inv, -1, sigma_match_inv);

	int threads = omp_get_max_threads();
	//int threads = 1;
	for(int i = 0; i < threads; ++i)
		temp.emplace_back(base_float.size());

	std::cout << "init: " << cv::getCPUTickCount() - start << std::endl;
}

void preparation_kernel(float* temp, const float* base, const float* match, int cols, int rows, int row_stride)
{
	for(int y = 0; y < rows; ++y)
	{
		const float* base_d_ptr = base + y*row_stride;
		const float* match_d_ptr = match + y*row_stride;
		for(int x = 0; x < cols; ++x)
			*temp++ = *base_d_ptr++ * *match_d_ptr++;
	}
}

void sncc_kernel(float* result, const float* temp, const float* mu_base, const float* mu_match, const float* sigma_base_inv, const float* sigma_match_inv, int rows, int cols, int row_stride)
{
	const float norm_factor = 1.0/9.0f;
	float* result_ptr = result;

	std::vector<float> box_temp(cols);
	std::vector<float> boxcol_temp(cols+2);
	for(int y = 0; y < rows; ++y)
	{
		const float *temp_1 = temp + (y+0)*(cols+2);
		const float *temp_2 = temp + (y+1)*(cols+2);
		const float *temp_3 = temp + (y+2)*(cols+2);
		for(int x = 0; x < cols; ++x)
		{
			boxcol_temp[x] = *temp_1++ + *temp_2++ + *temp_3++;
		}

		/*for(int x = 0; x < cols; ++x)
		{
			float sum = 0.0f;
			for(int dy = 0; dy < 3; ++dy)
			{
				const float *temp_ptr = temp + (y+dy)*(cols+2)+x;
				for(int dx = 0; dx < 3; ++dx)
					sum += *temp_ptr++;
			}
			sum *= norm_factor;
			box_temp[x] = sum;
		}*/
		const float* boxcol_temp_ptr = boxcol_temp.data();
		for(int x = 0; x < cols; ++x)
		{
			float sum = 0.0f;
			/*for(int dy = 0; dy < 3; ++dy)
			{
				const float *temp_ptr = temp + (y+dy)*(cols+2)+x;
				for(int dx = 0; dx < 3; ++dx)
					sum += *temp_ptr++;
			}*/
			for(int dx = 0; dx < 3; ++dx)
				sum += *(boxcol_temp_ptr + dx);
			boxcol_temp_ptr++;

			sum *= norm_factor;
			box_temp[x] = sum;
		}

		int y_offset = y*row_stride;
		//float* result_ptr = result + y_offset;
		const float* mu_base_ptr = mu_base + y_offset;
		const float* mu_match_ptr = mu_match + y_offset;
		const float* sigma_base_inv_ptr = sigma_base_inv + y_offset;
		const float* sigma_match_inv_ptr = sigma_match_inv + y_offset;
		const float *box_ptr = box_temp.data();

		for(int x = 0; x < cols; ++x)
		{
			/*float sum = 0.0f;
			for(int dy = 0; dy < 3; ++dy)
			{
				const float *temp_ptr = temp + (y+dy)*(cols+2)+x;
				for(int dx = 0; dx < 3; ++dx)
					sum += *temp_ptr++;
			}
			sum *= norm_factor;*/

			*result_ptr++ = 1.0f - (*box_ptr++ - *mu_base_ptr++ * *mu_match_ptr++) * *sigma_base_inv_ptr++ * *sigma_match_inv_ptr++;
		}
	}
}

cv::Mat_<float> sncc_disparitywise_calculator::operator()(int d)
{
	const int offset_base = calculate_base_offset(d);
	const int offset_match = calculate_match_offset(d);
	const int row_length = calculate_row_length(base_float, d) - 2;
	const int rows = base_float.rows - 2;

	//cv::Mat_<float> result = prepare_result(cv::Size(row_length, rows), d, 100.0f);
	cv::Mat_<float> result(cv::Size(row_length, rows), 100.0f);

	int thread_idx = omp_get_thread_num();
	preparation_kernel(temp[thread_idx][0], base_float.ptr<float>() + offset_base, match_float.ptr<float>() + offset_match, row_length+2, rows+2, base_float.cols);
	//sncc_kernel(result[0] + offset_base, temp[thread_idx][0], mu_base[0] + offset_base, mu_match[0] + offset_match, sigma_base_inv[0] + offset_base, sigma_match_inv[0] + offset_match, rows, row_length, base_float.cols - 2);
	sncc_kernel(result[0], temp[thread_idx][0], mu_base[0] + offset_base, mu_match[0] + offset_match, sigma_base_inv[0] + offset_base, sigma_match_inv[0] + offset_match, rows, row_length, base_float.cols - 2);

	return result;
}

<commit_msg>performance opt of sncc<commit_after>#include "sncc_disparitywise_calculator.h"

#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <omp.h>

#include "disparitywise_calculator.h"

sncc_disparitywise_calculator::sncc_disparitywise_calculator(const cv::Mat& pbase, const cv::Mat& pmatch)
{
	long long start = cv::getCPUTickCount();
	cv::Size box_size(3,3);

	cv::Mat_<float> base_float_org;
	pbase.convertTo(base_float_org, CV_32F);
	cv::copyMakeBorder(base_float_org, base_float, 1,1,1,1, cv::BORDER_DEFAULT);
	cv::Mat base_square;
	cv::pow(base_float_org, 2, base_square);
	cv::boxFilter(base_float_org, mu_base, -1, box_size);
	cv::Mat mu_base_sq;
	cv::pow(mu_base, 2, mu_base_sq);
	cv::Mat sq_base_box;
	cv::boxFilter(base_square, sq_base_box, -1, box_size);
	cv::sqrt(sq_base_box - mu_base_sq, sigma_base_inv);
	cv::pow(sigma_base_inv, -1, sigma_base_inv);

	cv::Mat match_float_org;
	pmatch.convertTo(match_float_org, CV_32F);
	cv::copyMakeBorder(match_float_org, match_float, 1,1,1,1, cv::BORDER_DEFAULT);
	cv::Mat match_square;
	cv::pow(match_float_org, 2, match_square);
	cv::boxFilter(match_float_org, mu_match, -1, box_size);
	cv::Mat mu_match_sq;
	cv::pow(mu_match, 2, mu_match_sq);
	cv::Mat sq_match_box;
	cv::boxFilter(match_square, sq_match_box, -1, box_size);
	cv::sqrt(sq_match_box - mu_match_sq, sigma_match_inv);
	cv::pow(sigma_match_inv, -1, sigma_match_inv);

	int threads = omp_get_max_threads();
	//int threads = 1;
	for(int i = 0; i < threads; ++i)
		temp.emplace_back(base_float.size());

	std::cout << "init: " << cv::getCPUTickCount() - start << std::endl;
}

void preparation_kernel(float* temp, const float* base, const float* match, int cols, int rows, int row_stride)
{
	for(int y = 0; y < rows; ++y)
	{
		const float* base_d_ptr = base + y*row_stride;
		const float* match_d_ptr = match + y*row_stride;
		for(int x = 0; x < cols; ++x)
			*temp++ = *base_d_ptr++ * *match_d_ptr++;
	}
}

inline void prepare_line(float *temp, const float* base, const float* match, int cols)
{
	for(int x = 0; x < cols; ++x)
		*temp++ = *base++ * *match++;
}

void sncc_kernel(float* result, const float* mu_base, const float* mu_match, const float* sigma_base_inv, const float* sigma_match_inv, int rows, int cols, int row_stride, const float* base, const float *match)
{
	const float norm_factor = 1.0/9.0f;
	float* result_ptr = result;

	std::vector<std::vector<float>> coltemp(3, std::vector<float>(cols+2));
	//std::array<std::vector<float>,3> coltemp(std::vector<float>(cols+2));
	for(int i = 0; i < 2; ++i)
		prepare_line(coltemp[i].data(), base + i*(row_stride+2), match + i*(row_stride+2), cols+2);
	int replace_idx = 2;

	std::vector<float> box_temp(cols);
	std::vector<float> boxcol_temp(cols+2);
	for(int y = 0; y < rows; ++y)
	{
		prepare_line(coltemp[replace_idx].data(), base+(y+2)*(row_stride+2), match+(y+2)*(row_stride+2), cols+2);
		replace_idx = (replace_idx+1) %3;

		const float *temp_1 = coltemp[0].data();
		const float *temp_2 = coltemp[1].data();
		const float *temp_3 = coltemp[2].data();

		for(int x = 0; x < cols+2; ++x)
		{
			boxcol_temp[x] = *temp_1++ + *temp_2++ + *temp_3++;
		}

		const float* boxcol_temp_ptr = boxcol_temp.data();
		for(int x = 0; x < cols; ++x)
		{
			float sum = 0.0f;
			for(int dx = 0; dx < 3; ++dx)
				sum += *(boxcol_temp_ptr + dx);
			boxcol_temp_ptr++;

			sum *= norm_factor;
			box_temp[x] = sum;
		}

		int y_offset = y*row_stride;
		const float* mu_base_ptr = mu_base + y_offset;
		const float* mu_match_ptr = mu_match + y_offset;
		const float* sigma_base_inv_ptr = sigma_base_inv + y_offset;
		const float* sigma_match_inv_ptr = sigma_match_inv + y_offset;
		const float *box_ptr = box_temp.data();

		for(int x = 0; x < cols; ++x)
		{
			*result_ptr++ = 1.0f - (*box_ptr++ - *mu_base_ptr++ * *mu_match_ptr++) * *sigma_base_inv_ptr++ * *sigma_match_inv_ptr++;
		}
	}
}

cv::Mat_<float> sncc_disparitywise_calculator::operator()(int d)
{
	const int offset_base = calculate_base_offset(d);
	const int offset_match = calculate_match_offset(d);
	const int row_length = calculate_row_length(base_float, d) - 2;
	const int rows = base_float.rows - 2;

	//cv::Mat_<float> result = prepare_result(cv::Size(row_length, rows), d, 100.0f);
	cv::Mat_<float> result(cv::Size(row_length, rows), 100.0f);

	int thread_idx = omp_get_thread_num();
	//preparation_kernel(temp[thread_idx][0], base_float.ptr<float>() + offset_base, match_float.ptr<float>() + offset_match, row_length+2, rows+2, base_float.cols);
	//sncc_kernel(result[0] + offset_base, temp[thread_idx][0], mu_base[0] + offset_base, mu_match[0] + offset_match, sigma_base_inv[0] + offset_base, sigma_match_inv[0] + offset_match, rows, row_length, base_float.cols - 2);
	//sncc_kernel(result[0], temp[thread_idx][0], mu_base[0] + offset_base, mu_match[0] + offset_match, sigma_base_inv[0] + offset_base, sigma_match_inv[0] + offset_match, rows, row_length, base_float.cols - 2);
	sncc_kernel(result[0], mu_base[0] + offset_base, mu_match[0] + offset_match, sigma_base_inv[0] + offset_base, sigma_match_inv[0] + offset_match, rows, row_length, base_float.cols - 2, base_float.ptr<float>() + offset_base, match_float.ptr<float>() + offset_match);

	return result;
}

<|endoftext|>


<commit_before><commit_msg>Provide initialization of member variable<commit_after><|endoftext|>


<commit_before>#include "addscientist.h"
#include "ui_addscientist.h"
#include "scientist.h"
#include "listservices.h"
#include <string>
#include <cstdlib>

using namespace std;

addScientist::addScientist(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::addScientist)
{
    ui->setupUi(this);
    ui ->genderSelectBox ->addItem("Gender");
    ui ->genderSelectBox ->addItem("---");
    ui ->genderSelectBox ->addItem("Male");
    ui ->genderSelectBox ->addItem("Female");
    ui ->genderSelectBox ->addItem("Other");

}

addScientist::~addScientist()
{
    delete ui;
}

void addScientist::on_addScientistButton_clicked()
{
    //this boolean is true only when the entry is fully legal
    bool isLegalScientist = false;

    //set all errors to empty every time the button is clicked.
    ui ->birthYearLabel ->setText("");
    ui ->deathYearLabel ->setText("");
    ui ->firstNameLabel ->setText("");
    ui ->lastNameLabel ->setText("");
    ui ->genderLabel ->setText("");
    ui ->nationalityLabel ->setText("");

    //this runs if no required fields are empty.

        bool hasFirstName = getFirstName();
        bool hasLastName = getLastName();
        bool hasGender = getGender();
        bool hasNationality = getNationality();
        bool hasBirthYear; getBirthYear();
        bool hasDeathYear; // = _deathYear = (ui -> deathYearBox -> text()).toInt();
        bool hasAwardYear; // =_awardYear =(ui ->turingAwardBox -> text()).toInt();

    //if it's all legal, add the scientist to the database.  Maybe open a little popup.

    if(isLegalScientist)
    {
        Scientist newScientist(0, _firstName, _lastName, 'm', _nationality, _birthYear, _deathYear, _awardYear);
        _connection.addScientistToDatabase(newScientist);
    }

}

//NOT NEEDED!!
bool addScientist::checkForEmpty()
{
    bool hasContent = true;
    if((ui ->firstNameBox->text()).isEmpty())
    {
        ui -> firstNameLabel ->setText("First name required");
        hasContent = false;
    }
    if((ui ->lastNameBox->text()).isEmpty())
    {
        ui -> lastNameLabel ->setText("Last name required");
        hasContent = false;
    }
    if((ui ->nationalityBox->text()).isEmpty())
    {
        ui -> nationalityLabel ->setText("Nationality required");
        hasContent = false;
    }
    if((ui ->birthYearBox ->text()).isEmpty())
    {
        ui ->birthYearLabel ->setText("Birth year required");
        hasContent = false;
    }
    if(ui->genderSelectBox ->currentText() == "Gender" || ui->genderSelectBox ->currentText() == "---")
    {
        ui ->genderLabel ->setText("Gender required");
        hasContent = false;
    }
    //hasContent is true if and only if all required fields have entries.
    return hasContent;
}

bool addScientist::getGender()
{
    if(ui->genderLabel->selectedText() == "Male")
    {
        _gender = 'm';
        return true;
    }
    else if(ui ->genderLabel->selectedText() == "Female")
    {
        _gender = 'f';
        return true;
    }
    else if(ui ->genderLabel ->selectedText() == "Other")
    {
        _gender = 'o';
        return true;
    }
    else
    {
        ui -> genderLabel ->setText("Gender required");
        return false;
    }
}

//The integer this function returns indicates whether the name is legal, and if not, what the problem is.
bool addScientist::getFirstName()
{

    string potentialName = ui ->firstNameBox ->text().toStdString();

    bool hasOnlyChar = true;
    bool hasContent = true;

    //Checks that there is something in the field
    if((ui ->firstNameBox->text()).isEmpty())
    {
        hasContent = false;
    }

    //check that it has only characters
    for(unsigned int i = 0; i < potentialName.size(); i++)
    {
        if(isalpha(potentialName[i]))
        {
            //do nothing
        }
        else
        {
            hasOnlyChar = false;
        }
    }

    //Throws errors if any are needed
    if(!hasContent)
    {
        ui ->firstNameLabel ->setText("First name required");

    }
    else if(!hasOnlyChar)
    {
        ui ->firstNameLabel ->setText("Name can only contain latin characters");
    }
    else if(potentialName.size() < 3 || potentialName.size() > 16)
    {
        ui -> firstNameLabel ->setText("Name must be between 2 and 16 characters");
    }
    else
    {
        //If there are no problems, the first name is legal.
        _firstName = potentialName;
    }

    return (hasContent && hasOnlyChar && !(potentialName.size() < 3 || potentialName.size() > 16));
}

bool addScientist::getLastName()
{

    string potentialName = ui ->lastNameBox ->text().toStdString();

    bool hasOnlyChar = true;
    bool hasContent = true;

    //Checks that there is something in the field
    if((ui ->lastNameBox->text()).isEmpty())
    {
        hasContent = false;
    }

    //check that it has only characters
    for(unsigned int i = 0; i < potentialName.size(); i++)
    {
        if(isalpha(potentialName[i]))
        {
            //do nothing
        }
        else
        {
            hasOnlyChar = false;
        }
    }

    //Throws errors if any are needed
    if(!hasContent)
    {
        ui ->lastNameLabel ->setText("Last name required");
    }
    else if(!hasOnlyChar)
    {
        ui ->lastNameLabel ->setText("Name can only contain latin characters");
    }
    else if(potentialName.size() < 3 || potentialName.size() > 16)
    {
        ui -> lastNameLabel ->setText("Name must be between 2 and 16 characters");
    }
    else
    {
        //If there are no problems, the last name is legal.
        _lastName = potentialName;
    }

    return (hasContent && hasOnlyChar && !(potentialName.size() < 3 || potentialName.size() > 16));
}

bool addScientist::getNationality()
{

    string potentialNationality = ui ->nationalityBox ->text().toStdString();

    bool hasOnlyChar = true;
    bool hasContent = true;

    //Checks that there is something in the field
    if((ui ->nationalityBox->text()).isEmpty())
    {
        hasContent = false;
    }

    //check that it has only characters
    for(unsigned int i = 0; i < potentialNationality.size(); i++)
    {
        if(isalpha(potentialNationality[i]))
        {
            //do nothing
        }
        else
        {
            hasOnlyChar = false;
        }
    }

    //Throws errors if any are needed
    if(!hasContent)
    {
        ui ->nationalityLabel ->setText("Nationality required");

    }
    else if(!hasOnlyChar)
    {
        ui ->nationalityLabel ->setText("Nationality can only contain latin characters");
    }
    else if(potentialNationality.size() < 5 || potentialNationality.size() > 21)
    {
        ui ->nationalityLabel ->setText("Nationality be between 4 and 20 characters");
    }
    else
    {
        //If there are no problems, the first name is legal.
        _nationality = potentialNationality;
    }

    return (hasContent && hasOnlyChar && !(potentialNationality.size() < 5 || potentialNationality.size() > 21));
}

bool addScientist::getBirthYear()
{
    int potentialBirthYear = ui ->birthYearBox ->text().toInt();
    string potentialBirthYearString =(ui ->birthYearBox ->text()).toStdString();

    bool hasContent = true;
    bool hasOnlyNumbers = true;
    bool isInRange = true;

    //Checks that there is something in the field
    if((ui ->birthYearBox->text()).isEmpty())
    {
        hasContent = false;
    }

    //checks that it has only numbers
    for(unsigned int i = 0; i < potentialBirthYearString.size();i++)
    {
        if(!isdigit(potentialBirthYearString[0]))
        {
            hasOnlyNumbers = false;
        }
    }

    //checks that it is in range
    if(potentialBirthYear <1791 || potentialBirthYear > 2016)
    {
        isInRange = false;
    }

    //throws errors when necessary
    if(!hasContent)
    {
        ui ->birthYearLabel ->setText("Birth year required");

    }
    else if(!hasOnlyNumbers)
    {
        ui ->birthYearLabel ->setText("Birth year can only contain numbers");
    }
    else if(!isInRange)
    {
        ui ->birthYearLabel ->setText("No computer scientists born in this year ");
    }
    else
    {
        //If there are no problems, the birth year is legal.
        _birthYear = potentialBirthYear;
    }

    return(hasContent && hasOnlyNumbers && isInRange);

}

bool addScientist::getDeathYear()
{
    int potentialDeathYear = ui ->deathYearBox ->text().toInt();
    string potentialDeathYearString =(ui ->deathYearBox ->text()).toStdString();

    bool hasOnlyNumbers = true;
    bool isInRange = true;

    //Checks that there is something in the field
    if((ui ->deathYearBox->text()).isEmpty())
    {
        _deathYear = 0;
        return true;
    }

    //checks that it has only numbers
    for(unsigned int i = 0; i < potentialDeathYearString.size();i++)
    {
        if(!isdigit(potentialDeathYearString[0]))
        {
            hasOnlyNumbers = false;
        }
    }
    //checks that it is in range
    if(potentialDeathYear <_birthYear || potentialDeathYear > 2016)
    {
        isInRange = false;
    }

    //throws errors when necessary

    if(!hasOnlyNumbers)
    {
        ui ->deathYearLabel ->setText("Death year can only contain numbers");
    }
    else if(!isInRange)
    {
        ui ->deathYearLabel ->setText("Not legal death year");
    }
    else
    {
        //If there are no problems, the birth year is legal.
        _deathYear = potentialDeathYear;
    }

    return(hasOnlyNumbers && isInRange);

}
<commit_msg>add checks and all that<commit_after>#include "addscientist.h"
#include "ui_addscientist.h"
#include "scientist.h"
#include "listservices.h"
#include <string>
#include <cstdlib>

using namespace std;

addScientist::addScientist(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::addScientist)
{
    ui->setupUi(this);
    ui ->genderSelectBox ->addItem("Gender");
    ui ->genderSelectBox ->addItem("---");
    ui ->genderSelectBox ->addItem("Male");
    ui ->genderSelectBox ->addItem("Female");
    ui ->genderSelectBox ->addItem("Other");

}

addScientist::~addScientist()
{
    delete ui;
}

void addScientist::on_addScientistButton_clicked()
{
    //this boolean is true only when the entry is fully legal
    bool isLegalScientist = false;

    //set all errors to empty every time the button is clicked.
    ui ->birthYearLabel ->setText("");
    ui ->deathYearLabel ->setText("");
    ui ->firstNameLabel ->setText("");
    ui ->lastNameLabel ->setText("");
    ui ->genderLabel ->setText("");
    ui ->nationalityLabel ->setText("");

    //this runs if no required fields are empty.

        bool hasFirstName = getFirstName();
        bool hasLastName = getLastName();
        bool hasGender = getGender();
        bool hasNationality = getNationality();
        bool hasBirthYear = getBirthYear();
        bool hasDeathYear = getDeathYear();
        bool hasAwardYear; // =_awardYear =(ui ->turingAwardBox -> text()).toInt();

    //if it's all legal, add the scientist to the database.  Maybe open a little popup.

        isLegalScientist = (hasFirstName && hasLastName && hasGender && hasNationality && hasBirthYear);

    if(isLegalScientist)
    {
        Scientist newScientist(0, _firstName, _lastName, 'm', _nationality, _birthYear, _deathYear, _awardYear);
        _connection.addScientistToDatabase(newScientist);

        ui -> firstNameLabel -> setText("GREAT SUCCESS");
    }

}

//NOT NEEDED!!
bool addScientist::checkForEmpty()
{
    bool hasContent = true;
    if((ui ->firstNameBox->text()).isEmpty())
    {
        ui -> firstNameLabel ->setText("First name required");
        hasContent = false;
    }
    if((ui ->lastNameBox->text()).isEmpty())
    {
        ui -> lastNameLabel ->setText("Last name required");
        hasContent = false;
    }
    if((ui ->nationalityBox->text()).isEmpty())
    {
        ui -> nationalityLabel ->setText("Nationality required");
        hasContent = false;
    }
    if((ui ->birthYearBox ->text()).isEmpty())
    {
        ui ->birthYearLabel ->setText("Birth year required");
        hasContent = false;
    }
    if(ui->genderSelectBox ->currentIndex() == 0 || ui->genderSelectBox ->currentIndex() == 1)
    {
        ui ->genderLabel ->setText("Gender required");
        hasContent = false;
    }
    //hasContent is true if and only if all required fields have entries.
    return hasContent;
}

bool addScientist::getGender()
{
    if((ui->genderSelectBox->currentIndex()) == 2)
    {
        _gender = 'm';
        return true;
    }
    else if((ui ->genderSelectBox->currentIndex()) == 3)
    {
        _gender = 'f';
        return true;
    }
    else if((ui ->genderSelectBox ->currentIndex()) == 4)
    {
        _gender = 'o';
        return true;
    }
    else
    {
        ui -> genderLabel ->setText("Gender required");
        return false;
    }
}

//The integer this function returns indicates whether the name is legal, and if not, what the problem is.
bool addScientist::getFirstName()
{

    string potentialName = ui ->firstNameBox ->text().toStdString();

    bool hasOnlyChar = true;
    bool hasContent = true;

    //Checks that there is something in the field
    if((ui ->firstNameBox->text()).isEmpty())
    {
        hasContent = false;
    }

    //check that it has only characters
    for(unsigned int i = 0; i < potentialName.size(); i++)
    {
        if(isalpha(potentialName[i]))
        {
            //do nothing
        }
        else
        {
            hasOnlyChar = false;
        }
    }

    //Throws errors if any are needed
    if(!hasContent)
    {
        ui ->firstNameLabel ->setText("First name required");

    }
    else if(!hasOnlyChar)
    {
        ui ->firstNameLabel ->setText("Name can only contain latin characters");
    }
    else if(potentialName.size() < 3 || potentialName.size() > 16)
    {
        ui -> firstNameLabel ->setText("Name must be between 2 and 16 characters");
    }
    else
    {
        //If there are no problems, the first name is legal.
        _firstName = potentialName;
    }

    return (hasContent && hasOnlyChar && !(potentialName.size() < 3 || potentialName.size() > 16));
}

bool addScientist::getLastName()
{

    string potentialName = ui ->lastNameBox ->text().toStdString();

    bool hasOnlyChar = true;
    bool hasContent = true;

    //Checks that there is something in the field
    if((ui ->lastNameBox->text()).isEmpty())
    {
        hasContent = false;
    }

    //check that it has only characters
    for(unsigned int i = 0; i < potentialName.size(); i++)
    {
        if(isalpha(potentialName[i]))
        {
            //do nothing
        }
        else
        {
            hasOnlyChar = false;
        }
    }

    //Throws errors if any are needed
    if(!hasContent)
    {
        ui ->lastNameLabel ->setText("Last name required");
    }
    else if(!hasOnlyChar)
    {
        ui ->lastNameLabel ->setText("Name can only contain latin characters");
    }
    else if(potentialName.size() < 3 || potentialName.size() > 16)
    {
        ui -> lastNameLabel ->setText("Name must be between 2 and 16 characters");
    }
    else
    {
        //If there are no problems, the last name is legal.
        _lastName = potentialName;
    }

    return (hasContent && hasOnlyChar && !(potentialName.size() < 3 || potentialName.size() > 16));
}

bool addScientist::getNationality()
{

    string potentialNationality = ui ->nationalityBox ->text().toStdString();

    bool hasOnlyChar = true;
    bool hasContent = true;

    //Checks that there is something in the field
    if((ui ->nationalityBox->text()).isEmpty())
    {
        hasContent = false;
    }

    //check that it has only characters
    for(unsigned int i = 0; i < potentialNationality.size(); i++)
    {
        if(isalpha(potentialNationality[i]))
        {
            //do nothing
        }
        else
        {
            hasOnlyChar = false;
        }
    }

    //Throws errors if any are needed
    if(!hasContent)
    {
        ui ->nationalityLabel ->setText("Nationality required");

    }
    else if(!hasOnlyChar)
    {
        ui ->nationalityLabel ->setText("Nationality can only contain latin characters");
    }
    else if(potentialNationality.size() < 5 || potentialNationality.size() > 21)
    {
        ui ->nationalityLabel ->setText("Nationality be between 4 and 20 characters");
    }
    else
    {
        //If there are no problems, the first name is legal.
        _nationality = potentialNationality;
    }

    return (hasContent && hasOnlyChar && !(potentialNationality.size() < 5 || potentialNationality.size() > 21));
}

bool addScientist::getBirthYear()
{
    int potentialBirthYear = ui ->birthYearBox ->text().toInt();
    string potentialBirthYearString =(ui ->birthYearBox ->text()).toStdString();

    bool hasContent = true;
    bool hasOnlyNumbers = true;
    bool isInRange = true;

    //Checks that there is something in the field
    if((ui ->birthYearBox->text()).isEmpty())
    {
        hasContent = false;
    }

    //checks that it has only numbers
    for(unsigned int i = 0; i < potentialBirthYearString.size();i++)
    {
        if(!isdigit(potentialBirthYearString[0]))
        {
            hasOnlyNumbers = false;
        }
    }

    //checks that it is in range
    if(potentialBirthYear <1791 || potentialBirthYear > 2016)
    {
        isInRange = false;
    }

    //throws errors when necessary
    if(!hasContent)
    {
        ui ->birthYearLabel ->setText("Birth year required");

    }
    else if(!hasOnlyNumbers)
    {
        ui ->birthYearLabel ->setText("Birth year can only contain numbers");
    }
    else if(!isInRange)
    {
        ui ->birthYearLabel ->setText("No computer scientists born in this year ");
    }
    else
    {
        //If there are no problems, the birth year is legal.
        _birthYear = potentialBirthYear;
    }

    return(hasContent && hasOnlyNumbers && isInRange);

}

bool addScientist::getDeathYear()
{
    int potentialDeathYear = ui ->deathYearBox ->text().toInt();
    string potentialDeathYearString =(ui ->deathYearBox ->text()).toStdString();

    bool hasOnlyNumbers = true;
    bool isInRange = true;

    //Checks that there is something in the field
    if((ui ->deathYearBox->text()).isEmpty())
    {
        _deathYear = 0;
        return true;
    }

    //checks that it has only numbers
    for(unsigned int i = 0; i < potentialDeathYearString.size();i++)
    {
        if(!isdigit(potentialDeathYearString[0]))
        {
            hasOnlyNumbers = false;
        }
    }
    //checks that it is in range
    if(potentialDeathYear <_birthYear || potentialDeathYear > 2016)
    {
        isInRange = false;
    }

    //throws errors when necessary

    if(!hasOnlyNumbers)
    {
        ui ->deathYearLabel ->setText("Death year can only contain numbers");
    }
    else if(!isInRange)
    {
        ui ->deathYearLabel ->setText("Not legal death year");
    }
    else
    {
        //If there are no problems, the birth year is legal.
        _deathYear = potentialDeathYear;
    }

    return(hasOnlyNumbers && isInRange);

}
<|endoftext|>


<commit_before>// $Id$
/**************************************************************************
 * This file is property of and copyright by the ALICE HLT Project        *
 * ALICE Experiment at CERN, All rights reserved.                         *
 *                                                                        *
 * Primary Authors: Artur Szostak <artursz@iafrica.com>                   *
 *                  for The ALICE HLT Project.                            *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/// @file   AliHLTTrigger.h
/// @author Artur Szostak <artursz@iafrica.com>
/// @date   12 Aug 2008
/// @brief  Implementation of the AliHLTTrigger base component class.
///
/// The AliHLTTrigger class is the base class from which all HLT trigger components
/// should be derived.

#include "AliHLTTrigger.h"
#include "AliHLTTriggerDecision.h"
#include "AliHLTReadoutList.h"
#include "AliHLTTriggerDomain.h"
#include "AliHLTDomainEntry.h"
#include "AliHLTCTPData.h"

ClassImp(AliHLTTrigger)

AliHLTTrigger::AliHLTTrigger() :
	AliHLTProcessor(),
	fEventData(NULL),
	fTriggerData(NULL),
	fDecisionMade(false),
	fClearInfo(true),
	fTriggerEventResult(0),
	fDescription(),
	fReadoutList(),
	fTriggerDomain()
{
  // Default constructor sets pointers to NULL.
}

AliHLTTrigger::~AliHLTTrigger()
{
  // Default destructor.
}

void AliHLTTrigger::GetInputDataTypes(AliHLTComponentDataTypeList& list) const
{
  // Returns the kAliHLTAnyDataType type as input.
  list.push_back(kAliHLTAnyDataType);
}

void AliHLTTrigger::GetOutputDataTypes(AliHLTComponentDataTypeList& list) const
{
  // Returns the kAliHLTDataTypeTriggerDecision type as output.
  list.push_back(kAliHLTDataTypeTriggerDecision);
}

void AliHLTTrigger::GetOutputDataSize(unsigned long& constBase, double& inputMultiplier)
{
  // Returns output data size estimate.
  // See header file for more details.

  // Matthias 2009-07-03 this is presumably to small as the streamed object might be
  // bigger. This is actually the case in root v5-24-00
  // Just take 2x the size of the object
  constBase = 2*sizeof(AliHLTTriggerDecision);
  inputMultiplier = 1;
}

int AliHLTTrigger::DoEvent(const AliHLTComponentEventData& evtData, AliHLTComponentTriggerData& trigData)
{
  // Sets the pointers to the evtData and trigData, then calls the DoTrigger to
  // execute the actual trigger algorithm.

  fEventData = &evtData;
  fTriggerData = &trigData;
  fDecisionMade = false;
  fTriggerEventResult = 0;
  // Reset the description, readout list and trigger domain used by TriggerEvent
  // if requested to do so.
  if (fClearInfo)
  {
    fDescription = "";
    fReadoutList.Clear();
    fTriggerDomain.Clear();
  }

  int result = DoTrigger();
  if (result != 0) return result;

  // Fill in a default decision of false if none was made.
  if (not fDecisionMade)
  {
    TriggerEvent(false);
  }

  // Cleanup
  fEventData = NULL;
  fTriggerData = NULL;
  return fTriggerEventResult;
}

int AliHLTTrigger::TriggerEvent(bool value)
{
  // Sets the trigger decision for the current event.
  // See header file for more details.

  if (fTriggerEventResult != 0) return fTriggerEventResult;  // Do not do anything if a previous call failed.
  AliHLTTriggerDecision triggerResult(value, GetTriggerName(), fTriggerDomain, fDescription);
  // Append the readout list if it contains anything.
  triggerResult.TriggerDomain().Add(fReadoutList);
  return TriggerEvent(&triggerResult, kAliHLTDataTypeTObject|kAliHLTDataOriginOut);
}

int AliHLTTrigger::TriggerEvent(
    AliHLTTriggerDecision* result, const AliHLTComponentDataType& type,
    AliHLTUInt32_t spec
  )
{
  // Sets a custom trigger decision for the current event.
  // See header file for more details.

  AliHLTReadoutList readoutlist = result->ReadoutList();
  // mask the readout list according to the CTP trigger
  // if the classes have been initialized (mask non-zero)
  if (CTPData() != NULL and CTPData()->Mask() != 0x0) {
    AliHLTEventDDL eventDDL = CTPData()->ReadoutList(*GetTriggerData());
    AliHLTReadoutList ctpreadout(eventDDL);
    ctpreadout.Enable(AliHLTReadoutList::kHLT);
    readoutlist.AndEq(ctpreadout);
    result->ReadoutList(readoutlist); // override the readout list with the masked one.
  }

  if (fTriggerEventResult != 0) return fTriggerEventResult;  // Do not do anything if a previous call failed.
  fTriggerEventResult = PushBack(result, type, spec);
  if (fTriggerEventResult == 0) {
    fTriggerEventResult = PushBack(readoutlist.Buffer(), readoutlist.BufferSize(), kAliHLTDataTypeReadoutList);
  }

  if (fTriggerEventResult == 0) fDecisionMade = true;
  return fTriggerEventResult;
}

void AliHLTTrigger::GetInputDataTypes(AliHLTComponentDataTypeList& list)
{
  // Calls the const version of this method.

  // Assign to const temporary variable to make sure we call the constant version
  // of the GetOutputDataTypes method.
  const AliHLTTrigger* t = this;
  t->GetInputDataTypes(list);
}

int AliHLTTrigger::GetOutputDataTypes(AliHLTComponentDataTypeList& list)
{
  // Calls the const version of this method.

  // Assign to const temporary variable to make sure we call the constant version
  // of the GetOutputDataTypes method.
  const AliHLTTrigger* t = this;
  t->GetOutputDataTypes(list);
  list.push_back(kAliHLTDataTypeReadoutList);
  return list.size();
}

int AliHLTTrigger::CreateEventDoneReadoutFilter(const AliHLTTriggerDomain& domain, unsigned type)
{
  // add a readout filter to the EventDoneData
  int iResult=0;
  unsigned nofEntries=0;
  switch (type) {
  /* readout filter */
  case 3:
  /* monitoring filter */
  case 4:
    nofEntries=domain.GetNofEntries();
    break;
  /* monitoring event command */
  case 5:
    break;
  default:
    HLTError("unknown event done data command code 0x%08x", type);
    return -EINVAL;
  }

  // we need:
  //   1 word for the filter command: readout filter, monitoring filter, monitoring event
  //   1 word for the readout filter size
  // 4*n words for the filter list
  if ((iResult=ReserveEventDoneData((nofEntries*4 + 2) * sizeof(AliHLTUInt32_t)))<0) return iResult;
  AliHLTUInt32_t eddbuffer[4];

  // add the specific command
  eddbuffer[0]=type;
  if ((iResult=PushEventDoneData(eddbuffer[0]))<0) return iResult;

  // find the valid entries
  unsigned block=0;
  vector<const AliHLTDomainEntry*> entries;
  for (block=0; block<nofEntries; block++) {
    // skip all DAQ readout entries as they are handled by the readout list
    // 2009-12-03: this turned out to cause a bug, since all blocks with data type
    // id 'any' will also match this condition. In fact, it is not necessary to
    // filter the entries, disable this condition. Code can be cleaned up later
    // if this schema has been established and tested
    // https://savannah.cern.ch/bugs/index.php?60082
    //if (domain[block]==AliHLTDomainEntry(kAliHLTDataTypeDAQRDOUT)) continue;
    if (domain[block].Exclusive()) {
      // 2009-12-03 comment out that warning for the moment
      // there are suddenly exclusive entries in the list
      // https://savannah.cern.ch/bugs/index.php?60083
      //HLTWarning("exclusive trigger domain entries are currently not handled, skipping entry %s", domain[block].AsString().Data());
      continue;
    }
    entries.push_back(&(domain[block]));
  }

  // add the number of blocks if not monitoring event command
  if (type!=5) {
    eddbuffer[0]=entries.size();
    if ((iResult=PushEventDoneData(eddbuffer[0]))<0) return iResult;
  }

  for (vector<const AliHLTDomainEntry*>::iterator entry=entries.begin();
       entry!=entries.end(); entry++) {
    (*entry)->AsBinary(eddbuffer);
    for (int n=0; n<4; n++)
      if ((iResult=PushEventDoneData(eddbuffer[n]))<0) return iResult;
  }
  return iResult;
}
<commit_msg>Improving handling of error state.<commit_after>// $Id$
/**************************************************************************
 * This file is property of and copyright by the ALICE HLT Project        *
 * ALICE Experiment at CERN, All rights reserved.                         *
 *                                                                        *
 * Primary Authors: Artur Szostak <artursz@iafrica.com>                   *
 *                  for The ALICE HLT Project.                            *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/// @file   AliHLTTrigger.h
/// @author Artur Szostak <artursz@iafrica.com>
/// @date   12 Aug 2008
/// @brief  Implementation of the AliHLTTrigger base component class.
///
/// The AliHLTTrigger class is the base class from which all HLT trigger components
/// should be derived.

#include "AliHLTTrigger.h"
#include "AliHLTTriggerDecision.h"
#include "AliHLTReadoutList.h"
#include "AliHLTTriggerDomain.h"
#include "AliHLTDomainEntry.h"
#include "AliHLTCTPData.h"

ClassImp(AliHLTTrigger)

AliHLTTrigger::AliHLTTrigger() :
	AliHLTProcessor(),
	fEventData(NULL),
	fTriggerData(NULL),
	fDecisionMade(false),
	fClearInfo(true),
	fTriggerEventResult(0),
	fDescription(),
	fReadoutList(),
	fTriggerDomain()
{
  // Default constructor sets pointers to NULL.
}

AliHLTTrigger::~AliHLTTrigger()
{
  // Default destructor.
}

void AliHLTTrigger::GetInputDataTypes(AliHLTComponentDataTypeList& list) const
{
  // Returns the kAliHLTAnyDataType type as input.
  list.push_back(kAliHLTAnyDataType);
}

void AliHLTTrigger::GetOutputDataTypes(AliHLTComponentDataTypeList& list) const
{
  // Returns the kAliHLTDataTypeTriggerDecision type as output.
  list.push_back(kAliHLTDataTypeTriggerDecision);
}

void AliHLTTrigger::GetOutputDataSize(unsigned long& constBase, double& inputMultiplier)
{
  // Returns output data size estimate.
  // See header file for more details.

  // Matthias 2009-07-03 this is presumably to small as the streamed object might be
  // bigger. This is actually the case in root v5-24-00
  // Just take 2x the size of the object
  constBase = 2*sizeof(AliHLTTriggerDecision);
  inputMultiplier = 1;
}

int AliHLTTrigger::DoEvent(const AliHLTComponentEventData& evtData, AliHLTComponentTriggerData& trigData)
{
  // Sets the pointers to the evtData and trigData, then calls the DoTrigger to
  // execute the actual trigger algorithm.

  fEventData = &evtData;
  fTriggerData = &trigData;
  fDecisionMade = false;
  fTriggerEventResult = 0;
  // Reset the description, readout list and trigger domain used by TriggerEvent
  // if requested to do so.
  if (fClearInfo)
  {
    fDescription = "";
    fReadoutList.Clear();
    fTriggerDomain.Clear();
  }

  int result = DoTrigger();
  if (result != 0) return result;

  // Fill in a default decision of false if none was made.
  if (not fDecisionMade)
  {
    TriggerEvent(false);
  }

  // Cleanup
  fEventData = NULL;
  fTriggerData = NULL;
  return fTriggerEventResult;
}

int AliHLTTrigger::TriggerEvent(bool value)
{
  // Sets the trigger decision for the current event.
  // See header file for more details.

  if (fTriggerEventResult != 0) return fTriggerEventResult;  // Do not do anything if a previous call failed.
  AliHLTTriggerDecision triggerResult(value, GetTriggerName(), fTriggerDomain, fDescription);
  // Append the readout list if it contains anything.
  triggerResult.TriggerDomain().Add(fReadoutList);
  return TriggerEvent(&triggerResult, kAliHLTDataTypeTObject|kAliHLTDataOriginOut);
}

int AliHLTTrigger::TriggerEvent(
    AliHLTTriggerDecision* result, const AliHLTComponentDataType& type,
    AliHLTUInt32_t spec
  )
{
  // Sets a custom trigger decision for the current event.
  // See header file for more details.

  if (fTriggerEventResult != 0) return fTriggerEventResult;  // Do not do anything if a previous call failed.

  AliHLTReadoutList readoutlist = result->ReadoutList();
  // mask the readout list according to the CTP trigger
  // if the classes have been initialized (mask non-zero)
  if (CTPData() != NULL and CTPData()->Mask() != 0x0) {
    AliHLTEventDDL eventDDL = CTPData()->ReadoutList(*GetTriggerData());
    AliHLTReadoutList ctpreadout(eventDDL);
    ctpreadout.Enable(AliHLTReadoutList::kHLT);
    readoutlist.AndEq(ctpreadout);
    result->ReadoutList(readoutlist); // override the readout list with the masked one.
  }

  fTriggerEventResult = PushBack(result, type, spec);
  if (fTriggerEventResult == 0) {
    fTriggerEventResult = PushBack(readoutlist.Buffer(), readoutlist.BufferSize(), kAliHLTDataTypeReadoutList);
  }

  if (fTriggerEventResult == 0) fDecisionMade = true;
  return fTriggerEventResult;
}

void AliHLTTrigger::GetInputDataTypes(AliHLTComponentDataTypeList& list)
{
  // Calls the const version of this method.

  // Assign to const temporary variable to make sure we call the constant version
  // of the GetOutputDataTypes method.
  const AliHLTTrigger* t = this;
  t->GetInputDataTypes(list);
}

int AliHLTTrigger::GetOutputDataTypes(AliHLTComponentDataTypeList& list)
{
  // Calls the const version of this method.

  // Assign to const temporary variable to make sure we call the constant version
  // of the GetOutputDataTypes method.
  const AliHLTTrigger* t = this;
  t->GetOutputDataTypes(list);
  list.push_back(kAliHLTDataTypeReadoutList);
  return list.size();
}

int AliHLTTrigger::CreateEventDoneReadoutFilter(const AliHLTTriggerDomain& domain, unsigned type)
{
  // add a readout filter to the EventDoneData
  int iResult=0;
  unsigned nofEntries=0;
  switch (type) {
  /* readout filter */
  case 3:
  /* monitoring filter */
  case 4:
    nofEntries=domain.GetNofEntries();
    break;
  /* monitoring event command */
  case 5:
    break;
  default:
    HLTError("unknown event done data command code 0x%08x", type);
    return -EINVAL;
  }

  // we need:
  //   1 word for the filter command: readout filter, monitoring filter, monitoring event
  //   1 word for the readout filter size
  // 4*n words for the filter list
  if ((iResult=ReserveEventDoneData((nofEntries*4 + 2) * sizeof(AliHLTUInt32_t)))<0) return iResult;
  AliHLTUInt32_t eddbuffer[4];

  // add the specific command
  eddbuffer[0]=type;
  if ((iResult=PushEventDoneData(eddbuffer[0]))<0) return iResult;

  // find the valid entries
  unsigned block=0;
  vector<const AliHLTDomainEntry*> entries;
  for (block=0; block<nofEntries; block++) {
    // skip all DAQ readout entries as they are handled by the readout list
    // 2009-12-03: this turned out to cause a bug, since all blocks with data type
    // id 'any' will also match this condition. In fact, it is not necessary to
    // filter the entries, disable this condition. Code can be cleaned up later
    // if this schema has been established and tested
    // https://savannah.cern.ch/bugs/index.php?60082
    //if (domain[block]==AliHLTDomainEntry(kAliHLTDataTypeDAQRDOUT)) continue;
    if (domain[block].Exclusive()) {
      // 2009-12-03 comment out that warning for the moment
      // there are suddenly exclusive entries in the list
      // https://savannah.cern.ch/bugs/index.php?60083
      //HLTWarning("exclusive trigger domain entries are currently not handled, skipping entry %s", domain[block].AsString().Data());
      continue;
    }
    entries.push_back(&(domain[block]));
  }

  // add the number of blocks if not monitoring event command
  if (type!=5) {
    eddbuffer[0]=entries.size();
    if ((iResult=PushEventDoneData(eddbuffer[0]))<0) return iResult;
  }

  for (vector<const AliHLTDomainEntry*>::iterator entry=entries.begin();
       entry!=entries.end(); entry++) {
    (*entry)->AsBinary(eddbuffer);
    for (int n=0; n<4; n++)
      if ((iResult=PushEventDoneData(eddbuffer[n]))<0) return iResult;
  }
  return iResult;
}
<|endoftext|>