<commit_before>// Scintilla source code edit control
/** @file CallTip.cxx
 ** Code for displaying call tips.
 **/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <string.h>

#include "Platform.h"

#include "Scintilla.h"
#include "CallTip.h"

CallTip::CallTip() {
	wCallTip = 0;
	inCallTipMode = false;
	posStartCallTip = 0;
	val = 0;
	xUp = -100;
	xDown = -100;
	lineHeight = 1;
	startHighlight = 0;
	endHighlight = 0;

	colourBG.desired = ColourDesired(0xff, 0xff, 0xff);
	colourUnSel.desired = ColourDesired(0x80, 0x80, 0x80);
	colourSel.desired = ColourDesired(0, 0, 0x80);
	colourShade.desired = ColourDesired(0, 0, 0);
	colourLight.desired = ColourDesired(0xc0, 0xc0, 0xc0);
}

CallTip::~CallTip() {
	font.Release();
	wCallTip.Destroy();
	delete []val;
	val = 0;
}

const int widthArrow = 14;

void CallTip::RefreshColourPalette(Palette &pal, bool want) {
	pal.WantFind(colourBG, want);
	pal.WantFind(colourUnSel, want);
	pal.WantFind(colourSel, want);
	pal.WantFind(colourShade, want);
	pal.WantFind(colourLight, want);
}

void CallTip::DrawChunk(Surface *surface, int &x, const char *s,
	int posStart, int posEnd, int ytext, PRectangle rcClient,
	bool highlight, bool draw) {
	s += posStart;
	int len = posEnd - posStart;
	int maxEnd = 0;
	int ends[10];
	for (int i=0;i<len;i++) {
		if (s[i] <= '\002') {
			if (i > 0)
				ends[maxEnd++] = i;
			ends[maxEnd++] = i+1;
		}
	}
	ends[maxEnd++] = len;
	int startSeg = 0;
	int xEnd;
	for (int seg = 0; seg<maxEnd; seg++) {
		int endSeg = ends[seg];
		if (endSeg > startSeg) {
			if (s[startSeg] <= '\002') {
				xEnd = x + widthArrow;
				offsetMain = xEnd;
				if (draw) {
					const int halfWidth = widthArrow / 2 - 3;
					const int centreX = x + widthArrow / 2 - 1;
					const int centreY = ytext - halfWidth - 1;
					rcClient.left = x;
					rcClient.right = xEnd;
					surface->FillRectangle(rcClient, colourBG.allocated);
					PRectangle rcClientInner(rcClient.left+1, rcClient.top+1, rcClient.right-2, rcClient.bottom-1);
					surface->FillRectangle(rcClientInner, colourUnSel.allocated);

					if (s[startSeg] == '\001') {
						// Up arrow
						Point pts[] = {
    						Point(centreX - halfWidth, centreY + halfWidth / 2),
    						Point(centreX + halfWidth, centreY + halfWidth / 2),
    						Point(centreX, centreY - halfWidth + halfWidth / 2),
						};
						surface->Polygon(pts, sizeof(pts) / sizeof(pts[0]),
                 						colourBG.allocated, colourBG.allocated);
					} else {
						// Down arrow
						Point pts[] = {
    						Point(centreX - halfWidth, centreY - halfWidth / 2 + 2),
    						Point(centreX + halfWidth, centreY - halfWidth / 2 + 2),
    						Point(centreX, centreY + halfWidth - halfWidth / 2 + 2),
						};
						surface->Polygon(pts, sizeof(pts) / sizeof(pts[0]),
                 						colourBG.allocated, colourBG.allocated);
					}
				} else {
					if (s[startSeg] == '\001') {
						xUp = x+1;
					} else {
						xDown = x+1;
					}
				}
			} else {
				xEnd = x + surface->WidthText(font, s+startSeg, endSeg - startSeg);
				if (draw) {
					rcClient.left = x;
					rcClient.right = xEnd;
					surface->DrawTextNoClip(rcClient, font, ytext,
										s+startSeg, endSeg - startSeg,
										highlight ? colourSel.allocated : colourUnSel.allocated,
										colourBG.allocated);
				}
			}
			x = xEnd;
			startSeg = endSeg;
		}
	}
}

int CallTip::PaintContents(Surface *surfaceWindow, bool draw) {
	PRectangle rcClientPos = wCallTip.GetClientPosition();
	PRectangle rcClientSize(0, 0, rcClientPos.right - rcClientPos.left,
	                        rcClientPos.bottom - rcClientPos.top);
	PRectangle rcClient(1, 1, rcClientSize.right - 1, rcClientSize.bottom - 1);

	// To make a nice small call tip window, it is only sized to fit most normal characters without accents
	int ascent = surfaceWindow->Ascent(font) - surfaceWindow->InternalLeading(font);

	// For each line...
	// Draw the definition in three parts: before highlight, highlighted, after highlight
	int ytext = rcClient.top + ascent + 1;
	rcClient.bottom = ytext + surfaceWindow->Descent(font) + 1;
	char *chunkVal = val;
	bool moreChunks = true;
	int maxWidth = 0;
	while (moreChunks) {
		char *chunkEnd = strchr(chunkVal, '\n');
		if (chunkEnd == NULL) {
			chunkEnd = chunkVal + strlen(chunkVal);
			moreChunks = false;
		}
		int chunkOffset = chunkVal - val;
		int chunkLength = chunkEnd - chunkVal;
		int chunkEndOffset = chunkOffset + chunkLength;
		int thisStartHighlight = Platform::Maximum(startHighlight, chunkOffset);
		thisStartHighlight = Platform::Minimum(thisStartHighlight, chunkEndOffset);
		thisStartHighlight -= chunkOffset;
		int thisEndHighlight = Platform::Maximum(endHighlight, chunkOffset);
		thisEndHighlight = Platform::Minimum(thisEndHighlight, chunkEndOffset);
		thisEndHighlight -= chunkOffset;
		rcClient.top = ytext - ascent - 1;

		int x = 5;

		DrawChunk(surfaceWindow, x, chunkVal, 0, thisStartHighlight,
			ytext, rcClient, false, draw);
		DrawChunk(surfaceWindow, x, chunkVal, thisStartHighlight, thisEndHighlight,
			ytext, rcClient, true, draw);
		DrawChunk(surfaceWindow, x, chunkVal, thisEndHighlight, chunkLength,
			ytext, rcClient, false, draw);

		chunkVal = chunkEnd + 1;
		ytext += lineHeight;
		rcClient.bottom += lineHeight;
		maxWidth = Platform::Maximum(maxWidth, x);
	}
	return maxWidth;
}

void CallTip::PaintCT(Surface *surfaceWindow) {
	if (!val)
		return;
	PRectangle rcClientPos = wCallTip.GetClientPosition();
	PRectangle rcClientSize(0, 0, rcClientPos.right - rcClientPos.left,
	                        rcClientPos.bottom - rcClientPos.top);
	PRectangle rcClient(1, 1, rcClientSize.right - 1, rcClientSize.bottom - 1);

	surfaceWindow->FillRectangle(rcClient, colourBG.allocated);

	offsetMain = 5;
	PaintContents(surfaceWindow, true);

	// Draw a raised border around the edges of the window
	surfaceWindow->MoveTo(0, rcClientSize.bottom - 1);
	surfaceWindow->PenColour(colourShade.allocated);
	surfaceWindow->LineTo(rcClientSize.right - 1, rcClientSize.bottom - 1);
	surfaceWindow->LineTo(rcClientSize.right - 1, 0);
	surfaceWindow->PenColour(colourLight.allocated);
	surfaceWindow->LineTo(0, 0);
	surfaceWindow->LineTo(0, rcClientSize.bottom - 1);
}

void CallTip::MouseClick(Point pt) {
	clickPlace = 0;
	if (pt.y < lineHeight) {
		if ((pt.x > xUp) && (pt.x < xUp + widthArrow - 2)) {
			clickPlace = 1;
		} else if ((pt.x > xDown) && (pt.x < xDown + widthArrow - 2)) {
			clickPlace = 2;
		}
	}
}

PRectangle CallTip::CallTipStart(int pos, Point pt, const char *defn,
                                 const char *faceName, int size,
                                 int codePage_, Window &wParent) {
	clickPlace = 0;
	if (val)
		delete []val;
	val = new char[strlen(defn) + 1];
	if (!val)
		return PRectangle();
	strcpy(val, defn);
	codePage = codePage_;
	Surface *surfaceMeasure = Surface::Allocate();
	if (!surfaceMeasure)
		return PRectangle();
	surfaceMeasure->Init(wParent.GetID());
	surfaceMeasure->SetUnicodeMode(SC_CP_UTF8 == codePage);
	surfaceMeasure->SetDBCSMode(codePage);
	startHighlight = 0;
	endHighlight = 0;
	inCallTipMode = true;
	posStartCallTip = pos;
	int deviceHeight = surfaceMeasure->DeviceHeightFont(size);
	font.Create(faceName, SC_CHARSET_DEFAULT, deviceHeight, false, false);
	// Look for multiple lines in the text
	// Only support \n here - simply means container must avoid \r!
	int numLines = 1;
	const char *newline;
	const char *look = val;
	xUp = -100;
	xDown = -100;
	offsetMain = 5;
	int width = PaintContents(surfaceMeasure, false) + 5;
	while ((newline = strchr(look, '\n')) != NULL) {
		look = newline + 1;
		numLines++;
	}
	lineHeight = surfaceMeasure->Height(font);
	// Extra line for border and an empty line at top and bottom
	int height = lineHeight * numLines - surfaceMeasure->InternalLeading(font) + 2 + 2;
	delete surfaceMeasure;
	return PRectangle(pt.x - offsetMain, pt.y + 1, pt.x + width - offsetMain, pt.y + 1 + height);
}

void CallTip::CallTipCancel() {
	inCallTipMode = false;
	if (wCallTip.Created()) {
		wCallTip.Destroy();
	}
}

void CallTip::SetHighlight(int start, int end) {
	// Avoid flashing by checking something has really changed
	if ((start != startHighlight) || (end != endHighlight)) {
		startHighlight = start;
		endHighlight = end;
		if (wCallTip.Created()) {
			wCallTip.InvalidateAll();
		}
	}
}
<commit_msg>Tweaked arrow position slightly.<commit_after>// Scintilla source code edit control
/** @file CallTip.cxx
 ** Code for displaying call tips.
 **/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <string.h>

#include "Platform.h"

#include "Scintilla.h"
#include "CallTip.h"

CallTip::CallTip() {
	wCallTip = 0;
	inCallTipMode = false;
	posStartCallTip = 0;
	val = 0;
	xUp = -100;
	xDown = -100;
	lineHeight = 1;
	startHighlight = 0;
	endHighlight = 0;

	colourBG.desired = ColourDesired(0xff, 0xff, 0xff);
	colourUnSel.desired = ColourDesired(0x80, 0x80, 0x80);
	colourSel.desired = ColourDesired(0, 0, 0x80);
	colourShade.desired = ColourDesired(0, 0, 0);
	colourLight.desired = ColourDesired(0xc0, 0xc0, 0xc0);
}

CallTip::~CallTip() {
	font.Release();
	wCallTip.Destroy();
	delete []val;
	val = 0;
}

const int widthArrow = 14;

void CallTip::RefreshColourPalette(Palette &pal, bool want) {
	pal.WantFind(colourBG, want);
	pal.WantFind(colourUnSel, want);
	pal.WantFind(colourSel, want);
	pal.WantFind(colourShade, want);
	pal.WantFind(colourLight, want);
}

void CallTip::DrawChunk(Surface *surface, int &x, const char *s,
	int posStart, int posEnd, int ytext, PRectangle rcClient,
	bool highlight, bool draw) {
	s += posStart;
	int len = posEnd - posStart;
	int maxEnd = 0;
	int ends[10];
	for (int i=0;i<len;i++) {
		if (s[i] <= '\002') {
			if (i > 0)
				ends[maxEnd++] = i;
			ends[maxEnd++] = i+1;
		}
	}
	ends[maxEnd++] = len;
	int startSeg = 0;
	int xEnd;
	for (int seg = 0; seg<maxEnd; seg++) {
		int endSeg = ends[seg];
		if (endSeg > startSeg) {
			if (s[startSeg] <= '\002') {
				xEnd = x + widthArrow;
				offsetMain = xEnd;
				if (draw) {
					const int halfWidth = widthArrow / 2 - 3;
					const int centreX = x + widthArrow / 2 - 1;
					const int centreY = (rcClient.top + rcClient.bottom) / 2;
					rcClient.left = x;
					rcClient.right = xEnd;
					surface->FillRectangle(rcClient, colourBG.allocated);
					PRectangle rcClientInner(rcClient.left+1, rcClient.top+1, rcClient.right-2, rcClient.bottom-1);
					surface->FillRectangle(rcClientInner, colourUnSel.allocated);

					if (s[startSeg] == '\001') {
						// Up arrow
						Point pts[] = {
    						Point(centreX - halfWidth, centreY + halfWidth / 2),
    						Point(centreX + halfWidth, centreY + halfWidth / 2),
    						Point(centreX, centreY - halfWidth + halfWidth / 2),
						};
						surface->Polygon(pts, sizeof(pts) / sizeof(pts[0]),
                 						colourBG.allocated, colourBG.allocated);
					} else {
						// Down arrow
						Point pts[] = {
    						Point(centreX - halfWidth, centreY - halfWidth / 2),
    						Point(centreX + halfWidth, centreY - halfWidth / 2),
    						Point(centreX, centreY + halfWidth - halfWidth / 2),
						};
						surface->Polygon(pts, sizeof(pts) / sizeof(pts[0]),
                 						colourBG.allocated, colourBG.allocated);
					}
				} else {
					if (s[startSeg] == '\001') {
						xUp = x+1;
					} else {
						xDown = x+1;
					}
				}
			} else {
				xEnd = x + surface->WidthText(font, s+startSeg, endSeg - startSeg);
				if (draw) {
					rcClient.left = x;
					rcClient.right = xEnd;
					surface->DrawTextNoClip(rcClient, font, ytext,
										s+startSeg, endSeg - startSeg,
										highlight ? colourSel.allocated : colourUnSel.allocated,
										colourBG.allocated);
				}
			}
			x = xEnd;
			startSeg = endSeg;
		}
	}
}

