<commit_before>// Copyright (c) 2020 by Robert Bosch GmbH. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef IOX_DDS_INTERNAL_GATEWAY_DDS_TO_IOX_INL
#define IOX_DDS_INTERNAL_GATEWAY_DDS_TO_IOX_INL

#include "iceoryx_dds/internal/log/logging.hpp"
#include "iceoryx_posh/capro/service_description.hpp"
#include "iceoryx_utils/cxx/string.hpp"

#include "iceoryx_dds/gateway/dds_to_iox.hpp"

namespace iox
{
namespace dds
{
template <typename channel_t, typename gateway_t>
inline DDS2IceoryxGateway<channel_t, gateway_t>::DDS2IceoryxGateway() noexcept
    : gateway_t()
{
}

template <typename channel_t, typename gateway_t>
inline void DDS2IceoryxGateway<channel_t, gateway_t>::loadConfiguration(const GatewayConfig& config) noexcept
{
    iox::LogDebug() << "[DDS2IceoryxGateway] Configuring gateway.";
    for (const auto& service : config.m_configuredServices)
    {
        if (!this->findChannel(service.m_serviceDescription).has_value())
        {
            setupChannel(service.m_serviceDescription);
        }
    }
}

template <typename channel_t, typename gateway_t>
inline void
DDS2IceoryxGateway<channel_t, gateway_t>::discover([[gnu::unused]] const iox::capro::CaproMessage& msg) noexcept
{
    /// @note not implemented - requires dds discovery which is currently not implemented in the used dds stack.
}

template <typename channel_t, typename gateway_t>
inline void DDS2IceoryxGateway<channel_t, gateway_t>::forward(const channel_t& channel) noexcept
{
    auto publisher = channel.getIceoryxTerminal();
    auto reader = channel.getDDSTerminal();

    auto peekResult = reader->peekNextSize();
    if (peekResult.has_value())
    {
        // reserve a chunk for the sample
        auto size = peekResult.value();
        m_reservedChunk = publisher->allocateChunk(static_cast<uint32_t>(size));

        // read sample into reserved chunk
        auto buffer = static_cast<uint8_t*>(m_reservedChunk);
        auto takeResult = reader->takeNext(buffer, size);
        if (takeResult.has_error())
        {
            LogWarn() << "[DDS2IceoryxGateway] Encountered error reading from DDS network: "
                      << iox::dds::DataReaderErrorString[static_cast<uint8_t>(takeResult.get_error())];
        }
        else
        {
            // publish the sample
            publisher->sendChunk(buffer);
        }
    }
}

// ======================================== Private ======================================== //
template <typename channel_t, typename gateway_t>
iox::cxx::expected<channel_t, iox::dds::GatewayError>
DDS2IceoryxGateway<channel_t, gateway_t>::setupChannel(const iox::capro::ServiceDescription& service) noexcept
{
    return this->addChannel(service).on_success(
        [&service](iox::cxx::expected<channel_t, iox::dds::GatewayError> result) {
            auto channel = result.get_value();
            auto publisher = channel.getIceoryxTerminal();
            auto reader = channel.getDDSTerminal();
            publisher->offer();
            reader->connect();
            iox::LogDebug() << "[DDS2IceoryxGateway] Setup channel for service: {" << service.getServiceIDString()
                            << ", " << service.getInstanceIDString() << ", " << service.getEventIDString() << "}";
        });
}

} // namespace dds
} // namespace iox

#endif
<commit_msg>iox-#65 Remove header includion from inl file.<commit_after>// Copyright (c) 2020 by Robert Bosch GmbH. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef IOX_DDS_INTERNAL_GATEWAY_DDS_TO_IOX_INL
#define IOX_DDS_INTERNAL_GATEWAY_DDS_TO_IOX_INL

#include "iceoryx_dds/internal/log/logging.hpp"
#include "iceoryx_posh/capro/service_description.hpp"
#include "iceoryx_utils/cxx/string.hpp"

namespace iox
{
namespace dds
{
template <typename channel_t, typename gateway_t>
inline DDS2IceoryxGateway<channel_t, gateway_t>::DDS2IceoryxGateway() noexcept
    : gateway_t()
{
}

template <typename channel_t, typename gateway_t>
inline void DDS2IceoryxGateway<channel_t, gateway_t>::loadConfiguration(const GatewayConfig& config) noexcept
{
    iox::LogDebug() << "[DDS2IceoryxGateway] Configuring gateway.";
    for (const auto& service : config.m_configuredServices)
    {
        if (!this->findChannel(service.m_serviceDescription).has_value())
        {
            setupChannel(service.m_serviceDescription);
        }
    }
}

template <typename channel_t, typename gateway_t>
inline void
DDS2IceoryxGateway<channel_t, gateway_t>::discover([[gnu::unused]] const iox::capro::CaproMessage& msg) noexcept
{
    /// @note not implemented - requires dds discovery which is currently not implemented in the used dds stack.
}

template <typename channel_t, typename gateway_t>
inline void DDS2IceoryxGateway<channel_t, gateway_t>::forward(const channel_t& channel) noexcept
{
    auto publisher = channel.getIceoryxTerminal();
    auto reader = channel.getDDSTerminal();

    auto peekResult = reader->peekNextSize();
    if (peekResult.has_value())
    {
        // reserve a chunk for the sample
        auto size = peekResult.value();
        m_reservedChunk = publisher->allocateChunk(static_cast<uint32_t>(size));

        // read sample into reserved chunk
        auto buffer = static_cast<uint8_t*>(m_reservedChunk);
        auto takeResult = reader->takeNext(buffer, size);
        if (takeResult.has_error())
        {
            LogWarn() << "[DDS2IceoryxGateway] Encountered error reading from DDS network: "
                      << iox::dds::DataReaderErrorString[static_cast<uint8_t>(takeResult.get_error())];
        }
        else
        {
            // publish the sample
            publisher->sendChunk(buffer);
        }
    }
}

// ======================================== Private ======================================== //
template <typename channel_t, typename gateway_t>
iox::cxx::expected<channel_t, iox::dds::GatewayError>
DDS2IceoryxGateway<channel_t, gateway_t>::setupChannel(const iox::capro::ServiceDescription& service) noexcept
{
    return this->addChannel(service).on_success(
        [&service](iox::cxx::expected<channel_t, iox::dds::GatewayError> result) {
            auto channel = result.get_value();
            auto publisher = channel.getIceoryxTerminal();
            auto reader = channel.getDDSTerminal();
            publisher->offer();
            reader->connect();
            iox::LogDebug() << "[DDS2IceoryxGateway] Setup channel for service: {" << service.getServiceIDString()
                            << ", " << service.getInstanceIDString() << ", " << service.getEventIDString() << "}";
        });
}

} // namespace dds
} // namespace iox

#endif
<|endoftext|>


<commit_before>#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <iostream>
#include <cstring>
#include <fcntl.h>

#define sizeLim 10
using namespace std;

struct arguments
{
	int argc;
	char **argv;
};

arguments* readPrompt();
arguments* writePrompt();
void testArgs(arguments*);
void testSuite(arguments, string);
bool isValid(arguments*);
int redirectLeft(arguments*);
int redirectRight(arguments*);

bool run;

int main()
{

	run = true;
	while (run) {

		arguments * temp = writePrompt();
		//testArgs(temp);
		int in = redirectRight(temp);
		int out = redirectLeft(temp);

		if(in>-1){
			dup2(in, 0);
		}
		if(out>-1){
			dup2(out,1);
		}

		if (isValid(temp)) {

			int status;
			long head = (long)*temp->argv;
			long mHead = (long) temp->argv;
			if (fork() != 0) {
				//parent
				*temp->argv =(char*) head;
				waitpid(-1, &status, 0);

				if(in>-1){
					close(in);
				}
				if(out>-1){
					close(out);
				}
			}
			else {
				//child
				*temp->argv = (char*)head;

				execvp(temp->argv[0], temp->argv);
				cout<<"process failed, likley due to unknown command\n";
				return 0;
			}
		}
	}

    return 0;
}

arguments* readPrompt() {
	arguments* temp = new arguments;
	string rawInput;
	int aryLen =10;
	getline(std::cin,rawInput);
	temp->argc = 1;
	char** ptr = new char*[aryLen];
	temp->argv=ptr;

	int start = 0;
	int end=0;
	for (int i=0; start < rawInput.length();start=(end+=1), ++i){//we set start to begining of next segment

		if(i==aryLen){
			aryLen+=10;
			char** tempPtr= new char*[aryLen];
			for(int j=0;j<i;++j){
				tempPtr[j]=ptr[j];
			}
		ptr=tempPtr;
		}
		end = rawInput.find(' ', start);//get the end of the next segment
		if(end==-1){
			end=rawInput.length();//were finished fall out naturally
		}
		rawInput[end]='\0';//change whitespace to NULL
		ptr[i]=&rawInput[start]; //set a new charpointer to our new segment

	}
	ptr[rawInput.length()+1] = NULL;
	//testSuite(temp, rawInput);  commented out for production

	return temp;
}
bool isValid(arguments* args) {

	char* comp = (*args->argv);

	bool tf = true;

	if (strcmp("cd", comp)==0){
		chdir(&comp[3]);
		tf = false;
	}
	else if(strcmp("pwd", comp)==0) {
		char* WD = get_current_dir_name();
		cout<<*WD<<endl;
		delete WD;
		tf = false;
	}
	else if(strcmp("quit", comp)==0){
		run = false;
		tf = false;
	}
	*args->argv=comp;
	return tf;
}

arguments* writePrompt() {
	cout << ">";
	return readPrompt();
}

void testArgs(arguments* args) { //just tests using our args class
	char * head = *args->argv;
	char* ptr = (*args->argv);
	cout << "there are " << (args->argc) << " arguments" << endl;
	while(ptr!= NULL){
		cout<<*ptr<<endl;
		++ptr;
	}
	*args->argv = head;

}

void testSuite(arguments* args, string input) {

	char* ptr = (*args->argv);
	for (int i = 0; i < args->argc; ++i, ++ptr) {
		if (!input.find(ptr, strlen(ptr)-1)) {
			cout << "failed test at: " << i << endl;
		}
	}

}

int redirectLeft(arguments* args){
	char* comp;
	for(int i=0;i<args->argc;i++){
		comp=args->argv[i];
		if(strcmp("<", comp)==0){
			return open(args->argv[i+1], O_RDONLY);
		}
		else if(strcmp("<<", comp)==0){
			return open(args->argv[i+1], O_RDONLY);
		}
	}
	return -1;
}

int redirectRight(arguments* args){
	char* comp;
	for(int i=0;i<args->argc;i++){
		comp=args->argv[i];
		if(strcmp(">", comp)==0){
			return open(args->argv[i+1], O_WRONLY |O_TRUNC | O_CREAT, S_IRUSR | S_IRGRP | S_IWGRP | S_IWUSR);
		}
		else if(strcmp(">>", comp)==0){
			int temp;
			return open(args->argv[i+1], O_WRONLY |O_APPEND | O_CREAT, S_IRUSR | S_IRGRP | S_IWGRP | S_IWUSR);
			return temp;
		}
	}
	return -1;
}
<commit_msg>forgot to set argc<commit_after>#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <iostream>
#include <cstring>
#include <fcntl.h>

#define sizeLim 10
using namespace std;

struct arguments
{
	int argc;
	char **argv;
};

arguments* readPrompt();
arguments* writePrompt();
void testArgs(arguments*);
void testSuite(arguments, string);
bool isValid(arguments*);
int redirectLeft(arguments*);
int redirectRight(arguments*);

bool run;

int main()
{

	run = true;
	while (run) {

		arguments * temp = writePrompt();

		int in = redirectRight(temp);
		int out = redirectLeft(temp);

		if(in>-1){
			dup2(in, 0);
		}
		if(out>-1){
			dup2(out,1);
		}

		if (isValid(temp)) {

			int status;
			long head = (long)*temp->argv;
			long mHead = (long) temp->argv;
			if (fork() != 0) {
				//parent
				*temp->argv =(char*) head;
				waitpid(-1, &status, 0);

				if(in>-1){
					close(in);
				}
				if(out>-1){
					close(out);
				}
			}
			else {
				//child
				*temp->argv = (char*)head;

				execvp(temp->argv[0], temp->argv);
				cout<<"process failed, likley due to unknown command\n";
				return 0;
			}
		}
	}

    return 0;
}

