<commit_before>#include "vision_methods.hpp"
//#include <oepncv2/features2d.hpp>
#include <opencv2/opencv.hpp>
#include <string>

vision_methods::vision_methods () {
}

vision_methods::~vision_methods () {
}

cv::Mat vision_methods::preprocessing (const cv::Mat& image_in) {
    cv::Mat image_out;
    cvtColor (image_in, image_out, CV_BGR2GRAY);
    cv::GaussianBlur (image_out, image_out, cv::Size (_ksize_x, _ksize_y), _sigma_x, _sigma_y);
    return image_out;
}

cv::Mat vision_methods::segmentation (const cv::Mat& image_in) {
    cv::Mat image_out;

    cv::threshold (image_in, image_out, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);

    return image_out;
}

cv::Mat vision_methods::extraction (const cv::Mat& image_in,
std::map<unsigned int, cv::Point2f>& markers) {
    std::vector<cv::KeyPoint> key_points;
    cv::Mat image_out (image_in.rows, image_in.cols, CV_8UC1, cv::Scalar (0));

    // blob detector creation
    cv::SimpleBlobDetector::Params blob_detector_params;
    blob_detector_params.filterByArea = true;
    blob_detector_params.maxArea      = 10000.0;
    blob_detector_params.minArea      = 10.0;
    cv::SimpleBlobDetector blob_detector (blob_detector_params);

    // blob detection
    blob_detector.detect (image_in, key_points);

    // marker extraction
    std::vector<std::vector<cv::KeyPoint>> potential_markers;
    extract_groups (key_points, potential_markers);
    extract_markers (potential_markers, markers);

    // debug image construction
    for (cv::KeyPoint point : key_points) {
        circle (image_out, point.pt, point.size * 2, cv::Scalar (255), -1);
    }
    for (auto marker : markers) {
        putText (image_out, std::to_string (marker.first), marker.second,
        cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar (0));
    }
    return image_out;
}

void vision_methods::extract_groups (std::vector<cv::KeyPoint> key_points,
std::vector<std::vector<cv::KeyPoint>>& potential_markers) {
    // group keypoints into markers by proximity
    while (!key_points.empty ()) {
        std::vector<cv::KeyPoint> grouped_points;
        cv::KeyPoint key_point = key_points.back ();
        key_points.pop_back ();
        float x = key_point.pt.x;
        float y = key_point.pt.y;

        // check distance against all other key points
        for (auto itr = key_points.begin (); itr != key_points.end ();) {
            float dx       = x - itr->pt.x;
            float dy       = y - itr->pt.y;
            float distance = sqrt ((dx * dx) + (dy * dy));

            // if the point is in range, group it with current point
            if (distance < (key_point.size * _BLOB_SIZE_RATIO)) {
                grouped_points.push_back (*itr);
                key_points.erase (itr);
            } else {
                itr++;
            }
        }

        grouped_points.push_back (key_point);
        potential_markers.push_back (grouped_points);
    }
}

void vision_methods::extract_markers (std::vector<std::vector<cv::KeyPoint>>& potential_markers,
std::map<unsigned int, cv::Point2f>& markers) {
    // calculate marker properties (id, size, location)
    for (std::vector<cv::KeyPoint> marker_points : potential_markers) {
        const unsigned int marker_id = marker_points.size ();

        if (_MIN_MARKER_ID <= marker_id && marker_id <= _MAX_MARKER_ID) {
            cv::Point2f marker_pos;
            float average_x = 0;
            float average_y = 0;

            for (cv::KeyPoint key_point : marker_points) {
                //    average_size += key_point.size;
                average_x += key_point.pt.x;
                average_y += key_point.pt.y;
            }

            // average_size /= marker_id;
            marker_pos.x       = average_x / marker_id;
            marker_pos.y       = average_y / marker_id;
            markers[marker_id] = marker_pos;
        }
    }
}
<commit_msg>add psudo code for grouping algorithm<commit_after>#include "vision_methods.hpp"
//#include <oepncv2/features2d.hpp>
#include <opencv2/opencv.hpp>
#include <string>

vision_methods::vision_methods () {
}

vision_methods::~vision_methods () {
}

cv::Mat vision_methods::preprocessing (const cv::Mat& image_in) {
    cv::Mat image_out;
    cvtColor (image_in, image_out, CV_BGR2GRAY);
    cv::GaussianBlur (image_out, image_out, cv::Size (_ksize_x, _ksize_y), _sigma_x, _sigma_y);
    return image_out;
}

cv::Mat vision_methods::segmentation (const cv::Mat& image_in) {
    cv::Mat image_out;

    cv::threshold (image_in, image_out, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);

    return image_out;
}

cv::Mat vision_methods::extraction (const cv::Mat& image_in,
std::map<unsigned int, cv::Point2f>& markers) {
    std::vector<cv::KeyPoint> key_points;
    cv::Mat image_out (image_in.rows, image_in.cols, CV_8UC1, cv::Scalar (0));

    // blob detector creation
    cv::SimpleBlobDetector::Params blob_detector_params;
    blob_detector_params.filterByArea = true;
    blob_detector_params.maxArea      = 10000.0;
    blob_detector_params.minArea      = 10.0;
    cv::SimpleBlobDetector blob_detector (blob_detector_params);

    // blob detection
    blob_detector.detect (image_in, key_points);

    // marker extraction
    std::vector<std::vector<cv::KeyPoint>> potential_markers;
    extract_groups (key_points, potential_markers);
    extract_markers (potential_markers, markers);

    // debug image construction
    for (cv::KeyPoint point : key_points) {
        circle (image_out, point.pt, point.size * 2, cv::Scalar (255), -1);
    }
    for (auto marker : markers) {
        putText (image_out, std::to_string (marker.first), marker.second,
        cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar (0));
    }
    return image_out;
}

/*iterate over all blobs, find in-range-neighbours
store this in vector containing pairs? or struct:
    vector< vector<keypoints>::iterator> <- list of references to all neighbours
    keypoint

to create finalized markers:
if the vector of neighbours is 0, discard keypoint.
otherwise, get recursively group keypoints, deleting them from the main keypoint
vector before calling the recursive function again.
*/

void vision_methods::extract_groups (std::vector<cv::KeyPoint> key_points,
std::vector<std::vector<cv::KeyPoint>>& potential_markers) {
    // group keypoints into markers by proximity
    while (!key_points.empty ()) {
        std::vector<cv::KeyPoint> grouped_points;
        cv::KeyPoint key_point = key_points.back ();
        key_points.pop_back ();
        float x = key_point.pt.x;
        float y = key_point.pt.y;

        // check distance against all other key points
        for (auto itr = key_points.begin (); itr != key_points.end ();) {
            float dx       = x - itr->pt.x;
            float dy       = y - itr->pt.y;
            float distance = sqrt ((dx * dx) + (dy * dy));

            // if the point is in range, group it with current point
            if (distance < (key_point.size * _BLOB_SIZE_RATIO)) {
                grouped_points.push_back (*itr);
                key_points.erase (itr);
            } else {
                itr++;
            }
        }

        grouped_points.push_back (key_point);
        potential_markers.push_back (grouped_points);
    }
}

void vision_methods::extract_markers (std::vector<std::vector<cv::KeyPoint>>& potential_markers,
std::map<unsigned int, cv::Point2f>& markers) {
    // calculate marker properties (id, size, location)
    for (std::vector<cv::KeyPoint> marker_points : potential_markers) {
        const unsigned int marker_id = marker_points.size ();

        if (_MIN_MARKER_ID <= marker_id && marker_id <= _MAX_MARKER_ID) {
            cv::Point2f marker_pos;
            float average_x = 0;
            float average_y = 0;

            for (cv::KeyPoint key_point : marker_points) {
                //    average_size += key_point.size;
                average_x += key_point.pt.x;
                average_y += key_point.pt.y;
            }

            // average_size /= marker_id;
            marker_pos.x       = average_x / marker_id;
            marker_pos.y       = average_y / marker_id;
            markers[marker_id] = marker_pos;
        }
    }
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkMaskPolyData.cc
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-1995 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include "vtkMaskPolyData.hh"

vtkMaskPolyData::vtkMaskPolyData()
{
  this->OnRatio = 11;
  this->Offset = 0;
}

//
// Down sample polygonal data.  Don't down sample points (that is, use the
// original points, since usually not worth it.
//
void vtkMaskPolyData::Execute()
{
  int numVerts, numLines, numPolys, numStrips;
  vtkCellArray *inVerts,*inLines,*inPolys,*inStrips;
  int numNewVerts, numNewLines, numNewPolys, numNewStrips;
  vtkCellArray *newVerts=NULL, *newLines=NULL;
  vtkCellArray *newPolys=NULL, *newStrips=NULL;
  int id, interval;
  vtkPointData *pd;
  int npts, *pts;
  vtkPolyData *input=(vtkPolyData *)this->Input;
  vtkPolyData *output = this->GetOutput();

  //
  // Check input / pass data through
  //

  inVerts = input->GetVerts();
  numVerts = inVerts->GetNumberOfCells();
  numNewVerts = numVerts / this->OnRatio;

  inLines = input->GetLines();
  numLines = inLines->GetNumberOfCells();
  numNewLines = numLines / this->OnRatio;

  inPolys = input->GetPolys();
  numPolys = inPolys->GetNumberOfCells();
  numNewPolys = numPolys / this->OnRatio;

  inStrips = input->GetStrips();
  numStrips = inStrips->GetNumberOfCells();
  numNewStrips = numStrips / this->OnRatio;

  if ( numNewVerts < 1 && numNewLines < 1 &&
  numNewPolys < 1 && numNewStrips < 1 )
    {
    vtkErrorMacro (<<"No PolyData to mask!");
    return;
    }
//
// Allocate space
//
  if ( numNewVerts )
    newVerts = new vtkCellArray(numNewVerts);

  if ( numNewLines )
    {
    newLines = new vtkCellArray;
    newLines->Allocate(newLines->EstimateSize(numNewLines,2));
    }

  if ( numNewPolys )
    {
    newPolys = new vtkCellArray;
    newPolys->Allocate(newPolys->EstimateSize(numNewPolys,4));
    }

  if ( numNewStrips )
    {
    newStrips = new vtkCellArray;
    newStrips->Allocate(newStrips->EstimateSize(numNewStrips,6));
    }
//
// Traverse topological lists and traverse
//
  interval = this->Offset + this->OnRatio;
  if ( newVerts )
    {
    for (id=0, inVerts->InitTraversal(); inVerts->GetNextCell(npts,pts); id++)
      {
      if ( ! (id % interval) )
        {
        newVerts->InsertNextCell(npts,pts);
        }
      }
    }

  if ( newLines )
    {
    for (id=0, inLines->InitTraversal(); inLines->GetNextCell(npts,pts); id++)
      {
      if ( ! (id % interval) )
        {
        newLines->InsertNextCell(npts,pts);
        }
      }
    }

  if ( newPolys )
    {
    for (id=0, inPolys->InitTraversal(); inPolys->GetNextCell(npts,pts); id++)
      {
      if ( ! (id % interval) )
        {
        newPolys->InsertNextCell(npts,pts);
        }
      }
    }

  if ( newStrips )
    {
    for (id=0, inStrips->InitTraversal(); inStrips->GetNextCell(npts,pts); id++)
      {
      if ( ! (id % interval) )
        {
        newStrips->InsertNextCell(npts,pts);
        }
      }
    }
  //
  // Update ourselves and release memory
  //
  // pass through points and point data -- done by ToPoly filter now
  //output->SetPoints(input->GetPoints());
  //pd = input->GetPointData();
  //output->PointData = *pd;

  if (newVerts)
    {
    output->SetVerts(newVerts);
    newVerts->Delete();
    }

  if (newLines)
    {
    output->SetLines(newLines);
    newLines->Delete();
    }

  if (newPolys)
    {
    output->SetPolys(newPolys);
    newPolys->Delete();
    }

  if (newStrips)
    {
    output->SetStrips(newStrips);
    newStrips->Delete();
    }

  output->Squeeze();
}

void vtkMaskPolyData::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkPolyToPolyFilter::PrintSelf(os,indent);

  os << indent << "On Ratio: " << this->OnRatio << "\n";
  os << indent << "Offset: " << this->Offset << "\n";
}
<commit_msg>fixed bad bug<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkMaskPolyData.cc
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-1995 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include "vtkMaskPolyData.hh"

vtkMaskPolyData::vtkMaskPolyData()
{
  this->OnRatio = 11;
  this->Offset = 0;
}

