<commit_before>/* bzflag
 * Copyright (c) 1993 - 2007 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface header */
#include "FormatMenu.h"

/* common implementation headers */
#include "BzfDisplay.h"
#include "ErrorHandler.h"
#include "FontManager.h"

/* local implementation headers */
#include "MainMenu.h"
#include "playing.h"
#include "HUDui.h"
#include "HUDNavigationQueue.h"

const int		FormatMenu::NumReadouts = 4;
const int		FormatMenu::NumItems = 30;
const int		FormatMenu::NumColumns = 3;

bool FormatMenuDefaultKey::keyPress(const BzfKeyEvent& key)
{
  if (key.ascii == 0) switch (key.button) {
    case BzfKeyEvent::PageUp:
      if (HUDui::getFocus()) {
	menu->setPage(menu->page + 1);
      }
      return true;

    case BzfKeyEvent::PageDown:
      if (HUDui::getFocus()) {
	menu->setPage(menu->page - 1);
      }
      return true;

  } else if (key.ascii == 'T' || key.ascii == 't') {
    menu->setFormat(true);
    return true;
  }
  return MenuDefaultKey::keyPress(key);
}

bool FormatMenuDefaultKey::keyRelease(const BzfKeyEvent& key)
{
  switch (key.button) {
    case BzfKeyEvent::PageUp:
    case BzfKeyEvent::PageDown:
      return true;
  }
  switch (key.ascii) {
    case 27:	// escape
    case 13:	// return
    case 'T':
    case 't':
      return true;
  }
  return MenuDefaultKey::keyRelease(key);
}

size_t FormatMenu::navCallback(size_t oldFocus, size_t proposedFocus, HUDNavChangeMethod changeMethod, void* obj)
{
  FormatMenu* fm = (FormatMenu*)obj;
  // sync the menu's selected page with the focus item.
  if (changeMethod == hnNext) {
    if (oldFocus + 1 != proposedFocus) {
      // we have wrapped
      fm->setPage(fm->page + 1);
    } else if (((HUDuiLabel*)(fm->getNav()[proposedFocus]))->getString() == "") {
      // there was an odd number of items on the last page, and
      // we have run off the end of the list...wrap early
      fm->setPage(0);
      proposedFocus = 0;
    }
  } else if (changeMethod == hnPrev) {
    if (oldFocus - 1 != proposedFocus) {
      // we have wrapped backwards
      fm->setPage(fm->page - 1);
      // find the last non-empty entry (i.e. if we wrapped from first to last page)
      while (((HUDuiLabel*)(fm->getNav()[proposedFocus]))->getString() == "")
	--proposedFocus;
    }
  }
  return proposedFocus;
}

FormatMenu::FormatMenu() : defaultKey(this), badFormats(NULL)
{
  int i;

  BzfDisplay* display = getDisplay();
  numFormats = display->getNumResolutions();
  badFormats = new bool[numFormats];
  for (i = 0; i < numFormats; i++)
    badFormats[i] = false;

  // add controls
  addLabel("Video Format", "");
  addLabel("", "");			// instructions
  addLabel("", "Current Format:");	// current format readout
  addLabel("", "");			// page readout
  currentLabel = (HUDuiLabel*)(getElements()[NumReadouts - 2]);
  pageLabel = (HUDuiLabel*)(getElements()[NumReadouts - 1]);

  // add resolution list items
  for (i = 0; i < NumItems; ++i)
    addLabel("", "", true);

  // fill in static labels
  if (numFormats < 2) {
    currentLabel->setString("<switching not available>");
    HUDui::setFocus(NULL);
  } else {
    HUDuiLabel* label = (HUDuiLabel*)(getElements()[NumReadouts - 3]);
    label->setString("Press Enter to select and T to test a format. Esc to exit.");
    initNavigation();
    getNav().setCallback(&navCallback, this);
  }
}

FormatMenu::~FormatMenu()
{
  delete[] badFormats;
}

void FormatMenu::addLabel(const char* msg, const char* _label, bool navigable)
{
  HUDuiLabel* label = new HUDuiLabel;
  label->setFontFace(MainMenu::getFontFace());
  label->setString(msg);
  label->setLabel(_label);
  addControl(label, navigable);
}

void FormatMenu::setPage(int _page)
{
  if (_page == page) // no change
    return;

  // switch pages
  page = _page;

  // wrap from last page to first
  if (page > (int)(numFormats / NumItems))
    page = 1;
  // wrap from first page back to last
  if (page < 0)
    page = (int)(numFormats / NumItems);

  // fill items
  const int base = page * NumItems;
  std::vector<HUDuiElement*>& listHUD = getElements();
  BzfDisplay* display = getDisplay();
  for (int i = 0; i < NumItems; ++i) {
    HUDuiLabel* label = (HUDuiLabel*)listHUD[i + NumReadouts];
    if (base + i < numFormats)
      if (badFormats[base + i])
        label->setString("<unloadable>");
      else
        label->setString(display->getResolution(base + i)->name);
    else
      label->setString("");
  }

  // change page label
  if (numFormats > NumItems) {
    char msg[50];
    std::vector<std::string> args;
    sprintf(msg, "%d", page + 1);
    args.push_back(msg);
    sprintf(msg, "%d", (numFormats + NumItems - 1) / NumItems);
    args.push_back(msg);
    pageLabel->setString("Page {1} of {2}", &args);
  }
}

void FormatMenu::show()
{
  pageLabel->setString("");
  int selectedIndex = getDisplay()->getResolution();
  // sync focus and selection
  int _page = (selectedIndex / NumItems);
  setPage(_page);
  getNav().set(selectedIndex - (_page * NumItems));
  // set current format
  BzfDisplay* display = getDisplay();
  currentLabel->setString(display->getResolution(display->getResolution())->name);
}

void FormatMenu::execute()
{
  setFormat(false);
}

void FormatMenu::setFormat(bool test)
{
  int selectedIndex = (page * NumItems) + (int)getNav().getIndex();
  if (selectedIndex >= numFormats || badFormats[selectedIndex])
    return;

  if (!setVideoFormat(selectedIndex, test)) {
    // can't load format
    badFormats[selectedIndex] = true;
  } else if (!test) {
    // print OpenGL renderer, which might have changed
    printError((const char*)glGetString(GL_RENDERER));
  }

  BzfDisplay* display = getDisplay();
  currentLabel->setString(display->getResolution(display->getResolution())->name);
}