arguments* readPrompt() {
	arguments* temp = new arguments;
	string rawInput;
	int aryLen =10;
	getline(std::cin,rawInput);
	char** ptr = new char*[aryLen];
	temp->argv=ptr;

	int start = 0;
	int end=0;
	int i=0;
	for (; start < rawInput.length();start=(end+=1), ++i){//we set start to begining of next segment

		if(i==aryLen){
			aryLen+=10;
			char** tempPtr= new char*[aryLen];
			for(int j=0;j<i;++j){
				tempPtr[j]=ptr[j];
			}
		delete ptr;
		ptr=tempPtr;
		}
		end = rawInput.find(' ', start);//get the end of the next segment
		if(end==-1){
			end=rawInput.length();//were finished fall out naturally
		}
		rawInput[end]='\0';//change whitespace to NULL
		ptr[i]=&rawInput[start]; //set a new charpointer to our new segment
	}
	temp->argc=++i;
	temp->argv[i]=NULL;

	return temp;
}
bool isValid(arguments* args) {

	char* comp = (*args->argv);

	bool tf = true;

	if (strcmp("cd", comp)==0){
		chdir(&comp[3]);
		tf = false;
	}
	else if(strcmp("pwd", comp)==0) {
		char* WD = get_current_dir_name();
		cout<<*WD<<endl;
		delete WD;
		tf = false;
	}
	else if(strcmp("quit", comp)==0){
		run = false;
		tf = false;
	}
	*args->argv=comp;
	return tf;
}

arguments* writePrompt() {
	cout << ">";
	return readPrompt();
}

void testArgs(arguments* args) { //just tests using our args class
	char * head = *args->argv;
	char* ptr = (*args->argv);
	cout << "there are " << (args->argc) << " arguments" << endl;
	while(ptr!= NULL){
		cout<<*ptr<<endl;
		++ptr;
	}
	*args->argv = head;

}

void testSuite(arguments* args, string input) {

	char* ptr = (*args->argv);
	for (int i = 0; i < args->argc; ++i, ++ptr) {
		if (!input.find(ptr, strlen(ptr)-1)) {
			cout << "failed test at: " << i << endl;
		}
	}

}

int redirectLeft(arguments* args){
	char* comp;
	for(int i=0;i<args->argc-1;i++){
		comp=args->argv[i];
		if(strcmp("<", comp)==0){
			return open(args->argv[i+1], O_RDONLY);
		}
		else if(strcmp("<<", comp)==0){
			return open(args->argv[i+1], O_RDONLY);
		}
	}
	return -1;
}

int redirectRight(arguments* args){
	char* comp;
	for(int i=0;i<args->argc-1;i++){
		comp=args->argv[i];
		if(strcmp(">", comp)==0){
			return open(args->argv[i+1], O_WRONLY |O_TRUNC | O_CREAT);
		}
		else if(strcmp(">>", comp)==0){
			int temp;
			return open(args->argv[i+1], O_WRONLY |O_APPEND | O_CREAT);
			return temp;
		}
	}
	return -1;
}
<|endoftext|>


<commit_before>/*
grabber.cpp

Screen grabber

*/

/* Revision: 1.01 13.07.2000 $ */

/*
Modify:
  13.07.2000 SVS
    !  ४樨  ᯮ짮 new/delete/realloc
  25.06.2000 SVS
    ! ⮢ Master Copy
    ! 뤥  ⢥ ᠬ⥫쭮
*/

#include "headers.hpp"
#pragma hdrstop

/* $ 30.06.2000 IS
   ⠭
*/
#include "internalheaders.hpp"
/* IS $ */

Grabber::Grabber()
{
  SaveScr=new SaveScreen;

  PrevMacroMode=CtrlObject->Macro.GetMode();
  CtrlObject->Macro.SetMode(MACRO_OTHER);

  int Visible,Size;
  GetCursorType(Visible,Size);
  if (Visible)
    GetCursorPos(GArea.CurX,GArea.CurY);
  else
  {
    GArea.CurX=0;
    GArea.CurY=0;
  }
  GArea.X1=-1;

  SetCursorType(TRUE,60);

  PrevArea=GArea;
  ResetArea=TRUE;

  Process();
  delete SaveScr;
}

Grabber::~Grabber()
{
  CtrlObject->Macro.SetMode(PrevMacroMode);
}

void Grabber::CopyGrabbedArea(int Append)
{
  if (GArea.X1==-1)
    return;
  int X1,Y1,X2,Y2;
  X1=Min(GArea.X1,GArea.X2);
  X2=Max(GArea.X1,GArea.X2);
  Y1=Min(GArea.Y1,GArea.Y2);
  Y2=Max(GArea.Y1,GArea.Y2);
  int BufSize=(X2-X1+3)*(Y2-Y1+1);
  CHAR_INFO *CharBuf=new CHAR_INFO[BufSize];
  char *CopyBuf=new char[BufSize];
  GetText(X1,Y1,X2,Y2,CharBuf);
  *CopyBuf=0;
  for (int I=0;I<Y2-Y1+1;I++)
  {
    if (I>0)
      strcat(CopyBuf,"\r\n");
    for (int J=0;J<X2-X1+1;J++)
      strncat(CopyBuf,&CharBuf[I*(X2-X1+1)+J].Char.AsciiChar,1);
    for (int K=strlen(CopyBuf)-1;K>=0 && CopyBuf[K]==' ';K--)
      CopyBuf[K]=0;
  }
  if (Append)
  {
    char *AppendBuf=PasteFromClipboard();
    if (AppendBuf!=NULL)
    {
      int DataSize=strlen(AppendBuf);
      AppendBuf=(char *)realloc(AppendBuf,DataSize+BufSize);
      memcpy(AppendBuf+DataSize,CopyBuf,BufSize);
      /* $ 13.07.2000 SVS
         ࠧ 뢠 new[],  㦭 뢠 delete[]
      */
      delete[] CopyBuf;
      /* SVS $ */
      CopyBuf=AppendBuf;
    }
  }
  CopyToClipboard(CopyBuf);
  /* $ 13.07.2000 SVS
     ࠧ 뢠 new[],  㦭 뢠 delete[]
  */
  delete[] CopyBuf;
  delete[] CharBuf;
  /* SVS $ */
}

void Grabber::DisplayObject()
{
  MoveCursor(GArea.CurX,GArea.CurY);
  if (PrevArea.X1!=GArea.X1 || PrevArea.X2!=GArea.X2 ||
      PrevArea.Y1!=GArea.Y1 || PrevArea.Y2!=GArea.Y2)
  {
    int X1,Y1,X2,Y2;
    X1=Min(GArea.X1,GArea.X2);
    X2=Max(GArea.X1,GArea.X2);
    Y1=Min(GArea.Y1,GArea.Y2);
    Y2=Max(GArea.Y1,GArea.Y2);
    if (X1>Min(PrevArea.X1,PrevArea.X2) || X2<Max(PrevArea.X1,PrevArea.X2) ||
        Y1>Min(PrevArea.Y1,PrevArea.Y2) || Y2<Max(PrevArea.Y1,PrevArea.Y2))
      SaveScr->RestoreArea(FALSE);
    if (GArea.X1!=-1)
    {
      CHAR_INFO *CharBuf=new CHAR_INFO[(X2-X1+1)*(Y2-Y1+1)];
      CHAR_INFO *PrevBuf=SaveScr->GetBufferAddress();
      GetText(X1,Y1,X2,Y2,CharBuf);
      for (int X=X1;X<=X2;X++)
        for (int Y=Y1;Y<=Y2;Y++)
        {
          int NewColor;
          if ((PrevBuf[X+Y*(ScrX+1)].Attributes & B_LIGHTGRAY)==B_LIGHTGRAY)
            NewColor=B_BLACK|F_LIGHTGRAY;
          else
            NewColor=B_LIGHTGRAY|F_BLACK;
          int Pos=(X-X1)+(Y-Y1)*(X2-X1+1);
          CharBuf[Pos].Attributes=(CharBuf[Pos].Attributes & ~0xff) | NewColor;
        }
      PutText(X1,Y1,X2,Y2,CharBuf);
      /* $ 13.07.2000 SVS
         ࠧ 뢠 new[],  㦭 뢠 delete[]
      */
      delete[] CharBuf;
      /* SVS $ */
    }
    PrevArea=GArea;
  }
}

int Grabber::ProcessKey(int Key)
{
  if (ShiftPressed && Key!=KEY_NONE && ResetArea)
  {
    GArea.X1=GArea.X2=GArea.CurX;
    GArea.Y1=GArea.Y2=GArea.CurY;
    ResetArea=FALSE;
  }
  else
    if (Key!=KEY_NONE && Key!=KEY_SHIFT && !ShiftPressed)
      ResetArea=TRUE;

  switch(Key)
  {
    case KEY_ESC:
      SetExitCode(0);
      break;
    case KEY_ENTER:
    case KEY_CTRLINS:
    case KEY_CTRLADD:
      CopyGrabbedArea(Key==KEY_CTRLADD);
      SetExitCode(1);
      break;
    case KEY_LEFT:
      if (GArea.CurX>0)
        GArea.CurX--;
      break;
    case KEY_RIGHT:
      if (GArea.CurX<ScrX)
        GArea.CurX++;
      break;
    case KEY_UP:
      if (GArea.CurY>0)
        GArea.CurY--;
      break;
    case KEY_DOWN:
      if (GArea.CurY<ScrY)
        GArea.CurY++;
      break;
    case KEY_HOME:
      GArea.CurX=0;
      break;
    case KEY_END:
      GArea.CurX=ScrX;
      break;
    case KEY_PGUP:
      GArea.CurY=0;
      break;
    case KEY_PGDN:
      GArea.CurY=ScrY;
      break;
    case KEY_CTRLHOME:
      GArea.CurX=GArea.CurY=0;
      break;
    case KEY_CTRLEND:
      GArea.CurX=ScrX;
      GArea.CurY=ScrY;
      break;
    case KEY_CTRLLEFT:
      if ((GArea.CurX-=10)<0)
        GArea.CurX=0;
      break;
    case KEY_CTRLRIGHT:
      if ((GArea.CurX+=10)>ScrX)
        GArea.CurX=ScrX;
      break;
    case KEY_CTRLUP:
      if ((GArea.CurY-=5)<0)
        GArea.CurY=0;
      break;
    case KEY_CTRLDOWN:
      if ((GArea.CurY+=5)>ScrY)
        GArea.CurY=ScrY;
      break;
    case KEY_SHIFTLEFT:
      if (GArea.X1>0)
        GArea.X1--;
      GArea.CurX=GArea.X1;
      break;
    case KEY_SHIFTRIGHT:
      if (GArea.X1<ScrX)
        GArea.X1++;
      GArea.CurX=GArea.X1;
      break;
    case KEY_SHIFTUP:
      if (GArea.Y1>0)
        GArea.Y1--;
      GArea.CurY=GArea.Y1;
      break;
    case KEY_SHIFTDOWN:
      if (GArea.Y1<ScrY)
        GArea.Y1++;
      GArea.CurY=GArea.Y1;
      break;
    case KEY_SHIFTHOME:
      GArea.CurX=GArea.X1=0;
      break;
    case KEY_SHIFTEND:
      GArea.CurX=GArea.X1=ScrX;
      break;
    case KEY_SHIFTPGUP:
      GArea.CurY=GArea.Y1=0;
      break;
    case KEY_SHIFTPGDN:
      GArea.CurY=GArea.Y1=ScrY;
      break;
  }
  DisplayObject();
  return(TRUE);
}