//
// Down sample polygonal data.  Don't down sample points (that is, use the
// original points, since usually not worth it.
//
void vtkMaskPolyData::Execute()
{
  int numVerts, numLines, numPolys, numStrips;
  vtkCellArray *inVerts,*inLines,*inPolys,*inStrips;
  int numNewVerts, numNewLines, numNewPolys, numNewStrips;
  vtkCellArray *newVerts=NULL, *newLines=NULL;
  vtkCellArray *newPolys=NULL, *newStrips=NULL;
  int id, interval;
  vtkPointData *pd;
  int npts, *pts;
  vtkPolyData *input=(vtkPolyData *)this->Input;
  vtkPolyData *output = this->GetOutput();

  //
  // Check input / pass data through
  //

  inVerts = input->GetVerts();
  numVerts = inVerts->GetNumberOfCells();
  numNewVerts = numVerts / this->OnRatio;

  inLines = input->GetLines();
  numLines = inLines->GetNumberOfCells();
  numNewLines = numLines / this->OnRatio;

  inPolys = input->GetPolys();
  numPolys = inPolys->GetNumberOfCells();
  numNewPolys = numPolys / this->OnRatio;

  inStrips = input->GetStrips();
  numStrips = inStrips->GetNumberOfCells();
  numNewStrips = numStrips / this->OnRatio;

  if ( numNewVerts < 1 && numNewLines < 1 &&
  numNewPolys < 1 && numNewStrips < 1 )
    {
    vtkErrorMacro (<<"No PolyData to mask!");
    return;
    }
//
// Allocate space
//
  if ( numNewVerts )
    newVerts = new vtkCellArray(numNewVerts);

  if ( numNewLines )
    {
    newLines = new vtkCellArray;
    newLines->Allocate(newLines->EstimateSize(numNewLines,2));
    }

  if ( numNewPolys )
    {
    newPolys = new vtkCellArray;
    newPolys->Allocate(newPolys->EstimateSize(numNewPolys,4));
    }

  if ( numNewStrips )
    {
    newStrips = new vtkCellArray;
    newStrips->Allocate(newStrips->EstimateSize(numNewStrips,6));
    }
//
// Traverse topological lists and traverse
//
  interval = this->Offset + this->OnRatio;
  if ( newVerts )
    {
    for (id=0, inVerts->InitTraversal(); inVerts->GetNextCell(npts,pts); id++)
      {
      if ( ! (id % interval) )
        {
        newVerts->InsertNextCell(npts,pts);
        }
      }
    }

  if ( newLines )
    {
    for (id=0, inLines->InitTraversal(); inLines->GetNextCell(npts,pts); id++)
      {
      if ( ! (id % interval) )
        {
        newLines->InsertNextCell(npts,pts);
        }
      }
    }

  if ( newPolys )
    {
    for (id=0, inPolys->InitTraversal(); inPolys->GetNextCell(npts,pts); id++)
      {
      if ( ! (id % interval) )
        {
        newPolys->InsertNextCell(npts,pts);
        }
      }
    }

  if ( newStrips )
    {
    for (id=0, inStrips->InitTraversal(); inStrips->GetNextCell(npts,pts); id++)
      {
      if ( ! (id % interval) )
        {
        newStrips->InsertNextCell(npts,pts);
        }
      }
    }
  //
  // Update ourselves and release memory
  output->SetPoints(input->GetPoints());
  pd = input->GetPointData();
  output->GetPointData()->PassData(pd);

  if (newVerts)
    {
    output->SetVerts(newVerts);
    newVerts->Delete();
    }

  if (newLines)
    {
    output->SetLines(newLines);
    newLines->Delete();
    }

  if (newPolys)
    {
    output->SetPolys(newPolys);
    newPolys->Delete();
    }

  if (newStrips)
    {
    output->SetStrips(newStrips);
    newStrips->Delete();
    }

  output->Squeeze();
}

void vtkMaskPolyData::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkPolyToPolyFilter::PrintSelf(os,indent);

  os << indent << "On Ratio: " << this->OnRatio << "\n";
  os << indent << "Offset: " << this->Offset << "\n";
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    XglrRen.cc
  Language:  C++
  Date:      04/20/95
  Version:   1.2

Copyright (c) 1993-1995 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include <math.h>
#include <iostream.h>
#include "vtkXglrProperty.hh"
#include "vtkXglrCamera.hh"
#include "vtkXglrLight.hh"
#include "vtkXglrRenderWindow.hh"
#include "vtkXglrRenderer.hh"
#include "vtkVolumeRenderer.hh"

vtkXglrRenderer::vtkXglrRenderer()
{
}

// Description:
// Ask actors to build and draw themselves.
int vtkXglrRenderer::UpdateActors()
{
  vtkActor *anActor;
  int count = 0;

  // loop through actors
  for (this->Actors.InitTraversal(); (anActor = this->Actors.GetNextItem()); )
    {
    // if it's invisible, we can skip the rest
    if (anActor->GetVisibility())
      {
      count++;
      anActor->Render((vtkRenderer *)this);
      }
    }
  return count;
}

// Description:
// Ask active camera to load its view matrix.
int vtkXglrRenderer::UpdateCameras ()
{
  // update the viewing transformation
  if (!this->ActiveCamera) return 0;

  this->ActiveCamera->Render((vtkRenderer *)this);
  return 1;
}

// Description:
// Ask lights to load themselves into graphics pipeline.
int vtkXglrRenderer::UpdateLights ()
{
  vtkLight *light;
  short cur_light, idx;
  float status;
  int count = 0;
  Xgl_boolean xglr_switches[VTK_MAX_LIGHTS];
  Xgl_color   light_color;

  // first get the lights and switched from the context
  xgl_object_get(this->Context,XGL_3D_CTX_LIGHTS, this->XglrLights);
  xgl_object_get(this->Context,XGL_3D_CTX_LIGHT_SWITCHES, xglr_switches);

  // update the ambient light light# 0
  light_color.rgb.r = this->Ambient[0];
  light_color.rgb.g = this->Ambient[1];
  light_color.rgb.b = this->Ambient[2];
  xgl_object_set(this->XglrLights[0],
		 XGL_LIGHT_TYPE, XGL_LIGHT_AMBIENT,
		 XGL_LIGHT_COLOR, &light_color,
		 NULL);

  // set all lights off except the ambient light
  xglr_switches[0] = TRUE;
  for (idx = 1; idx < VTK_MAX_LIGHTS; idx++)
    {
    xglr_switches[idx] = FALSE;
    }

  cur_light = 1;

  for (this->Lights.InitTraversal();
       (light = this->Lights.GetNextItem()); )
    {
    status = light->GetSwitch();

    // if the light is on then define it and bind it.
    // also make sure we still have room.
    if ((status > 0.0)&& (cur_light < VTK_MAX_LIGHTS))
      {
      light->Render((vtkRenderer *)this,cur_light);
      xglr_switches[cur_light] = TRUE;
      // increment the current light by one
      cur_light++;
      count++;
      }
    }

  // now update the context
  xgl_object_set(this->Context,
		 XGL_3D_CTX_LIGHT_SWITCHES, xglr_switches,
		 NULL);

  this->NumberOfLightsBound = cur_light;

  return count;
}

// Description:
// Concrete XGL render method.
void vtkXglrRenderer::Render(void)
{
  vtkXglrRenderWindow *temp;

  if (this->StartRenderMethod)
    {
    (*this->StartRenderMethod)(this->StartRenderMethodArg);
    }

  // update our Context first
  temp = (vtkXglrRenderWindow *)this->GetRenderWindow();
  this->Context = *(temp->GetContext());

  if ( this->TwoSidedLighting )
    {
    xgl_object_set(this->Context, XGL_3D_CTX_SURF_FACE_DISTINGUISH, FALSE, 0);
    }
  else
    {
    xgl_object_set(this->Context, XGL_3D_CTX_SURF_FACE_DISTINGUISH, TRUE, 0);
    }

  // update our Context first  // standard render method
  this->DoCameras();
  this->DoLights();
  this->DoActors();
  if (this->VolumeRenderer)
    {
    this->VolumeRenderer->Render((vtkRenderer *)this);
    }

  if (this->EndRenderMethod)
    {
    (*this->EndRenderMethod)(this->EndRenderMethodArg);
    }
}

void vtkXglrRenderer::PrintSelf(ostream& os, vtkIndent indent)
{
  this->vtkRenderer::PrintSelf(os,indent);

  os << indent << "Number Of Lights Bound: " <<
    this->NumberOfLightsBound << "\n";
}

<commit_msg>Added a vtkNewVolumeRenderer Render() call<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    XglrRen.cc
  Language:  C++
  Date:      04/20/95
  Version:   1.2

Copyright (c) 1993-1995 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include <math.h>
#include <iostream.h>
#include "vtkXglrProperty.hh"
#include "vtkXglrCamera.hh"
#include "vtkXglrLight.hh"
#include "vtkXglrRenderWindow.hh"
#include "vtkXglrRenderer.hh"
#include "vtkVolumeRenderer.hh"

vtkXglrRenderer::vtkXglrRenderer()
{
}

// Description:
// Ask actors to build and draw themselves.
int vtkXglrRenderer::UpdateActors()
{
  vtkActor *anActor;
  int count = 0;

  // loop through actors
  for (this->Actors.InitTraversal(); (anActor = this->Actors.GetNextItem()); )
    {
    // if it's invisible, we can skip the rest
    if (anActor->GetVisibility())
      {
      count++;
      anActor->Render((vtkRenderer *)this);
      }
    }
  return count;
}

// Description:
// Ask active camera to load its view matrix.
int vtkXglrRenderer::UpdateCameras ()
{
  // update the viewing transformation
  if (!this->ActiveCamera) return 0;

  this->ActiveCamera->Render((vtkRenderer *)this);
  return 1;
}

// Description:
// Ask lights to load themselves into graphics pipeline.
int vtkXglrRenderer::UpdateLights ()
{
  vtkLight *light;
  short cur_light, idx;
  float status;
  int count = 0;
  Xgl_boolean xglr_switches[VTK_MAX_LIGHTS];
  Xgl_color   light_color;

  // first get the lights and switched from the context
  xgl_object_get(this->Context,XGL_3D_CTX_LIGHTS, this->XglrLights);
  xgl_object_get(this->Context,XGL_3D_CTX_LIGHT_SWITCHES, xglr_switches);

  // update the ambient light light# 0
  light_color.rgb.r = this->Ambient[0];
  light_color.rgb.g = this->Ambient[1];
  light_color.rgb.b = this->Ambient[2];
  xgl_object_set(this->XglrLights[0],
		 XGL_LIGHT_TYPE, XGL_LIGHT_AMBIENT,
		 XGL_LIGHT_COLOR, &light_color,
		 NULL);

  // set all lights off except the ambient light
  xglr_switches[0] = TRUE;
  for (idx = 1; idx < VTK_MAX_LIGHTS; idx++)
    {
    xglr_switches[idx] = FALSE;
    }

  cur_light = 1;

  for (this->Lights.InitTraversal();
       (light = this->Lights.GetNextItem()); )
    {
    status = light->GetSwitch();

    // if the light is on then define it and bind it.
    // also make sure we still have room.
    if ((status > 0.0)&& (cur_light < VTK_MAX_LIGHTS))
      {
      light->Render((vtkRenderer *)this,cur_light);
      xglr_switches[cur_light] = TRUE;
      // increment the current light by one
      cur_light++;
      count++;
      }
    }

  // now update the context
  xgl_object_set(this->Context,
		 XGL_3D_CTX_LIGHT_SWITCHES, xglr_switches,
		 NULL);

  this->NumberOfLightsBound = cur_light;

  return count;
}

// Description:
// Concrete XGL render method.
void vtkXglrRenderer::Render(void)
{
  vtkXglrRenderWindow *temp;

  if (this->StartRenderMethod)
    {
    (*this->StartRenderMethod)(this->StartRenderMethodArg);
    }

  // update our Context first
  temp = (vtkXglrRenderWindow *)this->GetRenderWindow();
  this->Context = *(temp->GetContext());

  if ( this->TwoSidedLighting )
    {
    xgl_object_set(this->Context, XGL_3D_CTX_SURF_FACE_DISTINGUISH, FALSE, 0);
    }
  else
    {
    xgl_object_set(this->Context, XGL_3D_CTX_SURF_FACE_DISTINGUISH, TRUE, 0);
    }

  // update our Context first  // standard render method
  this->DoCameras();
  this->DoLights();
  this->DoActors();
  if (this->VolumeRenderer)
    {
    this->VolumeRenderer->Render((vtkRenderer *)this);
    }

  if (this->NewVolumeRenderer)
    {
    this->NewVolumeRenderer->Render((vtkRenderer *)this);
    }

  if (this->EndRenderMethod)
    {
    (*this->EndRenderMethod)(this->EndRenderMethodArg);
    }
}