int CallTip::PaintContents(Surface *surfaceWindow, bool draw) {
	PRectangle rcClientPos = wCallTip.GetClientPosition();
	PRectangle rcClientSize(0, 0, rcClientPos.right - rcClientPos.left,
	                        rcClientPos.bottom - rcClientPos.top);
	PRectangle rcClient(1, 1, rcClientSize.right - 1, rcClientSize.bottom - 1);

	// To make a nice small call tip window, it is only sized to fit most normal characters without accents
	int ascent = surfaceWindow->Ascent(font) - surfaceWindow->InternalLeading(font);

	// For each line...
	// Draw the definition in three parts: before highlight, highlighted, after highlight
	int ytext = rcClient.top + ascent + 1;
	rcClient.bottom = ytext + surfaceWindow->Descent(font) + 1;
	char *chunkVal = val;
	bool moreChunks = true;
	int maxWidth = 0;
	while (moreChunks) {
		char *chunkEnd = strchr(chunkVal, '\n');
		if (chunkEnd == NULL) {
			chunkEnd = chunkVal + strlen(chunkVal);
			moreChunks = false;
		}
		int chunkOffset = chunkVal - val;
		int chunkLength = chunkEnd - chunkVal;
		int chunkEndOffset = chunkOffset + chunkLength;
		int thisStartHighlight = Platform::Maximum(startHighlight, chunkOffset);
		thisStartHighlight = Platform::Minimum(thisStartHighlight, chunkEndOffset);
		thisStartHighlight -= chunkOffset;
		int thisEndHighlight = Platform::Maximum(endHighlight, chunkOffset);
		thisEndHighlight = Platform::Minimum(thisEndHighlight, chunkEndOffset);
		thisEndHighlight -= chunkOffset;
		rcClient.top = ytext - ascent - 1;

		int x = 5;

		DrawChunk(surfaceWindow, x, chunkVal, 0, thisStartHighlight,
			ytext, rcClient, false, draw);
		DrawChunk(surfaceWindow, x, chunkVal, thisStartHighlight, thisEndHighlight,
			ytext, rcClient, true, draw);
		DrawChunk(surfaceWindow, x, chunkVal, thisEndHighlight, chunkLength,
			ytext, rcClient, false, draw);

		chunkVal = chunkEnd + 1;
		ytext += lineHeight;
		rcClient.bottom += lineHeight;
		maxWidth = Platform::Maximum(maxWidth, x);
	}
	return maxWidth;
}

void CallTip::PaintCT(Surface *surfaceWindow) {
	if (!val)
		return;
	PRectangle rcClientPos = wCallTip.GetClientPosition();
	PRectangle rcClientSize(0, 0, rcClientPos.right - rcClientPos.left,
	                        rcClientPos.bottom - rcClientPos.top);
	PRectangle rcClient(1, 1, rcClientSize.right - 1, rcClientSize.bottom - 1);

	surfaceWindow->FillRectangle(rcClient, colourBG.allocated);

	offsetMain = 5;
	PaintContents(surfaceWindow, true);

	// Draw a raised border around the edges of the window
	surfaceWindow->MoveTo(0, rcClientSize.bottom - 1);
	surfaceWindow->PenColour(colourShade.allocated);
	surfaceWindow->LineTo(rcClientSize.right - 1, rcClientSize.bottom - 1);
	surfaceWindow->LineTo(rcClientSize.right - 1, 0);
	surfaceWindow->PenColour(colourLight.allocated);
	surfaceWindow->LineTo(0, 0);
	surfaceWindow->LineTo(0, rcClientSize.bottom - 1);
}

void CallTip::MouseClick(Point pt) {
	clickPlace = 0;
	if (pt.y < lineHeight) {
		if ((pt.x > xUp) && (pt.x < xUp + widthArrow - 2)) {
			clickPlace = 1;
		} else if ((pt.x > xDown) && (pt.x < xDown + widthArrow - 2)) {
			clickPlace = 2;
		}
	}
}

PRectangle CallTip::CallTipStart(int pos, Point pt, const char *defn,
                                 const char *faceName, int size,
                                 int codePage_, Window &wParent) {
	clickPlace = 0;
	if (val)
		delete []val;
	val = new char[strlen(defn) + 1];
	if (!val)
		return PRectangle();
	strcpy(val, defn);
	codePage = codePage_;
	Surface *surfaceMeasure = Surface::Allocate();
	if (!surfaceMeasure)
		return PRectangle();
	surfaceMeasure->Init(wParent.GetID());
	surfaceMeasure->SetUnicodeMode(SC_CP_UTF8 == codePage);
	surfaceMeasure->SetDBCSMode(codePage);
	startHighlight = 0;
	endHighlight = 0;
	inCallTipMode = true;
	posStartCallTip = pos;
	int deviceHeight = surfaceMeasure->DeviceHeightFont(size);
	font.Create(faceName, SC_CHARSET_DEFAULT, deviceHeight, false, false);
	// Look for multiple lines in the text
	// Only support \n here - simply means container must avoid \r!
	int numLines = 1;
	const char *newline;
	const char *look = val;
	xUp = -100;
	xDown = -100;
	offsetMain = 5;
	int width = PaintContents(surfaceMeasure, false) + 5;
	while ((newline = strchr(look, '\n')) != NULL) {
		look = newline + 1;
		numLines++;
	}
	lineHeight = surfaceMeasure->Height(font);
	// Extra line for border and an empty line at top and bottom
	int height = lineHeight * numLines - surfaceMeasure->InternalLeading(font) + 2 + 2;
	delete surfaceMeasure;
	return PRectangle(pt.x - offsetMain, pt.y + 1, pt.x + width - offsetMain, pt.y + 1 + height);
}

void CallTip::CallTipCancel() {
	inCallTipMode = false;
	if (wCallTip.Created()) {
		wCallTip.Destroy();
	}
}

void CallTip::SetHighlight(int start, int end) {
	// Avoid flashing by checking something has really changed
	if ((start != startHighlight) || (end != endHighlight)) {
		startHighlight = start;
		endHighlight = end;
		if (wCallTip.Created()) {
			wCallTip.InvalidateAll();
		}
	}
}
<|endoftext|>


<commit_before>#include <cstdlib>
#include <ctime>
#include <sys/wait.h>

#include <fstream>
#include <set>
#include <string>
#include <iostream>
#include <deque>
#include <vector>

#include "Crawler.h"
#include "Downloader.h"

std::string Crawler::GenerateFileName()
{
  return data_directory_ +
    std::to_string(time(NULL)) + " " + std::to_string(rand());
}

// Return value:
// 0 - success
// 1 - failed to download
// 2 - received interruption signal
// 3 - download queue is empty
int Crawler::FetchNextPage()
{
  if (download_queue_.container.empty())
  {
    return 3;
  }
  std::string link = download_queue_.container.front();
  if (link.compare(0, root_path_.length(), root_path_) != 0)
  {
    link = root_path_ + link;
  }
  std::string filename = GenerateFileName();
  std::cout << "Downloading " << link << std::endl;
  int result = Downloader::DownloadPage(link, filename);
  // check if program got signal to quit
  if (WIFSIGNALED(result) &&
      (WTERMSIG(result) == SIGINT || WTERMSIG(result) == SIGQUIT))
  {
    return 2;
  }
  // decode value that was returned by system() call
  result = WEXITSTATUS(result);
  if (result != 0)
  {
    std::cerr << "\033[1;31mFailed to fetch page " <<
      link << "\033[0m" << std::endl;
  }
  if (result != 0)
  {
    return 1;
  }
  download_queue_.container.pop_front();

  GetLinks(filename);
  return 0;
}

void Crawler::GetLinks(const std::string& filename)
{
  std::ifstream file(filename);
  char ch;
  while (file.get(ch))
  {
    int current = 0;
    while (current < link_prefix_.length() &&
        ch == link_prefix_[current])
    {
      current++;
      if (!file.get(ch))
      {
        break;
      }
    }
    if (current != link_prefix_.length())
    {
      continue;
    }
    std::string link;
    bool flag = true;
    do
    {
      if (ch != '"')
      {
        link.append(1, ch);
      }
      if (!file.get(ch))
      {
        flag = false;
        break;
      }
      for (char banned_symbol : banned_symbols_)
      {
        if (ch == banned_symbol)
        {
          flag = false;
        }
      }
    } while (ch != '"');
    if (!flag ||
        link.compare(0,
          required_link_prefix_.length(),
          required_link_prefix_) != 0)
    {
      continue;
    }
    if (visited_links_.container.count(link) == 0)
    {
      visited_links_.container.insert(link);
      download_queue_.container.push_back(link);
    }
  }
}

Crawler::Crawler(const std::string& data_directory,
    const std::string& root_path,
    const std::string& required_link_prefix,
    const std::vector<char>& banned_symbols) :
  data_directory_(data_directory),
  root_path_(root_path),
  required_link_prefix_(required_link_prefix),
  banned_symbols_(banned_symbols)
{
  download_queue_ =
    SaveableStringContainer<std::deque<std::string>>
    (data_directory_ + queue_filename_);
  visited_links_ =
    SaveableStringContainer<std::unordered_set<std::string>>
    (data_directory_ + visited_filename_);
}

void Crawler::Crawl(const std::string& start_page)
{
  if (download_queue_.container.empty())
  {
    download_queue_.container.push_back(start_page);
    visited_links_.container.insert(start_page);
  }
  while (FetchNextPage() <= 1)
  { }
}
<commit_msg>Fix bug with 404 pages.<commit_after>#include <cstdlib>
#include <ctime>
#include <sys/wait.h>

#include <fstream>
#include <set>
#include <string>
#include <iostream>
#include <deque>
#include <vector>

#include "Crawler.h"
#include "Downloader.h"

std::string Crawler::GenerateFileName()
{
  return data_directory_ +
    std::to_string(time(NULL)) + " " + std::to_string(rand());
}

// Return value:
// 0 - success
// 1 - failed to download
// 2 - received interruption signal
// 3 - download queue is empty
int Crawler::FetchNextPage()
{
  if (download_queue_.container.empty())
  {
    return 3;
  }
  std::string link = download_queue_.container.front();
  if (link.compare(0, root_path_.length(), root_path_) != 0)
  {
    link = root_path_ + link;
  }
  std::string filename = GenerateFileName();
  std::cout << "Downloading " << link << std::endl;
  int result = Downloader::DownloadPage(link, filename);
  // check if program got signal to quit
  if (WIFSIGNALED(result) &&
      (WTERMSIG(result) == SIGINT || WTERMSIG(result) == SIGQUIT))
  {
    return 2;
  }
  // decode value that was returned by system() call
  result = WEXITSTATUS(result);
  if (result != 0)
  {
    std::cerr << "\033[1;31mFailed to fetch page " <<
      link << "\033[0m" << std::endl;
  }
  if (result != 0 && result != 8)
    // 8 means server issued an error response (like 404) and we should
    // probably just ignore it
  {
    return 1;
  }
  download_queue_.container.pop_front();

  GetLinks(filename);
  return 0;
}

void Crawler::GetLinks(const std::string& filename)
{
  std::ifstream file(filename);
  char ch;
  while (file.get(ch))
  {
    int current = 0;
    while (current < link_prefix_.length() &&
        ch == link_prefix_[current])
    {
      current++;
      if (!file.get(ch))
      {
        break;
      }
    }
    if (current != link_prefix_.length())
    {
      continue;
    }
    std::string link;
    bool flag = true;
    do
    {
      if (ch != '"')
      {
        link.append(1, ch);
      }
      if (!file.get(ch))
      {
        flag = false;
        break;
      }
      for (char banned_symbol : banned_symbols_)
      {
        if (ch == banned_symbol)
        {
          flag = false;
        }
      }
    } while (ch != '"');
    if (!flag ||
        link.compare(0,
          required_link_prefix_.length(),
          required_link_prefix_) != 0)
    {
      continue;
    }
    if (visited_links_.container.count(link) == 0)
    {
      visited_links_.container.insert(link);
      download_queue_.container.push_back(link);
    }
  }
}

Crawler::Crawler(const std::string& data_directory,
    const std::string& root_path,
    const std::string& required_link_prefix,
    const std::vector<char>& banned_symbols) :
  data_directory_(data_directory),
  root_path_(root_path),
  required_link_prefix_(required_link_prefix),
  banned_symbols_(banned_symbols)
{
  download_queue_ =
    SaveableStringContainer<std::deque<std::string>>
    (data_directory_ + queue_filename_);
  visited_links_ =
    SaveableStringContainer<std::unordered_set<std::string>>
    (data_directory_ + visited_filename_);
}

void Crawler::Crawl(const std::string& start_page)
{
  if (download_queue_.container.empty())
  {
    download_queue_.container.push_back(start_page);
    visited_links_.container.insert(start_page);
  }
  while (FetchNextPage() <= 1)
  { }
}
<|endoftext|>


<commit_before>/**
* @file      Decoder.cpp
* @copyright (c) 2014 by Petr Zemek (s3rvac@gmail.com) and contributors
* @license   BSD, see the @c LICENSE file for more details
* @brief     Implementation of the Decoder class.
*/

#include "Decoder.h"

#include <cassert>
#include <regex>
#include <sstream>

#include "BInteger.h"
#include "Utils.h"