int Grabber::ProcessMouse(MOUSE_EVENT_RECORD *MouseEvent)
{
  if (MouseEvent->dwEventFlags==DOUBLE_CLICK ||
      MouseEvent->dwEventFlags==0 && (MouseEvent->dwButtonState & RIGHTMOST_BUTTON_PRESSED))
  {
    ProcessKey(KEY_ENTER);
    return(TRUE);
  }
  if (!LButtonPressed)
    return(FALSE);
  GArea.CurX=MouseX;
  GArea.CurY=MouseY;
  if (MouseEvent->dwEventFlags==0)
    ResetArea=TRUE;
  else
    if (MouseEvent->dwEventFlags==MOUSE_MOVED)
    {
      if (ResetArea)
      {
        GArea.X2=GArea.CurX;
        GArea.Y2=GArea.CurY;
        ResetArea=FALSE;
      }
      GArea.X1=GArea.CurX;
      GArea.Y1=GArea.CurY;
    }
  DisplayObject();
  return(TRUE);
}

<commit_msg>FAR patch 00127.grabber.cpp Дата              : 14.08.2000 Сделал            : andrey tretjakov Описание          : убирает трап при проигрывании макроса c ShiftEnd Измененные файлы  : grabber.cpp Состав            : grabber.cpp.txt grabber.cpp.diff Основан на патче  : 124 Дополнение        :<commit_after>/*
grabber.cpp

Screen grabber

*/

/* Revision: 1.02 14.08.2000 $ */

/*
Modify:
  14.08.2000 tran
    - trap  ந뢠   蠬 ⨯ Shift...
  13.07.2000 SVS
    !  ४樨  ᯮ짮 new/delete/realloc
  25.06.2000 SVS
    ! ⮢ Master Copy
    ! 뤥  ⢥ ᠬ⥫쭮
*/

#include "headers.hpp"
#pragma hdrstop

/* $ 30.06.2000 IS
   ⠭
*/
#include "internalheaders.hpp"
/* IS $ */

Grabber::Grabber()
{
  SaveScr=new SaveScreen;

  PrevMacroMode=CtrlObject->Macro.GetMode();
  CtrlObject->Macro.SetMode(MACRO_OTHER);

  /* $ 14.08.2000 tran
        蠥 ,  㦥  ࠯ */
  memset(&GArea,0,sizeof(GArea));
  memset(&PrevArea,0,sizeof(PrevArea));
  /* tran 14.08.2000 $ */

  int Visible,Size;
  GetCursorType(Visible,Size);
  if (Visible)
    GetCursorPos(GArea.CurX,GArea.CurY);
  else
  {
    GArea.CurX=0;
    GArea.CurY=0;
  }
  GArea.X1=-1;

  SetCursorType(TRUE,60);

  PrevArea=GArea;
  ResetArea=TRUE;

  Process();
  delete SaveScr;
}

Grabber::~Grabber()
{
  CtrlObject->Macro.SetMode(PrevMacroMode);
}

void Grabber::CopyGrabbedArea(int Append)
{
  if (GArea.X1==-1)
    return;
  int X1,Y1,X2,Y2;
  X1=Min(GArea.X1,GArea.X2);
  X2=Max(GArea.X1,GArea.X2);
  Y1=Min(GArea.Y1,GArea.Y2);
  Y2=Max(GArea.Y1,GArea.Y2);
  int BufSize=(X2-X1+3)*(Y2-Y1+1);
  CHAR_INFO *CharBuf=new CHAR_INFO[BufSize];
  char *CopyBuf=new char[BufSize];
  GetText(X1,Y1,X2,Y2,CharBuf);
  *CopyBuf=0;
  for (int I=0;I<Y2-Y1+1;I++)
  {
    if (I>0)
      strcat(CopyBuf,"\r\n");
    for (int J=0;J<X2-X1+1;J++)
      strncat(CopyBuf,&CharBuf[I*(X2-X1+1)+J].Char.AsciiChar,1);
    for (int K=strlen(CopyBuf)-1;K>=0 && CopyBuf[K]==' ';K--)
      CopyBuf[K]=0;
  }
  if (Append)
  {
    char *AppendBuf=PasteFromClipboard();
    if (AppendBuf!=NULL)
    {
      int DataSize=strlen(AppendBuf);
      AppendBuf=(char *)realloc(AppendBuf,DataSize+BufSize);
      memcpy(AppendBuf+DataSize,CopyBuf,BufSize);
      /* $ 13.07.2000 SVS
         ࠧ 뢠 new[],  㦭 뢠 delete[]
      */
      delete[] CopyBuf;
      /* SVS $ */
      CopyBuf=AppendBuf;
    }
  }
  CopyToClipboard(CopyBuf);
  /* $ 13.07.2000 SVS
     ࠧ 뢠 new[],  㦭 뢠 delete[]
  */
  delete[] CopyBuf;
  delete[] CharBuf;
  /* SVS $ */
}

void Grabber::DisplayObject()
{
  MoveCursor(GArea.CurX,GArea.CurY);
  if (PrevArea.X1!=GArea.X1 || PrevArea.X2!=GArea.X2 ||
      PrevArea.Y1!=GArea.Y1 || PrevArea.Y2!=GArea.Y2)
  {
    int X1,Y1,X2,Y2;
    X1=Min(GArea.X1,GArea.X2);
    X2=Max(GArea.X1,GArea.X2);
    Y1=Min(GArea.Y1,GArea.Y2);
    Y2=Max(GArea.Y1,GArea.Y2);
    if (X1>Min(PrevArea.X1,PrevArea.X2) || X2<Max(PrevArea.X1,PrevArea.X2) ||
        Y1>Min(PrevArea.Y1,PrevArea.Y2) || Y2<Max(PrevArea.Y1,PrevArea.Y2))
      SaveScr->RestoreArea(FALSE);
    if (GArea.X1!=-1)
    {
      CHAR_INFO *CharBuf=new CHAR_INFO[(X2-X1+1)*(Y2-Y1+1)];
      CHAR_INFO *PrevBuf=SaveScr->GetBufferAddress();
      GetText(X1,Y1,X2,Y2,CharBuf);
      for (int X=X1;X<=X2;X++)
        for (int Y=Y1;Y<=Y2;Y++)
        {
          int NewColor;
          if ((PrevBuf[X+Y*(ScrX+1)].Attributes & B_LIGHTGRAY)==B_LIGHTGRAY)
            NewColor=B_BLACK|F_LIGHTGRAY;
          else
            NewColor=B_LIGHTGRAY|F_BLACK;
          int Pos=(X-X1)+(Y-Y1)*(X2-X1+1);
          CharBuf[Pos].Attributes=(CharBuf[Pos].Attributes & ~0xff) | NewColor;
        }
      PutText(X1,Y1,X2,Y2,CharBuf);
      /* $ 13.07.2000 SVS
         ࠧ 뢠 new[],  㦭 뢠 delete[]
      */
      delete[] CharBuf;
      /* SVS $ */
    }
    PrevArea=GArea;
  }
}

int Grabber::ProcessKey(int Key)
{
  if (ShiftPressed && Key!=KEY_NONE && ResetArea)
  {
    GArea.X1=GArea.X2=GArea.CurX;
    GArea.Y1=GArea.Y2=GArea.CurY;
    ResetArea=FALSE;
  }
  else
    if (Key!=KEY_NONE && Key!=KEY_SHIFT && !ShiftPressed)
      ResetArea=TRUE;

  switch(Key)
  {
    case KEY_ESC:
      SetExitCode(0);
      break;
    case KEY_ENTER:
    case KEY_CTRLINS:
    case KEY_CTRLADD:
      CopyGrabbedArea(Key==KEY_CTRLADD);
      SetExitCode(1);
      break;
    case KEY_LEFT:
      if (GArea.CurX>0)
        GArea.CurX--;
      break;
    case KEY_RIGHT:
      if (GArea.CurX<ScrX)
        GArea.CurX++;
      break;
    case KEY_UP:
      if (GArea.CurY>0)
        GArea.CurY--;
      break;
    case KEY_DOWN:
      if (GArea.CurY<ScrY)
        GArea.CurY++;
      break;
    case KEY_HOME:
      GArea.CurX=0;
      break;
    case KEY_END:
      GArea.CurX=ScrX;
      break;
    case KEY_PGUP:
      GArea.CurY=0;
      break;
    case KEY_PGDN:
      GArea.CurY=ScrY;
      break;
    case KEY_CTRLHOME:
      GArea.CurX=GArea.CurY=0;
      break;
    case KEY_CTRLEND:
      GArea.CurX=ScrX;
      GArea.CurY=ScrY;
      break;
    case KEY_CTRLLEFT:
      if ((GArea.CurX-=10)<0)
        GArea.CurX=0;
      break;
    case KEY_CTRLRIGHT:
      if ((GArea.CurX+=10)>ScrX)
        GArea.CurX=ScrX;
      break;
    case KEY_CTRLUP:
      if ((GArea.CurY-=5)<0)
        GArea.CurY=0;
      break;
    case KEY_CTRLDOWN:
      if ((GArea.CurY+=5)>ScrY)
        GArea.CurY=ScrY;
      break;
    case KEY_SHIFTLEFT:
      if (GArea.X1>0)
        GArea.X1--;
      GArea.CurX=GArea.X1;
      break;
    case KEY_SHIFTRIGHT:
      if (GArea.X1<ScrX)
        GArea.X1++;
      GArea.CurX=GArea.X1;
      break;
    case KEY_SHIFTUP:
      if (GArea.Y1>0)
        GArea.Y1--;
      GArea.CurY=GArea.Y1;
      break;
    case KEY_SHIFTDOWN:
      if (GArea.Y1<ScrY)
        GArea.Y1++;
      GArea.CurY=GArea.Y1;
      break;
    case KEY_SHIFTHOME:
      GArea.CurX=GArea.X1=0;
      break;
    case KEY_SHIFTEND:
      GArea.CurX=GArea.X1=ScrX;
      break;
    case KEY_SHIFTPGUP:
      GArea.CurY=GArea.Y1=0;
      break;
    case KEY_SHIFTPGDN:
      GArea.CurY=GArea.Y1=ScrY;
      break;
  }
  DisplayObject();
  return(TRUE);
}

int Grabber::ProcessMouse(MOUSE_EVENT_RECORD *MouseEvent)
{
  if (MouseEvent->dwEventFlags==DOUBLE_CLICK ||
      MouseEvent->dwEventFlags==0 && (MouseEvent->dwButtonState & RIGHTMOST_BUTTON_PRESSED))
  {
    ProcessKey(KEY_ENTER);
    return(TRUE);
  }
  if (!LButtonPressed)
    return(FALSE);
  GArea.CurX=MouseX;
  GArea.CurY=MouseY;
  if (MouseEvent->dwEventFlags==0)
    ResetArea=TRUE;
  else
    if (MouseEvent->dwEventFlags==MOUSE_MOVED)
    {
      if (ResetArea)
      {
        GArea.X2=GArea.CurX;
        GArea.Y2=GArea.CurY;
        ResetArea=FALSE;
      }
      GArea.X1=GArea.CurX;
      GArea.Y1=GArea.CurY;
    }
  DisplayObject();
  return(TRUE);
}

<|endoftext|>


<commit_before>// ======================================================================== //
// Copyright 2009-2015 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#include "QOSPRayWindow.h"

QOSPRayWindow::QOSPRayWindow(QMainWindow *parent,
                             OSPRenderer renderer,
                             bool showFrameRate,
                             std::string writeFramesFilename)
  : parent(parent),
    showFrameRate(showFrameRate),
    frameCount(0),
    renderingEnabled(false),
    rotationRate(0.f),
    benchmarkWarmUpFrames(0),
    benchmarkFrames(0),
    frameBuffer(NULL),
    renderer(NULL),
    camera(NULL),
    writeFramesFilename(writeFramesFilename)
{
  // assign renderer
  if(!renderer)
    throw std::runtime_error("QOSPRayWindow: must be constructed with an existing renderer");

  this->renderer = renderer;

  // setup camera
  camera = ospNewCamera("perspective");

  if(!camera)
    throw std::runtime_error("QOSPRayWindow: could not create camera type 'perspective'");

  ospCommit(camera);

  ospSetObject(renderer, "camera", camera);

  // connect signals and slots
  connect(&renderTimer, SIGNAL(timeout()), this, SLOT(updateGL()));
}