void vtkXglrRenderer::PrintSelf(ostream& os, vtkIndent indent)
{
  this->vtkRenderer::PrintSelf(os,indent);

  os << indent << "Number Of Lights Bound: " <<
    this->NumberOfLightsBound << "\n";
}

<|endoftext|>


<commit_before>/**
 * @file
 * @author Jason Lingle
 * @brief Implementation of src/weapon/missile.hxx
 */

/*
 * missile.cxx
 *
 *  Created on: 07.03.2011
 *      Author: jason
 */

#include <cmath>
#include <vector>
#include <typeinfo>

#include <GL/gl.h>

#include "missile.hxx"
#include "src/sim/game_object.hxx"
#include "src/sim/game_field.hxx"
#include "src/background/explosion.hxx"
#include "src/sim/objdl.hxx"
#include "src/sim/blast.hxx"
#include "src/globals.hxx"
#include "src/sim/collision.hxx"
#include "src/secondary/light_trail.hxx"
#include "src/ship/ship.hxx"
#include "src/ship/cell/cell.hxx" //For STD_CELL_SZ
#include "src/graphics/vec.hxx"
#include "src/graphics/matops.hxx"
#include "src/graphics/shader.hxx"
#include "src/graphics/cmn_shaders.hxx"
#include "src/graphics/shader_loader.hxx"
#include "src/graphics/square.hxx"
#include "src/graphics/glhelp.hxx"

//All level-related constants based on level 1

#define LIFETIME 5000.0f
#define ACCEL_BIAS (0)
#define DAMAGE_MUL 2.0f
#define ACCELERATION 0.000002f //2 screen/sec/sec
//Lose 3% of speed per second
#define FRICTION 0.00003f
#define RADIUS (STD_CELL_SZ)
#define HOMING_THRESHHOLD 0.95f
#define SQRT2 1.4142136f
#define MAX_DIST 3.5f

using namespace std;

#ifndef AB_OPENGL_14
  struct MisUniform {
    float green;
  };
  #define UNIFORM_TYPE MisUniform
  #define VERTEX_TYPE shader::VertTexc
  DELAY_SHADER(missile)
    sizeof(VERTEX_TYPE),
    VATTRIB(vertex), VATTRIB(texCoord), NULL,
    true, UNIFLOAT(green), NULL
  END_DELAY_SHADER(static missileShader);
#endif /* not defined AB_OPENGL_14 */

Missile::Missile(GameField* field, int lvl, float x, float y, float vx,
                 float vy, Ship* par, GameObject* tgt)
: GameObject(field, x, y, vx, vy),
  explodeListeners(NULL),
  trail(NULL), target(tgt), parent(par),
  level(lvl), timeAlive(0), exploded(false),
  blame(par->blame),
  ax(0), ay(0), xdir(0), ydir(0)
{
  collisionBounds.push_back(&colrect);
  classification = GameObject::HeavyWeapon;
  colrect.radius = RADIUS;

  isExportable=true;
}

//Networking constructor
Missile::Missile(GameField* field, int lvl, float x, float y, float vx,
                 float vy, float ax_, float ay_, float ta)
: GameObject(field, x, y, vx, vy),
  explodeListeners(NULL),
  trail(NULL), target(NULL), parent(NULL),
  level(lvl), timeAlive(ta), exploded(false), blame(0xFFFFFF),
  ax(ax_), ay(ay_), xdir(0), ydir(0)
{
  isExportable=true;
  isRemote=true;
  includeInCollisionDetection=false;
  decorative=true;
}

Missile::~Missile() {
  //Remove any ExplodeListener chain attached
  if (explodeListeners)
    explodeListeners->prv = NULL;
}

bool Missile::update(float et) noth {
  x += vx*et;
  y += vy*et;
  timeAlive += et;
  if (timeAlive > LIFETIME && !isRemote) {
    explode(this);
    return false;
  }
  if (isRemote) {
    REMOTE_XYCK;
  }

  if (target.ref && currentVFrameLast && !isRemote) {
    GameObject* t=target.ref;
    //Acceleration increases until halfway through the life, then falls off
    //again, according to a sine curve.
    //For the purposes of this calculations, all times are increased by
    //ACCEL_BIAS
    float accel=ACCELERATION/level*sin((timeAlive+ACCEL_BIAS)*pi/
                                       (LIFETIME+ACCEL_BIAS));
    /*
    float dx = x-t->getX()+(vx-t->getVX())*512,
          dy = y-t->getY()+(vy-t->getVY())*512;
    float dist = sqrt(dx*dx + dy*dy);
    dx /= dist;
    dy /= dist;

    //Home in
    vx -= dx*accel*currentFrameTime;
    vy -= dy*accel*currentFrameTime;
    */
    float dx = t->getX()-x, dy = t->getY()-y;
    float dot = vx*dx + vy*dy;

    float speed = sqrt(vx*vx+vy*vy);
    float dist  = sqrt(dx*dx+dy*dy);
    float cross = vx*dy - vy*dx;
    float sign = (cross > 0? -1 : +1);
    ax = -sign*vy/speed*accel;
    ay = +sign*vx/speed*accel;
    if (dot/speed/dist > HOMING_THRESHHOLD || dot < 0) {
      ax = (ax*SQRT2 - SQRT2*dx/dist*accel)/2;
      ay = (ay*SQRT2 - SQRT2*dy/dist*accel)/2;
    }

    vx -= ax*currentFrameTime;
    vy -= ay*currentFrameTime;

    xdir = dx/dist*accel;
    ydir = dy/dist*accel;

    //Die if more than MAX_DIST from source, or if the source no longer exists
    if (!parent.ref) {
      explode(this);
      return false;
    }
    float pdx = x - parent.ref->getX();
    float pdy = y - parent.ref->getY();
    if (pdx*pdx + pdy*pdy > MAX_DIST*MAX_DIST) {
      explode(this);
      return false;
    }
  } else if (isRemote) {
    vx += ax*et;
    vy += ay*et;
  }
  if (EXPCLOSE(x,y) && !headless && currentVFrameLast
  &&  xdir != 0 && ydir != 0
  &&  (isRemote || target.ref)) {
    if (!trail.ref) {
      trail.assign(new LightTrail(field, 3000, 64, 4*RADIUS, RADIUS,
                                  0.8f, 0.8f, 1.0f, 1.0f,
                                  0.0f, -0.5f, -1.0f, -2.0f));
      field->add(trail.ref);
    }
    LightTrail* trail=(LightTrail*)this->trail.ref;
    trail->emit(x, y, vx-xdir*1000*level, vy-ydir*1000*level);
  }

  //Friction
  //vx -= vx*FRICTION*et/level;
  //vy -= vy*FRICTION*et/level;
  return true;
}

void Missile::draw() noth {
  #ifndef AB_OPENGL_14
    mPush();
    mTrans(x,y);
    mUScale(RADIUS);
    mTrans(-0.5f,-0.5f);
    MisUniform uni = { 1.0f - timeAlive/LIFETIME };
    square_graphic::bind();
    missileShader->activate(&uni);
    square_graphic::draw();
    mPop();
  #else
    glPushMatrix();
    glTranslatef(x, y, 0);
    gl32emu::setShaderEmulation(gl32emu::SE_quick);
    glColor3f(1.0f, 1.0f - timeAlive/LIFETIME, 0.0f);
    glBegin(GL_TRIANGLE_FAN);
    glVertex2f(0, 0);
    glColor3f(1.0f, 1.0f, 1.0f);
    for (int i=0; i<6; ++i)
      glVertex2f(RADIUS*cos(i/3.0f*pi), RADIUS*sin(i/3.0f*pi));
    glVertex2f(RADIUS, 0);
    glEnd();
    glPopMatrix();
  #endif /* AB_OPENGL_14 */
}

float Missile::getRadius() const noth {
  return RADIUS;
}

CollisionResult Missile::checkCollision(GameObject* go) noth {
  //Don't collide with other missiles
  if (go->getClassification() == HeavyWeapon
  &&  typeid(*go) == typeid(Missile)) return NoCollision;
  if (go != parent.ref && objectsCollide(this, go)) return YesCollision;
  return NoCollision;
}

bool Missile::collideWith(GameObject* go) noth {
  if (go != this) explode(go);
  return false;
}

const vector<CollisionRectangle*>* Missile::getCollisionBounds() noth {
  colrect.vertices[0].first = x-RADIUS;
  colrect.vertices[0].second= y-RADIUS;
  colrect.vertices[1].first = x+RADIUS;
  colrect.vertices[1].second= y-RADIUS;
  colrect.vertices[2].first = x+RADIUS;
  colrect.vertices[2].second= y+RADIUS;
  colrect.vertices[3].first = x-RADIUS;
  colrect.vertices[3].second= y+RADIUS;
  return &collisionBounds;
}

void Missile::explode(GameObject* ref) noth {
  if (!ref) ref=this;
  if (!isRemote)
    field->inject(new Blast(field, blame, x, y, STD_CELL_SZ*3.5f,
                            level*DAMAGE_MUL, true, RADIUS));
  if (EXPCLOSE(x,y))
    field->add(new Explosion(field, Explosion::Simple, 0.8f, 0.8f, 1.0f,
                             sqrt((float)level)*2.5f, level/2000.0f,
                             1000, x, y, ref->getVX(), ref->getVY()));

  //Reset velocities to that of ref so that the explosion's velocity
  //can be communicated over the network.
  vx = ref->getVX();
  vy = ref->getVY();

  exploded=true;
  for (ExplodeListener<Missile>* l = explodeListeners; l; l = l->nxt)
    l->exploded(this);
}
<commit_msg>Increase maximum distance for missiles to 4.5 screens.<commit_after>/**
 * @file
 * @author Jason Lingle
 * @brief Implementation of src/weapon/missile.hxx
 */

/*
 * missile.cxx
 *
 *  Created on: 07.03.2011
 *      Author: jason
 */

#include <cmath>
#include <vector>
#include <typeinfo>

#include <GL/gl.h>

#include "missile.hxx"
#include "src/sim/game_object.hxx"
#include "src/sim/game_field.hxx"
#include "src/background/explosion.hxx"
#include "src/sim/objdl.hxx"
#include "src/sim/blast.hxx"
#include "src/globals.hxx"
#include "src/sim/collision.hxx"
#include "src/secondary/light_trail.hxx"
#include "src/ship/ship.hxx"
#include "src/ship/cell/cell.hxx" //For STD_CELL_SZ
#include "src/graphics/vec.hxx"
#include "src/graphics/matops.hxx"
#include "src/graphics/shader.hxx"
#include "src/graphics/cmn_shaders.hxx"
#include "src/graphics/shader_loader.hxx"
#include "src/graphics/square.hxx"
#include "src/graphics/glhelp.hxx"

//All level-related constants based on level 1

#define LIFETIME 5000.0f
#define ACCEL_BIAS (0)
#define DAMAGE_MUL 2.0f
#define ACCELERATION 0.000002f //2 screen/sec/sec
//Lose 3% of speed per second
#define FRICTION 0.00003f
#define RADIUS (STD_CELL_SZ)
#define HOMING_THRESHHOLD 0.95f
#define SQRT2 1.4142136f
#define MAX_DIST 4.5f

using namespace std;

#ifndef AB_OPENGL_14
  struct MisUniform {
    float green;
  };
  #define UNIFORM_TYPE MisUniform
  #define VERTEX_TYPE shader::VertTexc
  DELAY_SHADER(missile)
    sizeof(VERTEX_TYPE),
    VATTRIB(vertex), VATTRIB(texCoord), NULL,
    true, UNIFLOAT(green), NULL
  END_DELAY_SHADER(static missileShader);
#endif /* not defined AB_OPENGL_14 */

Missile::Missile(GameField* field, int lvl, float x, float y, float vx,
                 float vy, Ship* par, GameObject* tgt)