namespace bencoding {

/**
* @brief Constructs a new exception with the given message.
*/
DecodingError::DecodingError(const std::string &what):
	std::runtime_error(what) {}

/**
* @brief Constructs a decoder.
*/
Decoder::Decoder() {}

/**
* @brief Creates a new decoder.
*/
std::unique_ptr<Decoder> Decoder::create() {
	return std::unique_ptr<Decoder>(new Decoder());
}

/**
* @brief Decodes the given bencoded data and returns them.
*/
std::unique_ptr<BItem> Decoder::decode(const std::string &data) {
	std::istringstream input(data);
	return decode(input);
}

/**
* @brief Reads all the data from the given @a input, decodes them and returns
*        them.
*/
std::unique_ptr<BItem> Decoder::decode(std::istream &input) {
	switch (input.peek()) {
		case 'i':
			return decodeInteger(input);
		default:
			throw DecodingError("unexpected character: '" +
				std::to_string(input.peek()) + "'");
	}

	assert(false && "should never happen");
	return std::unique_ptr<BItem>();
}

/**
* @brief Decodes an integer from @a input.
*
* @par Format
* @code
* i<integer encoded in base ten ASCII>e
* @endcode
*
* @par Example
* @code
* i3e represents the integer 3
* @endcode
*
* Moreover, only the significant digits should be used, one cannot pad the
* integer with zeroes, such as @c i04e (see the
* specification).
*/
std::unique_ptr<BInteger> Decoder::decodeInteger(std::istream &input) const {
	return decodeEncodedInteger(readEncodedInteger(input));
}

/**
* @brief Reads an encoded integer from @a input.
*/
std::string Decoder::readEncodedInteger(std::istream &input) const {
	// See the description of decodeInteger() for the format and example.
	std::string encodedInteger;
	bool encodedIntegerReadCorrectly = readUntil(input, encodedInteger, 'e');
	if (!encodedIntegerReadCorrectly) {
		throw DecodingError("error during the decoding of an integer near '" +
			encodedInteger + "'");
	}

	return encodedInteger;
}

/**
* @brief Decodes the given encoded integer.
*/
std::unique_ptr<BInteger> Decoder::decodeEncodedInteger(
		const std::string &encodedInteger) const {
	// See the description of decodeInteger() for the format and example.
	std::regex integerRegex("i([-+]?(0|[1-9][0-9]*))e");
	std::smatch match;
	bool valid = std::regex_match(encodedInteger, match, integerRegex);
	if (!valid) {
		throw DecodingError("encountered an encoded integer of invalid format: '" +
			encodedInteger + "'");
	}

	BInteger::ValueType integerValue;
	strToNum(match[1].str(), integerValue);
	return BInteger::create(integerValue);
}

} // namespace bencoding
<commit_msg>Decoder: Fix the message of DecodingError with input.peek().<commit_after>/**
* @file      Decoder.cpp
* @copyright (c) 2014 by Petr Zemek (s3rvac@gmail.com) and contributors
* @license   BSD, see the @c LICENSE file for more details
* @brief     Implementation of the Decoder class.
*/

#include "Decoder.h"

#include <cassert>
#include <regex>
#include <sstream>

#include "BInteger.h"
#include "Utils.h"

namespace bencoding {

/**
* @brief Constructs a new exception with the given message.
*/
DecodingError::DecodingError(const std::string &what):
	std::runtime_error(what) {}

/**
* @brief Constructs a decoder.
*/
Decoder::Decoder() {}

/**
* @brief Creates a new decoder.
*/
std::unique_ptr<Decoder> Decoder::create() {
	return std::unique_ptr<Decoder>(new Decoder());
}

/**
* @brief Decodes the given bencoded data and returns them.
*/
std::unique_ptr<BItem> Decoder::decode(const std::string &data) {
	std::istringstream input(data);
	return decode(input);
}

/**
* @brief Reads all the data from the given @a input, decodes them and returns
*        them.
*/
std::unique_ptr<BItem> Decoder::decode(std::istream &input) {
	switch (input.peek()) {
		case 'i':
			return decodeInteger(input);
		default:
			throw DecodingError(std::string("unexpected character: '") +
				static_cast<char>(input.peek()) + "'");
	}

	assert(false && "should never happen");
	return std::unique_ptr<BItem>();
}

/**
* @brief Decodes an integer from @a input.
*
* @par Format
* @code
* i<integer encoded in base ten ASCII>e
* @endcode
*
* @par Example
* @code
* i3e represents the integer 3
* @endcode
*
* Moreover, only the significant digits should be used, one cannot pad the
* integer with zeroes, such as @c i04e (see the
* specification).
*/
std::unique_ptr<BInteger> Decoder::decodeInteger(std::istream &input) const {
	return decodeEncodedInteger(readEncodedInteger(input));
}

/**
* @brief Reads an encoded integer from @a input.
*/
std::string Decoder::readEncodedInteger(std::istream &input) const {
	// See the description of decodeInteger() for the format and example.
	std::string encodedInteger;
	bool encodedIntegerReadCorrectly = readUntil(input, encodedInteger, 'e');
	if (!encodedIntegerReadCorrectly) {
		throw DecodingError("error during the decoding of an integer near '" +
			encodedInteger + "'");
	}

	return encodedInteger;
}

/**
* @brief Decodes the given encoded integer.
*/
std::unique_ptr<BInteger> Decoder::decodeEncodedInteger(
		const std::string &encodedInteger) const {
	// See the description of decodeInteger() for the format and example.
	std::regex integerRegex("i([-+]?(0|[1-9][0-9]*))e");
	std::smatch match;
	bool valid = std::regex_match(encodedInteger, match, integerRegex);
	if (!valid) {
		throw DecodingError("encountered an encoded integer of invalid format: '" +
			encodedInteger + "'");
	}

	BInteger::ValueType integerValue;
	strToNum(match[1].str(), integerValue);
	return BInteger::create(integerValue);
}

} // namespace bencoding
<|endoftext|>


<commit_before>#include <cmath>
#include <limits>

#include "Lander/Geometry.h"

namespace {

const Lander::Point INVALID_POINT(
        std::numeric_limits<double>::quiet_NaN(),
        std::numeric_limits<double>::quiet_NaN()
);

/**
 * Based on a:
 * public domain function by Darel Rex Finley, 2006
 * Determines the intersection point of the line segment defined by points A and B
 * with the line segment defined by points C and D.
 *
 * @return a Point if the intersection point was found.
 * Returns an invalid Point if there is no determinable intersection point.
 */
bool lineSegmentIntersection(
    double Ax, double Ay,
    double Bx, double By,
    double Cx, double Cy,
    double Dx, double Dy,
    double *X, double *Y
) {
    double  distAB, theCos, theSin, newX, ABpos ;

    //  Fail if the segments share an end-point.
    if ((Ax==Cx && Ay==Cy) || (Bx==Cx && By==Cy)
            ||  (Ax==Dx && Ay==Dy) || (Bx==Dx && By==Dy)) {
        return false; }

    //  (1) Translate the system so that point A is on the origin.
    Bx-=Ax; By-=Ay;
    Cx-=Ax; Cy-=Ay;
    Dx-=Ax; Dy-=Ay;

    //  Discover the length of segment A-B.
    distAB = sqrt(Bx * Bx + By * By);

    //  (2) Rotate the system so that point B is on the positive X axis.
    theCos = Bx / distAB;
    theSin = By / distAB;
    newX = Cx * theCos + Cy * theSin;
    Cy = Cy * theCos - Cx * theSin;
    Cx = newX;
    newX = Dx * theCos + Dy * theSin;
    Dy = Dy * theCos - Dx * theSin;
    Dx = newX;

    //  Fail if segment C-D doesn't cross line A-B.
    if ((Cy < 0.0 && Dy < 0.0) || (Cy >= 0.0 && Dy >= 0.0))
        return false;

    //  (3) Discover the position of the intersection point along line A-B.
    ABpos=Dx+(Cx-Dx)*Dy/(Dy-Cy);

    //  Fail if segment C-D crosses line A-B outside of segment A-B.
    if ((ABpos < 0.0) || (ABpos > distAB)) return false;

    //  (4) Apply the discovered position to line A-B in the original coordinate system.
    *X=Ax+ABpos*theCos;
    *Y=Ay+ABpos*theSin;

    //  Success.
    return true;
}

}

namespace Lander {

/* Point utilities! */
Point::operator bool() const
{
    return !(isnan(x) || isnan(y));
}

Point Point::operator-() const
{
    return Point(-x, -y);
}

Point Point::operator+(const Point& other) const
{
    return Point(x + other.x, y + other.y);
}

Point Point::operator-(const Point& other) const
{
    return *this + -other;
}

bool Point::operator==(const Point& other) const
{
    return x == other.x && y == other.y;
}

/*
 * Line utilities!
 */

Line Line::translate(const Point& origin) const
{
    return Line(start + origin, end + origin);
}

Point Line::intersection(const Line& other) const
{
    double x, y;

    //  Fail if either line segment is zero-length.
    if (isZeroLength() || other.isZeroLength()) return INVALID_POINT;

    bool didIntersect = lineSegmentIntersection(
            this->start.x, this->start.y,
            this->end.x, this->end.y,
            other.start.x, other.start.y,
            other.end.x, other.end.y,
            &x, &y
    );

    if (didIntersect) {
        return Point(x, y);
    } else {
        return INVALID_POINT;
    }
}

bool Line::isZeroLength() const
{
    return start == end;
}

}
<commit_msg>Use line translation.<commit_after>#include <cmath>
#include <limits>

#include "Lander/Geometry.h"

//#include <iostream>

namespace {

const Lander::Point INVALID_POINT(
        std::numeric_limits<double>::quiet_NaN(),
        std::numeric_limits<double>::quiet_NaN()
);

/**
 * Based on a:
 * public domain function by Darel Rex Finley, 2006
 * Determines the intersection point of the line segment defined by points A and B
 * with the line segment defined by points C and D.
 *
 * @return a Point if the intersection point was found.
 * Returns an invalid Point if there is no determinable intersection point.
 */
bool lineSegmentIntersection(
    double Ax, double Ay,
    double Bx, double By,
    double Cx, double Cy,
    double Dx, double Dy,
    double *X, double *Y
) {
    double  distAB, theCos, theSin, newX, ABpos ;

    //  Discover the length of segment A-B.
    distAB = sqrt(Bx * Bx + By * By);

    //std::cerr << Ax << ',' << Ay << "=>" << Bx << ',' << By << std::endl;
    //std::cerr << Cx << ',' << Cy << "=>" << Dx << ',' << Dy << std::endl;

    //  (2) Rotate the system so that point B is on the positive X axis.
    theCos = Bx / distAB;
    theSin = By / distAB;
    newX = Cx * theCos + Cy * theSin;
    Cy = Cy * theCos - Cx * theSin;
    Cx = newX;
    newX = Dx * theCos + Dy * theSin;
    Dy = Dy * theCos - Dx * theSin;
    Dx = newX;

    //  Fail if segment C-D doesn't cross line A-B.
    if ((Cy < 0.0 && Dy < 0.0) || (Cy >= 0.0 && Dy >= 0.0))
        return false;

    //  (3) Discover the position of the intersection point along line A-B.
    ABpos=Dx+(Cx-Dx)*Dy/(Dy-Cy);

    //  Fail if segment C-D crosses line A-B outside of segment A-B.
    if ((ABpos < 0.0) || (ABpos > distAB)) return false;

    //  (4) Apply the discovered position to line A-B in the original coordinate system.
    *X=Ax+ABpos*theCos;
    *Y=Ay+ABpos*theSin;

    //  Success.
    return true;
}

}

namespace Lander {

/* Point utilities! */
Point::operator bool() const
{
    return !(isnan(x) || isnan(y));
}

Point Point::operator-() const
{
    return Point(-x, -y);
}

Point Point::operator+(const Point& other) const
{
    return Point(x + other.x, y + other.y);
}

Point Point::operator-(const Point& other) const
{
    return *this + -other;
}

bool Point::operator==(const Point& other) const
{
    return x == other.x && y == other.y;
}

/*
 * Line utilities!
 */

Line Line::translate(const Point& origin) const
{
    return Line(start + origin, end + origin);
}

Point Line::intersection(const Line& other) const
{
    double x, y;

    // Fail if either line segment is zero-length.
    if (isZeroLength() || other.isZeroLength()) return INVALID_POINT;

    // SKIPPED: Fail if the segments share an end-point.

    //  (1) Translate the system so that point A is on the origin.
    Line a = this->translate(-start);
    Line b = other.translate(-start);

    bool didIntersect = lineSegmentIntersection(
            a.start.x, a.start.y,
            a.end.x, a.end.y,
            b.start.x, b.start.y,
            b.end.x, b.end.y,
            &x, &y
    );

    if (didIntersect) {
        return Point(x, y);
    } else {
        return INVALID_POINT;
    }
}

bool Line::isZeroLength() const
{
    return start == end;
}

}
<|endoftext|>


<commit_before>#include "JWModules.hpp"
#include "dsp/digital.hpp"

struct GridSeq : Module {
	enum ParamIds {
		RUN_PARAM,
		CLOCK_PARAM,
		RESET_PARAM,
		CELL_PARAM,
		GATE_PARAM = CELL_PARAM + 16,
		NUM_PARAMS = GATE_PARAM + 16,
	};
	enum InputIds {
		CLOCK_INPUT,
		EXT_CLOCK_INPUT,
		RESET_INPUT,
		RIGHT_INPUT, LEFT_INPUT, DOWN_INPUT, UP_INPUT,
		NUM_INPUTS
	};
	enum OutputIds {
		GATES_OUTPUT,
		CELL_OUTPUT,
		NUM_OUTPUTS
	};

	SchmittTrigger rightTrigger;
	SchmittTrigger leftTrigger;
	SchmittTrigger downTrigger;
	SchmittTrigger upTrigger;

	SchmittTrigger runningTrigger;
	SchmittTrigger resetTrigger;
	SchmittTrigger gateTriggers[16];

	int index = 0;
	int posX = 0;
	int posY = 0;
	float phase = 0.0;
	bool gateState[16] = {};
	bool running = true;

	enum GateMode { TRIGGER, RETRIGGER, CONTINUOUS };
	GateMode gateMode = TRIGGER;
	PulseGenerator gatePulse;

	// Lights
	float resetLight = 0.0;
	float runningLight = 0.0;
	float stepLights[16] = {};
	float gateLights[16] = {};