QOSPRayWindow::~QOSPRayWindow()
{
  // free the frame buffer and camera
  // we don't own the renderer!
  if(frameBuffer)
    ospFreeFrameBuffer(frameBuffer);

  if(camera)
    ospRelease(camera);
}

void QOSPRayWindow::setRenderingEnabled(bool renderingEnabled)
{
  this->renderingEnabled = renderingEnabled;

  // trigger render if true
  if(renderingEnabled == true)
    renderTimer.start();
  else
    renderTimer.stop();
}

void QOSPRayWindow::setRotationRate(float rotationRate)
{
  this->rotationRate = rotationRate;
}

void QOSPRayWindow::setBenchmarkParameters(int benchmarkWarmUpFrames, int benchmarkFrames)
{
  this->benchmarkWarmUpFrames = benchmarkWarmUpFrames;
  this->benchmarkFrames = benchmarkFrames;
}

void QOSPRayWindow::setWorldBounds(const osp::box3f &worldBounds)
{
  this->worldBounds = worldBounds;

  // set viewport look at point to center of world bounds
  viewport.at = center(worldBounds);

  // set viewport from point relative to center of world bounds
  viewport.from = viewport.at - 1.5f * viewport.frame.l.vy;

  updateGL();
}

void QOSPRayWindow::paintGL()
{
  if(!renderingEnabled || !frameBuffer || !renderer)
    return;

  // if we're benchmarking and we've completed the required number of warm-up frames, start the timer
  if(benchmarkFrames > 0 && frameCount == benchmarkWarmUpFrames) {
    std::cout << "starting benchmark timer" << std::endl;
    benchmarkTimer.start();
  }

  // update OSPRay camera if viewport has been modified
  if(viewport.modified) {
    ospSetVec3f(camera,"pos" ,viewport.from);
    ospSetVec3f(camera,"dir" ,viewport.at - viewport.from);
    ospSetVec3f(camera,"up", viewport.up);
    ospSetf(camera,"aspect", viewport.aspect);
    ospSetf(camera,"fovy", viewport.fovY);

    ospCommit(camera);

    viewport.modified = false;
  }

  renderFrameTimer.start();
  ospRenderFrame(frameBuffer, renderer, OSP_FB_COLOR | OSP_FB_ACCUM);
  double framesPerSecond = 1000.0 / renderFrameTimer.elapsed();
  char title[1024];  sprintf(title, "OSPRay Volume Viewer (%.4f fps)", framesPerSecond);
  if (showFrameRate == true) parent->setWindowTitle(title);

  uint32 *mappedFrameBuffer = (unsigned int *) ospMapFrameBuffer(frameBuffer);

  glDrawPixels(windowSize.x, windowSize.y, GL_RGBA, GL_UNSIGNED_BYTE, mappedFrameBuffer);
  if (writeFramesFilename.length()) writeFrameBufferToFile(mappedFrameBuffer);

  ospUnmapFrameBuffer(mappedFrameBuffer, frameBuffer);

  // automatic rotation
  if(rotationRate != 0.f) {
    resetAccumulationBuffer();
    rotateCenter(rotationRate, 0.f);
  }

  // increment frame counter
  frameCount++;

  // quit if we're benchmarking and have exceeded the needed number of frames
  if(benchmarkFrames > 0 && frameCount >= benchmarkWarmUpFrames + benchmarkFrames) {

    float elapsedSeconds = float(benchmarkTimer.elapsed()) / 1000.f;

    std::cout << "benchmark: " << elapsedSeconds << " elapsed seconds ==> " << float(benchmarkFrames) / elapsedSeconds << " fps" << std::endl;

    QCoreApplication::quit();
  }
}

void QOSPRayWindow::resizeGL(int width, int height)
{
  windowSize = osp::vec2i(width, height);

  // reallocate OSPRay framebuffer for new size
  if(frameBuffer)
    ospFreeFrameBuffer(frameBuffer);

  frameBuffer = ospNewFrameBuffer(windowSize, OSP_RGBA_I8, OSP_FB_COLOR | OSP_FB_ACCUM);

  // update viewport aspect ratio
  viewport.aspect = float(width) / float(height);
  viewport.modified = true;

  // update OpenGL viewport and force redraw
  glViewport(0, 0, width, height);
  updateGL();
}

void QOSPRayWindow::mousePressEvent(QMouseEvent * event)
{
  lastMousePosition = event->pos();
}

void QOSPRayWindow::mouseReleaseEvent(QMouseEvent * event)
{
  lastMousePosition = event->pos();
}

void QOSPRayWindow::mouseMoveEvent(QMouseEvent * event)
{
  resetAccumulationBuffer();

  int dx = event->x() - lastMousePosition.x();
  int dy = event->y() - lastMousePosition.y();

  if(event->buttons() & Qt::LeftButton) {

    // camera rotation about center point
    const float rotationSpeed = 0.003f;

    float du = dx * rotationSpeed;
    float dv = dy * rotationSpeed;

    rotateCenter(du, dv);
  }
  else if(event->buttons() & Qt::RightButton) {

    // camera distance from center point
    const float motionSpeed = 0.012f;

    float forward = dy * motionSpeed;
    float oldDistance = length(viewport.at - viewport.from);
    float newDistance = oldDistance - forward;

    if(newDistance < 1e-3f)
      return;

    viewport.from = viewport.at - newDistance * viewport.frame.l.vy;
    viewport.frame.p = viewport.from;

    viewport.modified = true;
  }

  lastMousePosition = event->pos();

  updateGL();
}

void QOSPRayWindow::rotateCenter(float du, float dv)
{
  const osp::vec3f pivot = center(worldBounds);

  osp::affine3f xfm = osp::affine3f::translate(pivot)
    * osp::affine3f::rotate(viewport.frame.l.vx, -dv)
    * osp::affine3f::rotate(viewport.frame.l.vz, -du)
    * osp::affine3f::translate(-pivot);

  viewport.frame = xfm * viewport.frame;
  viewport.from  = xfmPoint(xfm, viewport.from);
  viewport.at    = xfmPoint(xfm, viewport.at);
  viewport.snapUp();

  viewport.modified = true;
}

void QOSPRayWindow::writeFrameBufferToFile(const uint32 *pixelData)
{
  static uint32 frameNumber = 0;
  char filename[1024];
  sprintf(filename, "%s_%05u.ppm", writeFramesFilename.c_str(), frameNumber++);
  FILE *file = fopen(filename, "wb");  if (!file) { std::cerr << "unable to write to file '" << filename << "'" << std::endl;  return; }

  fprintf(file, "P6\n%i %i\n255\n", windowSize.x, windowSize.y);
  unsigned char out[3 * windowSize.x];
  for (int y=0 ; y < windowSize.y ; y++) {
    const unsigned char *in = (const unsigned char *) &pixelData[(windowSize.y - 1 - y) * windowSize.x];
    for (int x=0 ; x < windowSize.x ; x++) {
      out[3 * x + 0] = in[4 * x + 0];
      out[3 * x + 1] = in[4 * x + 1];
      out[3 * x + 2] = in[4 * x + 2];
    }
    fwrite(&out, 3 * windowSize.x, sizeof(char), file);
  }
  fprintf(file, "\n");
  fclose(file);
}
<commit_msg>volume viewer resets accumulation on window resize.<commit_after>// ======================================================================== //
// Copyright 2009-2015 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#include "QOSPRayWindow.h"

QOSPRayWindow::QOSPRayWindow(QMainWindow *parent,
                             OSPRenderer renderer,
                             bool showFrameRate,
                             std::string writeFramesFilename)
  : parent(parent),
    showFrameRate(showFrameRate),
    frameCount(0),
    renderingEnabled(false),
    rotationRate(0.f),
    benchmarkWarmUpFrames(0),
    benchmarkFrames(0),
    frameBuffer(NULL),
    renderer(NULL),
    camera(NULL),
    writeFramesFilename(writeFramesFilename)
{
  // assign renderer
  if(!renderer)
    throw std::runtime_error("QOSPRayWindow: must be constructed with an existing renderer");

  this->renderer = renderer;

  // setup camera
  camera = ospNewCamera("perspective");

  if(!camera)
    throw std::runtime_error("QOSPRayWindow: could not create camera type 'perspective'");

  ospCommit(camera);

  ospSetObject(renderer, "camera", camera);

  // connect signals and slots
  connect(&renderTimer, SIGNAL(timeout()), this, SLOT(updateGL()));
}

QOSPRayWindow::~QOSPRayWindow()
{
  // free the frame buffer and camera
  // we don't own the renderer!
  if(frameBuffer)
    ospFreeFrameBuffer(frameBuffer);

  if(camera)
    ospRelease(camera);
}

void QOSPRayWindow::setRenderingEnabled(bool renderingEnabled)
{
  this->renderingEnabled = renderingEnabled;

  // trigger render if true
  if(renderingEnabled == true)
    renderTimer.start();
  else
    renderTimer.stop();
}

void QOSPRayWindow::setRotationRate(float rotationRate)
{
  this->rotationRate = rotationRate;
}

void QOSPRayWindow::setBenchmarkParameters(int benchmarkWarmUpFrames, int benchmarkFrames)
{
  this->benchmarkWarmUpFrames = benchmarkWarmUpFrames;
  this->benchmarkFrames = benchmarkFrames;
}

void QOSPRayWindow::setWorldBounds(const osp::box3f &worldBounds)
{
  this->worldBounds = worldBounds;

  // set viewport look at point to center of world bounds
  viewport.at = center(worldBounds);

  // set viewport from point relative to center of world bounds
  viewport.from = viewport.at - 1.5f * viewport.frame.l.vy;

  updateGL();
}

void QOSPRayWindow::paintGL()
{
  if(!renderingEnabled || !frameBuffer || !renderer)
    return;

  // if we're benchmarking and we've completed the required number of warm-up frames, start the timer
  if(benchmarkFrames > 0 && frameCount == benchmarkWarmUpFrames) {
    std::cout << "starting benchmark timer" << std::endl;
    benchmarkTimer.start();
  }

  // update OSPRay camera if viewport has been modified
  if(viewport.modified) {
    ospSetVec3f(camera,"pos" ,viewport.from);
    ospSetVec3f(camera,"dir" ,viewport.at - viewport.from);
    ospSetVec3f(camera,"up", viewport.up);
    ospSetf(camera,"aspect", viewport.aspect);
    ospSetf(camera,"fovy", viewport.fovY);

    ospCommit(camera);

    viewport.modified = false;
  }

  renderFrameTimer.start();
  ospRenderFrame(frameBuffer, renderer, OSP_FB_COLOR | OSP_FB_ACCUM);
  double framesPerSecond = 1000.0 / renderFrameTimer.elapsed();
  char title[1024];  sprintf(title, "OSPRay Volume Viewer (%.4f fps)", framesPerSecond);
  if (showFrameRate == true) parent->setWindowTitle(title);

  uint32 *mappedFrameBuffer = (unsigned int *) ospMapFrameBuffer(frameBuffer);

  glDrawPixels(windowSize.x, windowSize.y, GL_RGBA, GL_UNSIGNED_BYTE, mappedFrameBuffer);
  if (writeFramesFilename.length()) writeFrameBufferToFile(mappedFrameBuffer);

  ospUnmapFrameBuffer(mappedFrameBuffer, frameBuffer);

  // automatic rotation
  if(rotationRate != 0.f) {
    resetAccumulationBuffer();
    rotateCenter(rotationRate, 0.f);
  }

  // increment frame counter
  frameCount++;

  // quit if we're benchmarking and have exceeded the needed number of frames
  if(benchmarkFrames > 0 && frameCount >= benchmarkWarmUpFrames + benchmarkFrames) {

    float elapsedSeconds = float(benchmarkTimer.elapsed()) / 1000.f;

    std::cout << "benchmark: " << elapsedSeconds << " elapsed seconds ==> " << float(benchmarkFrames) / elapsedSeconds << " fps" << std::endl;

    QCoreApplication::quit();
  }
}