: GameObject(field, x, y, vx, vy),
  explodeListeners(NULL),
  trail(NULL), target(tgt), parent(par),
  level(lvl), timeAlive(0), exploded(false),
  blame(par->blame),
  ax(0), ay(0), xdir(0), ydir(0)
{
  collisionBounds.push_back(&colrect);
  classification = GameObject::HeavyWeapon;
  colrect.radius = RADIUS;

  isExportable=true;
}

//Networking constructor
Missile::Missile(GameField* field, int lvl, float x, float y, float vx,
                 float vy, float ax_, float ay_, float ta)
: GameObject(field, x, y, vx, vy),
  explodeListeners(NULL),
  trail(NULL), target(NULL), parent(NULL),
  level(lvl), timeAlive(ta), exploded(false), blame(0xFFFFFF),
  ax(ax_), ay(ay_), xdir(0), ydir(0)
{
  isExportable=true;
  isRemote=true;
  includeInCollisionDetection=false;
  decorative=true;
}

Missile::~Missile() {
  //Remove any ExplodeListener chain attached
  if (explodeListeners)
    explodeListeners->prv = NULL;
}

bool Missile::update(float et) noth {
  x += vx*et;
  y += vy*et;
  timeAlive += et;
  if (timeAlive > LIFETIME && !isRemote) {
    explode(this);
    return false;
  }
  if (isRemote) {
    REMOTE_XYCK;
  }

  if (target.ref && currentVFrameLast && !isRemote) {
    GameObject* t=target.ref;
    //Acceleration increases until halfway through the life, then falls off
    //again, according to a sine curve.
    //For the purposes of this calculations, all times are increased by
    //ACCEL_BIAS
    float accel=ACCELERATION/level*sin((timeAlive+ACCEL_BIAS)*pi/
                                       (LIFETIME+ACCEL_BIAS));
    /*
    float dx = x-t->getX()+(vx-t->getVX())*512,
          dy = y-t->getY()+(vy-t->getVY())*512;
    float dist = sqrt(dx*dx + dy*dy);
    dx /= dist;
    dy /= dist;

    //Home in
    vx -= dx*accel*currentFrameTime;
    vy -= dy*accel*currentFrameTime;
    */
    float dx = t->getX()-x, dy = t->getY()-y;
    float dot = vx*dx + vy*dy;

    float speed = sqrt(vx*vx+vy*vy);
    float dist  = sqrt(dx*dx+dy*dy);
    float cross = vx*dy - vy*dx;
    float sign = (cross > 0? -1 : +1);
    ax = -sign*vy/speed*accel;
    ay = +sign*vx/speed*accel;
    if (dot/speed/dist > HOMING_THRESHHOLD || dot < 0) {
      ax = (ax*SQRT2 - SQRT2*dx/dist*accel)/2;
      ay = (ay*SQRT2 - SQRT2*dy/dist*accel)/2;
    }

    vx -= ax*currentFrameTime;
    vy -= ay*currentFrameTime;

    xdir = dx/dist*accel;
    ydir = dy/dist*accel;

    //Die if more than MAX_DIST from source, or if the source no longer exists
    if (!parent.ref) {
      explode(this);
      return false;
    }
    float pdx = x - parent.ref->getX();
    float pdy = y - parent.ref->getY();
    if (pdx*pdx + pdy*pdy > MAX_DIST*MAX_DIST) {
      explode(this);
      return false;
    }
  } else if (isRemote) {
    vx += ax*et;
    vy += ay*et;
  }
  if (EXPCLOSE(x,y) && !headless && currentVFrameLast
  &&  xdir != 0 && ydir != 0
  &&  (isRemote || target.ref)) {
    if (!trail.ref) {
      trail.assign(new LightTrail(field, 3000, 64, 4*RADIUS, RADIUS,
                                  0.8f, 0.8f, 1.0f, 1.0f,
                                  0.0f, -0.5f, -1.0f, -2.0f));
      field->add(trail.ref);
    }
    LightTrail* trail=(LightTrail*)this->trail.ref;
    trail->emit(x, y, vx-xdir*1000*level, vy-ydir*1000*level);
  }

  //Friction
  //vx -= vx*FRICTION*et/level;
  //vy -= vy*FRICTION*et/level;
  return true;
}

void Missile::draw() noth {
  #ifndef AB_OPENGL_14
    mPush();
    mTrans(x,y);
    mUScale(RADIUS);
    mTrans(-0.5f,-0.5f);
    MisUniform uni = { 1.0f - timeAlive/LIFETIME };
    square_graphic::bind();
    missileShader->activate(&uni);
    square_graphic::draw();
    mPop();
  #else
    glPushMatrix();
    glTranslatef(x, y, 0);
    gl32emu::setShaderEmulation(gl32emu::SE_quick);
    glColor3f(1.0f, 1.0f - timeAlive/LIFETIME, 0.0f);
    glBegin(GL_TRIANGLE_FAN);
    glVertex2f(0, 0);
    glColor3f(1.0f, 1.0f, 1.0f);
    for (int i=0; i<6; ++i)
      glVertex2f(RADIUS*cos(i/3.0f*pi), RADIUS*sin(i/3.0f*pi));
    glVertex2f(RADIUS, 0);
    glEnd();
    glPopMatrix();
  #endif /* AB_OPENGL_14 */
}

float Missile::getRadius() const noth {
  return RADIUS;
}

CollisionResult Missile::checkCollision(GameObject* go) noth {
  //Don't collide with other missiles
  if (go->getClassification() == HeavyWeapon
  &&  typeid(*go) == typeid(Missile)) return NoCollision;
  if (go != parent.ref && objectsCollide(this, go)) return YesCollision;
  return NoCollision;
}

bool Missile::collideWith(GameObject* go) noth {
  if (go != this) explode(go);
  return false;
}

const vector<CollisionRectangle*>* Missile::getCollisionBounds() noth {
  colrect.vertices[0].first = x-RADIUS;
  colrect.vertices[0].second= y-RADIUS;
  colrect.vertices[1].first = x+RADIUS;
  colrect.vertices[1].second= y-RADIUS;
  colrect.vertices[2].first = x+RADIUS;
  colrect.vertices[2].second= y+RADIUS;
  colrect.vertices[3].first = x-RADIUS;
  colrect.vertices[3].second= y+RADIUS;
  return &collisionBounds;
}

void Missile::explode(GameObject* ref) noth {
  if (!ref) ref=this;
  if (!isRemote)
    field->inject(new Blast(field, blame, x, y, STD_CELL_SZ*3.5f,
                            level*DAMAGE_MUL, true, RADIUS));
  if (EXPCLOSE(x,y))
    field->add(new Explosion(field, Explosion::Simple, 0.8f, 0.8f, 1.0f,
                             sqrt((float)level)*2.5f, level/2000.0f,
                             1000, x, y, ref->getVX(), ref->getVY()));

  //Reset velocities to that of ref so that the explosion's velocity
  //can be communicated over the network.
  vx = ref->getVX();
  vy = ref->getVY();

  exploded=true;
  for (ExplodeListener<Missile>* l = explodeListeners; l; l = l->nxt)
    l->exploded(this);
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) Qxt Foundation. Some rights reserved.
**
** This file is part of the QxtWeb  module of the Qt eXTension library
**
** This library is free software; you can redistribute it and/or modify it
** under the terms of th Common Public License, version 1.0, as published by
** IBM.
**
** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
** FITNESS FOR A PARTICULAR PURPOSE.
**
** You should have received a copy of the CPL along with this file.
** See the LICENSE file and the cpl1.0.txt file included with the source
** distribution for more information. If you did not receive a copy of the
** license, contact the Qxt Foundation.
**
** <http://libqxt.org>  <foundation@libqxt.org>
**
****************************************************************************/
#include "qxtwebcore.h"
#include "qxtwebcore_p.h"

#include <QTimer>
#include <QUrl>
#include "qxtwebcontroller.h"
#include <QCoreApplication>
#include <QTcpSocket>
#include <QVariant>
#include <QtDebug>
#include <QUrl>
#include <ctime>

/*!
        \class QxtWebCore QxtWebCore
        \ingroup QxtWeb
        \brief qxtweb application core class. communicates, delegates, does all of the magic ;)

        QxtWebCore is the base class of your web application.
        it listens to the scgi protocoll

        construct one webcore object in the main function of your application.
        you must contruct it AFTER QCoreApplication and BEFORe any controllers.

        \code
        int main(int argc,char ** argv)
                {
                QCoreApplication  app(argc,argv);
                QxtWebCore core();
                core.listen(8080);
                QxtWebController controller("root");
                app.exec();
                }
        \endcode
*/

/*!
        \fn static QxtWebCore* instance();
        singleton accessor
        \fn static void send(QByteArray);
        Send data to the client. Use this rarely, but use it always when sending binary data such as images. \n
        normal text/html comunication should be done using the controllers echo() function \n
        note that after you called send the first time you cannot modify the header anymore \n
        sending may be ignored by the transport when there is no client currently handled
        \fn static QIODevice * socket();
        direct access to a iodevice for writing binary data. \n
        You shouldn't use that unless it's absolutly nessesary
        \fn static QxtError parseString(QByteArray str, post_t & POST);
        much like phps parse_string \n
        \fn static QByteArray readContent(int maxsize=5000);
        reads the content from the current socket if any has sent. \n
        returns an empty QByteArray on any error.  \n
        the content is cut at maxsize and not read from the socket.  \n
        FIXME:\warning: this function is BLOCKING.  while content is read from the client, no other requests can be handled.
        FIXME:\warning: due to paranoid timeouts this might not work for slow clients
 */

static QxtWebLegacyEngine * singleton_m=0;

//-----------------------interface----------------------------
QxtWebLegacyEngine::QxtWebLegacyEngine(QxtWebStatelessConnector * t):QObject()
{
    if (singleton_m)
        qFatal("you're trying to construct QxtWebCore twice!");
    singleton_m=this;
    sc=t;
    cc=0;
    connect(sc,SIGNAL(newConnection()),this,SLOT(incomming()));
}

QxtWebLegacyEngine::~QxtWebLegacyEngine()
{
    singleton_m=0;
}

void QxtWebLegacyEngine::send(QString a)
{
    Q_ASSERT(instance()->cc);
    instance()->cc->write(a.toUtf8());
}
void QxtWebLegacyEngine::header(QString a,QString b)
{
    Q_ASSERT(instance()->cc);
    instance()->cc->response().setValue(a,b);
}

QHttpRequestHeader &  QxtWebLegacyEngine::SERVER()
{
    Q_ASSERT(instance()->cc);
    return instance()->cc->request();
}

QIODevice * QxtWebLegacyEngine::socket()
{
    Q_ASSERT(instance()->cc);
    return instance()->cc;
}

void QxtWebLegacyEngine::redirect(QString l,int code)
{
     if(!instance()->cc)
        return;

    QByteArray loc =QUrl(l).toEncoded ();

    if (loc.isEmpty())
        loc="/";
    instance()->cc->response().setStatusLine(code);
    instance()->cc->response().setValue("location",loc);
    instance()->cc->write(QByteArray(""+loc+""));

}

QxtWebLegacyEngine * QxtWebLegacyEngine::instance()
{
    if (!singleton_m)
        qFatal("no QxtWebCore constructed");
    return singleton_m;
}

void QxtWebLegacyEngine::close()
{
     if(!instance()->cc)
        return;
    instance()->cc->close();
    delete instance()->cc;
    instance()->cc=0;
}