	GridSeq() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {}
	void step();

	json_t *toJson() {
		json_t *rootJ = json_object();

		// running
		json_object_set_new(rootJ, "running", json_boolean(running));

		// gates
		json_t *gatesJ = json_array();
		for (int i = 0; i < 16; i++) {
			json_t *gateJ = json_integer((int) gateState[i]);
			json_array_append_new(gatesJ, gateJ);
		}
		json_object_set_new(rootJ, "gates", gatesJ);

		// gateMode
		json_t *gateModeJ = json_integer((int) gateMode);
		json_object_set_new(rootJ, "gateMode", gateModeJ);

		return rootJ;
	}

	void fromJson(json_t *rootJ) {
		// running
		json_t *runningJ = json_object_get(rootJ, "running");
		if (runningJ)
			running = json_is_true(runningJ);

		// gates
		json_t *gatesJ = json_object_get(rootJ, "gates");
		if (gatesJ) {
			for (int i = 0; i < 16; i++) {
				json_t *gateJ = json_array_get(gatesJ, i);
				if (gateJ)
					gateState[i] = !!json_integer_value(gateJ);
			}
		}

		// gateMode
		json_t *gateModeJ = json_object_get(rootJ, "gateMode");
		if (gateModeJ)
			gateMode = (GateMode)json_integer_value(gateModeJ);
	}

	void initialize() {
		for (int i = 0; i < 8; i++) {
			gateState[i] = true;
		}
	}

	void randomize() {
		for (int i = 0; i < 8; i++) {
			gateState[i] = (randomf() > 0.5);
		}
	}
};

void GridSeq::step() {
	const float lightLambda = 0.075;
	// Run
	if (runningTrigger.process(params[RUN_PARAM].value)) {
		running = !running;
	}
	runningLight = running ? 1.0 : 0.0;

	bool nextStep = false;

	// Reset
	if (resetTrigger.process(params[RESET_PARAM].value + inputs[RESET_INPUT].value)) {
		phase = 0.0;
		posX = 0;
		posY = 0;
		nextStep = true;
		resetLight = 1.0;
	}

	if(running){
		if (rightTrigger.process(inputs[RIGHT_INPUT].value)) {
			nextStep = true;
			posX = posX == 3 ? 0 : posX + 1;
		}
		if (leftTrigger.process(inputs[LEFT_INPUT].value)) {
			nextStep = true;
			posX = posX == 0 ? 3 : posX - 1;
		}
		if (downTrigger.process(inputs[DOWN_INPUT].value)) {
			nextStep = true;
			posY = posY == 3 ? 0 : posY + 1;
		}
		if (upTrigger.process(inputs[UP_INPUT].value)) {
			nextStep = true;
			posY = posY == 0 ? 3 : posY - 1;
		}
	}

	if (nextStep) {
		index = posX + (posY * 4);
		stepLights[index] = 1.0;
		gatePulse.trigger(1e-3);
	}

	resetLight -= resetLight / lightLambda / gSampleRate;
	bool pulse = gatePulse.process(1.0 / gSampleRate);

	// Gate buttons
	for (int i = 0; i < 16; i++) {
		if (gateTriggers[i].process(params[GATE_PARAM + i].value)) {
			gateState[i] = !gateState[i];
		}
		bool gateOn = (running && i == index && gateState[i]);
		if (gateMode == TRIGGER)
			gateOn = gateOn && pulse;
		else if (gateMode == RETRIGGER)
			gateOn = gateOn && !pulse;

		stepLights[i] -= stepLights[i] / lightLambda / gSampleRate;
		gateLights[i] = gateState[i] ? 1.0 - stepLights[i] : stepLights[i];
	}

	// Cells
	bool gatesOn = (running && gateState[index]);
	if (gateMode == TRIGGER)
		gatesOn = gatesOn && pulse;
	else if (gateMode == RETRIGGER)
		gatesOn = gatesOn && !pulse;

	// Outputs
	float cellVal = params[CELL_PARAM + index].value;
	outputs[CELL_OUTPUT].value = cellVal;
	outputs[GATES_OUTPUT].value = gatesOn ? 10.0 : 0.0;
}

GridSeqWidget::GridSeqWidget() {
	GridSeq *module = new GridSeq();
	setModule(module);
	box.size = Vec(15*20, 380);

	{
		SVGPanel *panel = new SVGPanel();
		panel->box.size = box.size;
		panel->setBackground(SVG::load(assetPlugin(plugin, "res/GridSeq.svg")));
		addChild(panel);
	}

	addChild(createScrew<ScrewSilver>(Vec(15, 0)));
	addChild(createScrew<ScrewSilver>(Vec(box.size.x-30, 0)));
	addChild(createScrew<ScrewSilver>(Vec(15, 365)));
	addChild(createScrew<ScrewSilver>(Vec(box.size.x-30, 365)));

	addParam(createParam<LEDButton>(Vec(23, 90), module, GridSeq::RUN_PARAM, 0.0, 1.0, 0.0));
	addChild(createValueLight<SmallLight<MyBlueValueLight>>(Vec(23+5, 90+5), &module->runningLight));

	addInput(createInput<PJ301MPort>(Vec(20, 160), module, GridSeq::RESET_INPUT));
	addParam(createParam<LEDButton>(Vec(23, 130), module, GridSeq::RESET_PARAM, 0.0, 1.0, 0.0));
	addChild(createValueLight<SmallLight<GreenValueLight>>(Vec(23+5, 130+5), &module->resetLight));

	addOutput(createOutput<PJ301MPort>(Vec(20, 238), module, GridSeq::GATES_OUTPUT));
	addOutput(createOutput<PJ301MPort>(Vec(20, 299), module, GridSeq::CELL_OUTPUT));

	addInput(createInput<PJ301MPort>(Vec(83, 90), module, GridSeq::RIGHT_INPUT));
	addInput(createInput<PJ301MPort>(Vec(138, 90), module, GridSeq::LEFT_INPUT));
	addInput(createInput<PJ301MPort>(Vec(193, 90), module, GridSeq::DOWN_INPUT));
	addInput(createInput<PJ301MPort>(Vec(248, 90), module, GridSeq::UP_INPUT));

	int boxSize = 55;
	for (int x = 0; x < 4; x++) {
		for (int y = 0; y < 4; y++) {
			int knobX = x * boxSize + 76;
			int knobY = y * boxSize + 149;
			int idx = (x+(y*4));
			addParam(createParam<SmallWhiteKnob>(Vec(knobX, knobY), module, GridSeq::CELL_PARAM + idx, 0.0, 6.0, 0.0));
			addParam(createParam<LEDButton>(Vec(knobX+22, knobY-15), module, GridSeq::GATE_PARAM + idx, 0.0, 1.0, 0.0));
			addChild(createValueLight<SmallLight<MyBlueValueLight>>(Vec(knobX+27, knobY-10), &module->gateLights[idx]));
		}
	}
}

struct GridSeqGateModeItem : MenuItem {
	GridSeq *gridSeq;
	GridSeq::GateMode gateMode;
	void onAction() {
		gridSeq->gateMode = gateMode;
	}
	void step() {
		rightText = (gridSeq->gateMode == gateMode) ? "✔" : "";
	}
};

Menu *GridSeqWidget::createContextMenu() {
	Menu *menu = ModuleWidget::createContextMenu();

	MenuLabel *spacerLabel = new MenuLabel();
	menu->pushChild(spacerLabel);

	GridSeq *gridSeq = dynamic_cast<GridSeq*>(module);
	assert(gridSeq);

	MenuLabel *modeLabel = new MenuLabel();
	modeLabel->text = "Gate Mode";
	menu->pushChild(modeLabel);

	GridSeqGateModeItem *triggerItem = new GridSeqGateModeItem();
	triggerItem->text = "Trigger";
	triggerItem->gridSeq = gridSeq;
	triggerItem->gateMode = GridSeq::TRIGGER;
	menu->pushChild(triggerItem);

	GridSeqGateModeItem *retriggerItem = new GridSeqGateModeItem();
	retriggerItem->text = "Retrigger";
	retriggerItem->gridSeq = gridSeq;
	retriggerItem->gateMode = GridSeq::RETRIGGER;
	menu->pushChild(retriggerItem);

	GridSeqGateModeItem *continuousItem = new GridSeqGateModeItem();
	continuousItem->text = "Continuous";
	continuousItem->gridSeq = gridSeq;
	continuousItem->gateMode = GridSeq::CONTINUOUS;
	menu->pushChild(continuousItem);

	return menu;
}
<commit_msg>fixed init<commit_after>#include "JWModules.hpp"
#include "dsp/digital.hpp"

struct GridSeq : Module {
	enum ParamIds {
		RUN_PARAM,
		CLOCK_PARAM,
		RESET_PARAM,
		CELL_PARAM,
		GATE_PARAM = CELL_PARAM + 16,
		NUM_PARAMS = GATE_PARAM + 16,
	};
	enum InputIds {
		CLOCK_INPUT,
		EXT_CLOCK_INPUT,
		RESET_INPUT,
		RIGHT_INPUT, LEFT_INPUT, DOWN_INPUT, UP_INPUT,
		NUM_INPUTS
	};
	enum OutputIds {
		GATES_OUTPUT,
		CELL_OUTPUT,
		NUM_OUTPUTS
	};

	SchmittTrigger rightTrigger;
	SchmittTrigger leftTrigger;
	SchmittTrigger downTrigger;
	SchmittTrigger upTrigger;

	SchmittTrigger runningTrigger;
	SchmittTrigger resetTrigger;
	SchmittTrigger gateTriggers[16];

	int index = 0;
	int posX = 0;
	int posY = 0;
	float phase = 0.0;
	bool gateState[16] = {};
	bool running = true;

	enum GateMode { TRIGGER, RETRIGGER, CONTINUOUS };
	GateMode gateMode = TRIGGER;
	PulseGenerator gatePulse;

	// Lights
	float resetLight = 0.0;
	float runningLight = 0.0;
	float stepLights[16] = {};
	float gateLights[16] = {};

	GridSeq() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {}
	void step();

	json_t *toJson() {
		json_t *rootJ = json_object();

		// running
		json_object_set_new(rootJ, "running", json_boolean(running));

		// gates
		json_t *gatesJ = json_array();
		for (int i = 0; i < 16; i++) {
			json_t *gateJ = json_integer((int) gateState[i]);
			json_array_append_new(gatesJ, gateJ);
		}
		json_object_set_new(rootJ, "gates", gatesJ);

		// gateMode
		json_t *gateModeJ = json_integer((int) gateMode);
		json_object_set_new(rootJ, "gateMode", gateModeJ);

		return rootJ;
	}

	void fromJson(json_t *rootJ) {
		// running
		json_t *runningJ = json_object_get(rootJ, "running");
		if (runningJ)
			running = json_is_true(runningJ);

		// gates
		json_t *gatesJ = json_object_get(rootJ, "gates");
		if (gatesJ) {
			for (int i = 0; i < 16; i++) {
				json_t *gateJ = json_array_get(gatesJ, i);
				if (gateJ)
					gateState[i] = !!json_integer_value(gateJ);
			}
		}

		// gateMode
		json_t *gateModeJ = json_object_get(rootJ, "gateMode");
		if (gateModeJ)
			gateMode = (GateMode)json_integer_value(gateModeJ);
	}

	void initialize() {
		for (int i = 0; i < 16; i++) {
			gateState[i] = true;
		}
	}

	void randomize() {
		for (int i = 0; i < 16; i++) {
			gateState[i] = (randomf() > 0.5);
		}
	}
};

void GridSeq::step() {
	const float lightLambda = 0.075;
	// Run
	if (runningTrigger.process(params[RUN_PARAM].value)) {
		running = !running;
	}
	runningLight = running ? 1.0 : 0.0;

	bool nextStep = false;

	// Reset
	if (resetTrigger.process(params[RESET_PARAM].value + inputs[RESET_INPUT].value)) {
		phase = 0.0;
		posX = 0;
		posY = 0;
		nextStep = true;
		resetLight = 1.0;
	}

	if(running){
		if (rightTrigger.process(inputs[RIGHT_INPUT].value)) {
			nextStep = true;
			posX = posX == 3 ? 0 : posX + 1;
		}
		if (leftTrigger.process(inputs[LEFT_INPUT].value)) {
			nextStep = true;
			posX = posX == 0 ? 3 : posX - 1;
		}
		if (downTrigger.process(inputs[DOWN_INPUT].value)) {
			nextStep = true;
			posY = posY == 3 ? 0 : posY + 1;
		}
		if (upTrigger.process(inputs[UP_INPUT].value)) {
			nextStep = true;
			posY = posY == 0 ? 3 : posY - 1;
		}
	}

	if (nextStep) {
		index = posX + (posY * 4);
		stepLights[index] = 1.0;
		gatePulse.trigger(1e-3);
	}

	resetLight -= resetLight / lightLambda / gSampleRate;
	bool pulse = gatePulse.process(1.0 / gSampleRate);

	// Gate buttons
	for (int i = 0; i < 16; i++) {
		if (gateTriggers[i].process(params[GATE_PARAM + i].value)) {
			gateState[i] = !gateState[i];
		}
		bool gateOn = (running && i == index && gateState[i]);
		if (gateMode == TRIGGER)
			gateOn = gateOn && pulse;
		else if (gateMode == RETRIGGER)
			gateOn = gateOn && !pulse;

		stepLights[i] -= stepLights[i] / lightLambda / gSampleRate;
		gateLights[i] = gateState[i] ? 1.0 - stepLights[i] : stepLights[i];
	}

	// Cells
	bool gatesOn = (running && gateState[index]);
	if (gateMode == TRIGGER)
		gatesOn = gatesOn && pulse;
	else if (gateMode == RETRIGGER)
		gatesOn = gatesOn && !pulse;

	// Outputs
	float cellVal = params[CELL_PARAM + index].value;
	outputs[CELL_OUTPUT].value = cellVal;
	outputs[GATES_OUTPUT].value = gatesOn ? 10.0 : 0.0;
}