void QOSPRayWindow::resizeGL(int width, int height)
{
  windowSize = osp::vec2i(width, height);

  // reallocate OSPRay framebuffer for new size
  if(frameBuffer)
    ospFreeFrameBuffer(frameBuffer);

  frameBuffer = ospNewFrameBuffer(windowSize, OSP_RGBA_I8, OSP_FB_COLOR | OSP_FB_ACCUM);

  resetAccumulationBuffer();

  // update viewport aspect ratio
  viewport.aspect = float(width) / float(height);
  viewport.modified = true;

  // update OpenGL viewport and force redraw
  glViewport(0, 0, width, height);
  updateGL();
}

void QOSPRayWindow::mousePressEvent(QMouseEvent * event)
{
  lastMousePosition = event->pos();
}

void QOSPRayWindow::mouseReleaseEvent(QMouseEvent * event)
{
  lastMousePosition = event->pos();
}

void QOSPRayWindow::mouseMoveEvent(QMouseEvent * event)
{
  resetAccumulationBuffer();

  int dx = event->x() - lastMousePosition.x();
  int dy = event->y() - lastMousePosition.y();

  if(event->buttons() & Qt::LeftButton) {

    // camera rotation about center point
    const float rotationSpeed = 0.003f;

    float du = dx * rotationSpeed;
    float dv = dy * rotationSpeed;

    rotateCenter(du, dv);
  }
  else if(event->buttons() & Qt::RightButton) {

    // camera distance from center point
    const float motionSpeed = 0.012f;

    float forward = dy * motionSpeed;
    float oldDistance = length(viewport.at - viewport.from);
    float newDistance = oldDistance - forward;

    if(newDistance < 1e-3f)
      return;

    viewport.from = viewport.at - newDistance * viewport.frame.l.vy;
    viewport.frame.p = viewport.from;

    viewport.modified = true;
  }

  lastMousePosition = event->pos();

  updateGL();
}

void QOSPRayWindow::rotateCenter(float du, float dv)
{
  const osp::vec3f pivot = center(worldBounds);

  osp::affine3f xfm = osp::affine3f::translate(pivot)
    * osp::affine3f::rotate(viewport.frame.l.vx, -dv)
    * osp::affine3f::rotate(viewport.frame.l.vz, -du)
    * osp::affine3f::translate(-pivot);

  viewport.frame = xfm * viewport.frame;
  viewport.from  = xfmPoint(xfm, viewport.from);
  viewport.at    = xfmPoint(xfm, viewport.at);
  viewport.snapUp();

  viewport.modified = true;
}

void QOSPRayWindow::writeFrameBufferToFile(const uint32 *pixelData)
{
  static uint32 frameNumber = 0;
  char filename[1024];
  sprintf(filename, "%s_%05u.ppm", writeFramesFilename.c_str(), frameNumber++);
  FILE *file = fopen(filename, "wb");  if (!file) { std::cerr << "unable to write to file '" << filename << "'" << std::endl;  return; }

  fprintf(file, "P6\n%i %i\n255\n", windowSize.x, windowSize.y);
  unsigned char out[3 * windowSize.x];
  for (int y=0 ; y < windowSize.y ; y++) {
    const unsigned char *in = (const unsigned char *) &pixelData[(windowSize.y - 1 - y) * windowSize.x];
    for (int x=0 ; x < windowSize.x ; x++) {
      out[3 * x + 0] = in[4 * x + 0];
      out[3 * x + 1] = in[4 * x + 1];
      out[3 * x + 2] = in[4 * x + 2];
    }
    fwrite(&out, 3 * windowSize.x, sizeof(char), file);
  }
  fprintf(file, "\n");
  fclose(file);
}
<|endoftext|>


<commit_before>#include <nan.h>
#include <v8-profiler.h>
#include <stdlib.h>
#if defined(_WIN32)
  #include <time.h>
  #define snprintf _snprintf
#else
  #include <sys/time.h>
#endif

using namespace v8;

char filename[256];
bool addTimestamp;

class FileOutputStream: public OutputStream {
  public:
    FileOutputStream(FILE* stream): stream_(stream) { }
    virtual int GetChunkSize() {
      return 65536;
    }
    virtual void EndOfStream() { }
    virtual WriteResult WriteAsciiChunk(char* data, int size) {
      const size_t len = static_cast<size_t>(size);
      size_t off = 0;
      while (off < len && !feof(stream_) && !ferror(stream_))
        off += fwrite(data + off, 1, len - off, stream_);
      return off == len ? kContinue : kAbort;
    }

  private:
    FILE* stream_;
};

void OnOOMError(const char *location, bool is_heap_oom) {
  if (addTimestamp) {
    // Add timestamp to filename
    time_t rawtime;
    struct tm* timeinfo;
    time(&rawtime);
    timeinfo = localtime(&rawtime);

    char * pch;
    pch = strstr (filename,".heapsnapshot");
    strncpy (pch,"",1);
    strcat (filename, "-%Y%m%dT%H%M%S.heapsnapshot");

    char newFilename[256];
    strftime(newFilename, sizeof(filename), filename, timeinfo);
    strcpy(filename, newFilename);
  }

  fprintf(stderr, "Generating Heapdump to '%s' now...\n", filename);
  FILE* fp = fopen(filename, "w");
  if (fp == NULL) abort();

  // Create heapdump, depending on which Node.js version this can differ
  // for now, just support Node.js 7 and higher
  const HeapSnapshot* snap = v8::Isolate::GetCurrent()->GetHeapProfiler()->TakeHeapSnapshot();

  FileOutputStream stream(fp);
  snap->Serialize(&stream, HeapSnapshot::kJSON);
  fclose(fp);

  fprintf(stderr, "Done! Exiting process now.\n");
  exit(1);
}

void ParseArgumentsAndSetErrorHandler(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();
  isolate->SetOOMErrorHandler(OnOOMError);

  // parse JS arguments
  // 1: filename
  // 2: addTimestamp boolean
  #if NODE_VERSION_AT_LEAST(9, 0, 0)
  String::Utf8Value fArg(isolate, args[0]->ToString());
  #else
  String::Utf8Value fArg(args[0]->ToString());
  #endif
  strncpy(filename, (const char*)(*fArg), sizeof(filename) - 1);

  addTimestamp = args[1]->BooleanValue();
}

void init(Local<Object> exports) {
  NODE_SET_METHOD(exports, "call", ParseArgumentsAndSetErrorHandler);
}

NODE_MODULE(NODE_OOM_HEAPDUMP_NATIVE, init)<commit_msg>Initial try-out for making it Node 12 compatible. Still we should look into using "Maybe" version of v8 API: https://github.com/joyeecheung/node/blob/v8-maybe-doc/CPP_STYLE_GUIDE.md#use-maybe-version-of-v8-apis<commit_after>#include <nan.h>
#include <v8-profiler.h>
#include <stdlib.h>
#if defined(_WIN32)
  #include <time.h>
  #define snprintf _snprintf
#else
  #include <sys/time.h>
#endif

using namespace v8;

char filename[256];
bool addTimestamp;

class FileOutputStream: public OutputStream {
  public:
    FileOutputStream(FILE* stream): stream_(stream) { }
    virtual int GetChunkSize() {
      return 65536;
    }
    virtual void EndOfStream() { }
    virtual WriteResult WriteAsciiChunk(char* data, int size) {
      const size_t len = static_cast<size_t>(size);
      size_t off = 0;
      while (off < len && !feof(stream_) && !ferror(stream_))
        off += fwrite(data + off, 1, len - off, stream_);
      return off == len ? kContinue : kAbort;
    }

  private:
    FILE* stream_;
};

void OnOOMError(const char *location, bool is_heap_oom) {
  if (addTimestamp) {
    // Add timestamp to filename
    time_t rawtime;
    struct tm* timeinfo;
    time(&rawtime);
    timeinfo = localtime(&rawtime);

    char * pch;
    pch = strstr (filename,".heapsnapshot");
    strncpy (pch,"",1);
    strcat (filename, "-%Y%m%dT%H%M%S.heapsnapshot");

    char newFilename[256];
    strftime(newFilename, sizeof(filename), filename, timeinfo);
    strcpy(filename, newFilename);
  }

  fprintf(stderr, "Generating Heapdump to '%s' now...\n", filename);
  FILE* fp = fopen(filename, "w");
  if (fp == NULL) abort();

  // Create heapdump, depending on which Node.js version this can differ
  // for now, just support Node.js 7 and higher
  const HeapSnapshot* snap = v8::Isolate::GetCurrent()->GetHeapProfiler()->TakeHeapSnapshot();

  FileOutputStream stream(fp);
  snap->Serialize(&stream, HeapSnapshot::kJSON);
  fclose(fp);

  fprintf(stderr, "Done! Exiting process now.\n");
  exit(1);
}

void ParseArgumentsAndSetErrorHandler(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();
  isolate->SetOOMErrorHandler(OnOOMError);

  // parse JS arguments
  // 1: filename
  // 2: addTimestamp boolean
  #if NODE_VERSION_AT_LEAST(12, 0, 0)
  String::Utf8Value fArg(isolate, args[0]->ToString(isolate));
  #elif NODE_VERSION_AT_LEAST(9, 0, 0)
  String::Utf8Value fArg(isolate, args[0]->ToString());
  #else
  String::Utf8Value fArg(args[0]->ToString());
  #endif
  strncpy(filename, (const char*)(*fArg), sizeof(filename) - 1);

  #if NODE_VERSION_AT_LEAST(12, 0, 0)
  addTimestamp = args[1]->BooleanValue(isolate);
  #else
  addTimestamp = args[1]->BooleanValue();
  #endif
}

void init(Local<Object> exports) {
  NODE_SET_METHOD(exports, "call", ParseArgumentsAndSetErrorHandler);
}

NODE_MODULE(NODE_OOM_HEAPDUMP_NATIVE, init)<|endoftext|>


<commit_before>#include "chi/GraphStruct.hpp"
#include "chi/Context.hpp"
#include "chi/GraphModule.hpp"

#include <llvm/IR/DIBuilder.h>
#include <llvm/IR/DebugInfo.h>
#include <llvm/IR/DerivedTypes.h>

namespace chi {

GraphStruct::GraphStruct(GraphModule& mod, std::string name)
    : mModule{&mod}, mContext{&mod.context()}, mName{std::move(name)} {}

void GraphStruct::addType(DataType ty, std::string name, size_t addBefore) {
	Expects(addBefore <= types().size() && ty.valid() && !name.empty());

	mTypes.emplace_back(name, ty);

	// invalidate the current DataType
	mDataType = {};
}

void GraphStruct::modifyType(size_t id, DataType newTy, std::string newName) {
	Expects(id < types().size() && newTy.valid() && !newName.empty());

	mTypes[id] = {std::move(newName), std::move(newTy)};

	// invalidate the current DataType
	mDataType = {};
}

void GraphStruct::removeType(size_t id) {
	Expects(id < types().size());

	mTypes.erase(mTypes.begin() + id);

	// invalidate the current DataType
	mDataType = {};
}

DataType GraphStruct::dataType() {
	// if we have already calculated this, use that
	if (mDataType.valid()) { return mDataType; }

	if (types().empty()) { return {}; }

	// create llvm::Type
	std::vector<llvm::Type*> llTypes;
	llTypes.reserve(types().size());

	std::vector<llvm::Metadata*> diTypes;
	diTypes.reserve(types().size());

	size_t currentOffset = 0;
	for (const auto& type : types()) {
		auto debugType = type.type.debugType();

		llTypes.push_back(type.type.llvmType());

#if LLVM_VERSION_MAJOR <= 3 && LLVM_VERSION_MINOR <= 6
		// make a temp module so we can make a DIBuilder
		auto tmpMod = std::make_unique<llvm::Module>("tmp", context().llvmContext());
		auto diBuilder = std::make_unique<llvm::DIBuilder>(*tmpMod);

		auto member = diBuilder->createMemberType(nullptr, type.name, nullptr, 0, debugType->getSizeInBits(), 8, currentOffset, 0, nullptr);
#else
		auto member =
		    llvm::DIDerivedType::get(context().llvmContext(), llvm::dwarf::DW_TAG_member,
#if LLVM_VERSION_MAJOR <= 3 && LLVM_VERSION_MINOR <= 8
		                             llvm::MDString::get(context().llvmContext(), type.name),
#else
		                             type.name,
#endif
		                             nullptr, 0, nullptr, debugType, debugType->getSizeInBits(), 8,
		                             currentOffset, llvm::DINode::DIFlags{}, nullptr);
#endif
		diTypes.push_back(member);

		currentOffset += debugType->getSizeInBits();
	}
	auto llType = llvm::StructType::create(llTypes, name());

	auto diStructType = llvm::DICompositeType::get(
	    context().llvmContext(), llvm::dwarf::DW_TAG_structure_type, name(), nullptr, 0, nullptr,
	    nullptr, currentOffset, 8, 0, llvm::DINode::DIFlags{},
	    llvm::MDTuple::get(context().llvmContext(), diTypes), 0, nullptr, {}, "");

	mDataType = DataType(&module(), name(), llType, diStructType);

	return mDataType;
}

}  // namespace chi
<commit_msg>Fix call to createMemberType<commit_after>#include "chi/GraphStruct.hpp"
#include "chi/Context.hpp"
#include "chi/GraphModule.hpp"