void QxtWebLegacyEngine::incomming()
{

    Q_ASSERT_X(!cc,Q_FUNC_INFO,"inconsistent state");

    if(!sc->hasPendingConnections())
        sc->waitForNewConnection(-1);

    while(sc->hasPendingConnections ())
    {
        cc=sc->nextPendingConnection();
        cc->waitForReadyRead(10000);
        qDebug("%i, %s -> %s",(int)time(NULL),qPrintable(SERVER().value("HTTP_HOST")),qPrintable(SERVER().path()));
        emit(request());

        ///--------------find controller ------------------
        QByteArray path="404";
        QStringList requestsplit = SERVER().path().split('/');
        if (requestsplit.count()>1)
        {
            path=requestsplit.at(1).toUtf8();
            if (path.trimmed().isEmpty())path="root";
        }
        else if (requestsplit.count()>0)
            path="root";

        ///--------------controller------------------

        QxtWebController * controller =qFindChild<QxtWebController *> (QCoreApplication::instance(), path );
        if (!controller)
        {
            header("Status","404");
            send("
404 Controller ");
            send(path);
            send(" not found
");
            close();
            qDebug("404 controller '%s' not found",path.constData());
            return;
        }

        int i=controller->invoke(cc);
        if (i!=0 && i!=2)
        {
            header("Status","404");
            send("
");
            send(QString::number(i));
            send("
Sorry,, that didn't work as expected. You might want to contact this systems administrator.");
        }
        if (i!=2) ///FIXME temporary solution for keepalive
            close();
    }
}

<commit_msg>finally removing that debug thing<commit_after>/****************************************************************************
**
** Copyright (C) Qxt Foundation. Some rights reserved.
**
** This file is part of the QxtWeb  module of the Qt eXTension library
**
** This library is free software; you can redistribute it and/or modify it
** under the terms of th Common Public License, version 1.0, as published by
** IBM.
**
** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
** FITNESS FOR A PARTICULAR PURPOSE.
**
** You should have received a copy of the CPL along with this file.
** See the LICENSE file and the cpl1.0.txt file included with the source
** distribution for more information. If you did not receive a copy of the
** license, contact the Qxt Foundation.
**
** <http://libqxt.org>  <foundation@libqxt.org>
**
****************************************************************************/
#include "qxtwebcore.h"
#include "qxtwebcore_p.h"

#include <QTimer>
#include <QUrl>
#include "qxtwebcontroller.h"
#include <QCoreApplication>
#include <QTcpSocket>
#include <QVariant>
#include <QtDebug>
#include <QUrl>
#include <ctime>

/*!
        \class QxtWebCore QxtWebCore
        \ingroup QxtWeb
        \brief qxtweb application core class. communicates, delegates, does all of the magic ;)

        QxtWebCore is the base class of your web application.
        it listens to the scgi protocoll

        construct one webcore object in the main function of your application.
        you must contruct it AFTER QCoreApplication and BEFORe any controllers.

        \code
        int main(int argc,char ** argv)
                {
                QCoreApplication  app(argc,argv);
                QxtWebCore core();
                core.listen(8080);
                QxtWebController controller("root");
                app.exec();
                }
        \endcode
*/

/*!
        \fn static QxtWebCore* instance();
        singleton accessor
        \fn static void send(QByteArray);
        Send data to the client. Use this rarely, but use it always when sending binary data such as images. \n
        normal text/html comunication should be done using the controllers echo() function \n
        note that after you called send the first time you cannot modify the header anymore \n
        sending may be ignored by the transport when there is no client currently handled
        \fn static QIODevice * socket();
        direct access to a iodevice for writing binary data. \n
        You shouldn't use that unless it's absolutly nessesary
        \fn static QxtError parseString(QByteArray str, post_t & POST);
        much like phps parse_string \n
        \fn static QByteArray readContent(int maxsize=5000);
        reads the content from the current socket if any has sent. \n
        returns an empty QByteArray on any error.  \n
        the content is cut at maxsize and not read from the socket.  \n
        FIXME:\warning: this function is BLOCKING.  while content is read from the client, no other requests can be handled.
        FIXME:\warning: due to paranoid timeouts this might not work for slow clients
 */

static QxtWebLegacyEngine * singleton_m=0;

//-----------------------interface----------------------------
QxtWebLegacyEngine::QxtWebLegacyEngine(QxtWebStatelessConnector * t):QObject()
{
    if (singleton_m)
        qFatal("you're trying to construct QxtWebCore twice!");
    singleton_m=this;
    sc=t;
    cc=0;
    connect(sc,SIGNAL(newConnection()),this,SLOT(incomming()));
}

QxtWebLegacyEngine::~QxtWebLegacyEngine()
{
    singleton_m=0;
}

void QxtWebLegacyEngine::send(QString a)
{
    Q_ASSERT(instance()->cc);
    instance()->cc->write(a.toUtf8());
}
void QxtWebLegacyEngine::header(QString a,QString b)
{
    Q_ASSERT(instance()->cc);
    instance()->cc->response().setValue(a,b);
}

QHttpRequestHeader &  QxtWebLegacyEngine::SERVER()
{
    Q_ASSERT(instance()->cc);
    return instance()->cc->request();
}

QIODevice * QxtWebLegacyEngine::socket()
{
    Q_ASSERT(instance()->cc);
    return instance()->cc;
}

void QxtWebLegacyEngine::redirect(QString l,int code)
{
     if(!instance()->cc)
        return;

    QByteArray loc =QUrl(l).toEncoded ();

    if (loc.isEmpty())
        loc="/";
    instance()->cc->response().setStatusLine(code);
    instance()->cc->response().setValue("location",loc);
    instance()->cc->write(QByteArray(""+loc+""));

}

QxtWebLegacyEngine * QxtWebLegacyEngine::instance()
{
    if (!singleton_m)
        qFatal("no QxtWebCore constructed");
    return singleton_m;
}

void QxtWebLegacyEngine::close()
{
     if(!instance()->cc)
        return;
    instance()->cc->close();
    delete instance()->cc;
    instance()->cc=0;
}

void QxtWebLegacyEngine::incomming()
{

    Q_ASSERT_X(!cc,Q_FUNC_INFO,"inconsistent state");

    if(!sc->hasPendingConnections())
        sc->waitForNewConnection(-1);

    while(sc->hasPendingConnections ())
    {
        cc=sc->nextPendingConnection();
        cc->waitForReadyRead(10000);
        emit(request());

        ///--------------find controller ------------------
        QByteArray path="404";
        QStringList requestsplit = SERVER().path().split('/');
        if (requestsplit.count()>1)
        {
            path=requestsplit.at(1).toUtf8();
            if (path.trimmed().isEmpty())path="root";
        }
        else if (requestsplit.count()>0)
            path="root";

        ///--------------controller------------------

        QxtWebController * controller =qFindChild<QxtWebController *> (QCoreApplication::instance(), path );
        if (!controller)
        {
            header("Status","404");
            send("
404 Controller ");
            send(path);
            send(" not found
");
            close();
            qDebug("404 controller '%s' not found",path.constData());
            return;
        }

        int i=controller->invoke(cc);
        if (i!=0 && i!=2)
        {
            header("Status","404");
            send("
");
            send(QString::number(i));
            send("
Sorry,, that didn't work as expected. You might want to contact this systems administrator.");
        }
        if (i!=2) ///FIXME temporary solution for keepalive
            close();
    }
}

<|endoftext|>


<commit_before>#include <glog/logging.h>
#include <websocket_pool.h>
#include <transport/ws_connection.h>
#include <util.h>
#include <iostream>
#include <driver.h>
#include <expression.h>

namespace {
  const size_t k_queue_capacity = 1000000;
  const float  k_ws_send_interval = 1;

  std::function<bool(const Event&)> filter_query(const std::string uri) {

    std::string index;
    std::map<std::string, std::string> params;

    query_fn_t true_query = [](const Event&) -> bool { return true; };

    if (!parse_uri(uri, index, params)) {
      VLOG(1) << "failed to parse uri";
      return true_query;
    }

    query_context query_ctx;
    queryparser::driver driver(query_ctx);

    if (driver.parse_string(params["query"], "query")) {
      return  query_ctx.evaluate();
    } else {
      return true_query;
    }
  }
}

using namespace std::placeholders;

websocket_pool::websocket_pool(size_t thread_num, pub_sub & pubsub)
:
  tcp_pool_(thread_num,
            {},
            std::bind(&websocket_pool::create_conn, this, _1, _2, _3),
            std::bind(&websocket_pool::data_ready, this, _1, _2),
            k_ws_send_interval,
            std::bind(&websocket_pool::timer, this, _1)),
  thread_event_queues_(0),
  fd_event_queues_(thread_num)
{

  for (size_t i = 0; i < thread_num; i++) {

    auto queue = std::make_shared<event_queue_t>();
    queue->set_capacity(k_queue_capacity);

    thread_event_queues_.push_back(queue);

    all_events_fn_ = pubsub.subscribe("index", queue);

  }

  tcp_pool_.start_threads();
}

void websocket_pool::add_client(int fd) {
  tcp_pool_.add_client(fd);
}

void websocket_pool::notify_event(const Event & event) {
  for (auto & queue: thread_event_queues_) {
    queue->push(event);
  }
}

void websocket_pool::create_conn(int fd, async_loop & loop,
                                 tcp_connection & conn)
{
  auto conn_data = std::make_tuple(ws_connection(conn),
                           std::function<bool(const Event&)>{},
                           std::queue<std::string>{});

  fd_event_queues_[loop.id()].insert({fd, std::move(conn_data)});
}

void websocket_pool::data_ready(async_fd & async, tcp_connection & tcp_conn) {

  auto & fd_conn = fd_event_queues_[async.loop().id()];

  auto it = fd_conn.find(async.fd());
  CHECK(it != fd_conn.end()) << "couldn't find fd";

  auto & ws_conn = std::get<0>(it->second);
  ws_conn.callback(async);

  if (tcp_conn.close_connection) {
    VLOG(1) << "Closing websocket connection";
    fd_conn.erase(it);
    return;
  }

  // Set query_fn if websocket is ready
  auto & query_fn = std::get<1>(it->second);
  if (!query_fn && (ws_conn.state() | ws_connection::k_read_frame_header)) {

    query_fn = filter_query(ws_conn.uri());

    auto & str_queue = std::get<2>(it->second);
    for (const auto & event : all_events_fn_()) {

      if (query_fn(event)) {
        str_queue.push(event_to_json(event));
      }
    }

  }
}

void websocket_pool::timer(async_loop & loop) {
  size_t loop_id =  loop.id();
  VLOG(3) << "loop_id: " << loop_id;
  auto event_queue = thread_event_queues_[loop_id];

  while (!event_queue->empty()) {

    Event event;
    if (!event_queue->try_pop(event)) {
      continue;
    }

    auto str_event = event_to_json(event);

    for (auto & fd_conn : fd_event_queues_[loop_id]) {

      auto query_fn = std::get<1>(fd_conn.second);

      if (!query_fn) {
        VLOG(3) << "query_fn not defined";
        continue;
      }

      if (!query_fn(event)) {
        continue;
      }

      auto ws_conn = std::get<0>(fd_conn.second);
      auto & str_queue = std::get<2>(fd_conn.second);

      if (str_queue.empty() && ws_conn.send_frame(str_event)) {
        loop.set_fd_mode(fd_conn.first, async_fd::readwrite);
        continue;
      }

      if (str_queue.size() > k_queue_capacity) {
        VLOG(1) << "Per connection event queue is full";
      } else {
        str_queue.push(str_event);
      }

    }
  }

  for (auto & fd_conn : fd_event_queues_[loop_id]) {

    auto ws_conn = std::get<0>(fd_conn.second);
    auto & str_queue = std::get<2>(fd_conn.second);

    while (!str_queue.empty()) {

      std::string str = str_queue.front();

      if (!ws_conn.send_frame(str)) {
        VLOG(1) << "buffer full to send frame";
        break;
      }

      str_queue.pop();

      loop.set_fd_mode(fd_conn.first, async_fd::readwrite);
    }
  }
}
<commit_msg>Set socket mode in ws dataready<commit_after>#include <glog/logging.h>
#include <websocket_pool.h>
#include <transport/ws_connection.h>
#include <util.h>
#include <iostream>
#include <driver.h>
#include <expression.h>

namespace {
  const size_t k_queue_capacity = 1000000;
  const float  k_ws_send_interval = 1;

  std::function<bool(const Event&)> filter_query(const std::string uri) {

    std::string index;
    std::map<std::string, std::string> params;

    query_fn_t true_query = [](const Event&) -> bool { return true; };

    if (!parse_uri(uri, index, params)) {
      VLOG(1) << "failed to parse uri";
      return true_query;
    }

    query_context query_ctx;
    queryparser::driver driver(query_ctx);

    if (driver.parse_string(params["query"], "query")) {
      return  query_ctx.evaluate();
    } else {
      return true_query;
    }
  }

  async_fd::mode conn_to_mode(const tcp_connection & conn) {
    if (conn.pending_read() && conn.pending_write()) {
      return async_fd::readwrite;
    } else if (conn.pending_read()) {
      return async_fd::read;
    } else if (conn.pending_write()) {
      return async_fd::write;
    } else {
      return async_fd::none;
    }
  }

}

using namespace std::placeholders;

websocket_pool::websocket_pool(size_t thread_num, pub_sub & pubsub)
:
  tcp_pool_(thread_num,
            {},
            std::bind(&websocket_pool::create_conn, this, _1, _2, _3),
            std::bind(&websocket_pool::data_ready, this, _1, _2),
            k_ws_send_interval,
            std::bind(&websocket_pool::timer, this, _1)),
  thread_event_queues_(0),
  fd_event_queues_(thread_num)
{

  for (size_t i = 0; i < thread_num; i++) {

    auto queue = std::make_shared<event_queue_t>();
    queue->set_capacity(k_queue_capacity);

    thread_event_queues_.push_back(queue);

    all_events_fn_ = pubsub.subscribe("index", queue);

  }

  tcp_pool_.start_threads();
}

void websocket_pool::add_client(int fd) {
  tcp_pool_.add_client(fd);
}

void websocket_pool::notify_event(const Event & event) {
  for (auto & queue: thread_event_queues_) {
    queue->push(event);
  }
}

void websocket_pool::create_conn(int fd, async_loop & loop,
                                 tcp_connection & conn)
{
  auto conn_data = std::make_tuple(ws_connection(conn),
                           std::function<bool(const Event&)>{},
                           std::queue<std::string>{});

  fd_event_queues_[loop.id()].insert({fd, std::move(conn_data)});
}

void websocket_pool::data_ready(async_fd & async, tcp_connection & tcp_conn) {

  auto & fd_conn = fd_event_queues_[async.loop().id()];

  auto it = fd_conn.find(async.fd());
  CHECK(it != fd_conn.end()) << "couldn't find fd";

  auto & ws_conn = std::get<0>(it->second);
  ws_conn.callback(async);

  async.set_mode(conn_to_mode(tcp_conn));

  if (tcp_conn.close_connection) {
    VLOG(1) << "Closing websocket connection";
    fd_conn.erase(it);
    return;
  }

  // Set query_fn if websocket is ready
  auto & query_fn = std::get<1>(it->second);
  if (!query_fn && (ws_conn.state() | ws_connection::k_read_frame_header)) {

    query_fn = filter_query(ws_conn.uri());

    auto & str_queue = std::get<2>(it->second);
    for (const auto & event : all_events_fn_()) {

      if (query_fn(event)) {
        str_queue.push(event_to_json(event));
      }
    }

  }
}

void websocket_pool::timer(async_loop & loop) {
  size_t loop_id =  loop.id();
  VLOG(3) << "loop_id: " << loop_id;
  auto event_queue = thread_event_queues_[loop_id];

  while (!event_queue->empty()) {

    Event event;
    if (!event_queue->try_pop(event)) {
      continue;
    }

    auto str_event = event_to_json(event);

    for (auto & fd_conn : fd_event_queues_[loop_id]) {

      auto query_fn = std::get<1>(fd_conn.second);

      if (!query_fn) {
        VLOG(3) << "query_fn not defined";
        continue;
      }

      if (!query_fn(event)) {
        continue;
      }

      auto ws_conn = std::get<0>(fd_conn.second);
      auto & str_queue = std::get<2>(fd_conn.second);

      if (str_queue.empty() && ws_conn.send_frame(str_event)) {
        loop.set_fd_mode(fd_conn.first, async_fd::readwrite);
        continue;
      }

      if (str_queue.size() > k_queue_capacity) {
        VLOG(1) << "Per connection event queue is full";
      } else {
        str_queue.push(str_event);
      }

    }
  }

  for (auto & fd_conn : fd_event_queues_[loop_id]) {

    auto ws_conn = std::get<0>(fd_conn.second);
    auto & str_queue = std::get<2>(fd_conn.second);

    while (!str_queue.empty()) {

      std::string str = str_queue.front();

      if (!ws_conn.send_frame(str)) {
        VLOG(1) << "buffer full to send frame";
        break;
      }

      str_queue.pop();

      loop.set_fd_mode(fd_conn.first, async_fd::readwrite);
    }
  }
}
<|endoftext|>


<commit_before>/**
 * \file Runner.cpp
 * \date Apr 1, 2010
 * \author samael
 */

#include <iostream>
#include <string>
#include <typeinfo>
#include <cstdio>
#include <unistd.h>
#include <sys/time.h>
#include <UDPSocket.h>
#include <TLVReaderWriter.h>
#include <HelperMacros.h>
#include "Runner.h"
#include "D2MCE.h"
#include "AbstractWorkerActor.h"

using namespace std;
using namespace cml;

namespace wfe
{

void Runner::run(unsigned short runner_port, unsigned short master_port,
		const string &appname)
{
	HostAddress addr;
	PINFO("Waiting for master notification.");
	if (!(addr = getMasterAddr(runner_port)).isValid()) {
		PERR << "Runner fails, exit now.\n";
		return;
	}

	TCPSocket sock;
	PINFO("Connection to the master node");
	if (!connectToMaster(&sock, addr, master_port)) {
		PERR << "Runner fails, exit now.\n";
		return;
	}
	PINFO(((string)"Connected with address = " + sock.currentAddress().toString()).c_str());

#ifdef ENABLE_D2MCE
	srand((unsigned)sock.currentAddress().toInetAddr());
	usleep((rand() % 30) * 33000); // sleep 0 ~ 1s, granularity 33ms.
	if (!joinGroup(appname)) {
		PERR << "Runner fails, exit now.\n";
		return;
	}
#endif

	runnerLoop(&sock);
}

/**
 * \internal
 * Listen and wait for master broadcasting a ADD_MASTER message.
 */
HostAddress Runner::getMasterAddr(unsigned short runner_port)
{
	UDPSocket usock;
	TLVReaderWriter udprw(&usock);
	TLVMessage *inmsg;
	HostAddress inaddr;
	unsigned short inport;

	usock.passiveOpen(runner_port);
	if (!(inmsg = dynamic_cast<TLVMessage *>(udprw.recvfrom(&inaddr, &inport)))) {
		PERR << "Invalid incoming message.\n";
		return HostAddress();
	}

	if (inmsg->command() != TLVMessage::HELLO_MASTER) {
		PERR << "Expected command " <<
				TLVMessage::CommandString[TLVMessage::HELLO_MASTER] <<
				" but got " << TLVMessage::CommandString[inmsg->command()] <<
				".\n";
		return HostAddress();
	}

	delete inmsg;

	return inaddr;
}

/**
 * \internal
 * Connect to the master node.
 */
bool Runner::connectToMaster(TCPSocket *sock, const HostAddress &addr,
		unsigned short master_port)
{
	TLVReaderWriter tcprw(sock);
	if (!sock->activeOpen(addr, master_port)) {
		PERR << "Unable to connect to the master node.\n";
		return false;
	}

	TLVMessage outmsg(TLVMessage::HELLO_SLAVE);
	return tcprw.write(outmsg);
}

/**
 * \internal
 * Join the computing group.
 */
bool Runner::joinGroup(const string &appname)
{
//	if (!D2MCE::instance()->join(appname)) {
//		fprintf(stderr, "Runner::run(): Unable to join group.\n");
//		return false;
//	}
	D2MCE::instance()->join(appname);
	printf("Info: %s: %d, %d nodes inside the group, node id = %d.\n",
			__PRETTY_FUNCTION__, __LINE__,
			D2MCE::instance()->getNumberOfNodes(),
			D2MCE::instance()->nodeId());

	return true;
}

/**
 * \internal
 * Process the command received.
 */
bool Runner::processCommand(TLVMessage *cmd)
{
	if (cmd->command() == TLVMessage::RUN_ACTOR) {
		AbstractWorkerActor *actor;
		if (!(actor = dynamic_cast<AbstractWorkerActor *>(cmd->parameter()))) {
			PERR << "Invalid parameter.\n";
			return false;
		}
		actor->setup();
		do {
			/// TODO: Add the power-aware load balancing feature.
			actor->prefire();
			actor->fire();
			actor->postfire();
		} while (actor->testfire());
		actor->wrapup();
		delete actor;
	} else {
		PERR << "Unexpected command \"" <<
				TLVMessage::CommandString[cmd->command()] << "\".\n";
		return false;
	}
	return true;
}

/**
 * \internal
 * Core loop of runner.
 */
void Runner::runnerLoop(TCPSocket *sock)
{
	TLVReaderWriter tcprw(sock);
	ITLVObject *inobj;
	TLVMessage *inmsg = NULL;

	while ((inobj = tcprw.read())) {
		if (!(inmsg = dynamic_cast<TLVMessage *>(inobj))) {
			PERR << "Invalid incoming message.\n";
			delete inobj;
		} else {
			if (!processCommand(inmsg)) {
				PERR << "One command failed to execute.\n";
			}
			delete inmsg;
		}
	}
}

}
<commit_msg><commit_after>/**
 * \file Runner.cpp
 * \date Apr 1, 2010
 * \author samael
 */

#include <iostream>
#include <string>
#include <typeinfo>
#include <cstdio>
#include <unistd.h>
#include <sys/time.h>
#include <UDPSocket.h>
#include <TLVReaderWriter.h>
#include <HelperMacros.h>
#include "Runner.h"
#include "D2MCE.h"
#include "AbstractWorkerActor.h"

using namespace std;
using namespace cml;

namespace wfe
{

void Runner::run(unsigned short runner_port, unsigned short master_port,
		const string &appname)
{
	HostAddress addr;
	PINFO("Waiting for master notification.");
	if (!(addr = getMasterAddr(runner_port)).isValid()) {
		PERR << "Runner fails, exit now.\n";
		return;
	}

	TCPSocket sock;
	PINFO("Connection to the master node");
	if (!connectToMaster(&sock, addr, master_port)) {
		PERR << "Runner fails, exit now.\n";
		return;
	}
	PINFO(((string)"Connected with address = " + sock.currentAddress().toString()).c_str());

#ifdef ENABLE_D2MCE
	// Random back-off.
	srand((unsigned)sock.currentAddress().toInetAddr());
	usleep((rand() % 30) * 33000); // sleep 0 ~ 1s, granularity 33ms.
	// Join.
	if (!joinGroup(appname)) {
		PERR << "Runner fails, exit now.\n";
		return;
	}
#endif

	runnerLoop(&sock);
}

/**
 * \internal
 * Listen and wait for master broadcasting a ADD_MASTER message.
 */
HostAddress Runner::getMasterAddr(unsigned short runner_port)
{
	UDPSocket usock;
	TLVReaderWriter udprw(&usock);
	TLVMessage *inmsg;
	HostAddress inaddr;
	unsigned short inport;

	usock.passiveOpen(runner_port);
	if (!(inmsg = dynamic_cast<TLVMessage *>(udprw.recvfrom(&inaddr, &inport)))) {
		PERR << "Invalid incoming message.\n";
		return HostAddress();
	}

	if (inmsg->command() != TLVMessage::HELLO_MASTER) {
		PERR << "Expected command " <<
				TLVMessage::CommandString[TLVMessage::HELLO_MASTER] <<
				" but got " << TLVMessage::CommandString[inmsg->command()] <<
				".\n";
		return HostAddress();
	}

	delete inmsg;

	return inaddr;
}

/**
 * \internal
 * Connect to the master node.
 */
bool Runner::connectToMaster(TCPSocket *sock, const HostAddress &addr,
		unsigned short master_port)
{
	TLVReaderWriter tcprw(sock);
	if (!sock->activeOpen(addr, master_port)) {
		PERR << "Unable to connect to the master node.\n";
		return false;
	}

	TLVMessage outmsg(TLVMessage::HELLO_SLAVE);
	return tcprw.write(outmsg);
}

/**
 * \internal
 * Join the computing group.
 */
bool Runner::joinGroup(const string &appname)
{
//	if (!D2MCE::instance()->join(appname)) {
//		fprintf(stderr, "Runner::run(): Unable to join group.\n");
//		return false;
//	}
	D2MCE::instance()->join(appname);
	printf("Info: %s: %d, %d nodes inside the group, node id = %d.\n",
			__PRETTY_FUNCTION__, __LINE__,
			D2MCE::instance()->getNumberOfNodes(),
			D2MCE::instance()->nodeId());

	return true;
}

/**
 * \internal
 * Process the command received.
 */
bool Runner::processCommand(TLVMessage *cmd)
{
	if (cmd->command() == TLVMessage::RUN_ACTOR) {
		AbstractWorkerActor *actor;
		if (!(actor = dynamic_cast<AbstractWorkerActor *>(cmd->parameter()))) {
			PERR << "Invalid parameter.\n";
			return false;
		}
		actor->setup();
		do {
			/// TODO: Add the power-aware load balancing feature.
			actor->prefire();
			actor->fire();
			actor->postfire();
		} while (actor->testfire());
		actor->wrapup();
		delete actor;
	} else {
		PERR << "Unexpected command \"" <<
				TLVMessage::CommandString[cmd->command()] << "\".\n";
		return false;
	}
	return true;
}

/**
 * \internal
 * Core loop of runner.
 */
void Runner::runnerLoop(TCPSocket *sock)
{
	TLVReaderWriter tcprw(sock);
	ITLVObject *inobj;
	TLVMessage *inmsg = NULL;

	while ((inobj = tcprw.read())) {
		if (!(inmsg = dynamic_cast<TLVMessage *>(inobj))) {
			PERR << "Invalid incoming message.\n";
			delete inobj;
		} else {
			if (!processCommand(inmsg)) {
				PERR << "One command failed to execute.\n";
			}
			delete inmsg;
		}
	}
}

}
<|endoftext|>


<commit_before>#include <Beacon.h>
#include "HCIDumpParser.h"

void HCIDumpParser::processHCI(HCIDumpCommand& parseCommand) {
    HCIDumpParser::parseCommand = &parseCommand;
    string clientID(parseCommand.getClientID());
    if(clientID.empty())
        clientID = parseCommand.getScannerID();
    publisher = MsgPublisher::create(parseCommand.getPubType(), parseCommand.getBrokerURL(), clientID, "", "");
    if(!parseCommand.isSkipPublish()) {
        publisher->setUseTopics(!parseCommand.isUseQueues());
        publisher->setDestinationName(parseCommand.getDestinationName());
        publisher->start(parseCommand.isAsyncMode());
    }
    else {
        printf("Skipping publish of parsed beacons\n");
    }
    if(batchCount > 0) {
        publisher->setUseTransactions(true);
        printf("Enabled transactions\n");
    }

    char cdev = parseCommand.getHciDev().at(parseCommand.getHciDev().size()-1);
    int device = cdev - '0';
    scan_frames(device,  beacon_event_callback);
}

void HCIDumpParser::beaconEvent(const beacon_info *info) {
    Beacon beacon(parseCommand->getScannerID(), info->uuid, info->code, info->manufacturer, info->major, info->minor,
    info->power, info->calibrated_power, info->rssi, info->time);
    vector<byte> msg = beacon.toByteMsg();
    // Check for heartbeat
    bool isHeartbeat = scannerUUID.compare(info->uuid) == 0;
    if(isHeartbeat)
        beacon.setMessageType(BeconEventType::SCANNER_HEARTBEAT);
    if(!parseCommand->isSkipPublish()) {
        if(batchCount > 0) {
            // Overwrite last event if it is a heartbeat and this is as well
            if(isHeartbeat && events.size() > 0 && events.back().getMessageType() == BeconEventType::SCANNER_HEARTBEAT)
                events.pop_back();
            events.push_back(beacon);
            if(shouldSendMessages()) {
#ifdef PRINT_DEBUG
printf("Sending msg batch, size=%d\n", events.size());
#endif
                publisher->publish(events);
                events.clear();
            } else {
#ifdef PRINT_DEBUG
printf("Batched msg, size=%d\n", events.size());
#endif
            }
        } else if(isHeartbeat) {
#ifdef PRINT_DEBUG
printf("Sending heartbeat\n");
#endif
            publisher->publishStatus(beacon);
        } else {
#ifdef PRINT_DEBUG
printf("Sending msg\n");
#endif
            publisher->publish("", MqttQOS::AT_MOST_ONCE, msg.data(), msg.size());
        }
    }
    else {
        const char *info = isHeartbeat ? "heartbeat" : "event";
        printf("Parsed(%s): %s\n", info, beacon.toString().c_str());
    }
}
void HCIDumpParser::cleanup() {
    if(publisher != nullptr)
        publisher->stop();
    publisher = nullptr;
}
<commit_msg>Move the setting of the transacted flag to before the publisher start<commit_after>#include <Beacon.h>
#include "HCIDumpParser.h"

void HCIDumpParser::processHCI(HCIDumpCommand& parseCommand) {
    HCIDumpParser::parseCommand = &parseCommand;
    string clientID(parseCommand.getClientID());
    if(clientID.empty())
        clientID = parseCommand.getScannerID();
    publisher = MsgPublisher::create(parseCommand.getPubType(), parseCommand.getBrokerURL(), clientID, "", "");
    if(!parseCommand.isSkipPublish()) {
        publisher->setUseTopics(!parseCommand.isUseQueues());
        publisher->setDestinationName(parseCommand.getDestinationName());
        if(batchCount > 0) {
            publisher->setUseTransactions(true);
            printf("Enabled transactions\n");
        }
        publisher->start(parseCommand.isAsyncMode());
    }
    else {
        printf("Skipping publish of parsed beacons\n");
    }

    char cdev = parseCommand.getHciDev().at(parseCommand.getHciDev().size()-1);
    int device = cdev - '0';
    scan_frames(device,  beacon_event_callback);
}

void HCIDumpParser::beaconEvent(const beacon_info *info) {
    Beacon beacon(parseCommand->getScannerID(), info->uuid, info->code, info->manufacturer, info->major, info->minor,
    info->power, info->calibrated_power, info->rssi, info->time);
    vector<byte> msg = beacon.toByteMsg();
    // Check for heartbeat
    bool isHeartbeat = scannerUUID.compare(info->uuid) == 0;
    if(isHeartbeat)
        beacon.setMessageType(BeconEventType::SCANNER_HEARTBEAT);
    if(!parseCommand->isSkipPublish()) {
        if(batchCount > 0) {
            // Overwrite last event if it is a heartbeat and this is as well
            if(isHeartbeat && events.size() > 0 && events.back().getMessageType() == BeconEventType::SCANNER_HEARTBEAT)
                events.pop_back();
            events.push_back(beacon);
            if(shouldSendMessages()) {
#ifdef PRINT_DEBUG
printf("Sending msg batch, size=%d\n", events.size());
#endif
                publisher->publish(events);
                events.clear();
            } else {
#ifdef PRINT_DEBUG
printf("Batched msg, size=%d\n", events.size());
#endif
            }
        } else if(isHeartbeat) {
#ifdef PRINT_DEBUG
printf("Sending heartbeat\n");
#endif
            publisher->publishStatus(beacon);
        } else {
#ifdef PRINT_DEBUG
printf("Sending msg\n");
#endif
            publisher->publish("", MqttQOS::AT_MOST_ONCE, msg.data(), msg.size());
        }
    }
    else {
        const char *info = isHeartbeat ? "heartbeat" : "event";
        printf("Parsed(%s): %s\n", info, beacon.toString().c_str());
    }
}
void HCIDumpParser::cleanup() {
    if(publisher != nullptr)
        publisher->stop();
    publisher = nullptr;
}
<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*! @file
    @brief  波形描画テンプレート・クラス
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2017, 2018 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include <vector>
#include "gl_fw/glutils.hpp"

namespace view {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  render_waves template class
		@param[in]	UNIT	波形の型
		@param[in]	LIMIT	最大波形数
		@param[in]	CHN		チャネル数
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <typename UNIT, uint32_t LIMIT, uint32_t CHN>
	class render_waves {
	public:
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief  チャネル描画パラメーター
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		struct chr_param {
			img::rgba8	color_;		///< 描画色
			vtx::ipos	offset_;	///< オフセット
			float		gain_;		///< 垂直ゲイン（電圧）

			bool		update_;	///< 描画の更新「true」

			chr_param() : color_(img::rgba8(255, 255)),
				offset_(0), gain_(1.0f), update_(false)
			{ }
		};

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief  インフォメーション描画パラメーター
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		class info_param {
		public:
			img::rgba8	grid_color_;	///< グリッド・カラー
			int32_t		grid_step_;		///< グリッド・ステップ
			uint16_t	grid_stipple_;	///< グリッド・破線パターン
			bool		grid_enable_;	///< グリッド有効

			img::rgba8	time_color_;	///< 時間軸カラー
			int32_t		time_org_;		///< 時間軸開始
			int32_t		time_len_;		///< 時間軸長さ
			uint16_t	time_stipple_;	///< 時間軸破線パターン
			bool		time_enable_;	///< 時間軸有効
//			bool		time_anime_;	///< 時間軸アニメーション

			img::rgba8	volt_color_;	///< 電圧軸カラー
			int32_t		volt_org_;		///< 電圧軸開始
			int32_t		volt_len_;		///< 電圧軸長さ
			uint16_t	volt_stipple_;	///< 電圧軸破線パターン
			bool		volt_enable_;	///< 電圧軸有効
//			bool		volt_anime_;	///< 電圧軸アニメーション

		private:
			vtx::sposs	grid_;
			vtx::sposs	time_;
			vtx::sposs	volt_;
			vtx::ipos	size_;

			uint32_t	count_;

			static void rotate_(uint16_t& bits) {
				auto mod = bits & 0x8000;
				bits <<= 1;
				if(mod) bits |= 1;
			}

		public:
			info_param() : grid_color_(img::rgba8(255, 255, 255, 96)), grid_step_(30),
				grid_stipple_(0b1111000011110000), grid_enable_(true),

				time_color_(img::rgba8(255, 255, 128, 192)),
				time_org_(0), time_len_(0),
				time_stipple_(0b1110110011101100), time_enable_(true),

				volt_color_(img::rgba8(128, 255, 128, 192)),
				volt_org_(0), volt_len_(0),
				volt_stipple_(0b1110110011101100), volt_enable_(true),
				grid_(), time_(), volt_(), size_(), count_(0)
			{ }

			void build(const vtx::ipos& size)
			{
				if(size == size_) return;
				size_ = size;

				grid_.clear();
				for(int h = 0; h < size.x; h += grid_step_) {  // |||
					grid_.push_back(vtx::spos(h, 0));
					grid_.push_back(vtx::spos(h, size.y));
				}
				for(int v = 0; v < size.y; v += grid_step_) {  // ---
					grid_.push_back(vtx::spos(0, v));
					grid_.push_back(vtx::spos(size.x, v));
				}

				time_.clear();
				time_.push_back(vtx::spos(0, 0));
				time_.push_back(vtx::spos(0, size.y));

				volt_.clear();
				volt_.push_back(vtx::spos(0, 0));
				volt_.push_back(vtx::spos(size.x, 0));
			}

			void render()
			{
				glEnable(GL_LINE_STIPPLE);
				if(!grid_.empty() && grid_enable_) {
					glLineStipple(1, grid_stipple_);
					gl::glColor(grid_color_);
					gl::draw_lines(grid_);
				}
				if(time_enable_) {
					glLineStipple(1, time_stipple_);
					glPushMatrix();
					gl::glTranslate(time_org_, 0);
					gl::glColor(time_color_);
					gl::draw_lines(time_);
					gl::glTranslate(time_len_, 0);
					gl::draw_lines(time_);
					glPopMatrix();
				}
				if(volt_enable_) {
					glLineStipple(1, volt_stipple_);
					glPushMatrix();
					gl::glTranslate(0, volt_org_);
					gl::glColor(volt_color_);
					gl::draw_lines(volt_);
					gl::glTranslate(0, volt_len_);
					gl::draw_lines(volt_);
					glPopMatrix();
				}
				if(count_ > 0) {
					--count_;
				} else {
					rotate_(time_stipple_);
					rotate_(volt_stipple_);
					count_ = 3;
				}
				glDisable(GL_LINE_STIPPLE);
			}
		};

	private:
		typedef std::vector<UNIT> UNITS;

		struct ch_t {
			chr_param	param_;
			uint32_t	tstep_;
			UNITS		units_;
			vtx::sposs	lines_;

			ch_t() : param_(), tstep_(0), units_(), lines_()
			{ }
		};

		info_param	info_;

		ch_t		ch_[CHN];
		double		div_;

		vtx::ipos	win_size_;

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
		*/
		//-----------------------------------------------------------------//
		render_waves() : ch_{ }, div_(0.0), win_size_(0) { }

		//-----------------------------------------------------------------//
		/*!
			@brief  波形の最大数を取得
			@return 波形の最大数
		*/
		//-----------------------------------------------------------------//
		uint32_t size() const { return LIMIT; }

		//-----------------------------------------------------------------//
		/*!
			@brief  パラメーターを取得
			@param[in]	ch	チャネル
			@return パラメーター
		*/
		//-----------------------------------------------------------------//
		const chr_param& get_param(uint32_t ch) const
		{
			if(ch >= CHN) {
				static chr_param p;
				return p;
			}
			return ch_[ch].param_;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  パラメーターを参照
			@param[in]	ch	チャネル
			@return パラメーター
		*/
		//-----------------------------------------------------------------//
		chr_param& at_param(uint32_t ch)
		{
			if(ch >= CHN) {
				static chr_param p;
				return p;
			}
			return ch_[ch].param_;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  情報パラメーターを取得
			@return 情報パラメーター
		*/
		//-----------------------------------------------------------------//
		const info_param& get_info() const {
			return info_;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  情報パラメーターを参照
			@return 情報パラメーター
		*/
		//-----------------------------------------------------------------//
		info_param& at_info() {
			return info_;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  波形生成
		*/
		//-----------------------------------------------------------------//
		void create_buffer()
		{
			for(int i = 0; i < CHN; ++i) {
				ch_[i].units_.resize(size());
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  テスト波形生成
			@param[in]	frq		周波数 [Hz]
		*/
		//-----------------------------------------------------------------//
		void build_sin(double frq)
		{
#if 0
			for(uint32_t i = 0; i < units_.size(); ++i) {
//				double t = 1.0 / frq;
				double t = 1.0 / 1024.0;
				units_[i] = 32768 - static_cast<UNIT>(sin(2.0 * vtx::get_pi<double>() * t * i) * 32767.0);
			}
#endif
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  波形コピー
			@param[in]	ch		チャネル
			@param[in]	src		波形ソース
			@param[in]	len		波形数
		*/
		//-----------------------------------------------------------------//
		void copy(uint32_t ch, const UNIT* src, uint32_t len)
		{
			if(len > ch_[ch].units_.size()) len = ch_[ch].units_.size();
			for(uint32_t i = 0; i < len; ++i) {
				ch_[ch].units_[i] = *src++;
			}
			ch_[ch].param_.update_ = true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  レンダリング
   			@param[in]	size	描画サイズ（ピクセル）
			@param[in]	step	時間軸ステップ（65536を1.0）
		*/
		//-----------------------------------------------------------------//
		void render(const vtx::ipos& size, uint32_t tstep)
		{
			bool update_win = win_size_ != size;
			win_size_ = size;
			for(uint32_t n = 0; n < CHN; ++n) {
				ch_t& t = ch_[n];
				bool update = update_win;
				if(t.units_.empty()) update = false;
				else {
					if(t.lines_.size() != size.x) {
						t.lines_.resize(size.x);
					}
					if(t.tstep_ != tstep) {
						t.tstep_ = tstep;
						update = true;
					}
				}
				int mod_x = 0;
				if(update || t.param_.update_) {
					float gain = t.param_.gain_;
					uint32_t tsc = t.param_.offset_.x * tstep;
					for(uint32_t i = 0; i < size.x; ++i) {
						uint32_t idx = (tsc >> 16) % t.units_.size();
						float v = static_cast<float>(t.units_[idx]);
						v -= 32768.0f;
						t.lines_[i] = vtx::spos(i, v * -gain);
						tsc += tstep;
					}
					t.param_.update_ = false;
				}
				if(!t.lines_.empty()) {
					glPushMatrix();
					gl::glTranslate(mod_x, t.param_.offset_.y);
					gl::glColor(t.param_.color_);
					gl::draw_line_strip(t.lines_);
					glPopMatrix();
				}
			}

			info_.build(size);

			info_.render();
		}
	};
}
<commit_msg>update: enable/disable renderring<commit_after>#pragma once
//=====================================================================//
/*! @file
    @brief  波形描画テンプレート・クラス
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2017, 2018 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include <vector>
#include "gl_fw/glutils.hpp"

namespace view {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  render_waves template class
		@param[in]	UNIT	波形の型
		@param[in]	LIMIT	最大波形数
		@param[in]	CHN		チャネル数
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <typename UNIT, uint32_t LIMIT, uint32_t CHN>
	class render_waves {
	public:
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief  チャネル描画パラメーター
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		struct chr_param {
			img::rgba8	color_;		///< 描画色
			vtx::ipos	offset_;	///< オフセット
			float		gain_;		///< 垂直ゲイン（電圧）

			bool		update_;	///< 描画の更新「true」
			bool		render_;	///< 描画しない場合「false」

			chr_param() : color_(img::rgba8(255, 255)),
				offset_(0), gain_(1.0f), update_(false), render_(true)
			{ }
		};

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief  インフォメーション描画パラメーター
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		class info_param {
		public:
			img::rgba8	grid_color_;	///< グリッド・カラー
			int32_t		grid_step_;		///< グリッド・ステップ
			uint16_t	grid_stipple_;	///< グリッド・破線パターン
			bool		grid_enable_;	///< グリッド有効

			img::rgba8	time_color_;	///< 時間軸カラー
			int32_t		time_org_;		///< 時間軸開始
			int32_t		time_len_;		///< 時間軸長さ
			uint16_t	time_stipple_;	///< 時間軸破線パターン
			bool		time_enable_;	///< 時間軸有効
//			bool		time_anime_;	///< 時間軸アニメーション

			img::rgba8	volt_color_;	///< 電圧軸カラー
			int32_t		volt_org_;		///< 電圧軸開始
			int32_t		volt_len_;		///< 電圧軸長さ
			uint16_t	volt_stipple_;	///< 電圧軸破線パターン
			bool		volt_enable_;	///< 電圧軸有効
//			bool		volt_anime_;	///< 電圧軸アニメーション

		private:
			vtx::sposs	grid_;
			vtx::sposs	time_;
			vtx::sposs	volt_;
			vtx::ipos	size_;

			uint32_t	count_;

			static void rotate_(uint16_t& bits) {
				auto mod = bits & 0x8000;
				bits <<= 1;
				if(mod) bits |= 1;
			}

		public:
			info_param() : grid_color_(img::rgba8(255, 255, 255, 96)), grid_step_(30),
				grid_stipple_(0b1111000011110000), grid_enable_(true),

				time_color_(img::rgba8(255, 255, 128, 192)),
				time_org_(0), time_len_(0),
				time_stipple_(0b1110110011101100), time_enable_(true),

				volt_color_(img::rgba8(128, 255, 128, 192)),
				volt_org_(0), volt_len_(0),
				volt_stipple_(0b1110110011101100), volt_enable_(true),
				grid_(), time_(), volt_(), size_(), count_(0)
			{ }

			void build(const vtx::ipos& size)
			{
				if(size == size_) return;
				size_ = size;

				grid_.clear();
				for(int h = 0; h < size.x; h += grid_step_) {  // |||
					grid_.push_back(vtx::spos(h, 0));
					grid_.push_back(vtx::spos(h, size.y));
				}
				for(int v = 0; v < size.y; v += grid_step_) {  // ---
					grid_.push_back(vtx::spos(0, v));
					grid_.push_back(vtx::spos(size.x, v));
				}

				time_.clear();
				time_.push_back(vtx::spos(0, 0));
				time_.push_back(vtx::spos(0, size.y));

				volt_.clear();
				volt_.push_back(vtx::spos(0, 0));
				volt_.push_back(vtx::spos(size.x, 0));
			}

			void render()
			{
				glEnable(GL_LINE_STIPPLE);
				if(!grid_.empty() && grid_enable_) {
					glLineStipple(1, grid_stipple_);
					gl::glColor(grid_color_);
					gl::draw_lines(grid_);
				}
				if(time_enable_) {
					glLineStipple(1, time_stipple_);
					glPushMatrix();
					gl::glTranslate(time_org_, 0);
					gl::glColor(time_color_);
					gl::draw_lines(time_);
					gl::glTranslate(time_len_, 0);
					gl::draw_lines(time_);
					glPopMatrix();
				}
				if(volt_enable_) {
					glLineStipple(1, volt_stipple_);
					glPushMatrix();
					gl::glTranslate(0, volt_org_);
					gl::glColor(volt_color_);
					gl::draw_lines(volt_);
					gl::glTranslate(0, volt_len_);
					gl::draw_lines(volt_);
					glPopMatrix();
				}
				if(count_ > 0) {
					--count_;
				} else {
					rotate_(time_stipple_);
					rotate_(volt_stipple_);
					count_ = 3;
				}
				glDisable(GL_LINE_STIPPLE);
			}
		};

	private:
		typedef std::vector<UNIT> UNITS;

		struct ch_t {
			chr_param	param_;
			uint32_t	tstep_;
			UNITS		units_;
			vtx::sposs	lines_;

			ch_t() : param_(), tstep_(0), units_(), lines_()
			{ }
		};

		info_param	info_;

		ch_t		ch_[CHN];
		double		div_;

		vtx::ipos	win_size_;

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
		*/
		//-----------------------------------------------------------------//
		render_waves() : ch_{ }, div_(0.0), win_size_(0) { }

		//-----------------------------------------------------------------//
		/*!
			@brief  波形の最大数を取得
			@return 波形の最大数
		*/
		//-----------------------------------------------------------------//
		uint32_t size() const { return LIMIT; }

		//-----------------------------------------------------------------//
		/*!
			@brief  パラメーターを取得
			@param[in]	ch	チャネル
			@return パラメーター
		*/
		//-----------------------------------------------------------------//
		const chr_param& get_param(uint32_t ch) const
		{
			if(ch >= CHN) {
				static chr_param p;
				return p;
			}
			return ch_[ch].param_;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  パラメーターを参照
			@param[in]	ch	チャネル
			@return パラメーター
		*/
		//-----------------------------------------------------------------//
		chr_param& at_param(uint32_t ch)
		{
			if(ch >= CHN) {
				static chr_param p;
				return p;
			}
			return ch_[ch].param_;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  情報パラメーターを取得
			@return 情報パラメーター
		*/
		//-----------------------------------------------------------------//
		const info_param& get_info() const {
			return info_;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  情報パラメーターを参照
			@return 情報パラメーター
		*/
		//-----------------------------------------------------------------//
		info_param& at_info() {
			return info_;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  波形生成
		*/
		//-----------------------------------------------------------------//
		void create_buffer()
		{
			for(int i = 0; i < CHN; ++i) {
				ch_[i].units_.resize(size());
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  テスト波形生成
			@param[in]	frq		周波数 [Hz]
		*/
		//-----------------------------------------------------------------//
		void build_sin(double frq)
		{
#if 0
			for(uint32_t i = 0; i < units_.size(); ++i) {
//				double t = 1.0 / frq;
				double t = 1.0 / 1024.0;
				units_[i] = 32768 - static_cast<UNIT>(sin(2.0 * vtx::get_pi<double>() * t * i) * 32767.0);
			}
#endif
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  波形コピー
			@param[in]	ch		チャネル
			@param[in]	src		波形ソース
			@param[in]	len		波形数
		*/
		//-----------------------------------------------------------------//
		void copy(uint32_t ch, const UNIT* src, uint32_t len)
		{
			if(len > ch_[ch].units_.size()) len = ch_[ch].units_.size();
			for(uint32_t i = 0; i < len; ++i) {
				ch_[ch].units_[i] = *src++;
			}
			ch_[ch].param_.update_ = true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  レンダリング
   			@param[in]	size	描画サイズ（ピクセル）
			@param[in]	step	時間軸ステップ（65536を1.0）
		*/
		//-----------------------------------------------------------------//
		void render(const vtx::ipos& size, uint32_t tstep)
		{
			bool update_win = win_size_ != size;
			win_size_ = size;
			for(uint32_t n = 0; n < CHN; ++n) {
				ch_t& t = ch_[n];
				if(!t.param_.render_) continue;

				bool update = update_win;
				if(t.units_.empty()) update = false;
				else {
					if(t.lines_.size() != size.x) {
						t.lines_.resize(size.x);
					}
					if(t.tstep_ != tstep) {
						t.tstep_ = tstep;
						update = true;
					}
				}
				int mod_x = 0;
				if(update || t.param_.update_) {
					float gain = t.param_.gain_;
					uint32_t tsc = t.param_.offset_.x * tstep;
					for(uint32_t i = 0; i < size.x; ++i) {
						uint32_t idx = (tsc >> 16) % t.units_.size();
						float v = static_cast<float>(t.units_[idx]);
						v -= 32768.0f;
						t.lines_[i] = vtx::spos(i, v * -gain);
						tsc += tstep;
					}
					t.param_.update_ = false;
				}
				if(!t.lines_.empty()) {
					glPushMatrix();
					gl::glTranslate(mod_x, t.param_.offset_.y);
					gl::glColor(t.param_.color_);
					gl::draw_line_strip(t.lines_);
					glPopMatrix();
				}
			}

			info_.build(size);

			info_.render();
		}
	};
}
<|endoftext|>