GridSeqWidget::GridSeqWidget() {
	GridSeq *module = new GridSeq();
	setModule(module);
	box.size = Vec(15*20, 380);

	{
		SVGPanel *panel = new SVGPanel();
		panel->box.size = box.size;
		panel->setBackground(SVG::load(assetPlugin(plugin, "res/GridSeq.svg")));
		addChild(panel);
	}

	addChild(createScrew<ScrewSilver>(Vec(15, 0)));
	addChild(createScrew<ScrewSilver>(Vec(box.size.x-30, 0)));
	addChild(createScrew<ScrewSilver>(Vec(15, 365)));
	addChild(createScrew<ScrewSilver>(Vec(box.size.x-30, 365)));

	addParam(createParam<LEDButton>(Vec(23, 90), module, GridSeq::RUN_PARAM, 0.0, 1.0, 0.0));
	addChild(createValueLight<SmallLight<MyBlueValueLight>>(Vec(23+5, 90+5), &module->runningLight));

	addInput(createInput<PJ301MPort>(Vec(20, 160), module, GridSeq::RESET_INPUT));
	addParam(createParam<LEDButton>(Vec(23, 130), module, GridSeq::RESET_PARAM, 0.0, 1.0, 0.0));
	addChild(createValueLight<SmallLight<GreenValueLight>>(Vec(23+5, 130+5), &module->resetLight));

	addOutput(createOutput<PJ301MPort>(Vec(20, 238), module, GridSeq::GATES_OUTPUT));
	addOutput(createOutput<PJ301MPort>(Vec(20, 299), module, GridSeq::CELL_OUTPUT));

	addInput(createInput<PJ301MPort>(Vec(83, 90), module, GridSeq::RIGHT_INPUT));
	addInput(createInput<PJ301MPort>(Vec(138, 90), module, GridSeq::LEFT_INPUT));
	addInput(createInput<PJ301MPort>(Vec(193, 90), module, GridSeq::DOWN_INPUT));
	addInput(createInput<PJ301MPort>(Vec(248, 90), module, GridSeq::UP_INPUT));

	int boxSize = 55;
	for (int x = 0; x < 4; x++) {
		for (int y = 0; y < 4; y++) {
			int knobX = x * boxSize + 76;
			int knobY = y * boxSize + 149;
			int idx = (x+(y*4));
			addParam(createParam<SmallWhiteKnob>(Vec(knobX, knobY), module, GridSeq::CELL_PARAM + idx, 0.0, 6.0, 0.0));
			addParam(createParam<LEDButton>(Vec(knobX+22, knobY-15), module, GridSeq::GATE_PARAM + idx, 0.0, 1.0, 0.0));
			addChild(createValueLight<SmallLight<MyBlueValueLight>>(Vec(knobX+27, knobY-10), &module->gateLights[idx]));
		}
	}
}

struct GridSeqGateModeItem : MenuItem {
	GridSeq *gridSeq;
	GridSeq::GateMode gateMode;
	void onAction() {
		gridSeq->gateMode = gateMode;
	}
	void step() {
		rightText = (gridSeq->gateMode == gateMode) ? "✔" : "";
	}
};