#include <llvm/IR/DIBuilder.h>
#include <llvm/IR/DebugInfo.h>
#include <llvm/IR/DerivedTypes.h>

namespace chi {

GraphStruct::GraphStruct(GraphModule& mod, std::string name)
    : mModule{&mod}, mContext{&mod.context()}, mName{std::move(name)} {}

void GraphStruct::addType(DataType ty, std::string name, size_t addBefore) {
	Expects(addBefore <= types().size() && ty.valid() && !name.empty());

	mTypes.emplace_back(name, ty);

	// invalidate the current DataType
	mDataType = {};
}

void GraphStruct::modifyType(size_t id, DataType newTy, std::string newName) {
	Expects(id < types().size() && newTy.valid() && !newName.empty());

	mTypes[id] = {std::move(newName), std::move(newTy)};

	// invalidate the current DataType
	mDataType = {};
}

void GraphStruct::removeType(size_t id) {
	Expects(id < types().size());

	mTypes.erase(mTypes.begin() + id);

	// invalidate the current DataType
	mDataType = {};
}

DataType GraphStruct::dataType() {
	// if we have already calculated this, use that
	if (mDataType.valid()) { return mDataType; }

	if (types().empty()) { return {}; }

	// create llvm::Type
	std::vector<llvm::Type*> llTypes;
	llTypes.reserve(types().size());

	std::vector<llvm::Metadata*> diTypes;
	diTypes.reserve(types().size());

	size_t currentOffset = 0;
	for (const auto& type : types()) {
		auto debugType = type.type.debugType();

		llTypes.push_back(type.type.llvmType());

#if LLVM_VERSION_MAJOR <= 3 && LLVM_VERSION_MINOR <= 6
		// make a temp module so we can make a DIBuilder
		auto tmpMod = std::make_unique<llvm::Module>("tmp", context().llvmContext());
		auto diBuilder = std::make_unique<llvm::DIBuilder>(*tmpMod);

		auto member = diBuilder->createMemberType(llvm::DIDescriptor(), type.name, llvm::DIFile(), 0, debugType->getSizeInBits(), 8, currentOffset, 0, *debugType);
#else
		auto member =
		    llvm::DIDerivedType::get(context().llvmContext(), llvm::dwarf::DW_TAG_member,
#if LLVM_VERSION_MAJOR <= 3 && LLVM_VERSION_MINOR <= 8
		                             llvm::MDString::get(context().llvmContext(), type.name),
#else
		                             type.name,
#endif
		                             nullptr, 0, nullptr, debugType, debugType->getSizeInBits(), 8,
		                             currentOffset, llvm::DINode::DIFlags{}, nullptr);
#endif
		diTypes.push_back(member);

		currentOffset += debugType->getSizeInBits();
	}
	auto llType = llvm::StructType::create(llTypes, name());

	auto diStructType = llvm::DICompositeType::get(
	    context().llvmContext(), llvm::dwarf::DW_TAG_structure_type, name(), nullptr, 0, nullptr,
	    nullptr, currentOffset, 8, 0, llvm::DINode::DIFlags{},
	    llvm::MDTuple::get(context().llvmContext(), diTypes), 0, nullptr, {}, "");

	mDataType = DataType(&module(), name(), llType, diStructType);

	return mDataType;
}

}  // namespace chi
<|endoftext|>


<commit_before>// Copyright (c) 2019 Franka Emika GmbH
// Use of this source code is governed by the Apache-2.0 license, see LICENSE
#include "franka/vacuum_gripper_state.h"

#include <cstring>

namespace franka {

std::ostream& operator<<(std::ostream& ostream,
                         const franka::VacuumGripperState& vacuum_gripper_state) {
  std::string device_status;
  switch (vacuum_gripper_state.device_status) {
    case VacuumGripperDeviceStatus::kGreen:
      device_status = "Green";
      break;
    case VacuumGripperDeviceStatus::kYellow:
      device_status = "Yellow";
      break;
    case VacuumGripperDeviceStatus::kOrange:
      device_status = "Orange";
      break;
    case VacuumGripperDeviceStatus::kRed:
      device_status = "Red";
      break;
  }

  ostream << "{\"in_control_range\": " << vacuum_gripper_state.in_control_range
          << ", \"part_detached\": " << vacuum_gripper_state.part_detached
          << ", \"part_present\": " << vacuum_gripper_state.part_present
          << ", \"device_status\": " << device_status
          << ", \"actual_power\": " << vacuum_gripper_state.actual_power
          << ", \"vacuum\": " << vacuum_gripper_state.vacuum
          << ", \"time\": " << vacuum_gripper_state.time.toSec() << "}";
  return ostream;
}

}  // namespace franka
<commit_msg>Fix JSON serializing of VacuumGripperState.<commit_after>// Copyright (c) 2019 Franka Emika GmbH
// Use of this source code is governed by the Apache-2.0 license, see LICENSE
#include "franka/vacuum_gripper_state.h"

#include <cstring>

namespace franka {

std::ostream& operator<<(std::ostream& ostream,
                         const franka::VacuumGripperState& vacuum_gripper_state) {
  std::string device_status;
  switch (vacuum_gripper_state.device_status) {
    case VacuumGripperDeviceStatus::kGreen:
      device_status = "Green";
      break;
    case VacuumGripperDeviceStatus::kYellow:
      device_status = "Yellow";
      break;
    case VacuumGripperDeviceStatus::kOrange:
      device_status = "Orange";
      break;
    case VacuumGripperDeviceStatus::kRed:
      device_status = "Red";
      break;
  }

  ostream << "{\"in_control_range\": " << vacuum_gripper_state.in_control_range
          << ", \"part_detached\": " << vacuum_gripper_state.part_detached
          << ", \"part_present\": " << vacuum_gripper_state.part_present << ", \"device_status\": "
          << "\"" << device_status << "\""
          << ", \"actual_power\": " << vacuum_gripper_state.actual_power
          << ", \"vacuum\": " << vacuum_gripper_state.vacuum
          << ", \"time\": " << vacuum_gripper_state.time.toSec() << "}";
  return ostream;
}

}  // namespace franka
<|endoftext|>