void FormatMenu::resize(int _width, int _height)
{
  HUDDialog::resize(_width, _height);

  // use a big font for title, smaller font for the rest
  const float titleFontSize = (float)_height / 15.0f;
  FontManager &fm = FontManager::instance();
  int fontFace = MainMenu::getFontFace();

  // reposition title
  float x, y;
  std::vector<HUDuiElement*>& listHUD = getElements();
  {
    HUDuiLabel* title = (HUDuiLabel*)listHUD[0];
    title->setFontSize(titleFontSize);
    const float titleWidth = fm.getStrLength(fontFace, titleFontSize, title->getString());
    const float titleHeight = fm.getStrHeight(fontFace, titleFontSize, " ");
    x = 0.5f * ((float)_width - titleWidth);
    y = (float)_height - titleHeight;
    title->setPosition(x, y);
  }

  // reposition test and current format messages
  float fontSize = (float)_height / 54.0f;
  {
    HUDuiLabel* label = (HUDuiLabel*)listHUD[1];
    label->setFontSize(fontSize);
    const float stringWidth = fm.getStrLength(fontFace, fontSize, label->getString());
    x = 0.5f * ((float)_width - stringWidth);
    y -= 1.5f * fm.getStrHeight(fontFace, fontSize, " ");
    label->setPosition(x, y);
  }
  {
    HUDuiLabel* label = currentLabel;
    label->setFontSize(fontSize);
    y -= 1.0f * fm.getStrHeight(fontFace, fontSize, " ");
    label->setPosition(0.5f * (float)_width, y);
  }

  // position page readout
  fontSize = (float)_height / 54.0f;
  {
    HUDuiLabel* label = pageLabel;
    label->setFontSize(fontSize);
    const float stringWidth = fm.getStrLength(fontFace, fontSize, label->getString());
    x = 0.5f * ((float)_width - stringWidth);
    y -= 2.0f * fm.getStrHeight(fontFace, fontSize, " ");
    label->setPosition(x, y);
  }

  // position format item list
  const float yBase = y;
  int lastColumn = -1;
  for (int i = 0; i < NumItems; ++i) {
    const int column = i * NumColumns / NumItems;
    if (column != lastColumn) {
      lastColumn = column;
      x = (float)_width * ((0.5f + (float)column) / (float)(NumColumns + 1));
      y = yBase;
    }

    HUDuiLabel* label = (HUDuiLabel*)listHUD[i + NumReadouts];
    label->setFontSize(fontSize);
    y -= 1.0f * fm.getStrHeight(fontFace, fontSize, " ");
    label->setPosition(x, y);
  }
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>page 1 is the "top", so page up should take the page number DOWN (and vice versa)<commit_after>/* bzflag
 * Copyright (c) 1993 - 2007 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface header */
#include "FormatMenu.h"

/* common implementation headers */
#include "BzfDisplay.h"
#include "ErrorHandler.h"
#include "FontManager.h"

/* local implementation headers */
#include "MainMenu.h"
#include "playing.h"
#include "HUDui.h"
#include "HUDNavigationQueue.h"

const int		FormatMenu::NumReadouts = 4;
const int		FormatMenu::NumItems = 30;
const int		FormatMenu::NumColumns = 3;

bool FormatMenuDefaultKey::keyPress(const BzfKeyEvent& key)
{
  if (key.ascii == 0) switch (key.button) {
    case BzfKeyEvent::PageUp:
      if (HUDui::getFocus()) {
	menu->setPage(menu->page - 1);
      }
      return true;

    case BzfKeyEvent::PageDown:
      if (HUDui::getFocus()) {
	menu->setPage(menu->page + 1);
      }
      return true;

  } else if (key.ascii == 'T' || key.ascii == 't') {
    menu->setFormat(true);
    return true;
  }
  return MenuDefaultKey::keyPress(key);
}

bool FormatMenuDefaultKey::keyRelease(const BzfKeyEvent& key)
{
  switch (key.button) {
    case BzfKeyEvent::PageUp:
    case BzfKeyEvent::PageDown:
      return true;
  }
  switch (key.ascii) {
    case 27:	// escape
    case 13:	// return
    case 'T':
    case 't':
      return true;
  }
  return MenuDefaultKey::keyRelease(key);
}

size_t FormatMenu::navCallback(size_t oldFocus, size_t proposedFocus, HUDNavChangeMethod changeMethod, void* obj)
{
  FormatMenu* fm = (FormatMenu*)obj;
  // sync the menu's selected page with the focus item.
  if (changeMethod == hnNext) {
    if (oldFocus + 1 != proposedFocus) {
      // we have wrapped
      fm->setPage(fm->page + 1);
    } else if (((HUDuiLabel*)(fm->getNav()[proposedFocus]))->getString() == "") {
      // there was an odd number of items on the last page, and
      // we have run off the end of the list...wrap early
      fm->setPage(0);
      proposedFocus = 0;
    }
  } else if (changeMethod == hnPrev) {
    if (oldFocus - 1 != proposedFocus) {
      // we have wrapped backwards
      fm->setPage(fm->page - 1);
      // find the last non-empty entry (i.e. if we wrapped from first to last page)
      while (((HUDuiLabel*)(fm->getNav()[proposedFocus]))->getString() == "")
	--proposedFocus;
    }
  }
  return proposedFocus;
}

FormatMenu::FormatMenu() : defaultKey(this), badFormats(NULL)
{
  int i;

  BzfDisplay* display = getDisplay();
  numFormats = display->getNumResolutions();
  badFormats = new bool[numFormats];
  for (i = 0; i < numFormats; i++)
    badFormats[i] = false;

  // add controls
  addLabel("Video Format", "");
  addLabel("", "");			// instructions
  addLabel("", "Current Format:");	// current format readout
  addLabel("", "");			// page readout
  currentLabel = (HUDuiLabel*)(getElements()[NumReadouts - 2]);
  pageLabel = (HUDuiLabel*)(getElements()[NumReadouts - 1]);

  // add resolution list items
  for (i = 0; i < NumItems; ++i)
    addLabel("", "", true);

  // fill in static labels
  if (numFormats < 2) {
    currentLabel->setString("<switching not available>");
    HUDui::setFocus(NULL);
  } else {
    HUDuiLabel* label = (HUDuiLabel*)(getElements()[NumReadouts - 3]);
    label->setString("Press Enter to select and T to test a format. Esc to exit.");
    initNavigation();
    getNav().setCallback(&navCallback, this);
  }
}

FormatMenu::~FormatMenu()
{
  delete[] badFormats;
}

void FormatMenu::addLabel(const char* msg, const char* _label, bool navigable)
{
  HUDuiLabel* label = new HUDuiLabel;
  label->setFontFace(MainMenu::getFontFace());
  label->setString(msg);
  label->setLabel(_label);
  addControl(label, navigable);
}

void FormatMenu::setPage(int _page)
{
  if (_page == page) // no change
    return;

  // switch pages
  page = _page;

  // wrap from last page to first
  if (page > (int)(numFormats / NumItems))
    page = 1;
  // wrap from first page back to last
  if (page < 0)
    page = (int)(numFormats / NumItems);

  // fill items
  const int base = page * NumItems;
  std::vector<HUDuiElement*>& listHUD = getElements();
  BzfDisplay* display = getDisplay();
  for (int i = 0; i < NumItems; ++i) {
    HUDuiLabel* label = (HUDuiLabel*)listHUD[i + NumReadouts];
    if (base + i < numFormats)
      if (badFormats[base + i])
        label->setString("<unloadable>");
      else
        label->setString(display->getResolution(base + i)->name);
    else
      label->setString("");
  }

  // change page label
  if (numFormats > NumItems) {
    char msg[50];
    std::vector<std::string> args;
    sprintf(msg, "%d", page + 1);
    args.push_back(msg);
    sprintf(msg, "%d", (numFormats + NumItems - 1) / NumItems);
    args.push_back(msg);
    pageLabel->setString("Page {1} of {2}", &args);
  }
}

void FormatMenu::show()
{
  pageLabel->setString("");
  int selectedIndex = getDisplay()->getResolution();
  // sync focus and selection
  int _page = (selectedIndex / NumItems);
  setPage(_page);
  getNav().set(selectedIndex - (_page * NumItems));
  // set current format
  BzfDisplay* display = getDisplay();
  currentLabel->setString(display->getResolution(display->getResolution())->name);
}

void FormatMenu::execute()
{
  setFormat(false);
}

void FormatMenu::setFormat(bool test)
{
  int selectedIndex = (page * NumItems) + (int)getNav().getIndex();
  if (selectedIndex >= numFormats || badFormats[selectedIndex])
    return;

  if (!setVideoFormat(selectedIndex, test)) {
    // can't load format
    badFormats[selectedIndex] = true;
  } else if (!test) {
    // print OpenGL renderer, which might have changed
    printError((const char*)glGetString(GL_RENDERER));
  }

  BzfDisplay* display = getDisplay();
  currentLabel->setString(display->getResolution(display->getResolution())->name);
}

void FormatMenu::resize(int _width, int _height)
{
  HUDDialog::resize(_width, _height);

  // use a big font for title, smaller font for the rest
  const float titleFontSize = (float)_height / 15.0f;
  FontManager &fm = FontManager::instance();
  int fontFace = MainMenu::getFontFace();

  // reposition title
  float x, y;
  std::vector<HUDuiElement*>& listHUD = getElements();
  {
    HUDuiLabel* title = (HUDuiLabel*)listHUD[0];
    title->setFontSize(titleFontSize);
    const float titleWidth = fm.getStrLength(fontFace, titleFontSize, title->getString());
    const float titleHeight = fm.getStrHeight(fontFace, titleFontSize, " ");
    x = 0.5f * ((float)_width - titleWidth);
    y = (float)_height - titleHeight;
    title->setPosition(x, y);
  }

  // reposition test and current format messages
  float fontSize = (float)_height / 54.0f;
  {
    HUDuiLabel* label = (HUDuiLabel*)listHUD[1];
    label->setFontSize(fontSize);
    const float stringWidth = fm.getStrLength(fontFace, fontSize, label->getString());
    x = 0.5f * ((float)_width - stringWidth);
    y -= 1.5f * fm.getStrHeight(fontFace, fontSize, " ");
    label->setPosition(x, y);
  }
  {
    HUDuiLabel* label = currentLabel;
    label->setFontSize(fontSize);
    y -= 1.0f * fm.getStrHeight(fontFace, fontSize, " ");
    label->setPosition(0.5f * (float)_width, y);
  }

  // position page readout
  fontSize = (float)_height / 54.0f;
  {
    HUDuiLabel* label = pageLabel;
    label->setFontSize(fontSize);
    const float stringWidth = fm.getStrLength(fontFace, fontSize, label->getString());
    x = 0.5f * ((float)_width - stringWidth);
    y -= 2.0f * fm.getStrHeight(fontFace, fontSize, " ");
    label->setPosition(x, y);
  }

  // position format item list
  const float yBase = y;
  int lastColumn = -1;
  for (int i = 0; i < NumItems; ++i) {
    const int column = i * NumColumns / NumItems;
    if (column != lastColumn) {
      lastColumn = column;
      x = (float)_width * ((0.5f + (float)column) / (float)(NumColumns + 1));
      y = yBase;
    }

    HUDuiLabel* label = (HUDuiLabel*)listHUD[i + NumReadouts];
    label->setFontSize(fontSize);
    y -= 1.0f * fm.getStrHeight(fontFace, fontSize, " ");
    label->setPosition(x, y);
  }
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>/* The MIT License (MIT)
 *
 * Copyright (c) 2014-2018 David Medina and Tim Warburton
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 */

namespace occa {
  namespace linalg {
    template <class VTYPE_IN, class VTYPE_OUT>
    kernelBuilder makeAssignmentBuilder(const std::string &kernelName,
                                        const int tileSize) {
      return kernelBuilder::fromFile(env::OCCA_DIR + "include/occa/array/kernels/assignment.okl",
                                     kernelName,
                                     "defines: {"
                                     "  VTYPE_IN: '"  + primitiveinfo<VTYPE_IN>::name  + "',"
                                     "  VTYPE_OUT: '" + primitiveinfo<VTYPE_OUT>::name + "',"
                                     "  TILESIZE: '"  + toString(tileSize) + "',"
                                     "}");
    }

    template <class VTYPE_IN, class VTYPE_OUT>
    kernelBuilderVector makeAssignmentBuilders(const std::string &kernelName) {
      kernelBuilderVector builders;
      for (int i = 0; i < usedTileSizeCount; ++i) {
        builders.push_back(makeAssignmentBuilder<VTYPE_IN,VTYPE_OUT>(kernelName,
                                                                     usedTileSizes[i]));
      }
      return builders;
    }

    template <class VTYPE, class RETTYPE>
    kernelBuilder makeLinalgBuilder(const std::string &kernelName) {
      return kernelBuilder::fromFile(env::OCCA_DIR + "include/occa/array/kernels/linalg.okl",
                                     kernelName,
                                     "defines: {"
                                     "  VTYPE: '" + primitiveinfo<VTYPE>::name + "',"
                                     "  VTYPE2: '" + primitiveinfo<VTYPE>::name + "',"
                                     "  RETTYPE: '" + primitiveinfo<RETTYPE>::name + "',"
                                     "  CPU_DOT_OUTER: 1024,"
                                     "  GPU_DOT_OUTER: 1024,"
                                     "  GPU_DOT_INNER: 128,"
                                     "}");
    }

    template <class VTYPE1, class VTYPE2, class RETTYPE>
    kernelBuilder makeLinalgBuilder(const std::string &kernelName) {
      return kernelBuilder::fromFile(env::OCCA_DIR + "include/occa/array/kernels/linalg.okl",
                                     kernelName,
                                     "defines: {"
                                     "  VTYPE: '"   + primitiveinfo<VTYPE1>::name  + "',"
                                     "  VTYPE2: '"  + primitiveinfo<VTYPE2>::name  + "',"
                                     "  RETTYPE: '" + primitiveinfo<RETTYPE>::name + "',"
                                     "  CPU_DOT_OUTER: 1024,"
                                     "  GPU_DOT_OUTER: 1024,"
                                     "  GPU_DOT_INNER: 128,"
                                     "}");
    }

    //---[ Assignment ]-----------------
    template <class VTYPE_OUT>
    void operator_eq(occa::memory vec,
                     const VTYPE_OUT value,
                     const int tileSize) {
      static kernelBuilderVector builders =
        makeAssignmentBuilders<VTYPE_OUT,VTYPE_OUT>("eq_const");

      const int entries = vec.size() / sizeof(VTYPE_OUT);
      getTiledKernel(builders,
                     vec.getDevice(),
                     tileSize)(entries, value, vec);
    }

    template <class VTYPE_OUT>
    void operator_plus_eq(occa::memory vec,
                          const VTYPE_OUT value,
                          const int tileSize) {
      static kernelBuilderVector builders =
        makeAssignmentBuilders<VTYPE_OUT,VTYPE_OUT>("plus_eq_const");

      const int entries = vec.size() / sizeof(VTYPE_OUT);
      getTiledKernel(builders,
                     vec.getDevice(),
                     tileSize)(entries, value, vec);
    }

    template <class VTYPE_IN, class VTYPE_OUT>
    void operator_plus_eq(occa::memory in,
                          occa::memory out,
                          const int tileSize) {
      static kernelBuilderVector builders =
        makeAssignmentBuilders<VTYPE_IN,VTYPE_OUT>("plus_eq");

      const int entries = in.size() / sizeof(VTYPE_OUT);
      getTiledKernel(builders,
                     in.getDevice(),
                     tileSize)(entries, in, out);
    }

    template <class VTYPE_OUT>
    void operator_sub_eq(occa::memory vec,
                         const VTYPE_OUT value,
                         const int tileSize) {
      static kernelBuilderVector builders =
        makeAssignmentBuilders<VTYPE_OUT,VTYPE_OUT>("sub_eq_const");

      const int entries = vec.size() / sizeof(VTYPE_OUT);
      getTiledKernel(builders,
                     vec.getDevice(),
                     tileSize)(entries, value, vec);
    }

    template <class VTYPE_IN, class VTYPE_OUT>
    void operator_sub_eq(occa::memory in,
                         occa::memory out,
                         const int tileSize) {
      static kernelBuilderVector builders =
        makeAssignmentBuilders<VTYPE_IN,VTYPE_OUT>("sub_eq");

      const int entries = in.size() / sizeof(VTYPE_OUT);
      getTiledKernel(builders,
                     in.getDevice(),
                     tileSize)(entries, in, out);
    }

    template <class VTYPE_OUT>
    void operator_mult_eq(occa::memory vec,
                          const VTYPE_OUT value,
                          const int tileSize) {
      static kernelBuilderVector builders =
        makeAssignmentBuilders<VTYPE_OUT,VTYPE_OUT>("mult_eq_const");

      const int entries = vec.size() / sizeof(VTYPE_OUT);
      getTiledKernel(builders,
                     vec.getDevice(),
                     tileSize)(entries, value, vec);
    }

    template <class VTYPE_IN, class VTYPE_OUT>
    void operator_mult_eq(occa::memory in,
                          occa::memory out,
                          const int tileSize) {
      static kernelBuilderVector builders =
        makeAssignmentBuilders<VTYPE_IN,VTYPE_OUT>("mult_eq");

      const int entries = in.size() / sizeof(VTYPE_OUT);
      getTiledKernel(builders,
                     in.getDevice(),
                     tileSize)(entries, in, out);
    }

    template <class VTYPE_OUT>
    void operator_div_eq(occa::memory vec,
                         const VTYPE_OUT value,
                         const int tileSize) {
      static kernelBuilderVector builders =
        makeAssignmentBuilders<VTYPE_OUT,VTYPE_OUT>("div_eq_const");

      const int entries = vec.size() / sizeof(VTYPE_OUT);
      getTiledKernel(builders,
                     vec.getDevice(),
                     tileSize)(entries, value, vec);
    }

    template <class VTYPE_IN, class VTYPE_OUT>
    void operator_div_eq(occa::memory in,
                         occa::memory out,
                         const int tileSize) {
      static kernelBuilderVector builders =
        makeAssignmentBuilders<VTYPE_IN,VTYPE_OUT>("div_eq");

      const int entries = in.size() / sizeof(VTYPE_OUT);
      getTiledKernel(builders,
                     in.getDevice(),
                     tileSize)(entries, in, out);
    }
    //==================================

    //---[ Linear Algebra ]-------------
    template <class TM>
    TM *hostReductionBuffer(const int size) {
      return new TM[size];
    }

    template <class TM>
    occa::memory deviceReductionBuffer(occa::device device,
                                       const int size) {
      return device.malloc(size * sizeof(TM));
    }

    template <class VTYPE, class RETTYPE>
    RETTYPE* reduce(occa::memory vec,
                    occa::kernelBuilder &builder,
                    const int bufferSize) {

      device dev = vec.getDevice();
      RETTYPE *hostBuffer = hostReductionBuffer<RETTYPE>(bufferSize);
      memory deviceBuffer = deviceReductionBuffer<RETTYPE>(dev, bufferSize);
      const int entries = vec.size() / sizeof(VTYPE);
      builder.build(dev)(entries,
                         vec,
                         deviceBuffer);
      deviceBuffer.copyTo(hostBuffer);
      return hostBuffer;
    }

    template <class VTYPE, class RETTYPE>
    RETTYPE l1Norm(occa::memory vec) {
      static kernelBuilder builder =
        makeLinalgBuilder<VTYPE, RETTYPE>("l1Norm");

      RETTYPE *partialReduction = reduce<VTYPE,RETTYPE>(vec, builder, 1024);
      RETTYPE ret = 0;
      for (int i = 0; i < 1024; ++i) {
        ret += partialReduction[i];
      }
      delete partialReduction;
      return ret;
    }

    template <class VTYPE, class RETTYPE>
    RETTYPE l2Norm(occa::memory vec) {
      static kernelBuilder builder =
        makeLinalgBuilder<VTYPE, RETTYPE>("l2Norm");

      RETTYPE *partialReduction = reduce<VTYPE,RETTYPE>(vec, builder, 1024);
      RETTYPE ret = 0;
      for (int i = 0; i < 1024; ++i) {
        ret += partialReduction[i];
      }
      delete partialReduction;
      return sqrt(ret);
    }

    template <class VTYPE, class RETTYPE>
    RETTYPE lpNorm(const float p,
                   occa::memory vec) {
      static kernelBuilder builder =
        makeLinalgBuilder<VTYPE, RETTYPE>("lpNorm");

      device dev = vec.getDevice();
      const int bufferSize = 1024;
      RETTYPE *hostBuffer = hostReductionBuffer<RETTYPE>(bufferSize);
      memory deviceBuffer = deviceReductionBuffer<RETTYPE>(dev, bufferSize);
      const int entries = vec.size() / sizeof(VTYPE);
      builder.build(dev)(entries,
                         p,
                         vec,
                         deviceBuffer);
      dev.finish();
      deviceBuffer.copyTo(hostBuffer);
      RETTYPE ret = 0;
      for (int i = 0; i < 1024; ++i) {
        ret += hostBuffer[i];
      }
      delete hostBuffer;
      return pow(ret, 1.0/p);
    }

    template <class VTYPE, class RETTYPE>
    RETTYPE lInfNorm(occa::memory vec) {
      static kernelBuilder builder =
        makeLinalgBuilder<VTYPE, RETTYPE>("lInfNorm");

      RETTYPE *partialReduction = reduce<VTYPE,RETTYPE>(vec, builder, 1024);
      RETTYPE ret = partialReduction[0];
      for (int i = 1; i < 1024; ++i) {
        const RETTYPE abs_i = partialReduction[i];
        if (ret < abs_i) {
          ret = abs_i;
        }
      }
      delete partialReduction;
      return ret;
    }

    template <class VTYPE, class RETTYPE>
    RETTYPE max(occa::memory vec) {
      static kernelBuilder builder =
        makeLinalgBuilder<VTYPE, RETTYPE>("vecMax");

      RETTYPE *partialReduction = reduce<VTYPE,RETTYPE>(vec, builder, 1024);
      RETTYPE ret = partialReduction[0];
      for (int i = 1; i < 1024; ++i) {
        if (ret < partialReduction[i]) {
          ret = partialReduction[i];
        }
      }
      delete partialReduction;
      return ret;
    }

    template <class VTYPE, class RETTYPE>
    RETTYPE min(occa::memory vec) {
      static kernelBuilder builder =
        makeLinalgBuilder<VTYPE, RETTYPE>("vecMin");

      RETTYPE *partialReduction = reduce<VTYPE,RETTYPE>(vec, builder, 1024);
      RETTYPE ret = partialReduction[0];
      for (int i = 1; i < 1024; ++i) {
        if (ret > partialReduction[i]) {
          ret = partialReduction[i];
        }
      }
      delete partialReduction;
      return ret;
    }

    template <class VTYPE1, class VTYPE2, class RETTYPE>
    RETTYPE dot(occa::memory vec1, occa::memory vec2) {
      static kernelBuilder builder =
        makeLinalgBuilder<VTYPE1, VTYPE2, RETTYPE>("dot");

      OCCA_ERROR("Vectors must be in the same device",
                 vec1.getDevice() == vec2.getDevice());

      device dev = vec1.getDevice();
      const int bufferSize = 1024;
      RETTYPE *hostBuffer = hostReductionBuffer<RETTYPE>(bufferSize);
      memory deviceBuffer = deviceReductionBuffer<RETTYPE>(dev, bufferSize);
      const int entries = vec1.size() / sizeof(VTYPE1);
      builder.build(dev)(entries,
                         vec1,
                         vec2,
                         deviceBuffer);
      dev.finish();
      deviceBuffer.copyTo(hostBuffer);
      RETTYPE ret = 0;
      for (int i = 0; i < 1024; ++i) {
        ret += hostBuffer[i];
      }
      delete [] hostBuffer;
      return ret;
    }

    template <class VTYPE1, class VTYPE2, class RETTYPE>
    RETTYPE distance(occa::memory vec1, occa::memory vec2) {
      static kernelBuilder builder =
        makeLinalgBuilder<VTYPE1, VTYPE2, RETTYPE>("distance");

      OCCA_ERROR("Vectors must be in the same device",
                 vec1.getDevice() == vec2.getDevice());

      device dev = vec1.getDevice();
      const int bufferSize = 1024;
      RETTYPE *hostBuffer = hostReductionBuffer<RETTYPE>(bufferSize);
      memory deviceBuffer = deviceReductionBuffer<RETTYPE>(dev, bufferSize);
      const int entries = vec1.size() / sizeof(VTYPE1);
      builder.build(dev)(entries,
                         vec1,
                         vec2,
                         deviceBuffer);
      dev.finish();
      deviceBuffer.copyTo(hostBuffer);
      RETTYPE ret = 0;
      for (int i = 0; i < 1024; ++i) {
        ret += hostBuffer[i];
      }
      delete hostBuffer;
      return sqrt(ret);
    }

    template <class VTYPE, class RETTYPE>
    RETTYPE sum(occa::memory vec) {
      static kernelBuilder builder =
        makeLinalgBuilder<VTYPE, RETTYPE>("sum");

      RETTYPE *partialReduction = reduce<VTYPE,RETTYPE>(vec, builder, 1024);
      RETTYPE ret = 0;
      for (int i = 0; i < 1024; ++i) {
        ret += partialReduction[i];
      }
      delete partialReduction;
      return ret;
    }

    template <class TYPE_A, class VTYPE_X, class VTYPE_Y>
    void axpy(const TYPE_A &alpha,
              occa::memory x,
              occa::memory y,
              const int tileSize) {

      static kernelBuilderVector builders;
      if (!builders.size()) {
        for (int i = 0; i < usedTileSizeCount; ++i) {
          kernelBuilder kerb =
            customLinearMethod("axpy",
                               "v0[i] += c0 * v1[i];",
                               "defines: {"
                               "  CTYPE0: '" + primitiveinfo<TYPE_A>::name + "',"
                               "  VTYPE0: '" + primitiveinfo<VTYPE_Y>::name + "',"
                               "  VTYPE1: '" + primitiveinfo<VTYPE_X>::name + "',"
                               "  TILESIZE: '" + toString(usedTileSizes[i]) + "',"
                               "}");
          builders.push_back(kerb);
        }
      }

      const int entries = y.size() / sizeof(VTYPE_Y);
      getTiledKernel(builders,
                     y.getDevice(),
                     tileSize)(entries, alpha, y, x);
    }
    //==================================
  }
}
<commit_msg>[Array] Fixed more mismatched new/deletes<commit_after>/* The MIT License (MIT)
 *
 * Copyright (c) 2014-2018 David Medina and Tim Warburton
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 */

namespace occa {
  namespace linalg {
    template <class VTYPE_IN, class VTYPE_OUT>
    kernelBuilder makeAssignmentBuilder(const std::string &kernelName,
                                        const int tileSize) {
      return kernelBuilder::fromFile(env::OCCA_DIR + "include/occa/array/kernels/assignment.okl",
                                     kernelName,
                                     "defines: {"
                                     "  VTYPE_IN: '"  + primitiveinfo<VTYPE_IN>::name  + "',"
                                     "  VTYPE_OUT: '" + primitiveinfo<VTYPE_OUT>::name + "',"
                                     "  TILESIZE: '"  + toString(tileSize) + "',"
                                     "}");
    }

    template <class VTYPE_IN, class VTYPE_OUT>
    kernelBuilderVector makeAssignmentBuilders(const std::string &kernelName) {
      kernelBuilderVector builders;
      for (int i = 0; i < usedTileSizeCount; ++i) {
        builders.push_back(makeAssignmentBuilder<VTYPE_IN,VTYPE_OUT>(kernelName,
                                                                     usedTileSizes[i]));
      }
      return builders;
    }

    template <class VTYPE, class RETTYPE>
    kernelBuilder makeLinalgBuilder(const std::string &kernelName) {
      return kernelBuilder::fromFile(env::OCCA_DIR + "include/occa/array/kernels/linalg.okl",
                                     kernelName,
                                     "defines: {"
                                     "  VTYPE: '" + primitiveinfo<VTYPE>::name + "',"
                                     "  VTYPE2: '" + primitiveinfo<VTYPE>::name + "',"
                                     "  RETTYPE: '" + primitiveinfo<RETTYPE>::name + "',"
                                     "  CPU_DOT_OUTER: 1024,"
                                     "  GPU_DOT_OUTER: 1024,"
                                     "  GPU_DOT_INNER: 128,"
                                     "}");
    }

    template <class VTYPE1, class VTYPE2, class RETTYPE>
    kernelBuilder makeLinalgBuilder(const std::string &kernelName) {
      return kernelBuilder::fromFile(env::OCCA_DIR + "include/occa/array/kernels/linalg.okl",
                                     kernelName,
                                     "defines: {"
                                     "  VTYPE: '"   + primitiveinfo<VTYPE1>::name  + "',"
                                     "  VTYPE2: '"  + primitiveinfo<VTYPE2>::name  + "',"
                                     "  RETTYPE: '" + primitiveinfo<RETTYPE>::name + "',"
                                     "  CPU_DOT_OUTER: 1024,"
                                     "  GPU_DOT_OUTER: 1024,"
                                     "  GPU_DOT_INNER: 128,"
                                     "}");
    }

    //---[ Assignment ]-----------------
    template <class VTYPE_OUT>
    void operator_eq(occa::memory vec,
                     const VTYPE_OUT value,
                     const int tileSize) {
      static kernelBuilderVector builders =
        makeAssignmentBuilders<VTYPE_OUT,VTYPE_OUT>("eq_const");

      const int entries = vec.size() / sizeof(VTYPE_OUT);
      getTiledKernel(builders,
                     vec.getDevice(),
                     tileSize)(entries, value, vec);
    }

    template <class VTYPE_OUT>
    void operator_plus_eq(occa::memory vec,
                          const VTYPE_OUT value,
                          const int tileSize) {
      static kernelBuilderVector builders =
        makeAssignmentBuilders<VTYPE_OUT,VTYPE_OUT>("plus_eq_const");

      const int entries = vec.size() / sizeof(VTYPE_OUT);
      getTiledKernel(builders,
                     vec.getDevice(),
                     tileSize)(entries, value, vec);
    }

    template <class VTYPE_IN, class VTYPE_OUT>
    void operator_plus_eq(occa::memory in,
                          occa::memory out,
                          const int tileSize) {
      static kernelBuilderVector builders =
        makeAssignmentBuilders<VTYPE_IN,VTYPE_OUT>("plus_eq");

      const int entries = in.size() / sizeof(VTYPE_OUT);
      getTiledKernel(builders,
                     in.getDevice(),
                     tileSize)(entries, in, out);
    }

    template <class VTYPE_OUT>
    void operator_sub_eq(occa::memory vec,
                         const VTYPE_OUT value,
                         const int tileSize) {
      static kernelBuilderVector builders =
        makeAssignmentBuilders<VTYPE_OUT,VTYPE_OUT>("sub_eq_const");

      const int entries = vec.size() / sizeof(VTYPE_OUT);
      getTiledKernel(builders,
                     vec.getDevice(),
                     tileSize)(entries, value, vec);
    }

    template <class VTYPE_IN, class VTYPE_OUT>
    void operator_sub_eq(occa::memory in,
                         occa::memory out,
                         const int tileSize) {
      static kernelBuilderVector builders =
        makeAssignmentBuilders<VTYPE_IN,VTYPE_OUT>("sub_eq");

      const int entries = in.size() / sizeof(VTYPE_OUT);
      getTiledKernel(builders,
                     in.getDevice(),
                     tileSize)(entries, in, out);
    }

    template <class VTYPE_OUT>
    void operator_mult_eq(occa::memory vec,
                          const VTYPE_OUT value,
                          const int tileSize) {
      static kernelBuilderVector builders =
        makeAssignmentBuilders<VTYPE_OUT,VTYPE_OUT>("mult_eq_const");

      const int entries = vec.size() / sizeof(VTYPE_OUT);
      getTiledKernel(builders,
                     vec.getDevice(),
                     tileSize)(entries, value, vec);
    }

    template <class VTYPE_IN, class VTYPE_OUT>
    void operator_mult_eq(occa::memory in,
                          occa::memory out,
                          const int tileSize) {
      static kernelBuilderVector builders =
        makeAssignmentBuilders<VTYPE_IN,VTYPE_OUT>("mult_eq");

      const int entries = in.size() / sizeof(VTYPE_OUT);
      getTiledKernel(builders,
                     in.getDevice(),
                     tileSize)(entries, in, out);
    }

    template <class VTYPE_OUT>
    void operator_div_eq(occa::memory vec,
                         const VTYPE_OUT value,
                         const int tileSize) {
      static kernelBuilderVector builders =
        makeAssignmentBuilders<VTYPE_OUT,VTYPE_OUT>("div_eq_const");

      const int entries = vec.size() / sizeof(VTYPE_OUT);
      getTiledKernel(builders,
                     vec.getDevice(),
                     tileSize)(entries, value, vec);
    }

    template <class VTYPE_IN, class VTYPE_OUT>
    void operator_div_eq(occa::memory in,
                         occa::memory out,
                         const int tileSize) {
      static kernelBuilderVector builders =
        makeAssignmentBuilders<VTYPE_IN,VTYPE_OUT>("div_eq");

      const int entries = in.size() / sizeof(VTYPE_OUT);
      getTiledKernel(builders,
                     in.getDevice(),
                     tileSize)(entries, in, out);
    }
    //==================================

    //---[ Linear Algebra ]-------------
    template <class TM>
    TM *hostReductionBuffer(const int size) {
      return new TM[size];
    }

    template <class TM>
    occa::memory deviceReductionBuffer(occa::device device,
                                       const int size) {
      return device.malloc(size * sizeof(TM));
    }

    template <class VTYPE, class RETTYPE>
    RETTYPE* reduce(occa::memory vec,
                    occa::kernelBuilder &builder,
                    const int bufferSize) {

      device dev = vec.getDevice();
      RETTYPE *hostBuffer = hostReductionBuffer<RETTYPE>(bufferSize);
      memory deviceBuffer = deviceReductionBuffer<RETTYPE>(dev, bufferSize);
      const int entries = vec.size() / sizeof(VTYPE);
      builder.build(dev)(entries,
                         vec,
                         deviceBuffer);
      deviceBuffer.copyTo(hostBuffer);
      return hostBuffer;
    }

    template <class VTYPE, class RETTYPE>
    RETTYPE l1Norm(occa::memory vec) {
      static kernelBuilder builder =
        makeLinalgBuilder<VTYPE, RETTYPE>("l1Norm");

      RETTYPE *partialReduction = reduce<VTYPE,RETTYPE>(vec, builder, 1024);
      RETTYPE ret = 0;
      for (int i = 0; i < 1024; ++i) {
        ret += partialReduction[i];
      }
      delete [] partialReduction;
      return ret;
    }

    template <class VTYPE, class RETTYPE>
    RETTYPE l2Norm(occa::memory vec) {
      static kernelBuilder builder =
        makeLinalgBuilder<VTYPE, RETTYPE>("l2Norm");

      RETTYPE *partialReduction = reduce<VTYPE,RETTYPE>(vec, builder, 1024);
      RETTYPE ret = 0;
      for (int i = 0; i < 1024; ++i) {
        ret += partialReduction[i];
      }
      delete [] partialReduction;
      return sqrt(ret);
    }

    template <class VTYPE, class RETTYPE>
    RETTYPE lpNorm(const float p,
                   occa::memory vec) {
      static kernelBuilder builder =
        makeLinalgBuilder<VTYPE, RETTYPE>("lpNorm");

      device dev = vec.getDevice();
      const int bufferSize = 1024;
      RETTYPE *hostBuffer = hostReductionBuffer<RETTYPE>(bufferSize);
      memory deviceBuffer = deviceReductionBuffer<RETTYPE>(dev, bufferSize);
      const int entries = vec.size() / sizeof(VTYPE);
      builder.build(dev)(entries,
                         p,
                         vec,
                         deviceBuffer);
      dev.finish();
      deviceBuffer.copyTo(hostBuffer);
      RETTYPE ret = 0;
      for (int i = 0; i < 1024; ++i) {
        ret += hostBuffer[i];
      }
      delete [] hostBuffer;
      return pow(ret, 1.0/p);
    }

    template <class VTYPE, class RETTYPE>
    RETTYPE lInfNorm(occa::memory vec) {
      static kernelBuilder builder =
        makeLinalgBuilder<VTYPE, RETTYPE>("lInfNorm");

      RETTYPE *partialReduction = reduce<VTYPE,RETTYPE>(vec, builder, 1024);
      RETTYPE ret = partialReduction[0];
      for (int i = 1; i < 1024; ++i) {
        const RETTYPE abs_i = partialReduction[i];
        if (ret < abs_i) {
          ret = abs_i;
        }
      }
      delete [] partialReduction;
      return ret;
    }

    template <class VTYPE, class RETTYPE>
    RETTYPE max(occa::memory vec) {
      static kernelBuilder builder =
        makeLinalgBuilder<VTYPE, RETTYPE>("vecMax");

      RETTYPE *partialReduction = reduce<VTYPE,RETTYPE>(vec, builder, 1024);
      RETTYPE ret = partialReduction[0];
      for (int i = 1; i < 1024; ++i) {
        if (ret < partialReduction[i]) {
          ret = partialReduction[i];
        }
      }
      delete [] partialReduction;
      return ret;
    }

    template <class VTYPE, class RETTYPE>
    RETTYPE min(occa::memory vec) {
      static kernelBuilder builder =
        makeLinalgBuilder<VTYPE, RETTYPE>("vecMin");

      RETTYPE *partialReduction = reduce<VTYPE,RETTYPE>(vec, builder, 1024);
      RETTYPE ret = partialReduction[0];
      for (int i = 1; i < 1024; ++i) {
        if (ret > partialReduction[i]) {
          ret = partialReduction[i];
        }
      }
      delete [] partialReduction;
      return ret;
    }

    template <class VTYPE1, class VTYPE2, class RETTYPE>
    RETTYPE dot(occa::memory vec1, occa::memory vec2) {
      static kernelBuilder builder =
        makeLinalgBuilder<VTYPE1, VTYPE2, RETTYPE>("dot");

      OCCA_ERROR("Vectors must be in the same device",
                 vec1.getDevice() == vec2.getDevice());

      device dev = vec1.getDevice();
      const int bufferSize = 1024;
      RETTYPE *hostBuffer = hostReductionBuffer<RETTYPE>(bufferSize);
      memory deviceBuffer = deviceReductionBuffer<RETTYPE>(dev, bufferSize);
      const int entries = vec1.size() / sizeof(VTYPE1);
      builder.build(dev)(entries,
                         vec1,
                         vec2,
                         deviceBuffer);
      dev.finish();
      deviceBuffer.copyTo(hostBuffer);
      RETTYPE ret = 0;
      for (int i = 0; i < 1024; ++i) {
        ret += hostBuffer[i];
      }
      delete [] hostBuffer;
      return ret;
    }

    template <class VTYPE1, class VTYPE2, class RETTYPE>
    RETTYPE distance(occa::memory vec1, occa::memory vec2) {
      static kernelBuilder builder =
        makeLinalgBuilder<VTYPE1, VTYPE2, RETTYPE>("distance");

      OCCA_ERROR("Vectors must be in the same device",
                 vec1.getDevice() == vec2.getDevice());

      device dev = vec1.getDevice();
      const int bufferSize = 1024;
      RETTYPE *hostBuffer = hostReductionBuffer<RETTYPE>(bufferSize);
      memory deviceBuffer = deviceReductionBuffer<RETTYPE>(dev, bufferSize);
      const int entries = vec1.size() / sizeof(VTYPE1);
      builder.build(dev)(entries,
                         vec1,
                         vec2,
                         deviceBuffer);
      dev.finish();
      deviceBuffer.copyTo(hostBuffer);
      RETTYPE ret = 0;
      for (int i = 0; i < 1024; ++i) {
        ret += hostBuffer[i];
      }
      delete [] hostBuffer;
      return sqrt(ret);
    }

    template <class VTYPE, class RETTYPE>
    RETTYPE sum(occa::memory vec) {
      static kernelBuilder builder =
        makeLinalgBuilder<VTYPE, RETTYPE>("sum");

      RETTYPE *partialReduction = reduce<VTYPE,RETTYPE>(vec, builder, 1024);
      RETTYPE ret = 0;
      for (int i = 0; i < 1024; ++i) {
        ret += partialReduction[i];
      }
      delete [] partialReduction;
      return ret;
    }

    template <class TYPE_A, class VTYPE_X, class VTYPE_Y>
    void axpy(const TYPE_A &alpha,
              occa::memory x,
              occa::memory y,
              const int tileSize) {

      static kernelBuilderVector builders;
      if (!builders.size()) {
        for (int i = 0; i < usedTileSizeCount; ++i) {
          kernelBuilder kerb =
            customLinearMethod("axpy",
                               "v0[i] += c0 * v1[i];",
                               "defines: {"
                               "  CTYPE0: '" + primitiveinfo<TYPE_A>::name + "',"
                               "  VTYPE0: '" + primitiveinfo<VTYPE_Y>::name + "',"
                               "  VTYPE1: '" + primitiveinfo<VTYPE_X>::name + "',"
                               "  TILESIZE: '" + toString(usedTileSizes[i]) + "',"
                               "}");
          builders.push_back(kerb);
        }
      }

      const int entries = y.size() / sizeof(VTYPE_Y);
      getTiledKernel(builders,
                     y.getDevice(),
                     tileSize)(entries, alpha, y, x);
    }
    //==================================
  }
}
<|endoftext|>


<commit_before>//---------------------------------------------------------
// Copyright 2015 Ontario Institute for Cancer Research
// Written by Jared Simpson (jared.simpson@oicr.on.ca)
//---------------------------------------------------------
//
// nanopolish_call_variants -- find variants wrt a reference
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <vector>
#include <inttypes.h>
#include <assert.h>
#include <math.h>
#include <sys/time.h>
#include <algorithm>
#include <queue>
#include <sstream>
#include <set>
#include <omp.h>
#include <getopt.h>
#include "htslib/faidx.h"
#include "nanopolish_poremodel.h"
#include "nanopolish_khmm_parameters.h"
#include "nanopolish_matrix.h"
#include "nanopolish_klcs.h"
#include "nanopolish_profile_hmm.h"
#include "nanopolish_alignment_db.h"
#include "nanopolish_anchor.h"
#include "nanopolish_fast5_map.h"
#include "nanopolish_variant.h"
#include "nanopolish_haplotype.h"
#include "profiler.h"
#include "progress.h"
#include "stdaln.h"

// Macros
#define max3(x,y,z) std::max(std::max(x,y), z)

// Flags to turn on/off debugging information

//#define DEBUG_HMM_UPDATE 1
//#define DEBUG_HMM_EMISSION 1
//#define DEBUG_TRANSITION 1
//#define DEBUG_PATH_SELECTION 1
//#define DEBUG_SINGLE_SEGMENT 1
//#define DEBUG_SHOW_TOP_TWO 1
//#define DEBUG_SEGMENT_ID 193
//#define DEBUG_BENCHMARK 1

//
// Getopt
//
#define SUBPROGRAM "consensus"

static const char *CONSENSUS_VERSION_MESSAGE =
SUBPROGRAM " Version " PACKAGE_VERSION "\n"
"Written by Jared Simpson.\n"
"\n"
"Copyright 2015 Ontario Institute for Cancer Research\n";

static const char *CONSENSUS_USAGE_MESSAGE =
"Usage: " PACKAGE_NAME " " SUBPROGRAM " [OPTIONS] --reads reads.fa --bam alignments.bam --genome genome.fa\n"
"Compute a new consensus sequence for an assembly using a signal-level HMM\n"
"\n"
"  -v, --verbose                        display verbose output\n"
"      --version                        display version\n"
"      --help                           display this help and exit\n"
"      --snps                           only call SNPs\n"
"  -w, --window=STR                     compute the consensus for window STR (format: ctg:start_id-end_id)\n"
"  -r, --reads=FILE                     the 2D ONT reads are in fasta FILE\n"
"  -b, --bam=FILE                       the reads aligned to the genome assembly are in bam FILE\n"
"  -e, --event-bam=FILE                 the events aligned to the genome assembly are in bam FILE\n"
"  -g, --genome=FILE                    the genome we are computing a consensus for is in FILE\n"
"  -o, --outfile=FILE                   write result to FILE [default: stdout]\n"
"  -t, --threads=NUM                    use NUM threads (default: 1)\n"
"\nReport bugs to " PACKAGE_BUGREPORT "\n\n";

namespace opt
{
    static unsigned int verbose;
    static std::string reads_file;
    static std::string bam_file;
    static std::string event_bam_file;
    static std::string genome_file;
    static std::string output_file;
    static std::string window;
    static int snps_only = 0;
    static int show_progress = 0;
    static int num_threads = 1;
}

static const char* shortopts = "r:b:g:t:w:o:e:m:v";

enum { OPT_HELP = 1, OPT_VERSION, OPT_VCF, OPT_PROGRESS, OPT_SNPS_ONLY };

static const struct option longopts[] = {
    { "verbose",           no_argument,       NULL, 'v' },
    { "reads",             required_argument, NULL, 'r' },
    { "bam",               required_argument, NULL, 'b' },
    { "event-bam",         required_argument, NULL, 'e' },
    { "genome",            required_argument, NULL, 'g' },
    { "window",            required_argument, NULL, 'w' },
    { "outfile",           required_argument, NULL, 'o' },
    { "threads",           required_argument, NULL, 't' },
    { "min-read-evidence", required_argument, NULL, 'm' },
    { "snps",              no_argument,       NULL, OPT_SNPS_ONLY },
    { "progress",          no_argument,       NULL, OPT_PROGRESS },
    { "help",              no_argument,       NULL, OPT_HELP },
    { "version",           no_argument,       NULL, OPT_VERSION },
    { NULL, 0, NULL, 0 }
};

int get_contig_length(const std::string& contig)
{
    faidx_t *fai = fai_load(opt::genome_file.c_str());
    int len = faidx_seq_len(fai, contig.c_str());
    fai_destroy(fai);
    return len;
}

double parallel_score(const std::string& sequence, const std::vector<HMMInputData>& event_sequences)
{
    double score = 0.0f;

    #pragma omp parallel for
    for(size_t i = 0; i < event_sequences.size(); ++i) {
        double s = profile_hmm_score(sequence, event_sequences[i]);

        #pragma omp critical
        score += s;
    }
    return score;
}

Haplotype call_variants_for_region(const std::string& contig, int region_start, int region_end)
{
    const int BUFFER = 20;

    if(region_start < BUFFER)
        region_start = BUFFER;

    // load the region, accounting for the buffering
    AlignmentDB alignments(opt::reads_file, opt::genome_file, opt::bam_file, opt::event_bam_file);
    alignments.load_region(contig, region_start - BUFFER, region_end + BUFFER);
    Haplotype derived_haplotype(contig,
                                alignments.get_region_start(),
                                alignments.get_reference());

    // Step 1. Discover putative variants across the whole region
    std::vector<Variant> candidate_variants = alignments.get_variants_in_region(contig, region_start, region_end, 0.2, 20);

    // Step 2. Add variants to the haplotypes
    size_t calling_span = 15;
    size_t curr_variant_idx = 0;
    while(curr_variant_idx < candidate_variants.size()) {

        // Group the variants that are within calling_span bases of each other
        size_t end_variant_idx = curr_variant_idx;
        while(end_variant_idx < candidate_variants.size()) {
            int distance = candidate_variants[end_variant_idx].ref_position -
                           candidate_variants[curr_variant_idx].ref_position;
            if(distance > calling_span)
                break;
            end_variant_idx++;
        }

        size_t num_variants = end_variant_idx - curr_variant_idx;
        int calling_start = candidate_variants[curr_variant_idx].ref_position - calling_span;
        int calling_end = candidate_variants[end_variant_idx - 1].ref_position +
                          candidate_variants[end_variant_idx - 1].ref_seq.length() +
                          calling_span;
        int calling_size = calling_end - calling_start;

        if(opt::verbose > 2) {
            fprintf(stderr, "%zu variants in span [%d %d]\n", num_variants, calling_start, calling_end);
        }

        // Only try to call variants if there is a reasonable amount and the window is not too large
        if(num_variants <= 10 && calling_size <= 100) {

            // Subset the haplotype to the region we are calling
            Haplotype calling_haplotype =
                derived_haplotype.substr_by_reference(calling_start, calling_end);

            // Get the events for the calling region
            std::vector<HMMInputData> event_sequences =
                alignments.get_event_subsequences(contig, calling_start, calling_end);

            // Subset the variants
            std::vector<Variant> calling_variants(candidate_variants.begin() + curr_variant_idx,
                                                  candidate_variants.begin() + end_variant_idx);

            // Select the best set of variants
            std::vector<Variant> selected_variants =
                select_variant_set(calling_variants, calling_haplotype, event_sequences);

            // Apply them to the final haplotype
            for(size_t vi = 0; vi < selected_variants.size(); vi++) {
                derived_haplotype.apply_variant(selected_variants[vi]);

                if(opt::verbose > 1) {
                    selected_variants[vi].write_vcf(stderr);
                }
            }
        }

        // advance to start of next region
        curr_variant_idx = end_variant_idx;
    }

    return derived_haplotype;
}

void parse_call_variants_options(int argc, char** argv)
{
    bool die = false;
    for (char c; (c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1;) {
        std::istringstream arg(optarg != NULL ? optarg : "");
        switch (c) {
            case 'r': arg >> opt::reads_file; break;
            case 'g': arg >> opt::genome_file; break;
            case 'b': arg >> opt::bam_file; break;
            case 'e': arg >> opt::event_bam_file; break;
            case 'w': arg >> opt::window; break;
            case 'o': arg >> opt::output_file; break;
            case '?': die = true; break;
            case 't': arg >> opt::num_threads; break;
            case 'v': opt::verbose++; break;
            case OPT_SNPS_ONLY: opt::snps_only = 1; break;
            case OPT_PROGRESS: opt::show_progress = 1; break;
            case OPT_HELP:
                std::cout << CONSENSUS_USAGE_MESSAGE;
                exit(EXIT_SUCCESS);
            case OPT_VERSION:
                std::cout << CONSENSUS_VERSION_MESSAGE;
                exit(EXIT_SUCCESS);
        }
    }

    if (argc - optind < 0) {
        std::cerr << SUBPROGRAM ": missing arguments\n";
        die = true;
    } else if (argc - optind > 0) {
        std::cerr << SUBPROGRAM ": too many arguments\n";
        die = true;
    }

    if(opt::num_threads <= 0) {
        std::cerr << SUBPROGRAM ": invalid number of threads: " << opt::num_threads << "\n";
        die = true;
    }

    if(opt::reads_file.empty()) {
        std::cerr << SUBPROGRAM ": a --reads file must be provided\n";
        die = true;
    }

    if(opt::genome_file.empty()) {
        std::cerr << SUBPROGRAM ": a --genome file must be provided\n";
        die = true;
    }

    if(opt::bam_file.empty()) {
        std::cerr << SUBPROGRAM ": a --bam file must be provided\n";
        die = true;
    }

    if (die)
    {
        std::cout << "\n" << CONSENSUS_USAGE_MESSAGE;
        exit(EXIT_FAILURE);
    }
}

int call_variants_main(int argc, char** argv)
{
    parse_call_variants_options(argc, argv);
    omp_set_num_threads(opt::num_threads);

    // Parse the window string
    // Replace ":" and "-" with spaces to make it parseable with stringstream
    std::replace(opt::window.begin(), opt::window.end(), ':', ' ');
    std::replace(opt::window.begin(), opt::window.end(), '-', ' ');

    std::stringstream parser(opt::window);
    std::string contig;
    int start_base;
    int end_base;

    parser >> contig >> start_base >> end_base;
    end_base = std::min(end_base, get_contig_length(contig) - 1);

    FILE* out_fp;
    if(!opt::output_file.empty()) {
        out_fp = fopen(opt::output_file.c_str(), "w");
    } else {
        out_fp = stdout;
    }

    Variant::write_vcf_header(out_fp);

    fprintf(stderr, "TODO: train model\n");
    fprintf(stderr, "TODO: filter data\n");

    Haplotype haplotype = call_variants_for_region(contig, start_base, end_base);

    std::vector<Variant> variants = haplotype.get_variants();
    for(size_t vi = 0; vi < variants.size(); vi++) {
        variants[vi].write_vcf(out_fp);
    }

    if(out_fp != stdout) {
        fclose(out_fp);
    }
}
<commit_msg>fix variant clustering<commit_after>//---------------------------------------------------------
// Copyright 2015 Ontario Institute for Cancer Research
// Written by Jared Simpson (jared.simpson@oicr.on.ca)
//---------------------------------------------------------
//
// nanopolish_call_variants -- find variants wrt a reference
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <vector>
#include <inttypes.h>
#include <assert.h>
#include <math.h>
#include <sys/time.h>
#include <algorithm>
#include <queue>
#include <sstream>
#include <set>
#include <omp.h>
#include <getopt.h>
#include "htslib/faidx.h"
#include "nanopolish_poremodel.h"
#include "nanopolish_khmm_parameters.h"
#include "nanopolish_matrix.h"
#include "nanopolish_klcs.h"
#include "nanopolish_profile_hmm.h"
#include "nanopolish_alignment_db.h"
#include "nanopolish_anchor.h"
#include "nanopolish_fast5_map.h"
#include "nanopolish_variant.h"
#include "nanopolish_haplotype.h"
#include "profiler.h"
#include "progress.h"
#include "stdaln.h"

// Macros
#define max3(x,y,z) std::max(std::max(x,y), z)

// Flags to turn on/off debugging information

//#define DEBUG_HMM_UPDATE 1
//#define DEBUG_HMM_EMISSION 1
//#define DEBUG_TRANSITION 1
//#define DEBUG_PATH_SELECTION 1
//#define DEBUG_SINGLE_SEGMENT 1
//#define DEBUG_SHOW_TOP_TWO 1
//#define DEBUG_SEGMENT_ID 193
//#define DEBUG_BENCHMARK 1

//
// Getopt
//
#define SUBPROGRAM "consensus"

static const char *CONSENSUS_VERSION_MESSAGE =
SUBPROGRAM " Version " PACKAGE_VERSION "\n"
"Written by Jared Simpson.\n"
"\n"
"Copyright 2015 Ontario Institute for Cancer Research\n";

static const char *CONSENSUS_USAGE_MESSAGE =
"Usage: " PACKAGE_NAME " " SUBPROGRAM " [OPTIONS] --reads reads.fa --bam alignments.bam --genome genome.fa\n"
"Compute a new consensus sequence for an assembly using a signal-level HMM\n"
"\n"
"  -v, --verbose                        display verbose output\n"
"      --version                        display version\n"
"      --help                           display this help and exit\n"
"      --snps                           only call SNPs\n"
"  -w, --window=STR                     compute the consensus for window STR (format: ctg:start_id-end_id)\n"
"  -r, --reads=FILE                     the 2D ONT reads are in fasta FILE\n"
"  -b, --bam=FILE                       the reads aligned to the genome assembly are in bam FILE\n"
"  -e, --event-bam=FILE                 the events aligned to the genome assembly are in bam FILE\n"
"  -g, --genome=FILE                    the genome we are computing a consensus for is in FILE\n"
"  -o, --outfile=FILE                   write result to FILE [default: stdout]\n"
"  -t, --threads=NUM                    use NUM threads (default: 1)\n"
"\nReport bugs to " PACKAGE_BUGREPORT "\n\n";

namespace opt
{
    static unsigned int verbose;
    static std::string reads_file;
    static std::string bam_file;
    static std::string event_bam_file;
    static std::string genome_file;
    static std::string output_file;
    static std::string window;
    static int snps_only = 0;
    static int show_progress = 0;
    static int num_threads = 1;
}

static const char* shortopts = "r:b:g:t:w:o:e:m:v";

enum { OPT_HELP = 1, OPT_VERSION, OPT_VCF, OPT_PROGRESS, OPT_SNPS_ONLY };

static const struct option longopts[] = {
    { "verbose",           no_argument,       NULL, 'v' },
    { "reads",             required_argument, NULL, 'r' },
    { "bam",               required_argument, NULL, 'b' },
    { "event-bam",         required_argument, NULL, 'e' },
    { "genome",            required_argument, NULL, 'g' },
    { "window",            required_argument, NULL, 'w' },
    { "outfile",           required_argument, NULL, 'o' },
    { "threads",           required_argument, NULL, 't' },
    { "min-read-evidence", required_argument, NULL, 'm' },
    { "snps",              no_argument,       NULL, OPT_SNPS_ONLY },
    { "progress",          no_argument,       NULL, OPT_PROGRESS },
    { "help",              no_argument,       NULL, OPT_HELP },
    { "version",           no_argument,       NULL, OPT_VERSION },
    { NULL, 0, NULL, 0 }
};

int get_contig_length(const std::string& contig)
{
    faidx_t *fai = fai_load(opt::genome_file.c_str());
    int len = faidx_seq_len(fai, contig.c_str());
    fai_destroy(fai);
    return len;
}

double parallel_score(const std::string& sequence, const std::vector<HMMInputData>& event_sequences)
{
    double score = 0.0f;

    #pragma omp parallel for
    for(size_t i = 0; i < event_sequences.size(); ++i) {
        double s = profile_hmm_score(sequence, event_sequences[i]);

        #pragma omp critical
        score += s;
    }
    return score;
}

Haplotype call_variants_for_region(const std::string& contig, int region_start, int region_end)
{
    const int BUFFER = 20;

    if(region_start < BUFFER)
        region_start = BUFFER;

    // load the region, accounting for the buffering
    AlignmentDB alignments(opt::reads_file, opt::genome_file, opt::bam_file, opt::event_bam_file);
    alignments.load_region(contig, region_start - BUFFER, region_end + BUFFER);
    Haplotype derived_haplotype(contig,
                                alignments.get_region_start(),
                                alignments.get_reference());

    // Step 1. Discover putative variants across the whole region
    std::vector<Variant> candidate_variants = alignments.get_variants_in_region(contig, region_start, region_end, 0.2, 20);

    // Step 2. Add variants to the haplotypes
    size_t calling_span = 15;
    size_t curr_variant_idx = 0;
    while(curr_variant_idx < candidate_variants.size()) {

        // Group the variants that are within calling_span bases of each other
        size_t end_variant_idx = curr_variant_idx + 1;
        while(end_variant_idx < candidate_variants.size()) {
            int distance = candidate_variants[end_variant_idx].ref_position -
                           candidate_variants[end_variant_idx - 1].ref_position;
            if(distance > calling_span)
                break;
            end_variant_idx++;
        }

        size_t num_variants = end_variant_idx - curr_variant_idx;
        int calling_start = candidate_variants[curr_variant_idx].ref_position - calling_span;
        int calling_end = candidate_variants[end_variant_idx - 1].ref_position +
                          candidate_variants[end_variant_idx - 1].ref_seq.length() +
                          calling_span;
        int calling_size = calling_end - calling_start;

        if(opt::verbose > 2) {
            fprintf(stderr, "%zu variants in span [%d %d]\n", num_variants, calling_start, calling_end);
        }

        // Only try to call variants if there is a reasonable amount and the window is not too large
        if(num_variants <= 10 && calling_size <= 100) {

            // Subset the haplotype to the region we are calling
            Haplotype calling_haplotype =
                derived_haplotype.substr_by_reference(calling_start, calling_end);

            // Get the events for the calling region
            std::vector<HMMInputData> event_sequences =
                alignments.get_event_subsequences(contig, calling_start, calling_end);

            // Subset the variants
            std::vector<Variant> calling_variants(candidate_variants.begin() + curr_variant_idx,
                                                  candidate_variants.begin() + end_variant_idx);

            // Select the best set of variants
            std::vector<Variant> selected_variants =
                select_variant_set(calling_variants, calling_haplotype, event_sequences);

            // Apply them to the final haplotype
            for(size_t vi = 0; vi < selected_variants.size(); vi++) {
                derived_haplotype.apply_variant(selected_variants[vi]);

                if(opt::verbose > 1) {
                    selected_variants[vi].write_vcf(stderr);
                }
            }
        }

        // advance to start of next region
        curr_variant_idx = end_variant_idx;
    }

    return derived_haplotype;
}

void parse_call_variants_options(int argc, char** argv)
{
    bool die = false;
    for (char c; (c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1;) {
        std::istringstream arg(optarg != NULL ? optarg : "");
        switch (c) {
            case 'r': arg >> opt::reads_file; break;
            case 'g': arg >> opt::genome_file; break;
            case 'b': arg >> opt::bam_file; break;
            case 'e': arg >> opt::event_bam_file; break;
            case 'w': arg >> opt::window; break;
            case 'o': arg >> opt::output_file; break;
            case '?': die = true; break;
            case 't': arg >> opt::num_threads; break;
            case 'v': opt::verbose++; break;
            case OPT_SNPS_ONLY: opt::snps_only = 1; break;
            case OPT_PROGRESS: opt::show_progress = 1; break;
            case OPT_HELP:
                std::cout << CONSENSUS_USAGE_MESSAGE;
                exit(EXIT_SUCCESS);
            case OPT_VERSION:
                std::cout << CONSENSUS_VERSION_MESSAGE;
                exit(EXIT_SUCCESS);
        }
    }

    if (argc - optind < 0) {
        std::cerr << SUBPROGRAM ": missing arguments\n";
        die = true;
    } else if (argc - optind > 0) {
        std::cerr << SUBPROGRAM ": too many arguments\n";
        die = true;
    }

    if(opt::num_threads <= 0) {
        std::cerr << SUBPROGRAM ": invalid number of threads: " << opt::num_threads << "\n";
        die = true;
    }

    if(opt::reads_file.empty()) {
        std::cerr << SUBPROGRAM ": a --reads file must be provided\n";
        die = true;
    }

    if(opt::genome_file.empty()) {
        std::cerr << SUBPROGRAM ": a --genome file must be provided\n";
        die = true;
    }

    if(opt::bam_file.empty()) {
        std::cerr << SUBPROGRAM ": a --bam file must be provided\n";
        die = true;
    }

    if (die)
    {
        std::cout << "\n" << CONSENSUS_USAGE_MESSAGE;
        exit(EXIT_FAILURE);
    }
}

int call_variants_main(int argc, char** argv)
{
    parse_call_variants_options(argc, argv);
    omp_set_num_threads(opt::num_threads);

    // Parse the window string
    // Replace ":" and "-" with spaces to make it parseable with stringstream
    std::replace(opt::window.begin(), opt::window.end(), ':', ' ');
    std::replace(opt::window.begin(), opt::window.end(), '-', ' ');

    std::stringstream parser(opt::window);
    std::string contig;
    int start_base;
    int end_base;

    parser >> contig >> start_base >> end_base;
    end_base = std::min(end_base, get_contig_length(contig) - 1);

    FILE* out_fp;
    if(!opt::output_file.empty()) {
        out_fp = fopen(opt::output_file.c_str(), "w");
    } else {
        out_fp = stdout;
    }

    Variant::write_vcf_header(out_fp);

    fprintf(stderr, "TODO: train model\n");
    fprintf(stderr, "TODO: filter data\n");

    Haplotype haplotype = call_variants_for_region(contig, start_base, end_base);

    std::vector<Variant> variants = haplotype.get_variants();
    for(size_t vi = 0; vi < variants.size(); vi++) {
        variants[vi].write_vcf(out_fp);
    }

    if(out_fp != stdout) {
        fclose(out_fp);
    }
}
<|endoftext|>


<commit_before>/* Definition of the pqxx::notification_receiver functor interface.
 *
 * pqxx::notification_receiver handles incoming notifications.
 *
 * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/notification instead.
 *
 * Copyright (c) 2000-2020, Jeroen T. Vermeulen.
 *
 * See COPYING for copyright license.  If you did not receive a file called
 * COPYING with this source code, please notify the distributor of this
 * mistake, or contact the author.
 */
#ifndef PQXX_H_NOTIFICATION
#define PQXX_H_NOTIFICATION

#include "pqxx/compiler-public.hxx"
#include "pqxx/internal/compiler-internal-pre.hxx"

#include <string>

#include "pqxx/types.hxx"

namespace pqxx
{
/// "Observer" base class for notifications.
/** @addtogroup notification Notifications and Receivers
 *
 * To listen on a notification issued using the NOTIFY command, derive your own
 * class from notification_receiver and define its function-call operator to
 * perform whatever action you wish to take when the given notification
 * arrives. Then create an object of that class and pass it to your connection.
 * DO NOT use raw SQL to listen for notifications, or your attempts to listen
 * won't be resumed when a connection fails--and you'll have no way to notice.
 *
 * Notifications never arrive inside a transaction, not even in a
 * nontransaction.  Therefore, you are free to open a transaction of your own
 * inside your receiver's function invocation operator.
 *
 * Notifications you are listening for may arrive anywhere within libpqxx code,
 * but be aware that @b PostgreSQL @b defers @b notifications @b occurring
 * @b inside @b transactions.  (This was done for excellent reasons; just think
 * about what happens if the transaction where you happen to handle an incoming
 * notification is later rolled back for other reasons).  So if you're keeping
 * a transaction open, don't expect any of your receivers on the same
 * connection to be notified.
 *
 * (For very similar reasons, outgoing notifications are also not sent until
 * the transaction that sends them commits.)
 *
 * Multiple receivers on the same connection may listen on a notification of
 * the same name.  An incoming notification is processed by invoking all
 * receivers (zero or more) of the same name.
 */
class PQXX_LIBEXPORT PQXX_NOVTABLE notification_receiver
{
public:
  /// Register the receiver with a connection.
  /**
   * @param c Connnection to operate on.
   * @param channel Name of the notification to listen for.
   */
  notification_receiver(connection &c, std::string_view channel);
  notification_receiver(notification_receiver const &) = delete;
  notification_receiver &operator=(notification_receiver const &) = delete;
  virtual ~notification_receiver();

  /// The channel that this receiver listens on.
  [[nodiscard]] std::string const &channel() const { return m_channel; }

  // TODO: Can we phase this out in favour of zview or string_view?
  /// Overridable: action to invoke when notification arrives.
  /**
   * @param payload An optional string that may have been passed to the NOTIFY
   * command.
   * @param backend_pid Process ID of the database backend process that served
   * our connection when the notification arrived.  The actual process ID
   * behind the connection may have changed by the time this method is called.
   */
  virtual void operator()(std::string const &payload, int backend_pid) = 0;

protected:
  connection &conn() const noexcept { return m_conn; }

private:
  connection &m_conn;
  std::string m_channel;
};
} // namespace pqxx

#include "pqxx/internal/compiler-internal-post.hxx"
#endif
<commit_msg>Comment.<commit_after>/* Definition of the pqxx::notification_receiver functor interface.
 *
 * pqxx::notification_receiver handles incoming notifications.
 *
 * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/notification instead.
 *
 * Copyright (c) 2000-2020, Jeroen T. Vermeulen.
 *
 * See COPYING for copyright license.  If you did not receive a file called
 * COPYING with this source code, please notify the distributor of this
 * mistake, or contact the author.
 */
#ifndef PQXX_H_NOTIFICATION
#define PQXX_H_NOTIFICATION

#include "pqxx/compiler-public.hxx"
#include "pqxx/internal/compiler-internal-pre.hxx"

#include <string>

#include "pqxx/types.hxx"

namespace pqxx
{
/// "Observer" base class for notifications.
/** @addtogroup notification Notifications and Receivers
 *
 * To listen on a notification issued using the NOTIFY command, derive your own
 * class from notification_receiver and define its function-call operator to
 * perform whatever action you wish to take when the given notification
 * arrives. Then create an object of that class and pass it to your connection.
 * DO NOT use raw SQL to listen for notifications, or your attempts to listen
 * won't be resumed when a connection fails--and you'll have no way to notice.
 *
 * Notifications never arrive inside a transaction, not even in a
 * nontransaction.  Therefore, you are free to open a transaction of your own
 * inside your receiver's function invocation operator.
 *
 * Notifications you are listening for may arrive anywhere within libpqxx code,
 * but be aware that @b PostgreSQL @b defers @b notifications @b occurring
 * @b inside @b transactions.  (This was done for excellent reasons; just think
 * about what happens if the transaction where you happen to handle an incoming
 * notification is later rolled back for other reasons).  So if you're keeping
 * a transaction open, don't expect any of your receivers on the same
 * connection to be notified.
 *
 * (For very similar reasons, outgoing notifications are also not sent until
 * the transaction that sends them commits.)
 *
 * Multiple receivers on the same connection may listen on a notification of
 * the same name.  An incoming notification is processed by invoking all
 * receivers (zero or more) of the same name.
 */
class PQXX_LIBEXPORT PQXX_NOVTABLE notification_receiver
{
public:
  /// Register the receiver with a connection.
  /**
   * @param c Connnection to operate on.
   * @param channel Name of the notification to listen for.
   */
  notification_receiver(connection &c, std::string_view channel);
  notification_receiver(notification_receiver const &) = delete;
  notification_receiver &operator=(notification_receiver const &) = delete;
  virtual ~notification_receiver();

  /// The channel that this receiver listens on.
  [[nodiscard]] std::string const &channel() const { return m_channel; }

  // TODO: Change API to take payload as zview instead of string ref.
  /// Overridable: action to invoke when notification arrives.
  /**
   * @param payload An optional string that may have been passed to the NOTIFY
   * command.
   * @param backend_pid Process ID of the database backend process that served
   * our connection when the notification arrived.  The actual process ID
   * behind the connection may have changed by the time this method is called.
   */
  virtual void operator()(std::string const &payload, int backend_pid) = 0;

protected:
  connection &conn() const noexcept { return m_conn; }

private:
  connection &m_conn;
  std::string m_channel;
};
} // namespace pqxx

#include "pqxx/internal/compiler-internal-post.hxx"
#endif
<|endoftext|>


<commit_before>#include <bgfx/bgfx.h>
//#include "core/log.h"
//#include "core/file.h"
//#include "core/core.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#define sizeof_array(t) (sizeof(t) / sizeof(t[0]))

#if defined(__clang__) || defined(__gcc__)
#define PD_NO_RETURN __attribute__((noreturn))
#else
#define PD_NO_RETURN
#endif

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static void* File_loadToMemory(const char* filename, size_t* size, size_t padAllocSize) {
    FILE* f = fopen(filename, "rb");
    void* data = 0;
    size_t s = 0, t = 0;

    *size = 0;

    if (!f)
        return 0;

    // TODO: Use fstat here?

    fseek(f, 0, SEEK_END);
    long ts = ftell(f);

    if (ts < 0)
        goto end;

    s = (size_t)ts;

    data = malloc(s + padAllocSize);

    if (!data)
        goto end;

    fseek(f, 0, SEEK_SET);

    t = fread(data, s, 1, f);
    (void)t;

    *size = s;

    end:

    fclose(f);

    return data;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static bgfx::UniformHandle s_tex;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

struct ProgramAttribs {
    bgfx::Attrib::Enum attrib;
    uint8_t num;
    bgfx::AttribType::Enum type;
    bool norm;
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

struct ProgramInfo {
    ProgramAttribs* attribs;
    const char* vsName;
    const char* fsName;
    bgfx::VertexDecl vertexDecl;
    bgfx::ProgramHandle handle;
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static const bgfx::Memory* loadShader(const char* filename) {
    size_t size;
    uint8_t* data = (uint8_t*)File_loadToMemory(filename, &size, 1);

    if (!data) {
        printf("Unable to load shader %s\n", filename);
        return 0;
    }

    const bgfx::Memory* mem = bgfx::makeRef(data, size + 1, NULL, NULL);

    // terminate strings
    data[size] = 0;

    return mem;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

bgfx::ProgramHandle loadProgram(const char* vsName, const char* fsName) {
    bgfx::ProgramHandle ph = { bgfx::invalidHandle };

    const bgfx::Memory* vsShader = loadShader(vsName);
    const bgfx::Memory* fsShader = loadShader(fsName);

    if (!vsShader)
        return ph;

    if (!fsShader)
        return ph;

    bgfx::ShaderHandle vsHandle = bgfx::createShader(vsShader);
    bgfx::ShaderHandle fsHandle = bgfx::createShader(fsShader);

    if (!isValid(vsHandle)) {
        printf("Unable to load vsShader %s\n", vsName);
        return ph;
    }

    if (!isValid(fsHandle)) {
        printf("Unable to load fsShader %s\n", fsName);
        return ph;
    }

    ph = bgfx::createProgram(vsHandle, fsHandle, true);

    if (!isValid(ph))
        printf("Unable to create shader program for %s %s\n", vsName, fsName);

    return ph;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static ProgramAttribs posTexColorAttribs[] =
{
    { bgfx::Attrib::Position, 2, bgfx::AttribType::Float, false },
    { bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float, false },
    { bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true },
    { bgfx::Attrib::Count, 0, bgfx::AttribType::Uint8, false },
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static ProgramAttribs posColorAttribs[] =
{
    { bgfx::Attrib::Position, 2, bgfx::AttribType::Float, false },
    { bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true },
    { bgfx::Attrib::Count, 0, bgfx::AttribType::Uint8, false },
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static ProgramInfo s_programs[] =
{
    {
        (ProgramAttribs*)&posColorAttribs,
        OBJECT_DIR "/_generated/data/shaders/ui_pos_color/vs_pos_color.vs",
        OBJECT_DIR "/_generated/data/shaders/ui_pos_color/fs_pos_color.fs",
    },

    {
        (ProgramAttribs*)&posTexColorAttribs,
        OBJECT_DIR "/_generated/data/shaders/ui_pos_tex_r_color/vs_pos_tex_r_color.vs",
        OBJECT_DIR "/_generated/data/shaders/ui_pos_tex_r_color/fs_pos_tex_r_color.fs",
    },

    {
        (ProgramAttribs*)&posTexColorAttribs,
        OBJECT_DIR "/_generated/data/shaders/imgui/vs_imgui.vs",
        OBJECT_DIR "/_generated/data/shaders/imgui/fs_imgui.fs",
    },
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

enum {
    Program_PosColor,
    Program_PosTexRColor,
    Program_PosTexColor,
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool UIRender_init() {
    s_tex = bgfx::createUniform("s_tex", bgfx::UniformType::Int1);

    for (int i = 0; i < (int)sizeof_array(s_programs); ++i) {
        ProgramInfo* program = &s_programs[i];

        program->handle = loadProgram(program->vsName, program->fsName);

        if (!isValid(program->handle))
            return false;

        const ProgramAttribs* attribs = program->attribs;
        bgfx::VertexDecl& decl = program->vertexDecl;

        decl.begin();

        while (attribs->attrib != bgfx::Attrib::Count) {
            decl = decl.add(attribs->attrib, attribs->num, attribs->type, attribs->norm);
            attribs++;
        }

        decl.end();
    }

    return true;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void UIRender_allocPosTexColorTb(bgfx::TransientVertexBuffer* buffer, uint32_t count) {
    assert(bgfx::checkAvailTransientVertexBuffer(count, s_programs[Program_PosTexColor].vertexDecl));
    bgfx::allocTransientVertexBuffer(buffer, count, s_programs[Program_PosTexColor].vertexDecl);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void UIRender_allocPosColorTb(bgfx::TransientVertexBuffer* buffer, uint32_t count) {
    assert(bgfx::checkAvailTransientVertexBuffer(count, s_programs[Program_PosColor].vertexDecl));
    bgfx::allocTransientVertexBuffer(buffer, count, s_programs[Program_PosColor].vertexDecl);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void UIRender_posTexColor(bgfx::TransientVertexBuffer* vertexBuffer, uint32_t offset, uint32_t count, bgfx::TextureHandle texHandle) {
    bgfx::setTexture(0, s_tex, texHandle);
    bgfx::setVertexBuffer(vertexBuffer, offset, count);
    //NOTE(marco): the program handle is now part of bgfx::submit
    //bgfx::setProgram(s_programs[Program_PosTexColor].handle);
    bgfx::submit(0, s_programs[Program_PosTexColor].handle);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void UIRender_posIdxTexColor(bgfx::TransientVertexBuffer* vertexBuffer, bgfx::TransientIndexBuffer* indexBuffer, uint32_t vtxSize, uint32_t offset, uint32_t count, bgfx::TextureHandle texHandle) {
    bgfx::setTexture(0, s_tex, texHandle);
    bgfx::setVertexBuffer(vertexBuffer, 0, vtxSize);
    bgfx::setIndexBuffer(indexBuffer, offset, count);
    //NOTE(marco): the program handle is now part of bgfx::submit
    //bgfx::setProgram(s_programs[Program_PosTexColor].handle);
    bgfx::submit(0, s_programs[Program_PosTexColor].handle);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void UIRender_posTexRColor(bgfx::TransientVertexBuffer* vertexBuffer, uint32_t offset, uint32_t count, bgfx::TextureHandle texHandle) {
    bgfx::setTexture(0, s_tex, texHandle);
    bgfx::setVertexBuffer(vertexBuffer, offset, count);
    //NOTE(marco): the program handle is now part of bgfx::submit
    //bgfx::setProgram(s_programs[Program_PosTexRColor].handle);
    bgfx::submit(0, s_programs[Program_PosTexRColor].handle);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void UIRender_posColor(bgfx::TransientVertexBuffer* vertexBuffer, uint32_t offset, uint32_t count) {
    bgfx::setVertexBuffer(vertexBuffer, offset, count);
    //NOTE(marco): the program handle is now part of bgfx::submit
    //bgfx::setProgram(s_programs[Program_PosColor].handle);
    bgfx::submit(0, s_programs[Program_PosColor].handle);
}

bgfx::ProgramHandle UIRender_getProgramHandle(uint32_t programIndex) {
    return s_programs[2].handle;
}

<commit_msg>Fixed win64 build error<commit_after>#include <bgfx/bgfx.h>
//#include "core/log.h"
//#include "core/file.h"
//#include "core/core.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#define sizeof_array(t) (sizeof(t) / sizeof(t[0]))

#if defined(__clang__) || defined(__gcc__)
#define PD_NO_RETURN __attribute__((noreturn))
#else
#define PD_NO_RETURN
#endif

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static void* File_loadToMemory(const char* filename, size_t* size, size_t padAllocSize) {
    FILE* f = fopen(filename, "rb");
    void* data = 0;
    size_t s = 0, t = 0;

    *size = 0;

    if (!f)
        return 0;

    // TODO: Use fstat here?

    fseek(f, 0, SEEK_END);
    long ts = ftell(f);

    if (ts < 0)
        goto end;

    s = (size_t)ts;

    data = malloc(s + padAllocSize);

    if (!data)
        goto end;

    fseek(f, 0, SEEK_SET);

    t = fread(data, s, 1, f);
    (void)t;

    *size = s;

    end:

    fclose(f);

    return data;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static bgfx::UniformHandle s_tex;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

struct ProgramAttribs {
    bgfx::Attrib::Enum attrib;
    uint8_t num;
    bgfx::AttribType::Enum type;
    bool norm;
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

struct ProgramInfo {
    ProgramAttribs* attribs;
    const char* vsName;
    const char* fsName;
    bgfx::VertexDecl vertexDecl;
    bgfx::ProgramHandle handle;
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static const bgfx::Memory* loadShader(const char* filename) {
    size_t size;
    uint8_t* data = (uint8_t*)File_loadToMemory(filename, &size, 1);

    if (!data) {
        printf("Unable to load shader %s\n", filename);
        return 0;
    }

    const bgfx::Memory* mem = bgfx::makeRef(data, (uint32_t)(size + 1), NULL, NULL);

    // terminate strings
    data[size] = 0;

    return mem;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

bgfx::ProgramHandle loadProgram(const char* vsName, const char* fsName) {
    bgfx::ProgramHandle ph = { bgfx::invalidHandle };

    const bgfx::Memory* vsShader = loadShader(vsName);
    const bgfx::Memory* fsShader = loadShader(fsName);

    if (!vsShader)
        return ph;

    if (!fsShader)
        return ph;

    bgfx::ShaderHandle vsHandle = bgfx::createShader(vsShader);
    bgfx::ShaderHandle fsHandle = bgfx::createShader(fsShader);

    if (!isValid(vsHandle)) {
        printf("Unable to load vsShader %s\n", vsName);
        return ph;
    }

    if (!isValid(fsHandle)) {
        printf("Unable to load fsShader %s\n", fsName);
        return ph;
    }

    ph = bgfx::createProgram(vsHandle, fsHandle, true);

    if (!isValid(ph))
        printf("Unable to create shader program for %s %s\n", vsName, fsName);

    return ph;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static ProgramAttribs posTexColorAttribs[] =
{
    { bgfx::Attrib::Position, 2, bgfx::AttribType::Float, false },
    { bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float, false },
    { bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true },
    { bgfx::Attrib::Count, 0, bgfx::AttribType::Uint8, false },
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static ProgramAttribs posColorAttribs[] =
{
    { bgfx::Attrib::Position, 2, bgfx::AttribType::Float, false },
    { bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true },
    { bgfx::Attrib::Count, 0, bgfx::AttribType::Uint8, false },
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static ProgramInfo s_programs[] =
{
    {
        (ProgramAttribs*)&posColorAttribs,
        OBJECT_DIR "/_generated/data/shaders/ui_pos_color/vs_pos_color.vs",
        OBJECT_DIR "/_generated/data/shaders/ui_pos_color/fs_pos_color.fs",
    },

    {
        (ProgramAttribs*)&posTexColorAttribs,
        OBJECT_DIR "/_generated/data/shaders/ui_pos_tex_r_color/vs_pos_tex_r_color.vs",
        OBJECT_DIR "/_generated/data/shaders/ui_pos_tex_r_color/fs_pos_tex_r_color.fs",
    },

    {
        (ProgramAttribs*)&posTexColorAttribs,
        OBJECT_DIR "/_generated/data/shaders/imgui/vs_imgui.vs",
        OBJECT_DIR "/_generated/data/shaders/imgui/fs_imgui.fs",
    },
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

enum {
    Program_PosColor,
    Program_PosTexRColor,
    Program_PosTexColor,
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool UIRender_init() {
    s_tex = bgfx::createUniform("s_tex", bgfx::UniformType::Int1);

    for (int i = 0; i < (int)sizeof_array(s_programs); ++i) {
        ProgramInfo* program = &s_programs[i];

        program->handle = loadProgram(program->vsName, program->fsName);

        if (!isValid(program->handle))
            return false;

        const ProgramAttribs* attribs = program->attribs;
        bgfx::VertexDecl& decl = program->vertexDecl;

        decl.begin();

        while (attribs->attrib != bgfx::Attrib::Count) {
            decl = decl.add(attribs->attrib, attribs->num, attribs->type, attribs->norm);
            attribs++;
        }

        decl.end();
    }

    return true;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void UIRender_allocPosTexColorTb(bgfx::TransientVertexBuffer* buffer, uint32_t count) {
    assert(bgfx::checkAvailTransientVertexBuffer(count, s_programs[Program_PosTexColor].vertexDecl));
    bgfx::allocTransientVertexBuffer(buffer, count, s_programs[Program_PosTexColor].vertexDecl);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void UIRender_allocPosColorTb(bgfx::TransientVertexBuffer* buffer, uint32_t count) {
    assert(bgfx::checkAvailTransientVertexBuffer(count, s_programs[Program_PosColor].vertexDecl));
    bgfx::allocTransientVertexBuffer(buffer, count, s_programs[Program_PosColor].vertexDecl);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void UIRender_posTexColor(bgfx::TransientVertexBuffer* vertexBuffer, uint32_t offset, uint32_t count, bgfx::TextureHandle texHandle) {
    bgfx::setTexture(0, s_tex, texHandle);
    bgfx::setVertexBuffer(vertexBuffer, offset, count);
    //NOTE(marco): the program handle is now part of bgfx::submit
    //bgfx::setProgram(s_programs[Program_PosTexColor].handle);
    bgfx::submit(0, s_programs[Program_PosTexColor].handle);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void UIRender_posIdxTexColor(bgfx::TransientVertexBuffer* vertexBuffer, bgfx::TransientIndexBuffer* indexBuffer, uint32_t vtxSize, uint32_t offset, uint32_t count, bgfx::TextureHandle texHandle) {
    bgfx::setTexture(0, s_tex, texHandle);
    bgfx::setVertexBuffer(vertexBuffer, 0, vtxSize);
    bgfx::setIndexBuffer(indexBuffer, offset, count);
    //NOTE(marco): the program handle is now part of bgfx::submit
    //bgfx::setProgram(s_programs[Program_PosTexColor].handle);
    bgfx::submit(0, s_programs[Program_PosTexColor].handle);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void UIRender_posTexRColor(bgfx::TransientVertexBuffer* vertexBuffer, uint32_t offset, uint32_t count, bgfx::TextureHandle texHandle) {
    bgfx::setTexture(0, s_tex, texHandle);
    bgfx::setVertexBuffer(vertexBuffer, offset, count);
    //NOTE(marco): the program handle is now part of bgfx::submit
    //bgfx::setProgram(s_programs[Program_PosTexRColor].handle);
    bgfx::submit(0, s_programs[Program_PosTexRColor].handle);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void UIRender_posColor(bgfx::TransientVertexBuffer* vertexBuffer, uint32_t offset, uint32_t count) {
    bgfx::setVertexBuffer(vertexBuffer, offset, count);
    //NOTE(marco): the program handle is now part of bgfx::submit
    //bgfx::setProgram(s_programs[Program_PosColor].handle);
    bgfx::submit(0, s_programs[Program_PosColor].handle);
}

bgfx::ProgramHandle UIRender_getProgramHandle(uint32_t programIndex) {
    return s_programs[2].handle;
}

<|endoftext|>