Menu *GridSeqWidget::createContextMenu() {
	Menu *menu = ModuleWidget::createContextMenu();

	MenuLabel *spacerLabel = new MenuLabel();
	menu->pushChild(spacerLabel);

	GridSeq *gridSeq = dynamic_cast<GridSeq*>(module);
	assert(gridSeq);

	MenuLabel *modeLabel = new MenuLabel();
	modeLabel->text = "Gate Mode";
	menu->pushChild(modeLabel);

	GridSeqGateModeItem *triggerItem = new GridSeqGateModeItem();
	triggerItem->text = "Trigger";
	triggerItem->gridSeq = gridSeq;
	triggerItem->gateMode = GridSeq::TRIGGER;
	menu->pushChild(triggerItem);

	GridSeqGateModeItem *retriggerItem = new GridSeqGateModeItem();
	retriggerItem->text = "Retrigger";
	retriggerItem->gridSeq = gridSeq;
	retriggerItem->gateMode = GridSeq::RETRIGGER;
	menu->pushChild(retriggerItem);

	GridSeqGateModeItem *continuousItem = new GridSeqGateModeItem();
	continuousItem->text = "Continuous";
	continuousItem->gridSeq = gridSeq;
	continuousItem->gateMode = GridSeq::CONTINUOUS;
	menu->pushChild(continuousItem);

	return menu;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <cassert>
#include "HelpCmd.h"
#include "CommandSet.h"

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

cigma::HelpCmd::HelpCmd()
{
    name = "help";
    commands = 0;
}

cigma::HelpCmd::~HelpCmd()
{
}

void cigma::HelpCmd::setCmdMap(CommandSet::CmdMap *cmds)
{
    /* pointer to set of commands */
    this->commands = cmds;

    /* prepare usage list from current set of commands */
    usageList.clear();
    std::string prefix = "   ";
    CommandSet::CmdMap::iterator it;
    for (it = commands->begin(); it != commands->end(); ++it)
    {
        Command *cmd = it->second;
        usageList.push_back(prefix + (cmd->name));
    }
}

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

void cigma::HelpCmd::setupOptions(AnyOption *opt)
{
    //std::cout << "Calling cigma::HelpCmd::setupOptions()" << std::endl;

    assert(opt != 0);

    /* prepare preamble */
    opt->addUsage("Usage: cigma <subcommand> [options] [args]");
    opt->addUsage("Type 'cigma help <subcommand>' for help on a specific subcommand.");
    opt->addUsage("");
    opt->addUsage("Available subcommands");

    /* pass contents of usage list to opt object */
    std::vector<std::string>::iterator it;
    for (it = usageList.begin(); it != usageList.end(); ++it)
    {
        opt->addUsage(it->c_str());
    }

    // XXX: need to set at least one flag or option (bug in AnyOption)
    opt->setFlag("help",'h');
}

void cigma::HelpCmd::configure(AnyOption *opt)
{
    //std::cout << "Calling cigma::HelpCmd::configure()" << std::endl;

    assert(opt != 0);

    int argc = opt->getArgc();

    subcommand = "";
    if (argc == 0)
    {
        subcommand = "help";
    }
    else
    {
        subcommand = opt->getArgv(0);
        if (argc >= 2)
        {
            // XXX: too many args!
            std::cerr << "Too many arguments! "
                      << "Taking only '"
                      << subcommand
                      << "'" << std::endl;
        }
    }
}

int cigma::HelpCmd::run()
{
    //std::cout << "Calling cigma::HelpCmd::run()" << std::endl;

    CommandSet::CmdMap::iterator it = commands->find(subcommand);

    if (it != commands->end())
    {
        AnyOption opt;
        Command *cmd = it->second;
        cmd->setupOptions(&opt);
        opt.printUsage();
        return 0;
    }
    else
    {
        std::cerr << "Unknown command: '"
                  << subcommand
                  << "'" << std::endl;
    }

    return 1;
}

<commit_msg>Added 'using namespace cigma' to HelpCmd.cpp<commit_after>#include <iostream>
#include <cassert>
#include "HelpCmd.h"
#include "CommandSet.h"

using namespace cigma;

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

HelpCmd::HelpCmd()
{
    name = "help";
    commands = 0;
}

HelpCmd::~HelpCmd()
{
}

void HelpCmd::setCmdMap(CommandSet::CmdMap *cmds)
{
    /* pointer to set of commands */
    this->commands = cmds;

    /* prepare usage list from current set of commands */
    usageList.clear();
    std::string prefix = "   ";
    CommandSet::CmdMap::iterator it;
    for (it = commands->begin(); it != commands->end(); ++it)
    {
        Command *cmd = it->second;
        usageList.push_back(prefix + (cmd->name));
    }
}

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

void HelpCmd::setupOptions(AnyOption *opt)
{
    //std::cout << "Calling cigma::HelpCmd::setupOptions()" << std::endl;

    assert(opt != 0);

    /* prepare preamble */
    opt->addUsage("Usage: cigma <subcommand> [options] [args]");
    opt->addUsage("Type 'cigma help <subcommand>' for help on a specific subcommand.");
    opt->addUsage("");
    opt->addUsage("Available subcommands");

    /* pass contents of usage list to opt object */
    std::vector<std::string>::iterator it;
    for (it = usageList.begin(); it != usageList.end(); ++it)
    {
        opt->addUsage(it->c_str());
    }

    // XXX: need to set at least one flag or option (bug in AnyOption)
    opt->setFlag("help",'h');
}

void HelpCmd::configure(AnyOption *opt)
{
    //std::cout << "Calling cigma::HelpCmd::configure()" << std::endl;

    assert(opt != 0);

    int argc = opt->getArgc();

    subcommand = "";
    if (argc == 0)
    {
        subcommand = "help";
    }
    else
    {
        subcommand = opt->getArgv(0);
        if (argc >= 2)
        {
            // XXX: too many args!
            std::cerr << "Too many arguments! "
                      << "Taking only '"
                      << subcommand
                      << "'" << std::endl;
        }
    }
}

int HelpCmd::run()
{
    //std::cout << "Calling cigma::HelpCmd::run()" << std::endl;

    CommandSet::CmdMap::iterator it = commands->find(subcommand);

    if (it != commands->end())
    {
        AnyOption opt;
        Command *cmd = it->second;
        cmd->setupOptions(&opt);
        opt.printUsage();
        return 0;
    }
    else
    {
        std::cerr << "Unknown command: '"
                  << subcommand
                  << "'" << std::endl;
    }

    return 1;
}

<|endoftext|>


<commit_before>
#include "Internal.hpp"
#include <LuminoEngine/Tilemap/TilemapLayer.hpp>
#include <LuminoEngine/Tilemap/TilemapModel.hpp>
#include <LuminoEngine/Tilemap/Tileset.hpp>

namespace ln {

//==============================================================================
// AbstractTilemapLayer

AbstractTilemapLayer::AbstractTilemapLayer()
    : m_tileSize(1, 1)
    , m_orientation(TilemapOrientation::UpFlow)
{
}

AbstractTilemapLayer::~AbstractTilemapLayer()
{
}

void AbstractTilemapLayer::init()
{
    Object::init();
}

//void AbstractTilemapLayer::resize(int width, int height)
//{
//    m_size.set(width, height);
//    m_data.resize(width * height);
//}
//
//void AbstractTilemapLayer::setTileId(int x, int y, int id)
//{
//    m_data[y * m_size.width + x] = id;
//}
//
//int AbstractTilemapLayer::getTileId(int x, int y) const
//{
//    // TODO: round
//    // clamp
//    if (x < 0 || m_size.width <= x) return 0;
//    if (y < 0 || m_size.height <= y) return 0;
//
//    return m_data[y * m_size.width + x];
//}

void AbstractTilemapLayer::setTileSize(const Size& size)
{
    m_tileSize = size;
}

// bounds: Y+ を上方向とした、ローカル空間上の描画範囲
void AbstractTilemapLayer::render(TilemapModel* model, RenderingContext* context, const Matrix& transform, const detail::TilemapBounds& bounds)
{

    //int l, t, r, b;         // 2D array としてどの範囲を描画するか
    float wL, wT, wR, wB;   // world としてどの範囲を描画するか
    //Vector3 offset;
    int l, t, r, b;
    {
        wL = l = static_cast<int>(bounds.l / m_tileSize.width);
        wT = t = static_cast<int>(bounds.t / m_tileSize.height);
        wR = r = static_cast<int>(bounds.r / m_tileSize.width);
        wB = b = static_cast<int>(bounds.b / m_tileSize.height);
        //wL *= m_tileSize.width;
        //wT *= m_tileSize.height;
        //wR *= m_tileSize.width;
        //wB *= m_tileSize.height;
        //t = -t;
        //b = -b;

        //if (m_orientation == TilemapOrientation::UpFlow)
        //{
        //    offset.y = m_tileSize.height * m_size.height;
        //    // Y=0 から↑へ向かって配置する。(0, 0) = [0, m_size.height-1]
        //    //t = m_size.height - t;
        //    //b = m_size.height - b;
        //}
        //else if (m_orientation == TilemapOrientation::DownFlow)
        //{
        //    // Y=0 から↓へ向かって配置する。(0, 0) = [0, 0]
        //    //t = -t;
        //    //b = -b;
        //}
        //else
        //{
        //    LN_UNREACHABLE();
        //}
    }

    int width = getWidth();
    int height = getHeight();

    //float tw = m_tileSize.width;
    //float th = m_tileSize.height;
    for (int y = t; y >= b; y--)
    {
        // clamp
        //if (y < 0 || m_size.height <= y) continue;

        for (int x = l; x < r; x++)
        {
            // clamp
            //if (x < 0 || m_size.width <= x) continue;
            int tileId = 0;

            if (m_orientation == TilemapOrientation::UpFlow)
            {
                tileId = getTileId(x, height - y - 1);
            }
            else if (m_orientation == TilemapOrientation::DownFlow) {
                tileId = getTileId(x, -y);
            }
            else {
                LN_UNREACHABLE();
            }

            if (tileId > 0)
            {
                Vector3 pos(x * m_tileSize.width, y * m_tileSize.height, 0);
                Tileset* tileset;
                int localId;
                if (model->fetchTileset(tileId, &tileset, &localId)) {
                    tileset->drawTile(context, localId, pos, m_tileSize);
                }
            }
        }
    }

    //for (int y = t; y < renderRange.bottom; ++y)
    //{
    //    Vector3 pos = offset + (stepY * y) + (stepX * renderRange.left);
    //    for (int x = renderRange.left; x < renderRange.right; ++x)
    //    {
    //    }
    //}

}

//==============================================================================
// TilemapLayer

Ref<TilemapLayer> TilemapLayer::create()
{
    return newObject<TilemapLayer>();
}

TilemapLayer::TilemapLayer()
{
}

TilemapLayer::~TilemapLayer()
{
}

void TilemapLayer::init()
{
    AbstractTilemapLayer::init();
}

void TilemapLayer::resize(int width, int height)
{
    m_size.set(width, height);
    m_data.resize(width * height);
}

void TilemapLayer::setTileId(int x, int y, int id)
{
    m_data[y * m_size.width + x] = id;
}

int TilemapLayer::getTileId(int x, int y) const
{
    // TODO: round
    // clamp
    if (x < 0 || m_size.width <= x) return 0;
    if (y < 0 || m_size.height <= y) return 0;

    return m_data[y * m_size.width + x];
}

} // namespace ln

<commit_msg>border<commit_after>
#include "Internal.hpp"
#include <LuminoEngine/Tilemap/TilemapLayer.hpp>
#include <LuminoEngine/Tilemap/TilemapModel.hpp>
#include <LuminoEngine/Tilemap/Tileset.hpp>

namespace ln {

//==============================================================================
// AbstractTilemapLayer

AbstractTilemapLayer::AbstractTilemapLayer()
    : m_tileSize(1, 1)
    , m_orientation(TilemapOrientation::UpFlow)
{
}

AbstractTilemapLayer::~AbstractTilemapLayer()
{
}

void AbstractTilemapLayer::init()
{
    Object::init();
}

//void AbstractTilemapLayer::resize(int width, int height)
//{
//    m_size.set(width, height);
//    m_data.resize(width * height);
//}
//
//void AbstractTilemapLayer::setTileId(int x, int y, int id)
//{
//    m_data[y * m_size.width + x] = id;
//}
//
//int AbstractTilemapLayer::getTileId(int x, int y) const
//{
//    // TODO: round
//    // clamp
//    if (x < 0 || m_size.width <= x) return 0;
//    if (y < 0 || m_size.height <= y) return 0;
//
//    return m_data[y * m_size.width + x];
//}

void AbstractTilemapLayer::setTileSize(const Size& size)
{
    m_tileSize = size;
}

// bounds: Y+ を上方向とした、ローカル空間上の描画範囲
void AbstractTilemapLayer::render(TilemapModel* model, RenderingContext* context, const Matrix& transform, const detail::TilemapBounds& bounds)
{

    //int l, t, r, b;         // 2D array としてどの範囲を描画するか
    float wL, wT, wR, wB;   // world としてどの範囲を描画するか
    //Vector3 offset;
    int l, t, r, b;
    {
        wL = l = static_cast<int>(bounds.l / m_tileSize.width);
        wT = t = static_cast<int>(bounds.t / m_tileSize.height);
        wR = r = static_cast<int>(bounds.r / m_tileSize.width);
        wB = b = static_cast<int>(bounds.b / m_tileSize.height);
        //wL *= m_tileSize.width;
        //wT *= m_tileSize.height;
        //wR *= m_tileSize.width;
        //wB *= m_tileSize.height;
        //t = -t;
        //b = -b;

        //if (m_orientation == TilemapOrientation::UpFlow)
        //{
        //    offset.y = m_tileSize.height * m_size.height;
        //    // Y=0 から↑へ向かって配置する。(0, 0) = [0, m_size.height-1]
        //    //t = m_size.height - t;
        //    //b = m_size.height - b;
        //}
        //else if (m_orientation == TilemapOrientation::DownFlow)
        //{
        //    // Y=0 から↓へ向かって配置する。(0, 0) = [0, 0]
        //    //t = -t;
        //    //b = -b;
        //}
        //else
        //{
        //    LN_UNREACHABLE();
        //}

        r += 1;
        b -= 1;
    }

    int width = getWidth();
    int height = getHeight();

    //float tw = m_tileSize.width;
    //float th = m_tileSize.height;
    for (int y = t; y >= b; y--)
    {
        // clamp
        //if (y < 0 || m_size.height <= y) continue;

        for (int x = l; x < r; x++)
        {
            // clamp
            //if (x < 0 || m_size.width <= x) continue;
            int tileId = 0;

            if (m_orientation == TilemapOrientation::UpFlow)
            {
                tileId = getTileId(x, height - y - 1);
            }
            else if (m_orientation == TilemapOrientation::DownFlow) {
                tileId = getTileId(x, -y);
            }
            else {
                LN_UNREACHABLE();
            }

            if (tileId > 0)
            {
                Vector3 pos(x * m_tileSize.width, y * m_tileSize.height, 0);
                Tileset* tileset;
                int localId;
                if (model->fetchTileset(tileId, &tileset, &localId)) {
                    tileset->drawTile(context, localId, pos, m_tileSize);
                }
            }
        }
    }

    //for (int y = t; y < renderRange.bottom; ++y)
    //{
    //    Vector3 pos = offset + (stepY * y) + (stepX * renderRange.left);
    //    for (int x = renderRange.left; x < renderRange.right; ++x)
    //    {
    //    }
    //}

}

//==============================================================================
// TilemapLayer

Ref<TilemapLayer> TilemapLayer::create()
{
    return newObject<TilemapLayer>();
}

TilemapLayer::TilemapLayer()
{
}

TilemapLayer::~TilemapLayer()
{
}

void TilemapLayer::init()
{
    AbstractTilemapLayer::init();
}

void TilemapLayer::resize(int width, int height)
{
    m_size.set(width, height);
    m_data.resize(width * height);
}

void TilemapLayer::setTileId(int x, int y, int id)
{
    m_data[y * m_size.width + x] = id;
}

int TilemapLayer::getTileId(int x, int y) const
{
    // TODO: round
    // clamp
    if (x < 0 || m_size.width <= x) return 0;
    if (y < 0 || m_size.height <= y) return 0;

    return m_data[y * m_size.width + x];
}

} // namespace ln

<|endoftext|>


<commit_before>//template provided by SurgicalSteel a.k.a Yuwono Bangun Nagoro for competitive programming purposes
#include <bits/stdc++.h>
#define Mas_Bangun using
#define cinta namespace
#define Mbak_IsyanaSarasvati std
#define PI 3.1415926535897932384626433832795
#define MOD 1000000007
#define PB push_back
#define MP make_pair

Mas_Bangun cinta Mbak_IsyanaSarasvati;
struct point{int x,y;};
int toInt(string x)
{
    istringstream ss(x);
    int a;
    ss>>a;
    return a;
}
string tostr(int x)
{
    ostringstream ss;
    ss<<x;
    return ss.str();
}
vector<int> sieve(int n)
{
	vector <int> res;
	int temp=1;
    for(int i=2;i<=n;i++)
    {
        for(int a=2;a<=i;a++)
        {if(i%a==0){temp++;}}
        if(temp==2){res.PB(i);}
        temp=1;
    }
    return res;
}
string eliminateAt(string x, int num)//eliminates a single substring of a string in a given position
{
    if(num==0){return x.substr(1,x.length()-1);}
    else if(num==x.length()-1){return x.substr(0,x.length()-1);}
    else{return x.substr(0,num)+x.substr(num+1,x.length()-1);}
}
long long factorial(int num) //finds factorial of given integer
{
  if(num==0){return 1;}
  else{return num*factorial(num-1);}
}
long long pangkatp(int base,int exp) //powers base by exponen
{
    if(exp==0){return 1;}
    else{return base*pangkatp(base,exp-1);}
}
int sumdigit(string a) //sums all digit on given string (if the string only contains digits)
{
    int sum=0;
    for(int x=0;x<a.length();x++){sum+=toInt(a.substr(x,1));}
    return sum;
}
int absolutey(int a) //returns absolute value of an integer
{if(a<0){return a*-1;}else{return a;}}
bool contains(string a,string b) //Checks if string a contains string b, where a.length()>=b.length()
{
    bool valid=false;
    int x=0;
    while(x<a.length()-b.length()&&!valid)
    {
        if(a.substr(x,b.length())==b){valid=true;}
        else{x++;}
    }
    return valid;
}
char toCharSingle(string x)//single substring as input. Converts single substring to single char
{
  char a[1];
  strncpy(a,x.c_str(),sizeof(a));
  return a[0];
}
string toStringSingle(char x) //converts single char to single substring
{
  string c;
  stringstream ss;
  ss<<x;
  ss>>c;
  return c;
}
string reverse(string a) //reverses a given string
{
  string x;
  for(int y=a.length()-1;y>=0;y--)
  {x+=a.substr(y,1);}
  return x;
}
string tobase(int num,int base) //translates bitmask from decimal number to base n. 2<=n<=9
{
  string a;
  while(num>0)
  {
    a+=tostr(num%base);
    num=(num-(num%base))/base;
  }
  return reverse(a);
}
int main()
{
    //MAIN SECTION GOES HERE
    /* //In case you need, use them like cin and cout
    fstream fin("input.txt");
    fstream fout("output.txt");
    */

    return 0;
}
<commit_msg>edit sieve on template<commit_after>//template provided by SurgicalSteel a.k.a Yuwono Bangun Nagoro for competitive programming purposes
#include <bits/stdc++.h>
#define Mas_Bangun using
#define cinta namespace
#define Mbak_IsyanaSarasvati std
#define PI 3.1415926535897932384626433832795
#define MOD 1000000007
#define PB push_back
#define MP make_pair

Mas_Bangun cinta Mbak_IsyanaSarasvati;
struct point{int x,y;};
int toInt(string x)
{
    istringstream ss(x);
    int a;
    ss>>a;
    return a;
}
string tostr(int x)
{
    ostringstream ss;
    ss<<x;
    return ss.str();
}
vector<int> sieve(int n)
{
    vector <int> res;
    int temp=1;
    for(int i=2;i<=n;i++)
    {
        for(int a=2;a<=i;a++)
        {if(i%a==0){temp++;}}
        if(temp==2){res.PB(i);}
        temp=1;
    }
    return res;
}
string eliminateAt(string x, int num)//eliminates a single substring of a string in a given position
{
    if(num==0){return x.substr(1,x.length()-1);}
    else if(num==x.length()-1){return x.substr(0,x.length()-1);}
    else{return x.substr(0,num)+x.substr(num+1,x.length()-1);}
}
long long factorial(int num) //finds factorial of given integer
{
  if(num==0){return 1;}
  else{return num*factorial(num-1);}
}
long long pangkatp(int base,int exp) //powers base by exponen
{
    if(exp==0){return 1;}
    else{return base*pangkatp(base,exp-1);}
}
int sumdigit(string a) //sums all digit on given string (if the string only contains digits)
{
    int sum=0;
    for(int x=0;x<a.length();x++){sum+=toInt(a.substr(x,1));}
    return sum;
}
int absolutey(int a) //returns absolute value of an integer
{if(a<0){return a*-1;}else{return a;}}
bool contains(string a,string b) //Checks if string a contains string b, where a.length()>=b.length()
{
    bool valid=false;
    int x=0;
    while(x<a.length()-b.length()&&!valid)
    {
        if(a.substr(x,b.length())==b){valid=true;}
        else{x++;}
    }
    return valid;
}
char toCharSingle(string x)//single substring as input. Converts single substring to single char
{
  char a[1];
  strncpy(a,x.c_str(),sizeof(a));
  return a[0];
}
string toStringSingle(char x) //converts single char to single substring
{
  string c;
  stringstream ss;
  ss<<x;
  ss>>c;
  return c;
}
string reverse(string a) //reverses a given string
{
  string x;
  for(int y=a.length()-1;y>=0;y--)
  {x+=a.substr(y,1);}
  return x;
}
string tobase(int num,int base) //translates bitmask from decimal number to base n. 2<=n<=9
{
  string a;
  while(num>0)
  {
    a+=tostr(num%base);
    num=(num-(num%base))/base;
  }
  return reverse(a);
}
int main()
{
    //MAIN SECTION GOES HERE
    /* //In case you need, use them like cin and cout
    fstream fin("input.txt");
    fstream fout("output.txt");
    */

    return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017 Samsung Electronics Co., Ltd.
 *
 * 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.
 *
 */

// CLASS HEADER
#include <dali/internal/graphics/gles20/egl-implementation.h>

// EXTERNAL INCLUDES
#include <dali/integration-api/debug.h>
#include <dali/public-api/common/dali-common.h>
#include <dali/public-api/common/dali-vector.h>

// INTERNAL INCLUDES
#include <dali/internal/graphics/gles20/gl-implementation.h>
#include <dali/internal/graphics/gles20/egl-debug.h>

// EGL constants use C style casts
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wold-style-cast"

namespace Dali
{

namespace Internal
{

namespace Adaptor
{

#define TEST_EGL_ERROR(lastCommand) \
{ \
  EGLint err = eglGetError(); \
  if (err != EGL_SUCCESS) \
  { \
    DALI_LOG_ERROR("EGL error after %s\n", lastCommand); \
    Egl::PrintError(err); \
    DALI_ASSERT_ALWAYS(0 && "EGL error"); \
  } \
}

EglImplementation::EglImplementation( int multiSamplingLevel,
                                      Integration::DepthBufferAvailable depthBufferRequired,
                                      Integration::StencilBufferAvailable stencilBufferRequired )
: mContextAttribs(),
  mEglNativeDisplay( 0 ),
  mEglNativeWindow( 0 ),
  mCurrentEglNativePixmap( 0 ),
  mEglDisplay( 0 ),
  mEglConfig( 0 ),
  mEglContext( 0 ),
  mCurrentEglSurface( 0 ),
  mMultiSamplingLevel( multiSamplingLevel ),
  mColorDepth( COLOR_DEPTH_24 ),
  mGlesInitialized( false ),
  mIsOwnSurface( true ),
  mContextCurrent( false ),
  mIsWindow( true ),
  mDepthBufferRequired( depthBufferRequired == Integration::DepthBufferAvailable::TRUE ),
  mStencilBufferRequired( stencilBufferRequired == Integration::StencilBufferAvailable::TRUE )
{
}

EglImplementation::~EglImplementation()
{
  TerminateGles();
}

bool EglImplementation::InitializeGles( EGLNativeDisplayType display, bool isOwnSurface )
{
  if ( !mGlesInitialized )
  {
    mEglNativeDisplay = display;

    //@todo see if we can just EGL_DEFAULT_DISPLAY instead
    mEglDisplay = eglGetDisplay(mEglNativeDisplay);
    EGLint error = eglGetError();

    if( mEglDisplay == NULL && error != EGL_SUCCESS )
    {
      throw Dali::DaliException( "", "OpenGL ES is not supported");
    }

    EGLint majorVersion = 0;
    EGLint minorVersion = 0;
    if ( !eglInitialize( mEglDisplay, &majorVersion, &minorVersion ) )
    {
      return false;
    }
    eglBindAPI(EGL_OPENGL_ES_API);

    mContextAttribs.Clear();

#if DALI_GLES_VERSION >= 30

    mContextAttribs.Reserve(5);
    mContextAttribs.PushBack( EGL_CONTEXT_MAJOR_VERSION_KHR );
    mContextAttribs.PushBack( DALI_GLES_VERSION / 10 );
    mContextAttribs.PushBack( EGL_CONTEXT_MINOR_VERSION_KHR );
    mContextAttribs.PushBack( DALI_GLES_VERSION % 10 );

#else // DALI_GLES_VERSION >= 30

    mContextAttribs.Reserve(3);
    mContextAttribs.PushBack( EGL_CONTEXT_CLIENT_VERSION );
    mContextAttribs.PushBack( 2 );

#endif // DALI_GLES_VERSION >= 30

    mContextAttribs.PushBack( EGL_NONE );

    mGlesInitialized = true;
    mIsOwnSurface = isOwnSurface;
  }

  return mGlesInitialized;
}

bool EglImplementation::CreateContext()
{
  // make sure a context isn't created twice
  DALI_ASSERT_ALWAYS( (mEglContext == 0) && "EGL context recreated" );

  mEglContext = eglCreateContext(mEglDisplay, mEglConfig, NULL, &(mContextAttribs[0]));
  TEST_EGL_ERROR("eglCreateContext render thread");

  DALI_ASSERT_ALWAYS( EGL_NO_CONTEXT != mEglContext && "EGL context not created" );

  DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_VENDOR : %s ***\n", glGetString(GL_VENDOR));
  DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_RENDERER : %s ***\n", glGetString(GL_RENDERER));
  DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_VERSION : %s ***\n", glGetString(GL_VERSION));
  DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_SHADING_LANGUAGE_VERSION : %s***\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
  DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** Supported Extensions ***\n%s\n\n", glGetString(GL_EXTENSIONS));

  return true;
}

void EglImplementation::DestroyContext()
{
  DALI_ASSERT_ALWAYS( mEglContext && "no EGL context" );

  eglDestroyContext( mEglDisplay, mEglContext );
  mEglContext = 0;
}

void EglImplementation::DestroySurface()
{
  if(mIsOwnSurface && mCurrentEglSurface)
  {
    // Make context null to prevent crash in driver side
    MakeContextNull();
    eglDestroySurface( mEglDisplay, mCurrentEglSurface );
    mCurrentEglSurface = 0;
  }
}

void EglImplementation::MakeContextCurrent()
{
  mContextCurrent = true;

  if(mIsOwnSurface)
  {
    eglMakeCurrent( mEglDisplay, mCurrentEglSurface, mCurrentEglSurface, mEglContext );
  }

  EGLint error = eglGetError();

  if ( error != EGL_SUCCESS )
  {
    Egl::PrintError(error);

    DALI_ASSERT_ALWAYS(false && "MakeContextCurrent failed!");
  }

  // We want to display this information all the time, so use the LogMessage directly
  Integration::Log::LogMessage(Integration::Log::DebugInfo, "EGL Information\n"
      "            Vendor:        %s\n"
      "            Version:       %s\n"
      "            Client APIs:   %s\n"
      "            Extensions:    %s\n",
      eglQueryString(mEglDisplay, EGL_VENDOR),
      eglQueryString(mEglDisplay, EGL_VERSION),
      eglQueryString(mEglDisplay, EGL_CLIENT_APIS),
      eglQueryString(mEglDisplay, EGL_EXTENSIONS));
}

void EglImplementation::MakeCurrent( EGLNativePixmapType pixmap, EGLSurface eglSurface )
{
  mCurrentEglNativePixmap = pixmap;
  mCurrentEglSurface = eglSurface;

  if(mIsOwnSurface)
  {
    eglMakeCurrent( mEglDisplay, mCurrentEglSurface, mCurrentEglSurface, mEglContext );
  }

  EGLint error = eglGetError();

  if ( error != EGL_SUCCESS )
  {
    Egl::PrintError(error);

    DALI_ASSERT_ALWAYS(false && "MakeCurrent failed!");
  }
}

void EglImplementation::MakeContextNull()
{
  mContextCurrent = false;
  // clear the current context
  eglMakeCurrent( mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
}

void EglImplementation::TerminateGles()
{
  if ( mGlesInitialized )
  {
    // Make context null to prevent crash in driver side
    MakeContextNull();

    if(mIsOwnSurface && mCurrentEglSurface)
    {
      eglDestroySurface(mEglDisplay, mCurrentEglSurface);
    }
    eglDestroyContext(mEglDisplay, mEglContext);

    eglTerminate(mEglDisplay);

    mEglDisplay = NULL;
    mEglConfig  = NULL;
    mEglContext = NULL;
    mCurrentEglSurface = NULL;

    mGlesInitialized = false;
  }
}

bool EglImplementation::IsGlesInitialized() const
{
  return mGlesInitialized;
}

void EglImplementation::SwapBuffers()
{
  eglSwapBuffers( mEglDisplay, mCurrentEglSurface );
}

void EglImplementation::CopyBuffers()
{
  eglCopyBuffers( mEglDisplay, mCurrentEglSurface, mCurrentEglNativePixmap );
}

void EglImplementation::WaitGL()
{
  eglWaitGL();
}

void EglImplementation::ChooseConfig( bool isWindowType, ColorDepth depth )
{
  if(mEglConfig && isWindowType == mIsWindow && mColorDepth == depth)
  {
    return;
  }

  mIsWindow = isWindowType;

  EGLint numConfigs;
  Vector<EGLint> configAttribs;
  configAttribs.Reserve(31);

  if(isWindowType)
  {
    configAttribs.PushBack( EGL_SURFACE_TYPE );
    configAttribs.PushBack( EGL_WINDOW_BIT );
  }
  else
  {
    configAttribs.PushBack( EGL_SURFACE_TYPE );
    configAttribs.PushBack( EGL_PIXMAP_BIT );
  }

  configAttribs.PushBack( EGL_RENDERABLE_TYPE );

#if DALI_GLES_VERSION >= 30

#ifdef _ARCH_ARM_
  configAttribs.PushBack( EGL_OPENGL_ES3_BIT_KHR );
#else
  // There is a bug in the desktop emulator
  // Requesting for ES3 causes eglCreateContext even though it allows to ask
  // for a configuration that supports GLES 3.0
  configAttribs.PushBack( EGL_OPENGL_ES2_BIT );
#endif // _ARCH_ARM_

#else // DALI_GLES_VERSION >= 30

  Integration::Log::LogMessage( Integration::Log::DebugInfo, "Using OpenGL ES 2 \n" );
  configAttribs.PushBack( EGL_OPENGL_ES2_BIT );

#endif //DALI_GLES_VERSION >= 30

#if DALI_GLES_VERSION >= 30
// TODO: enable this flag when it becomes supported
//  configAttribs.PushBack( EGL_CONTEXT_FLAGS_KHR );
//  configAttribs.PushBack( EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR );
#endif //DALI_GLES_VERSION >= 30

  configAttribs.PushBack( EGL_RED_SIZE );
  configAttribs.PushBack( 8 );
  configAttribs.PushBack( EGL_GREEN_SIZE );
  configAttribs.PushBack( 8 );
  configAttribs.PushBack( EGL_BLUE_SIZE );
  configAttribs.PushBack( 8 );

  configAttribs.PushBack( EGL_ALPHA_SIZE );
#ifdef _ARCH_ARM_
  configAttribs.PushBack( (depth == COLOR_DEPTH_32) ? 8 : 0 );
#else
  // There is a bug in the desktop emulator
  // setting EGL_ALPHA_SIZE to 8 results in eglChooseConfig failing
  configAttribs.PushBack( 0 );
#endif // _ARCH_ARM_

  configAttribs.PushBack( EGL_DEPTH_SIZE );
  configAttribs.PushBack( mDepthBufferRequired ? 24 : 0 );
  configAttribs.PushBack( EGL_STENCIL_SIZE );
  configAttribs.PushBack( mStencilBufferRequired ? 8 : 0 );

#ifndef DALI_PROFILE_UBUNTU
  if( mMultiSamplingLevel != EGL_DONT_CARE )
  {
    configAttribs.PushBack( EGL_SAMPLES );
    configAttribs.PushBack( mMultiSamplingLevel );
    configAttribs.PushBack( EGL_SAMPLE_BUFFERS );
    configAttribs.PushBack( 1 );
  }
#endif // DALI_PROFILE_UBUNTU
  configAttribs.PushBack( EGL_NONE );

  if ( eglChooseConfig( mEglDisplay, &(configAttribs[0]), &mEglConfig, 1, &numConfigs ) != EGL_TRUE )
  {
    EGLint error = eglGetError();
    switch (error)
    {
      case EGL_BAD_DISPLAY:
      {
        DALI_LOG_ERROR("Display is not an EGL display connection\n");
        break;
      }
      case EGL_BAD_ATTRIBUTE:
      {
        DALI_LOG_ERROR("The parameter configAttribs contains an invalid frame buffer configuration attribute or an attribute value that is unrecognized or out of range\n");
        break;
      }
      case EGL_NOT_INITIALIZED:
      {
        DALI_LOG_ERROR("Display has not been initialized\n");
        break;
      }
      case EGL_BAD_PARAMETER:
      {
        DALI_LOG_ERROR("The parameter numConfig is NULL\n");
        break;
      }
      default:
      {
        DALI_LOG_ERROR("Unknown error.\n");
      }
    }
    DALI_ASSERT_ALWAYS(false && "eglChooseConfig failed!");
  }

  if ( numConfigs != 1 )
  {
    DALI_LOG_ERROR("No configurations found.\n");

    TEST_EGL_ERROR("eglChooseConfig");
  }
}

void EglImplementation::CreateSurfaceWindow( EGLNativeWindowType window, ColorDepth depth )
{
  DALI_ASSERT_ALWAYS( ( mCurrentEglSurface == 0 ) && "EGL surface already exists" );

  mEglNativeWindow = window;
  mColorDepth = depth;
  mIsWindow = true;

  // egl choose config
  ChooseConfig(mIsWindow, mColorDepth);

  mCurrentEglSurface = eglCreateWindowSurface( mEglDisplay, mEglConfig, mEglNativeWindow, NULL );
  TEST_EGL_ERROR("eglCreateWindowSurface");

  DALI_ASSERT_ALWAYS( mCurrentEglSurface && "Create window surface failed" );
}

EGLSurface EglImplementation::CreateSurfacePixmap( EGLNativePixmapType pixmap, ColorDepth depth )
{
  mCurrentEglNativePixmap = pixmap;
  mColorDepth = depth;
  mIsWindow = false;

  // egl choose config
  ChooseConfig(mIsWindow, mColorDepth);

  mCurrentEglSurface = eglCreatePixmapSurface( mEglDisplay, mEglConfig, mCurrentEglNativePixmap, NULL );
  TEST_EGL_ERROR("eglCreatePixmapSurface");

  DALI_ASSERT_ALWAYS( mCurrentEglSurface && "Create pixmap surface failed" );

  return mCurrentEglSurface;
}

bool EglImplementation::ReplaceSurfaceWindow( EGLNativeWindowType window )
{
  bool contextLost = false;

  // display connection has not changed, then we can just create a new surface
  //  the surface is bound to the context, so set the context to null
  MakeContextNull();

  // destroy the surface
  DestroySurface();

  // create the EGL surface
  CreateSurfaceWindow( window, mColorDepth );

  // set the context to be current with the new surface
  MakeContextCurrent();

  return contextLost;
}

bool EglImplementation::ReplaceSurfacePixmap( EGLNativePixmapType pixmap, EGLSurface& eglSurface )
{
  bool contextLost = false;

  // display connection has not changed, then we can just create a new surface
  // create the EGL surface
  eglSurface = CreateSurfacePixmap( pixmap, mColorDepth );

  // set the eglSurface to be current
  MakeCurrent( pixmap, eglSurface );

  return contextLost;
}

EGLDisplay EglImplementation::GetDisplay() const
{
  return mEglDisplay;
}

EGLDisplay EglImplementation::GetContext() const
{
  return mEglContext;
}

} // namespace Adaptor

} // namespace Internal

} // namespace Dali

#pragma GCC diagnostic pop
<commit_msg>For underlay video playback, we also need to set the alpha value of the 24/32bit window.<commit_after>/*
 * Copyright (c) 2017 Samsung Electronics Co., Ltd.
 *
 * 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.
 *
 */

// CLASS HEADER
#include <dali/internal/graphics/gles20/egl-implementation.h>

// EXTERNAL INCLUDES
#include <dali/integration-api/debug.h>
#include <dali/public-api/common/dali-common.h>
#include <dali/public-api/common/dali-vector.h>

// INTERNAL INCLUDES
#include <dali/internal/graphics/gles20/gl-implementation.h>
#include <dali/internal/graphics/gles20/egl-debug.h>

// EGL constants use C style casts
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wold-style-cast"

namespace Dali
{

namespace Internal
{

namespace Adaptor
{

#define TEST_EGL_ERROR(lastCommand) \
{ \
  EGLint err = eglGetError(); \
  if (err != EGL_SUCCESS) \
  { \
    DALI_LOG_ERROR("EGL error after %s\n", lastCommand); \
    Egl::PrintError(err); \
    DALI_ASSERT_ALWAYS(0 && "EGL error"); \
  } \
}

EglImplementation::EglImplementation( int multiSamplingLevel,
                                      Integration::DepthBufferAvailable depthBufferRequired,
                                      Integration::StencilBufferAvailable stencilBufferRequired )
: mContextAttribs(),
  mEglNativeDisplay( 0 ),
  mEglNativeWindow( 0 ),
  mCurrentEglNativePixmap( 0 ),
  mEglDisplay( 0 ),
  mEglConfig( 0 ),
  mEglContext( 0 ),
  mCurrentEglSurface( 0 ),
  mMultiSamplingLevel( multiSamplingLevel ),
  mColorDepth( COLOR_DEPTH_24 ),
  mGlesInitialized( false ),
  mIsOwnSurface( true ),
  mContextCurrent( false ),
  mIsWindow( true ),
  mDepthBufferRequired( depthBufferRequired == Integration::DepthBufferAvailable::TRUE ),
  mStencilBufferRequired( stencilBufferRequired == Integration::StencilBufferAvailable::TRUE )
{
}

EglImplementation::~EglImplementation()
{
  TerminateGles();
}

bool EglImplementation::InitializeGles( EGLNativeDisplayType display, bool isOwnSurface )
{
  if ( !mGlesInitialized )
  {
    mEglNativeDisplay = display;

    //@todo see if we can just EGL_DEFAULT_DISPLAY instead
    mEglDisplay = eglGetDisplay(mEglNativeDisplay);
    EGLint error = eglGetError();

    if( mEglDisplay == NULL && error != EGL_SUCCESS )
    {
      throw Dali::DaliException( "", "OpenGL ES is not supported");
    }

    EGLint majorVersion = 0;
    EGLint minorVersion = 0;
    if ( !eglInitialize( mEglDisplay, &majorVersion, &minorVersion ) )
    {
      return false;
    }
    eglBindAPI(EGL_OPENGL_ES_API);

    mContextAttribs.Clear();

#if DALI_GLES_VERSION >= 30

    mContextAttribs.Reserve(5);
    mContextAttribs.PushBack( EGL_CONTEXT_MAJOR_VERSION_KHR );
    mContextAttribs.PushBack( DALI_GLES_VERSION / 10 );
    mContextAttribs.PushBack( EGL_CONTEXT_MINOR_VERSION_KHR );
    mContextAttribs.PushBack( DALI_GLES_VERSION % 10 );

#else // DALI_GLES_VERSION >= 30

    mContextAttribs.Reserve(3);
    mContextAttribs.PushBack( EGL_CONTEXT_CLIENT_VERSION );
    mContextAttribs.PushBack( 2 );

#endif // DALI_GLES_VERSION >= 30

    mContextAttribs.PushBack( EGL_NONE );

    mGlesInitialized = true;
    mIsOwnSurface = isOwnSurface;
  }

  return mGlesInitialized;
}

bool EglImplementation::CreateContext()
{
  // make sure a context isn't created twice
  DALI_ASSERT_ALWAYS( (mEglContext == 0) && "EGL context recreated" );

  mEglContext = eglCreateContext(mEglDisplay, mEglConfig, NULL, &(mContextAttribs[0]));
  TEST_EGL_ERROR("eglCreateContext render thread");

  DALI_ASSERT_ALWAYS( EGL_NO_CONTEXT != mEglContext && "EGL context not created" );

  DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_VENDOR : %s ***\n", glGetString(GL_VENDOR));
  DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_RENDERER : %s ***\n", glGetString(GL_RENDERER));
  DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_VERSION : %s ***\n", glGetString(GL_VERSION));
  DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_SHADING_LANGUAGE_VERSION : %s***\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
  DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** Supported Extensions ***\n%s\n\n", glGetString(GL_EXTENSIONS));

  return true;
}

void EglImplementation::DestroyContext()
{
  DALI_ASSERT_ALWAYS( mEglContext && "no EGL context" );

  eglDestroyContext( mEglDisplay, mEglContext );
  mEglContext = 0;
}

void EglImplementation::DestroySurface()
{
  if(mIsOwnSurface && mCurrentEglSurface)
  {
    // Make context null to prevent crash in driver side
    MakeContextNull();
    eglDestroySurface( mEglDisplay, mCurrentEglSurface );
    mCurrentEglSurface = 0;
  }
}

void EglImplementation::MakeContextCurrent()
{
  mContextCurrent = true;

  if(mIsOwnSurface)
  {
    eglMakeCurrent( mEglDisplay, mCurrentEglSurface, mCurrentEglSurface, mEglContext );
  }

  EGLint error = eglGetError();

  if ( error != EGL_SUCCESS )
  {
    Egl::PrintError(error);

    DALI_ASSERT_ALWAYS(false && "MakeContextCurrent failed!");
  }

  // We want to display this information all the time, so use the LogMessage directly
  Integration::Log::LogMessage(Integration::Log::DebugInfo, "EGL Information\n"
      "            Vendor:        %s\n"
      "            Version:       %s\n"
      "            Client APIs:   %s\n"
      "            Extensions:    %s\n",
      eglQueryString(mEglDisplay, EGL_VENDOR),
      eglQueryString(mEglDisplay, EGL_VERSION),
      eglQueryString(mEglDisplay, EGL_CLIENT_APIS),
      eglQueryString(mEglDisplay, EGL_EXTENSIONS));
}

void EglImplementation::MakeCurrent( EGLNativePixmapType pixmap, EGLSurface eglSurface )
{
  mCurrentEglNativePixmap = pixmap;
  mCurrentEglSurface = eglSurface;

  if(mIsOwnSurface)
  {
    eglMakeCurrent( mEglDisplay, mCurrentEglSurface, mCurrentEglSurface, mEglContext );
  }

  EGLint error = eglGetError();

  if ( error != EGL_SUCCESS )
  {
    Egl::PrintError(error);

    DALI_ASSERT_ALWAYS(false && "MakeCurrent failed!");
  }
}

void EglImplementation::MakeContextNull()
{
  mContextCurrent = false;
  // clear the current context
  eglMakeCurrent( mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
}

void EglImplementation::TerminateGles()
{
  if ( mGlesInitialized )
  {
    // Make context null to prevent crash in driver side
    MakeContextNull();

    if(mIsOwnSurface && mCurrentEglSurface)
    {
      eglDestroySurface(mEglDisplay, mCurrentEglSurface);
    }
    eglDestroyContext(mEglDisplay, mEglContext);

    eglTerminate(mEglDisplay);

    mEglDisplay = NULL;
    mEglConfig  = NULL;
    mEglContext = NULL;
    mCurrentEglSurface = NULL;

    mGlesInitialized = false;
  }
}

bool EglImplementation::IsGlesInitialized() const
{
  return mGlesInitialized;
}

void EglImplementation::SwapBuffers()
{
  eglSwapBuffers( mEglDisplay, mCurrentEglSurface );
}

void EglImplementation::CopyBuffers()
{
  eglCopyBuffers( mEglDisplay, mCurrentEglSurface, mCurrentEglNativePixmap );
}

void EglImplementation::WaitGL()
{
  eglWaitGL();
}

void EglImplementation::ChooseConfig( bool isWindowType, ColorDepth depth )
{
  if(mEglConfig && isWindowType == mIsWindow && mColorDepth == depth)
  {
    return;
  }

  mIsWindow = isWindowType;

  EGLint numConfigs;
  Vector<EGLint> configAttribs;
  configAttribs.Reserve(31);

  if(isWindowType)
  {
    configAttribs.PushBack( EGL_SURFACE_TYPE );
    configAttribs.PushBack( EGL_WINDOW_BIT );
  }
  else
  {
    configAttribs.PushBack( EGL_SURFACE_TYPE );
    configAttribs.PushBack( EGL_PIXMAP_BIT );
  }

  configAttribs.PushBack( EGL_RENDERABLE_TYPE );

#if DALI_GLES_VERSION >= 30

#ifdef _ARCH_ARM_
  configAttribs.PushBack( EGL_OPENGL_ES3_BIT_KHR );
#else
  // There is a bug in the desktop emulator
  // Requesting for ES3 causes eglCreateContext even though it allows to ask
  // for a configuration that supports GLES 3.0
  configAttribs.PushBack( EGL_OPENGL_ES2_BIT );
#endif // _ARCH_ARM_

#else // DALI_GLES_VERSION >= 30

  Integration::Log::LogMessage( Integration::Log::DebugInfo, "Using OpenGL ES 2 \n" );
  configAttribs.PushBack( EGL_OPENGL_ES2_BIT );

#endif //DALI_GLES_VERSION >= 30

#if DALI_GLES_VERSION >= 30
// TODO: enable this flag when it becomes supported
//  configAttribs.PushBack( EGL_CONTEXT_FLAGS_KHR );
//  configAttribs.PushBack( EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR );
#endif //DALI_GLES_VERSION >= 30

  configAttribs.PushBack( EGL_RED_SIZE );
  configAttribs.PushBack( 8 );
  configAttribs.PushBack( EGL_GREEN_SIZE );
  configAttribs.PushBack( 8 );
  configAttribs.PushBack( EGL_BLUE_SIZE );
  configAttribs.PushBack( 8 );

  configAttribs.PushBack( EGL_ALPHA_SIZE );
#ifdef _ARCH_ARM_
  // For underlay video playback, we also need to set the alpha value of the 24/32bit window.
  configAttribs.PushBack( 8 );
#else
  // There is a bug in the desktop emulator
  // setting EGL_ALPHA_SIZE to 8 results in eglChooseConfig failing
  configAttribs.PushBack( 0 );
#endif // _ARCH_ARM_

  configAttribs.PushBack( EGL_DEPTH_SIZE );
  configAttribs.PushBack( mDepthBufferRequired ? 24 : 0 );
  configAttribs.PushBack( EGL_STENCIL_SIZE );
  configAttribs.PushBack( mStencilBufferRequired ? 8 : 0 );

#ifndef DALI_PROFILE_UBUNTU
  if( mMultiSamplingLevel != EGL_DONT_CARE )
  {
    configAttribs.PushBack( EGL_SAMPLES );
    configAttribs.PushBack( mMultiSamplingLevel );
    configAttribs.PushBack( EGL_SAMPLE_BUFFERS );
    configAttribs.PushBack( 1 );
  }
#endif // DALI_PROFILE_UBUNTU
  configAttribs.PushBack( EGL_NONE );

  if ( eglChooseConfig( mEglDisplay, &(configAttribs[0]), &mEglConfig, 1, &numConfigs ) != EGL_TRUE )
  {
    EGLint error = eglGetError();
    switch (error)
    {
      case EGL_BAD_DISPLAY:
      {
        DALI_LOG_ERROR("Display is not an EGL display connection\n");
        break;
      }
      case EGL_BAD_ATTRIBUTE:
      {
        DALI_LOG_ERROR("The parameter configAttribs contains an invalid frame buffer configuration attribute or an attribute value that is unrecognized or out of range\n");
        break;
      }
      case EGL_NOT_INITIALIZED:
      {
        DALI_LOG_ERROR("Display has not been initialized\n");
        break;
      }
      case EGL_BAD_PARAMETER:
      {
        DALI_LOG_ERROR("The parameter numConfig is NULL\n");
        break;
      }
      default:
      {
        DALI_LOG_ERROR("Unknown error.\n");
      }
    }
    DALI_ASSERT_ALWAYS(false && "eglChooseConfig failed!");
  }

  if ( numConfigs != 1 )
  {
    DALI_LOG_ERROR("No configurations found.\n");

    TEST_EGL_ERROR("eglChooseConfig");
  }
}

void EglImplementation::CreateSurfaceWindow( EGLNativeWindowType window, ColorDepth depth )
{
  DALI_ASSERT_ALWAYS( ( mCurrentEglSurface == 0 ) && "EGL surface already exists" );

  mEglNativeWindow = window;
  mColorDepth = depth;
  mIsWindow = true;

  // egl choose config
  ChooseConfig(mIsWindow, mColorDepth);

  mCurrentEglSurface = eglCreateWindowSurface( mEglDisplay, mEglConfig, mEglNativeWindow, NULL );
  TEST_EGL_ERROR("eglCreateWindowSurface");

  DALI_ASSERT_ALWAYS( mCurrentEglSurface && "Create window surface failed" );
}

EGLSurface EglImplementation::CreateSurfacePixmap( EGLNativePixmapType pixmap, ColorDepth depth )
{
  mCurrentEglNativePixmap = pixmap;
  mColorDepth = depth;
  mIsWindow = false;

  // egl choose config
  ChooseConfig(mIsWindow, mColorDepth);

  mCurrentEglSurface = eglCreatePixmapSurface( mEglDisplay, mEglConfig, mCurrentEglNativePixmap, NULL );
  TEST_EGL_ERROR("eglCreatePixmapSurface");

  DALI_ASSERT_ALWAYS( mCurrentEglSurface && "Create pixmap surface failed" );

  return mCurrentEglSurface;
}

bool EglImplementation::ReplaceSurfaceWindow( EGLNativeWindowType window )
{
  bool contextLost = false;

  // display connection has not changed, then we can just create a new surface
  //  the surface is bound to the context, so set the context to null
  MakeContextNull();

  // destroy the surface
  DestroySurface();

  // create the EGL surface
  CreateSurfaceWindow( window, mColorDepth );

  // set the context to be current with the new surface
  MakeContextCurrent();

  return contextLost;
}

bool EglImplementation::ReplaceSurfacePixmap( EGLNativePixmapType pixmap, EGLSurface& eglSurface )
{
  bool contextLost = false;

  // display connection has not changed, then we can just create a new surface
  // create the EGL surface
  eglSurface = CreateSurfacePixmap( pixmap, mColorDepth );

  // set the eglSurface to be current
  MakeCurrent( pixmap, eglSurface );

  return contextLost;
}

EGLDisplay EglImplementation::GetDisplay() const
{
  return mEglDisplay;
}

EGLDisplay EglImplementation::GetContext() const
{
  return mEglContext;
}

} // namespace Adaptor

} // namespace Internal

} // namespace Dali

#pragma GCC diagnostic pop
<|endoftext|>