<commit_before>/**
 * This file is part of the Marble Virtual Globe.
 *
 * Copyright 2005-2007 Torsten Rahn <tackat@kde.org>
 * Copyright 2007      Inge Wallin  <ingwa@kde.org>
 * Copyright 2008, 2009, 2010 Jens-Michael Hoffmann <jensmh@gmx.de>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "StackedTileLoader.h"

#include "GeoSceneDocument.h"
#include "GeoSceneGroup.h"
#include "GeoSceneHead.h"
#include "GeoSceneLayer.h"
#include "GeoSceneMap.h"
#include "GeoSceneSettings.h"
#include "GeoSceneTexture.h"
#include "HttpDownloadManager.h"
#include "MapThemeManager.h"
#include "MarbleDebug.h"
#include "MarbleDirs.h"
#include "MergedLayerDecorator.h"
#include "StackedTile.h"
#include "TextureTile.h"
#include "TileLoader.h"
#include "TileLoaderHelper.h"
#include "global.h"

#include <QtCore/QCache>
#include <QtCore/QDateTime>
#include <QtCore/QHash>
#include <QtGui/QImage>

#ifdef Q_CC_MSVC
# ifndef KDEWIN_MATH_H
   long double log(int i) { return log((long double)i); }
# endif
#endif

namespace Marble
{

class StackedTileLoaderPrivate
{
public:
    StackedTileLoaderPrivate( TileLoader *tileLoader, SunLocator *sunLocator )
        : m_layerDecorator( tileLoader, sunLocator ),
          m_tileLoader( tileLoader ),
          m_maxTileLevel( 0 )
    {
        m_tileCache.setMaxCost( 20000 * 1024 ); // Cache size measured in bytes
    }

    void detectMaxTileLevel();
    QVector<GeoSceneTexture const *>
        findRelevantTextureLayers( TileId const & stackedTileId ) const;

    MergedLayerDecorator m_layerDecorator;
    TileLoader *m_tileLoader;
    int         m_maxTileLevel;
    QVector<GeoSceneTexture const *> m_textureLayers;
    QHash <TileId, StackedTile*>  m_tilesOnDisplay;
    QCache <TileId, StackedTile>  m_tileCache;
};

StackedTileLoader::StackedTileLoader( TileLoader * const tileLoader,
                                      SunLocator * const sunLocator )
    : d( new StackedTileLoaderPrivate( tileLoader, sunLocator ) )
{
    connect( d->m_tileLoader, SIGNAL( tileCompleted( TileId )),
             SLOT( updateTile( TileId )));
}

StackedTileLoader::~StackedTileLoader()
{
    flush();
    d->m_tileCache.clear();
    delete d;
}

void StackedTileLoader::setTextureLayers( QVector<GeoSceneTexture const *> & textureLayers )
{
    mDebug() << "StackedTileLoader::setTextureLayers";

    d->m_textureLayers = textureLayers;

    d->m_tilesOnDisplay.clear();
    d->m_tileCache.clear();

    d->detectMaxTileLevel();
}

void StackedTileLoader::setShowTileId( bool show )
{
    d->m_layerDecorator.setShowTileId( show );
}

int StackedTileLoader::tileColumnCount( int level ) const
{
    Q_ASSERT( !d->m_textureLayers.isEmpty() );

    const int levelZeroColumns = d->m_textureLayers.at( 0 )->levelZeroColumns();

    return TileLoaderHelper::levelToColumn( levelZeroColumns, level );
}

int StackedTileLoader::tileRowCount( int level ) const
{
    Q_ASSERT( !d->m_textureLayers.isEmpty() );

    const int levelZeroRows = d->m_textureLayers.at( 0 )->levelZeroRows();

    return TileLoaderHelper::levelToRow( levelZeroRows, level );
}

GeoSceneTexture::Projection StackedTileLoader::tileProjection() const
{
    Q_ASSERT( !d->m_textureLayers.isEmpty() );

    return d->m_textureLayers.at( 0 )->projection();
}

QSize StackedTileLoader::tileSize() const
{
    Q_ASSERT( !d->m_textureLayers.isEmpty() );

    return d->m_textureLayers.at( 0 )->tileSize();
}

void StackedTileLoader::resetTilehash()
{
    QHash<TileId, StackedTile*>::const_iterator it = d->m_tilesOnDisplay.constBegin();
    QHash<TileId, StackedTile*>::const_iterator const end = d->m_tilesOnDisplay.constEnd();
    for (; it != end; ++it ) {
        it.value()->setUsed( false );
    }
}

void StackedTileLoader::cleanupTilehash()
{
    // Make sure that tiles which haven't been used during the last
    // rendering of the map at all get removed from the tile hash.

    QHashIterator<TileId, StackedTile*> it( d->m_tilesOnDisplay );
    while ( it.hasNext() ) {
        it.next();
        if ( !it.value()->used() ) {
            // If insert call result is false then the cache is too small to store the tile
            // but the item will get deleted nevertheless and the pointer we have
            // doesn't get set to zero (so don't delete it in this case or it will crash!)
            d->m_tileCache.insert( it.key(), it.value(), it.value()->numBytes() );
            d->m_tilesOnDisplay.remove( it.key() );
        }
    }
}

void StackedTileLoader::flush()
{
    // move all tiles from m_tilesOnDisplay into tile cache
    QHash<TileId, StackedTile*>::const_iterator it = d->m_tilesOnDisplay.constBegin();
    QHash<TileId, StackedTile*>::const_iterator const end = d->m_tilesOnDisplay.constEnd();
    for (; it != end; ++it ) {
        // If insert call result is false then the cache is too small to store the tile
        // but the item will get deleted nevertheless and the pointer we have
        // doesn't get set to zero (so don't delete it in this case or it will crash!)
        d->m_tileCache.insert( it.key(), it.value(), it.value()->numBytes() );
    }
    d->m_tilesOnDisplay.clear();
}

StackedTile* StackedTileLoader::loadTile( TileId const & stackedTileId )
{
    // check if the tile is in the hash
    StackedTile * stackedTile = d->m_tilesOnDisplay.value( stackedTileId, 0 );
    if ( stackedTile ) {
        return stackedTile;
    }
    // here ends the performance critical section of this method

    mDebug() << "StackedTileLoader::loadTile" << stackedTileId.toString();

    // the tile was not in the hash or has been removed because of expiration
    // so check if it is in the cache
    stackedTile = d->m_tileCache.take( stackedTileId );
    if ( stackedTile ) {
        // the tile was in the cache, but is it up to date?
        d->m_tilesOnDisplay[ stackedTileId ] = stackedTile;
        return stackedTile;
    }

    // tile (valid) has not been found in hash or cache, so load it from disk
    // and place it in the hash from where it will get transferred to the cache

    // mDebug() << "load Tile from Disk: " << stackedTileId.toString();

    QVector<QSharedPointer<TextureTile> > tiles;
    QVector<GeoSceneTexture const *> const textureLayers = d->findRelevantTextureLayers( stackedTileId );
    QVector<GeoSceneTexture const *>::const_iterator pos = textureLayers.constBegin();
    QVector<GeoSceneTexture const *>::const_iterator const end = textureLayers.constEnd();
    for (; pos != end; ++pos ) {
        GeoSceneTexture const * const textureLayer = *pos;
        TileId const tileId( textureLayer->sourceDir(), stackedTileId.zoomLevel(),
                             stackedTileId.x(), stackedTileId.y() );
        mDebug() << "StackedTileLoader::loadTile: tile" << textureLayer->sourceDir()
                 << tileId.toString() << textureLayer->tileSize();
        QSharedPointer<TextureTile> const tile = d->m_tileLoader->loadTile( tileId, DownloadBrowse );
        if ( tile ) {
            tiles.append( tile );
        }
    }
    Q_ASSERT( !tiles.isEmpty() );

    stackedTile = new StackedTile( stackedTileId, tiles );
    d->m_tilesOnDisplay[ stackedTileId ] = stackedTile;
    mergeDecorations( stackedTile );

    return stackedTile;
}

void StackedTileLoader::downloadTile( TileId const & stackedTileId )
{
    QVector<GeoSceneTexture const *> const textureLayers = d->findRelevantTextureLayers( stackedTileId );
    QVector<GeoSceneTexture const *>::const_iterator pos = textureLayers.constBegin();
    QVector<GeoSceneTexture const *>::const_iterator const end = textureLayers.constEnd();
    for (; pos != end; ++pos ) {
        GeoSceneTexture const * const textureLayer = *pos;
        TileId const tileId( textureLayer->sourceDir(), stackedTileId.zoomLevel(),
                             stackedTileId.x(), stackedTileId.y() );
        d->m_tileLoader->downloadTile( tileId );
    }
}

quint64 StackedTileLoader::volatileCacheLimit() const
{
    return d->m_tileCache.maxCost() / 1024;
}

void StackedTileLoader::reloadVisibleTiles()
{
    foreach ( StackedTile * const displayedTile, d->m_tilesOnDisplay.values() ) {
        Q_ASSERT( displayedTile != 0 );
        foreach ( QSharedPointer<TextureTile> const & tile, *displayedTile->tiles() ) {
            // it's debatable here, whether DownloadBulk or DownloadBrowse should be used
            // but since "reload" or "refresh" seems to be a common action of a browser and it
            // allows for more connections (in our model), use "DownloadBrowse"
            d->m_tileLoader->reloadTile( tile, DownloadBrowse );
        }
        mergeDecorations( displayedTile );
    }

    emit tileUpdatesAvailable();
}

int StackedTileLoader::maximumTileLevel() const
{
    return d->m_maxTileLevel;
}

void StackedTileLoaderPrivate::detectMaxTileLevel()
{
    if ( m_textureLayers.isEmpty() ) {
        m_maxTileLevel = -1;
        return;
    }

    GeoSceneTexture const * const texture = m_textureLayers.at( 0 );

    // if maximum tile level is configured in the DGML files,
    // then use it, otherwise use old detection code.
    if ( texture->maximumTileLevel() >= 0 ) {
        m_maxTileLevel = texture->maximumTileLevel();
        return;
    }

    int maximumTileLevel = -1;
    QString tilepath = MarbleDirs::path( texture->themeStr() );
    //    mDebug() << "StackedTileLoader::maxPartialTileLevel tilepath" << tilepath;
    QStringList leveldirs = QDir( tilepath ).entryList( QDir::AllDirs | QDir::NoSymLinks
                                                        | QDir::NoDotAndDotDot );

    QStringList::const_iterator it = leveldirs.constBegin();
    QStringList::const_iterator const end = leveldirs.constEnd();
    for (; it != end; ++it ) {
        bool ok = true;
        const int value = (*it).toInt( &ok, 10 );

        if ( ok && value > maximumTileLevel )
            maximumTileLevel = value;
    }

    //    mDebug() << "Detected maximum tile level that contains data: "
    //             << maxtilelevel;
    m_maxTileLevel = maximumTileLevel + 1;
}

bool StackedTileLoader::baseTilesAvailable( GeoSceneLayer * layer )
{
    if ( !layer ) return false;

    GeoSceneTexture * texture = static_cast<GeoSceneTexture *>( layer->groundDataset() );

    const int  levelZeroColumns = texture->levelZeroColumns();
    const int  levelZeroRows    = texture->levelZeroRows();

    bool noerr = true;

    // Check whether the tiles from the lowest texture level are available
    //
    for ( int column = 0; noerr && column < levelZeroColumns; ++column ) {
        for ( int row = 0; noerr && row < levelZeroRows; ++row ) {

            const QString tilepath = MarbleDirs::path( texture->relativeTileFileName(
                TileId( texture->sourceDir(), 0, column, row )));
            noerr = QFile::exists( tilepath );
        }
    }

    return noerr;
}

void StackedTileLoader::setVolatileCacheLimit( quint64 kiloBytes )
{
    mDebug() << QString("Setting tile cache to %1 kilobytes.").arg( kiloBytes );
    d->m_tileCache.setMaxCost( kiloBytes * 1024 );
}

void StackedTileLoader::updateTile( TileId const & stackedTileId )
{
    d->detectMaxTileLevel();

    StackedTile * const displayedTile = d->m_tilesOnDisplay.value( stackedTileId, 0 );
    if ( displayedTile ) {
        mergeDecorations( displayedTile );
        emit tileUpdateAvailable( stackedTileId );
    }
    else {
        StackedTile * const cachedTile = d->m_tileCache.object( stackedTileId );
        if ( cachedTile ) {
            mergeDecorations( cachedTile );
            emit tileUpdateAvailable( stackedTileId );
        }
    }
}

void StackedTileLoader::update()
{
    mDebug() << "StackedTileLoader::update()";
    flush(); // trigger a reload of all tiles that are currently in use
    d->m_tileCache.clear(); // clear the tile cache in physical memory
    emit tileUpdatesAvailable();
}

//
QVector<GeoSceneTexture const *>
StackedTileLoaderPrivate::findRelevantTextureLayers( TileId const & stackedTileId ) const
{
    QVector<GeoSceneTexture const *> result;
    QVector<GeoSceneTexture const *>::const_iterator pos = m_textureLayers.constBegin();
    QVector<GeoSceneTexture const *>::const_iterator const end = m_textureLayers.constEnd();
    for (; pos != end; ++pos ) {
        GeoSceneTexture const * const candidate = dynamic_cast<GeoSceneTexture const *>( *pos );
        // check if layer is enabled. A layer is considered to be enabled if one of the
        // following conditions is true:
        // 1) it is the first layer
        // 2) there are no settings available (group "Texture Layers" not defined in DGML)
        // 3) the layer is configured and enabled in the settings
        // also check, if layer provides tiles for the current level
        if ( candidate
             && ( !candidate->hasMaximumTileLevel()
                  || stackedTileId.zoomLevel() <= candidate->maximumTileLevel() ))
            result.append( candidate );
    }
    return result;
}

void StackedTileLoader::mergeDecorations( StackedTile * const tile ) const
{
    Q_ASSERT( tile != 0 );
    Q_ASSERT( !tile->tiles()->isEmpty() );
    Q_ASSERT( !d->m_textureLayers.isEmpty() );
//    mDebug() << "MarbleModel::paintTile: " << "x: " << x << "y:" << y << "level: " << level
//             << "requestTileUpdate" << requestTileUpdate;

    tile->initResultTile();

    d->m_layerDecorator.setInfo( tile->id() );
    d->m_layerDecorator.setTile( tile->resultTile() );

    d->m_layerDecorator.paint( "maps/" + d->m_textureLayers.at( 0 )->sourceDir() );
}

}

#include "StackedTileLoader.moc"
<commit_msg>only update displayed tiles<commit_after>/**
 * This file is part of the Marble Virtual Globe.
 *
 * Copyright 2005-2007 Torsten Rahn <tackat@kde.org>
 * Copyright 2007      Inge Wallin  <ingwa@kde.org>
 * Copyright 2008, 2009, 2010 Jens-Michael Hoffmann <jensmh@gmx.de>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "StackedTileLoader.h"

#include "GeoSceneDocument.h"
#include "GeoSceneGroup.h"
#include "GeoSceneHead.h"
#include "GeoSceneLayer.h"
#include "GeoSceneMap.h"
#include "GeoSceneSettings.h"
#include "GeoSceneTexture.h"
#include "HttpDownloadManager.h"
#include "MapThemeManager.h"
#include "MarbleDebug.h"
#include "MarbleDirs.h"
#include "MergedLayerDecorator.h"
#include "StackedTile.h"
#include "TextureTile.h"
#include "TileLoader.h"
#include "TileLoaderHelper.h"
#include "global.h"

#include <QtCore/QCache>
#include <QtCore/QDateTime>
#include <QtCore/QHash>
#include <QtGui/QImage>

#ifdef Q_CC_MSVC
# ifndef KDEWIN_MATH_H
   long double log(int i) { return log((long double)i); }
# endif
#endif

namespace Marble
{

class StackedTileLoaderPrivate
{
public:
    StackedTileLoaderPrivate( TileLoader *tileLoader, SunLocator *sunLocator )
        : m_layerDecorator( tileLoader, sunLocator ),
          m_tileLoader( tileLoader ),
          m_maxTileLevel( 0 )
    {
        m_tileCache.setMaxCost( 20000 * 1024 ); // Cache size measured in bytes
    }

    void detectMaxTileLevel();
    QVector<GeoSceneTexture const *>
        findRelevantTextureLayers( TileId const & stackedTileId ) const;

    MergedLayerDecorator m_layerDecorator;
    TileLoader *m_tileLoader;
    int         m_maxTileLevel;
    QVector<GeoSceneTexture const *> m_textureLayers;
    QHash <TileId, StackedTile*>  m_tilesOnDisplay;
    QCache <TileId, StackedTile>  m_tileCache;
};

StackedTileLoader::StackedTileLoader( TileLoader * const tileLoader,
                                      SunLocator * const sunLocator )
    : d( new StackedTileLoaderPrivate( tileLoader, sunLocator ) )
{
    connect( d->m_tileLoader, SIGNAL( tileCompleted( TileId )),
             SLOT( updateTile( TileId )));
}

StackedTileLoader::~StackedTileLoader()
{
    flush();
    d->m_tileCache.clear();
    delete d;
}

void StackedTileLoader::setTextureLayers( QVector<GeoSceneTexture const *> & textureLayers )
{
    mDebug() << "StackedTileLoader::setTextureLayers";

    d->m_textureLayers = textureLayers;

    d->m_tilesOnDisplay.clear();
    d->m_tileCache.clear();

    d->detectMaxTileLevel();
}

void StackedTileLoader::setShowTileId( bool show )
{
    d->m_layerDecorator.setShowTileId( show );
}

int StackedTileLoader::tileColumnCount( int level ) const
{
    Q_ASSERT( !d->m_textureLayers.isEmpty() );

    const int levelZeroColumns = d->m_textureLayers.at( 0 )->levelZeroColumns();

    return TileLoaderHelper::levelToColumn( levelZeroColumns, level );
}

int StackedTileLoader::tileRowCount( int level ) const
{
    Q_ASSERT( !d->m_textureLayers.isEmpty() );

    const int levelZeroRows = d->m_textureLayers.at( 0 )->levelZeroRows();

    return TileLoaderHelper::levelToRow( levelZeroRows, level );
}

GeoSceneTexture::Projection StackedTileLoader::tileProjection() const
{
    Q_ASSERT( !d->m_textureLayers.isEmpty() );

    return d->m_textureLayers.at( 0 )->projection();
}

QSize StackedTileLoader::tileSize() const
{
    Q_ASSERT( !d->m_textureLayers.isEmpty() );

    return d->m_textureLayers.at( 0 )->tileSize();
}

void StackedTileLoader::resetTilehash()
{
    QHash<TileId, StackedTile*>::const_iterator it = d->m_tilesOnDisplay.constBegin();
    QHash<TileId, StackedTile*>::const_iterator const end = d->m_tilesOnDisplay.constEnd();
    for (; it != end; ++it ) {
        it.value()->setUsed( false );
    }
}

void StackedTileLoader::cleanupTilehash()
{
    // Make sure that tiles which haven't been used during the last
    // rendering of the map at all get removed from the tile hash.

    QHashIterator<TileId, StackedTile*> it( d->m_tilesOnDisplay );
    while ( it.hasNext() ) {
        it.next();
        if ( !it.value()->used() ) {
            // If insert call result is false then the cache is too small to store the tile
            // but the item will get deleted nevertheless and the pointer we have
            // doesn't get set to zero (so don't delete it in this case or it will crash!)
            d->m_tileCache.insert( it.key(), it.value(), it.value()->numBytes() );
            d->m_tilesOnDisplay.remove( it.key() );
        }
    }
}

void StackedTileLoader::flush()
{
    // move all tiles from m_tilesOnDisplay into tile cache
    QHash<TileId, StackedTile*>::const_iterator it = d->m_tilesOnDisplay.constBegin();
    QHash<TileId, StackedTile*>::const_iterator const end = d->m_tilesOnDisplay.constEnd();
    for (; it != end; ++it ) {
        // If insert call result is false then the cache is too small to store the tile
        // but the item will get deleted nevertheless and the pointer we have
        // doesn't get set to zero (so don't delete it in this case or it will crash!)
        d->m_tileCache.insert( it.key(), it.value(), it.value()->numBytes() );
    }
    d->m_tilesOnDisplay.clear();
}

StackedTile* StackedTileLoader::loadTile( TileId const & stackedTileId )
{
    // check if the tile is in the hash
    StackedTile * stackedTile = d->m_tilesOnDisplay.value( stackedTileId, 0 );
    if ( stackedTile ) {
        return stackedTile;
    }
    // here ends the performance critical section of this method

    mDebug() << "StackedTileLoader::loadTile" << stackedTileId.toString();

    // the tile was not in the hash or has been removed because of expiration
    // so check if it is in the cache
    stackedTile = d->m_tileCache.take( stackedTileId );
    if ( stackedTile ) {
        // the tile was in the cache, but is it up to date?
        d->m_tilesOnDisplay[ stackedTileId ] = stackedTile;
        return stackedTile;
    }

    // tile (valid) has not been found in hash or cache, so load it from disk
    // and place it in the hash from where it will get transferred to the cache

    // mDebug() << "load Tile from Disk: " << stackedTileId.toString();

    QVector<QSharedPointer<TextureTile> > tiles;
    QVector<GeoSceneTexture const *> const textureLayers = d->findRelevantTextureLayers( stackedTileId );
    QVector<GeoSceneTexture const *>::const_iterator pos = textureLayers.constBegin();
    QVector<GeoSceneTexture const *>::const_iterator const end = textureLayers.constEnd();
    for (; pos != end; ++pos ) {
        GeoSceneTexture const * const textureLayer = *pos;
        TileId const tileId( textureLayer->sourceDir(), stackedTileId.zoomLevel(),
                             stackedTileId.x(), stackedTileId.y() );
        mDebug() << "StackedTileLoader::loadTile: tile" << textureLayer->sourceDir()
                 << tileId.toString() << textureLayer->tileSize();
        QSharedPointer<TextureTile> const tile = d->m_tileLoader->loadTile( tileId, DownloadBrowse );
        if ( tile ) {
            tiles.append( tile );
        }
    }
    Q_ASSERT( !tiles.isEmpty() );

    stackedTile = new StackedTile( stackedTileId, tiles );
    d->m_tilesOnDisplay[ stackedTileId ] = stackedTile;
    mergeDecorations( stackedTile );

    return stackedTile;
}

void StackedTileLoader::downloadTile( TileId const & stackedTileId )
{
    QVector<GeoSceneTexture const *> const textureLayers = d->findRelevantTextureLayers( stackedTileId );
    QVector<GeoSceneTexture const *>::const_iterator pos = textureLayers.constBegin();
    QVector<GeoSceneTexture const *>::const_iterator const end = textureLayers.constEnd();
    for (; pos != end; ++pos ) {
        GeoSceneTexture const * const textureLayer = *pos;
        TileId const tileId( textureLayer->sourceDir(), stackedTileId.zoomLevel(),
                             stackedTileId.x(), stackedTileId.y() );
        d->m_tileLoader->downloadTile( tileId );
    }
}

quint64 StackedTileLoader::volatileCacheLimit() const
{
    return d->m_tileCache.maxCost() / 1024;
}

void StackedTileLoader::reloadVisibleTiles()
{
    foreach ( StackedTile * const displayedTile, d->m_tilesOnDisplay.values() ) {
        Q_ASSERT( displayedTile != 0 );
        foreach ( QSharedPointer<TextureTile> const & tile, *displayedTile->tiles() ) {
            // it's debatable here, whether DownloadBulk or DownloadBrowse should be used
            // but since "reload" or "refresh" seems to be a common action of a browser and it
            // allows for more connections (in our model), use "DownloadBrowse"
            d->m_tileLoader->reloadTile( tile, DownloadBrowse );
        }
        mergeDecorations( displayedTile );
    }

    emit tileUpdatesAvailable();
}

int StackedTileLoader::maximumTileLevel() const
{
    return d->m_maxTileLevel;
}

void StackedTileLoaderPrivate::detectMaxTileLevel()
{
    if ( m_textureLayers.isEmpty() ) {
        m_maxTileLevel = -1;
        return;
    }

    GeoSceneTexture const * const texture = m_textureLayers.at( 0 );

    // if maximum tile level is configured in the DGML files,
    // then use it, otherwise use old detection code.
    if ( texture->maximumTileLevel() >= 0 ) {
        m_maxTileLevel = texture->maximumTileLevel();
        return;
    }

    int maximumTileLevel = -1;
    QString tilepath = MarbleDirs::path( texture->themeStr() );
    //    mDebug() << "StackedTileLoader::maxPartialTileLevel tilepath" << tilepath;
    QStringList leveldirs = QDir( tilepath ).entryList( QDir::AllDirs | QDir::NoSymLinks
                                                        | QDir::NoDotAndDotDot );

    QStringList::const_iterator it = leveldirs.constBegin();
    QStringList::const_iterator const end = leveldirs.constEnd();
    for (; it != end; ++it ) {
        bool ok = true;
        const int value = (*it).toInt( &ok, 10 );

        if ( ok && value > maximumTileLevel )
            maximumTileLevel = value;
    }

    //    mDebug() << "Detected maximum tile level that contains data: "
    //             << maxtilelevel;
    m_maxTileLevel = maximumTileLevel + 1;
}

bool StackedTileLoader::baseTilesAvailable( GeoSceneLayer * layer )
{
    if ( !layer ) return false;

    GeoSceneTexture * texture = static_cast<GeoSceneTexture *>( layer->groundDataset() );

    const int  levelZeroColumns = texture->levelZeroColumns();
    const int  levelZeroRows    = texture->levelZeroRows();

    bool noerr = true;

    // Check whether the tiles from the lowest texture level are available
    //
    for ( int column = 0; noerr && column < levelZeroColumns; ++column ) {
        for ( int row = 0; noerr && row < levelZeroRows; ++row ) {

            const QString tilepath = MarbleDirs::path( texture->relativeTileFileName(
                TileId( texture->sourceDir(), 0, column, row )));
            noerr = QFile::exists( tilepath );
        }
    }

    return noerr;
}

void StackedTileLoader::setVolatileCacheLimit( quint64 kiloBytes )
{
    mDebug() << QString("Setting tile cache to %1 kilobytes.").arg( kiloBytes );
    d->m_tileCache.setMaxCost( kiloBytes * 1024 );
}

void StackedTileLoader::updateTile( TileId const & stackedTileId )
{
    d->detectMaxTileLevel();

    StackedTile * const displayedTile = d->m_tilesOnDisplay.value( stackedTileId, 0 );
    if ( displayedTile ) {
        mergeDecorations( displayedTile );
        emit tileUpdateAvailable( stackedTileId );
        return;
    }

    d->m_tileCache.remove( stackedTileId );
}

void StackedTileLoader::update()
{
    mDebug() << "StackedTileLoader::update()";
    flush(); // trigger a reload of all tiles that are currently in use
    d->m_tileCache.clear(); // clear the tile cache in physical memory
    emit tileUpdatesAvailable();
}

//
QVector<GeoSceneTexture const *>
StackedTileLoaderPrivate::findRelevantTextureLayers( TileId const & stackedTileId ) const
{
    QVector<GeoSceneTexture const *> result;
    QVector<GeoSceneTexture const *>::const_iterator pos = m_textureLayers.constBegin();
    QVector<GeoSceneTexture const *>::const_iterator const end = m_textureLayers.constEnd();
    for (; pos != end; ++pos ) {
        GeoSceneTexture const * const candidate = dynamic_cast<GeoSceneTexture const *>( *pos );
        // check if layer is enabled. A layer is considered to be enabled if one of the
        // following conditions is true:
        // 1) it is the first layer
        // 2) there are no settings available (group "Texture Layers" not defined in DGML)
        // 3) the layer is configured and enabled in the settings
        // also check, if layer provides tiles for the current level
        if ( candidate
             && ( !candidate->hasMaximumTileLevel()
                  || stackedTileId.zoomLevel() <= candidate->maximumTileLevel() ))
            result.append( candidate );
    }
    return result;
}

void StackedTileLoader::mergeDecorations( StackedTile * const tile ) const
{
    Q_ASSERT( tile != 0 );
    Q_ASSERT( !tile->tiles()->isEmpty() );
    Q_ASSERT( !d->m_textureLayers.isEmpty() );
//    mDebug() << "MarbleModel::paintTile: " << "x: " << x << "y:" << y << "level: " << level
//             << "requestTileUpdate" << requestTileUpdate;

    tile->initResultTile();

    d->m_layerDecorator.setInfo( tile->id() );
    d->m_layerDecorator.setTile( tile->resultTile() );

    d->m_layerDecorator.paint( "maps/" + d->m_textureLayers.at( 0 )->sourceDir() );
}

}

#include "StackedTileLoader.moc"
<|endoftext|>