<commit_before>/*
    Crystal Space utility library: string class
    Copyright (C) 1999,2000 by Andrew Zabolotny <bit@eltech.ru>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

extern "C" {
#include <ctype.h>
#include <stdarg.h>
}
#include "cssysdef.h"
#include "csutil/csstring.h"
#include "csutil/snprintf.h"

csString::~csString ()
{
  Free ();
}

void csString::Free ()
  {
  if (Data)
  {
    delete[] Data;
    Data = 0;
    Size = 0;
    MaxSize = 0;
  }
}

void csString::SetCapacity (size_t NewSize)
{
  NewSize++; // Plus one for implicit null byte.
  if (NewSize <= MaxSize)
    return;
  MaxSize = NewSize;

  char* buff = new char[MaxSize];
  if (Data == 0 || Size == 0)
    buff[0] = '\0';
  else
    memcpy(buff, Data, Size + 1);

  if (Data)
    delete[] Data;
  Data = buff;
}

csString &csString::Reclaim()
{
  if (Size == 0)
    Free();
  else
  {
    CS_ASSERT(Data != 0);
    MaxSize = Size + 1; // Plus one for implicit null byte.
    char* s = new char[MaxSize];
    memcpy(s, Data, MaxSize);
    delete[] Data;
    Data = s;
  }
  return *this;
}

csString &csString::Truncate (size_t iPos)
{
  if (iPos < Size)
  {
    Size = iPos;
    Data [Size] = '\0';
  }
  return *this;
}

csString &csString::DeleteAt (size_t iPos, size_t iCount)
{
#ifdef CS_DEBUG
  if (iPos >= Size || iPos + iCount > Size)
    STR_FATAL (("Tried to delete characters beyond the end of the string!\n"))
#endif
  if (iPos + iCount < Size)
    memmove(Data + iPos, Data + iPos + iCount, Size - (iPos + iCount));
  Size -= iCount;
  Data[Size] = '\0';
  return *this;
}

csString &csString::Insert (size_t iPos, const csString &iStr)
{
#ifdef CS_DEBUG
  if (iPos > Size)
    STR_FATAL (("Inserting `%s' beyond end of string `%s' at position %lu\n",
      iStr.GetData (), Data ? Data : "<null>", (unsigned long)iPos))
#endif

  if (Data == 0 || iPos == Size)
    return Append (iStr);

  size_t const sl = iStr.Length ();
  size_t const NewSize = sl + Size;
  SetCapacity (NewSize);
  memmove (Data + iPos + sl, Data + iPos, Size - iPos + 1); // Also move null.
  memcpy (Data + iPos, iStr.GetData (), sl);
  Size = NewSize;
  return *this;
}

csString &csString::Insert (size_t iPos, const char iChar)
{
  csString s(iChar);
  return Insert(iPos, s);
}

csString &csString::Overwrite (size_t iPos, const csString &iStr)
{
#ifdef CS_DEBUG
  if (iPos > Size)
    STR_FATAL (("Overwriting `%s' beyond end of string `%s' at position %lu\n",
      iStr.GetData (), Data ? Data : "<null>", (unsigned long)iPos))
#endif

  if (Data == 0 || iPos == Size)
    return Append (iStr);

  size_t const sl = iStr.Length ();
  size_t const NewSize = iPos + sl;
  SetCapacity (NewSize);
  memcpy (Data + iPos, iStr.GetData (), sl + 1); // Also copy null terminator.
  Size = NewSize;
  return *this;
}

csString &csString::Append (const csString &iStr, size_t iCount)
{
  return Append(iStr.GetData(), iCount);
}

csString &csString::Append (const char *iStr, size_t iCount)
{
  if (iStr == 0)
    return *this;
  if (iCount == (size_t)-1)
    iCount = strlen (iStr);
  if (iCount == 0)
    return *this;

  size_t const NewSize = Size + iCount;
  SetCapacity (NewSize);
  memcpy (Data + Size, iStr, iCount);
  Size = NewSize;
  Data [Size] = '\0';
  return *this;
}

csString &csString::LTrim()
{
  size_t i;
  for (i = 0; i < Size; i++)
    if (!isspace (Data[i]))
      break;
  if (i > 0)
    DeleteAt (0, i);
  return *this;
}

csString &csString::RTrim()
{
  if (Size > 0)
  {
    int i;
    for (i = Size - 1; i >= 0; i--)
      if (!isspace (Data[i]))
        break;
    if (i < Size - 1)
      Truncate(i + 1);
  }
  return *this;
}

csString &csString::Trim()
{
  return LTrim().RTrim();
}

csString &csString::Collapse()
{
  if (Size > 0)
  {
    char const* src = Data;
    char const* slim = Data + Size;
    char* dst = Data;
    bool saw_white = false;
    for ( ; src < slim; src++)
    {
      char const c = *src;
      if (isspace(c))
        saw_white = true;
      else
      {
        if (saw_white && dst > Data)
          *dst++ = ' ';
        *dst++ = c;
        saw_white = false;
      }
    }
    Size = dst - Data;
    Data[Size] = '\0';
  }
  return *this;
}

csString &csString::Format(const char *format, ...)
{
  va_list args;
  va_start(args, format);

  if (Data == 0) // Ensure that backing-store exists prior to vsnprintf().
    SetCapacity(255);

  int rc;
  while (1)
  {
    rc = cs_vsnprintf(Data, MaxSize, format, args);
    // Buffer was big enough for entire string?
    if (rc >= 0 && rc < MaxSize)
      break;
    // Some vsnprintf()s return -1 on failure, others return desired capacity.
    if (rc >= 0)
      SetCapacity(rc); // SetCapacity() ensures room for null byte.
    else
      SetCapacity(MaxSize * 2 - 1);
  }

  Size = rc;
  va_end(args);
  return *this;

}

#define STR_FORMAT(TYPE,FMT,SZ) \
csString csString::Format (TYPE v) \
{ char s[SZ]; cs_snprintf (s, SZ, #FMT, v); return csString ().Append (s); }
  STR_FORMAT(short, %hd, 32)
  STR_FORMAT(unsigned short, %hu, 32)
  STR_FORMAT(int, %d, 32)
  STR_FORMAT(unsigned int, %u, 32)
  STR_FORMAT(long, %ld, 32)
  STR_FORMAT(unsigned long, %lu, 32)
  STR_FORMAT(float, %g, 64)
  STR_FORMAT(double, %g, 64)
#undef STR_FORMAT

#define STR_FORMAT_INT(TYPE,FMT) \
csString csString::Format (TYPE v, int width, int prec/*=0*/) \
{ char s[64], s1[64]; \
  cs_snprintf (s1, sizeof(s1), "%%%d.%d"#FMT, width, prec); \
  cs_snprintf (s, sizeof(s), s1, v); \
  return csString ().Append (s); }
  STR_FORMAT_INT(short, hd)
  STR_FORMAT_INT(unsigned short, hu)
  STR_FORMAT_INT(int, d)
  STR_FORMAT_INT(unsigned int, u)
  STR_FORMAT_INT(long, ld)
  STR_FORMAT_INT(unsigned long, lu)
#undef STR_FORMAT_INT

#define STR_FORMAT_FLOAT(TYPE) \
csString csString::Format (TYPE v, int width, int prec/*=6*/) \
{ char s[64], s1[64]; \
  cs_snprintf (s1, sizeof(s1), "%%%d.%dg", width, prec); \
  cs_snprintf (s, sizeof(s), s1, v); \
  return csString ().Append (s); }
  STR_FORMAT_FLOAT(float)
  STR_FORMAT_FLOAT(double)
#undef STR_FORMAT_FLOAT

csString &csString::PadLeft (size_t iNewSize, char iChar)
{
  if (iNewSize > Size)
  {
    SetCapacity (iNewSize);
    const size_t toInsert = iNewSize - Size;
    memmove (Data + toInsert, Data, Size + 1); // Also move null terminator.
    for (size_t x = 0; x < toInsert; x++)
      Data [x] = iChar;
    Size = iNewSize;
  }
  return *this;
}

csString csString::AsPadLeft (size_t iNewSize, char iChar)
{
  csString newStr = Clone ();
  newStr.PadLeft (iChar, iNewSize);
  return newStr;
}

#define STR_PADLEFT(TYPE) \
csString csString::PadLeft (TYPE v, size_t iNewSize, char iChar) \
{ csString newStr; return newStr.Append (v).PadLeft (iNewSize, iChar); }
  STR_PADLEFT(const csString&)
  STR_PADLEFT(const char*)
  STR_PADLEFT(char)
  STR_PADLEFT(unsigned char)
  STR_PADLEFT(short)
  STR_PADLEFT(unsigned short)
  STR_PADLEFT(int)
  STR_PADLEFT(unsigned int)
  STR_PADLEFT(long)
  STR_PADLEFT(unsigned long)
  STR_PADLEFT(float)
  STR_PADLEFT(double)
#if !defined(CS_USE_FAKE_BOOL_TYPE)
  STR_PADLEFT(bool)
#endif
#undef STR_PADLEFT

csString& csString::PadRight (size_t iNewSize, char iChar)
{
  if (iNewSize > Size)
  {
    SetCapacity (iNewSize);
    for (size_t x = Size; x < iNewSize; x++)
      Data [x] = iChar;
    Size = iNewSize;
    Data [Size] = '\0';
  }
  return *this;
}

csString csString::AsPadRight (size_t iNewSize, char iChar)
{
  csString newStr = Clone ();
  newStr.PadRight (iChar, iNewSize);
  return newStr;
}

#define STR_PADRIGHT(TYPE) \
csString csString::PadRight (TYPE v, size_t iNewSize, char iChar) \
{ csString newStr; return newStr.Append (v).PadRight (iNewSize, iChar); }
  STR_PADRIGHT(const csString&)
  STR_PADRIGHT(const char*)
  STR_PADRIGHT(char)
  STR_PADRIGHT(unsigned char)
  STR_PADRIGHT(short)
  STR_PADRIGHT(unsigned short)
  STR_PADRIGHT(int)
  STR_PADRIGHT(unsigned int)
  STR_PADRIGHT(long)
  STR_PADRIGHT(unsigned long)
  STR_PADRIGHT(float)
  STR_PADRIGHT(double)
#if !defined(CS_USE_FAKE_BOOL_TYPE)
  STR_PADRIGHT(bool)
#endif
#undef STR_PADRIGHT

csString& csString::PadCenter (size_t iNewSize, char iChar)
{
  if (iNewSize > Size)
  {
    SetCapacity (iNewSize);
    const size_t toInsert = iNewSize - Size;
    const size_t halfInsert = toInsert / 2;
    if (Size > 0)
      memmove (Data + halfInsert, Data, Size);
    size_t x;
    for (x = 0; x < halfInsert; x++)
      Data [x] = iChar;
    for (x = halfInsert + Size; x < iNewSize; x++)
      Data [x] = iChar;
    Size = iNewSize;
    Data [Size] = '\0';
  }
  return *this;
}

csString csString::AsPadCenter (size_t iNewSize, char iChar)
{
  csString newStr = Clone ();
  newStr.PadCenter (iChar, iNewSize);
  return newStr;
}

#define STR_PADCENTER(TYPE) \
csString csString::PadCenter (TYPE v, size_t iNewSize, char iChar) \
{ csString newStr; return newStr.Append (v).PadCenter (iNewSize, iChar); }
  STR_PADCENTER(const csString&)
  STR_PADCENTER(const char*)
  STR_PADCENTER(char)
  STR_PADCENTER(unsigned char)
  STR_PADCENTER(short)
  STR_PADCENTER(unsigned short)
  STR_PADCENTER(int)
  STR_PADCENTER(unsigned int)
  STR_PADCENTER(long)
  STR_PADCENTER(unsigned long)
  STR_PADCENTER(float)
  STR_PADCENTER(double)
#if !defined(CS_USE_FAKE_BOOL_TYPE)
  STR_PADCENTER(bool)
#endif
#undef STR_PADCENTER
<commit_msg>Fixed a couple compilation warnings regarding "signed vs. unsigned" comparisions which were reported by a more strict compiler.<commit_after>/*
    Crystal Space utility library: string class
    Copyright (C) 1999,2000 by Andrew Zabolotny <bit@eltech.ru>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

extern "C" {
#include <ctype.h>
#include <stdarg.h>
}
#include "cssysdef.h"
#include "csutil/csstring.h"
#include "csutil/snprintf.h"

csString::~csString ()
{
  Free ();
}

void csString::Free ()
  {
  if (Data)
  {
    delete[] Data;
    Data = 0;
    Size = 0;
    MaxSize = 0;
  }
}

void csString::SetCapacity (size_t NewSize)
{
  NewSize++; // Plus one for implicit null byte.
  if (NewSize <= MaxSize)
    return;
  MaxSize = NewSize;

  char* buff = new char[MaxSize];
  if (Data == 0 || Size == 0)
    buff[0] = '\0';
  else
    memcpy(buff, Data, Size + 1);

  if (Data)
    delete[] Data;
  Data = buff;
}

csString &csString::Reclaim()
{
  if (Size == 0)
    Free();
  else
  {
    CS_ASSERT(Data != 0);
    MaxSize = Size + 1; // Plus one for implicit null byte.
    char* s = new char[MaxSize];
    memcpy(s, Data, MaxSize);
    delete[] Data;
    Data = s;
  }
  return *this;
}

csString &csString::Truncate (size_t iPos)
{
  if (iPos < Size)
  {
    Size = iPos;
    Data [Size] = '\0';
  }
  return *this;
}

csString &csString::DeleteAt (size_t iPos, size_t iCount)
{
#ifdef CS_DEBUG
  if (iPos >= Size || iPos + iCount > Size)
    STR_FATAL (("Tried to delete characters beyond the end of the string!\n"))
#endif
  if (iPos + iCount < Size)
    memmove(Data + iPos, Data + iPos + iCount, Size - (iPos + iCount));
  Size -= iCount;
  Data[Size] = '\0';
  return *this;
}

csString &csString::Insert (size_t iPos, const csString &iStr)
{
#ifdef CS_DEBUG
  if (iPos > Size)
    STR_FATAL (("Inserting `%s' beyond end of string `%s' at position %lu\n",
      iStr.GetData (), Data ? Data : "<null>", (unsigned long)iPos))
#endif

  if (Data == 0 || iPos == Size)
    return Append (iStr);

  size_t const sl = iStr.Length ();
  size_t const NewSize = sl + Size;
  SetCapacity (NewSize);
  memmove (Data + iPos + sl, Data + iPos, Size - iPos + 1); // Also move null.
  memcpy (Data + iPos, iStr.GetData (), sl);
  Size = NewSize;
  return *this;
}

csString &csString::Insert (size_t iPos, const char iChar)
{
  csString s(iChar);
  return Insert(iPos, s);
}

csString &csString::Overwrite (size_t iPos, const csString &iStr)
{
#ifdef CS_DEBUG
  if (iPos > Size)
    STR_FATAL (("Overwriting `%s' beyond end of string `%s' at position %lu\n",
      iStr.GetData (), Data ? Data : "<null>", (unsigned long)iPos))
#endif

  if (Data == 0 || iPos == Size)
    return Append (iStr);

  size_t const sl = iStr.Length ();
  size_t const NewSize = iPos + sl;
  SetCapacity (NewSize);
  memcpy (Data + iPos, iStr.GetData (), sl + 1); // Also copy null terminator.
  Size = NewSize;
  return *this;
}

csString &csString::Append (const csString &iStr, size_t iCount)
{
  return Append(iStr.GetData(), iCount);
}

csString &csString::Append (const char *iStr, size_t iCount)
{
  if (iStr == 0)
    return *this;
  if (iCount == (size_t)-1)
    iCount = strlen (iStr);
  if (iCount == 0)
    return *this;

  size_t const NewSize = Size + iCount;
  SetCapacity (NewSize);
  memcpy (Data + Size, iStr, iCount);
  Size = NewSize;
  Data [Size] = '\0';
  return *this;
}

csString &csString::LTrim()
{
  size_t i;
  for (i = 0; i < Size; i++)
    if (!isspace (Data[i]))
      break;
  if (i > 0)
    DeleteAt (0, i);
  return *this;
}

csString &csString::RTrim()
{
  if (Size > 0)
  {
    int i;
    for (i = Size - 1; i >= 0; i--)
      if (!isspace (Data[i]))
        break;
    if (i < int(Size - 1))
      Truncate(i + 1);
  }
  return *this;
}

csString &csString::Trim()
{
  return LTrim().RTrim();
}

csString &csString::Collapse()
{
  if (Size > 0)
  {
    char const* src = Data;
    char const* slim = Data + Size;
    char* dst = Data;
    bool saw_white = false;
    for ( ; src < slim; src++)
    {
      char const c = *src;
      if (isspace(c))
        saw_white = true;
      else
      {
        if (saw_white && dst > Data)
          *dst++ = ' ';
        *dst++ = c;
        saw_white = false;
      }
    }
    Size = dst - Data;
    Data[Size] = '\0';
  }
  return *this;
}

csString &csString::Format(const char *format, ...)
{
  va_list args;
  va_start(args, format);

  if (Data == 0) // Ensure that backing-store exists prior to vsnprintf().
    SetCapacity(255);

  int rc;
  while (1)
  {
    rc = cs_vsnprintf(Data, MaxSize, format, args);
    // Buffer was big enough for entire string?
    if (rc >= 0 && rc < (int)MaxSize)
      break;
    // Some vsnprintf()s return -1 on failure, others return desired capacity.
    if (rc >= 0)
      SetCapacity(rc); // SetCapacity() ensures room for null byte.
    else
      SetCapacity(MaxSize * 2 - 1);
  }

  Size = rc;
  va_end(args);
  return *this;

}

#define STR_FORMAT(TYPE,FMT,SZ) \
csString csString::Format (TYPE v) \
{ char s[SZ]; cs_snprintf (s, SZ, #FMT, v); return csString ().Append (s); }
  STR_FORMAT(short, %hd, 32)
  STR_FORMAT(unsigned short, %hu, 32)
  STR_FORMAT(int, %d, 32)
  STR_FORMAT(unsigned int, %u, 32)
  STR_FORMAT(long, %ld, 32)
  STR_FORMAT(unsigned long, %lu, 32)
  STR_FORMAT(float, %g, 64)
  STR_FORMAT(double, %g, 64)
#undef STR_FORMAT

#define STR_FORMAT_INT(TYPE,FMT) \
csString csString::Format (TYPE v, int width, int prec/*=0*/) \
{ char s[64], s1[64]; \
  cs_snprintf (s1, sizeof(s1), "%%%d.%d"#FMT, width, prec); \
  cs_snprintf (s, sizeof(s), s1, v); \
  return csString ().Append (s); }
  STR_FORMAT_INT(short, hd)
  STR_FORMAT_INT(unsigned short, hu)
  STR_FORMAT_INT(int, d)
  STR_FORMAT_INT(unsigned int, u)
  STR_FORMAT_INT(long, ld)
  STR_FORMAT_INT(unsigned long, lu)
#undef STR_FORMAT_INT

#define STR_FORMAT_FLOAT(TYPE) \
csString csString::Format (TYPE v, int width, int prec/*=6*/) \
{ char s[64], s1[64]; \
  cs_snprintf (s1, sizeof(s1), "%%%d.%dg", width, prec); \
  cs_snprintf (s, sizeof(s), s1, v); \
  return csString ().Append (s); }
  STR_FORMAT_FLOAT(float)
  STR_FORMAT_FLOAT(double)
#undef STR_FORMAT_FLOAT

csString &csString::PadLeft (size_t iNewSize, char iChar)
{
  if (iNewSize > Size)
  {
    SetCapacity (iNewSize);
    const size_t toInsert = iNewSize - Size;
    memmove (Data + toInsert, Data, Size + 1); // Also move null terminator.
    for (size_t x = 0; x < toInsert; x++)
      Data [x] = iChar;
    Size = iNewSize;
  }
  return *this;
}

csString csString::AsPadLeft (size_t iNewSize, char iChar)
{
  csString newStr = Clone ();
  newStr.PadLeft (iChar, iNewSize);
  return newStr;
}

#define STR_PADLEFT(TYPE) \
csString csString::PadLeft (TYPE v, size_t iNewSize, char iChar) \
{ csString newStr; return newStr.Append (v).PadLeft (iNewSize, iChar); }
  STR_PADLEFT(const csString&)
  STR_PADLEFT(const char*)
  STR_PADLEFT(char)
  STR_PADLEFT(unsigned char)
  STR_PADLEFT(short)
  STR_PADLEFT(unsigned short)
  STR_PADLEFT(int)
  STR_PADLEFT(unsigned int)
  STR_PADLEFT(long)
  STR_PADLEFT(unsigned long)
  STR_PADLEFT(float)
  STR_PADLEFT(double)
#if !defined(CS_USE_FAKE_BOOL_TYPE)
  STR_PADLEFT(bool)
#endif
#undef STR_PADLEFT

csString& csString::PadRight (size_t iNewSize, char iChar)
{
  if (iNewSize > Size)
  {
    SetCapacity (iNewSize);
    for (size_t x = Size; x < iNewSize; x++)
      Data [x] = iChar;
    Size = iNewSize;
    Data [Size] = '\0';
  }
  return *this;
}

csString csString::AsPadRight (size_t iNewSize, char iChar)
{
  csString newStr = Clone ();
  newStr.PadRight (iChar, iNewSize);
  return newStr;
}

#define STR_PADRIGHT(TYPE) \
csString csString::PadRight (TYPE v, size_t iNewSize, char iChar) \
{ csString newStr; return newStr.Append (v).PadRight (iNewSize, iChar); }
  STR_PADRIGHT(const csString&)
  STR_PADRIGHT(const char*)
  STR_PADRIGHT(char)
  STR_PADRIGHT(unsigned char)
  STR_PADRIGHT(short)
  STR_PADRIGHT(unsigned short)
  STR_PADRIGHT(int)
  STR_PADRIGHT(unsigned int)
  STR_PADRIGHT(long)
  STR_PADRIGHT(unsigned long)
  STR_PADRIGHT(float)
  STR_PADRIGHT(double)
#if !defined(CS_USE_FAKE_BOOL_TYPE)
  STR_PADRIGHT(bool)
#endif
#undef STR_PADRIGHT

csString& csString::PadCenter (size_t iNewSize, char iChar)
{
  if (iNewSize > Size)
  {
    SetCapacity (iNewSize);
    const size_t toInsert = iNewSize - Size;
    const size_t halfInsert = toInsert / 2;
    if (Size > 0)
      memmove (Data + halfInsert, Data, Size);
    size_t x;
    for (x = 0; x < halfInsert; x++)
      Data [x] = iChar;
    for (x = halfInsert + Size; x < iNewSize; x++)
      Data [x] = iChar;
    Size = iNewSize;
    Data [Size] = '\0';
  }
  return *this;
}

csString csString::AsPadCenter (size_t iNewSize, char iChar)
{
  csString newStr = Clone ();
  newStr.PadCenter (iChar, iNewSize);
  return newStr;
}

#define STR_PADCENTER(TYPE) \
csString csString::PadCenter (TYPE v, size_t iNewSize, char iChar) \
{ csString newStr; return newStr.Append (v).PadCenter (iNewSize, iChar); }
  STR_PADCENTER(const csString&)
  STR_PADCENTER(const char*)
  STR_PADCENTER(char)
  STR_PADCENTER(unsigned char)
  STR_PADCENTER(short)
  STR_PADCENTER(unsigned short)
  STR_PADCENTER(int)
  STR_PADCENTER(unsigned int)
  STR_PADCENTER(long)
  STR_PADCENTER(unsigned long)
  STR_PADCENTER(float)
  STR_PADCENTER(double)
#if !defined(CS_USE_FAKE_BOOL_TYPE)
  STR_PADCENTER(bool)
#endif
#undef STR_PADCENTER
<|endoftext|>


<commit_before>/*
    Crystal Space input library
    Copyright (C) 2000 by Andrew Zabolotny <bit@eltech.ru>
    Copyright (C) 2002 by Mathew Sutcliffe <oktal@gmx.co.uk>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"
#include "iutil/event.h"
#include "csutil/csevent.h"
#include "csutil/inpnames.h"

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

static struct csKeyCodeDef
{
  const char *key;
  int code;
} KeyDefs [] =
{
  { "Esc",	CSKEY_ESC	},
  { "Enter",	CSKEY_ENTER	},
  { "Tab",	CSKEY_TAB	},
  { "Back",	CSKEY_BACKSPACE },
  { "BackSpace",CSKEY_BACKSPACE },
  { "Up",	CSKEY_UP	},
  { "Down",	CSKEY_DOWN	},
  { "Left",	CSKEY_LEFT	},
  { "Right",	CSKEY_RIGHT	},
  { "PgUp",	CSKEY_PGUP	},
  { "PageUp",	CSKEY_PGUP	},
  { "PgDn",	CSKEY_PGDN	},
  { "PageDown",	CSKEY_PGDN	},
  { "Home",	CSKEY_HOME	},
  { "End",	CSKEY_END	},
  { "Ins",	CSKEY_INS	},
  { "Insert",	CSKEY_INS	},
  { "Del",	CSKEY_DEL	},
  { "Delete",	CSKEY_DEL	},
  { "Ctrl",	CSKEY_CTRL	},
  { "Control",	CSKEY_CTRL	},
  { "Alt",	CSKEY_ALT	},
  { "Shift",	CSKEY_SHIFT	},
  { "Center",	CSKEY_CENTER	},
  { "F1",	CSKEY_F1	},
  { "F2",	CSKEY_F2	},
  { "F3",	CSKEY_F3	},
  { "F4",	CSKEY_F4	},
  { "F5",	CSKEY_F5	},
  { "F6",	CSKEY_F6	},
  { "F7",	CSKEY_F7	},
  { "F8",	CSKEY_F8	},
  { "F9",	CSKEY_F9	},
  { "F10",	CSKEY_F10	},
  { "F11",	CSKEY_F11	},
  { "F12",	CSKEY_F12	},
  { "PAD+",	CSKEY_PADPLUS	},
  { "PAD-",	CSKEY_PADMINUS	},
  { "PAD*",	CSKEY_PADMULT	},
  { "PAD/",	CSKEY_PADDIV	},
  { NULL,	0		}
};

static struct csKeyMaskDef
{
  const char *key;
  int mask;
} KeyMasks [] =
{
  { "Ctrl+",	CSMASK_CTRL	},
  { "Alt+",	CSMASK_ALT	},
  { "Shift+",	CSMASK_SHIFT	},
  { NULL,	0		}
};

bool csParseInputDef (const char *name, iEvent* ev, bool use_shift)
{
  int mod = 0;
  bool ismask;
  do
  {
    ismask = false;
    for (csKeyMaskDef *m = KeyMasks; m->key; m++)
      if (! strncasecmp (m->key, name, strlen (m->key)))
      {
        if (use_shift) mod |= m->mask;
        name += strlen (m->key);
        ismask = true;
      }
  } while (ismask);

  if (! strncasecmp (name, "Mouse", 5))
  {
    name += 5;
    if (*name == 'X' || *name == 'x')
      *ev = csEvent (0, csevMouseMove, 1, 0, 0, 0);
    else if (*name == 'Y' || *name == 'y')
      *ev = csEvent (0, csevMouseMove, 0, 1, 0, 0);
    else *ev = csEvent (0, csevMouseDown, 0, 0, atoi (name), mod);
  }
  else if (! strncasecmp (name, "Joystick", 8))
  {
    name += 8;
    if (*name == 'X' || *name == 'x')
      *ev = csEvent (0, csevJoystickMove, 1, 1, 0, 0, 0);
    else if (*name == 'Y' || *name == 'y')
      *ev = csEvent (0, csevJoystickMove, 1, 0, 1, 0, 0);
    else *ev = csEvent (0, csevJoystickDown, 1, 0, 0, atoi (name), mod);
  }
  else
  {
    int code = 0;

    for (csKeyCodeDef *c = KeyDefs; c->key; c++)
      if (! strcasecmp (c->key, name)) { code = c->code; break; }

    if	(code)
      *ev = csEvent (0, csevKeyDown, code, 0, mod);
    else if (strlen (name) != 1)
      return false;
    else
      *ev = csEvent (0, csevKeyDown, 0, (int)*name, mod);
  }
  return true;
}

bool csParseInputDef (const char* name, csEvent& ev, bool use_shift)
{
  return csParseInputDef (name, &ev, use_shift);
}

bool csParseKeyDef (const char *name, int &key, int &shift, bool use_shift)
{
  csEvent ev;
  bool ret = csParseInputDef (name, ev, use_shift);
  if (ret)
  {
    if (ev.Key.Code >= CSKEY_FIRST && ev.Key.Code <= CSKEY_LAST)
      key = ev.Key.Code;
    else if (ev.Key.Char < 256 && ev.Key.Char > 0)
      key = ev.Key.Char;
    else return false;
    shift = ev.Key.Modifiers;
  }
  return ret;
}

bool csParseMouseDef (const char *name, int &button, int &shift, bool use_shift)
{
  csEvent ev;
  bool ret = csParseInputDef (name, ev, use_shift);
  if (ret)
  {
    if (ev.Type == csevMouseMove)
      button = ev.Mouse.x > ev.Mouse.y ? CSAXIS_X : CSAXIS_Y;
    else button = ev.Mouse.Button;
    shift = ev.Mouse.Modifiers;
  }
  return ret;
}

bool csParseJoyDef (const char *name, int &button, int &shift, bool use_shift)
{
  csEvent ev;
  bool ret = csParseInputDef (name, ev, use_shift);
  if (ret)
  {
    if (ev.Type == csevJoystickMove)
      button = ev.Joystick.x > ev.Joystick.y ? CSAXIS_X : CSAXIS_Y;
    else button = ev.Joystick.Button;
    shift = ev.Joystick.Modifiers;
  }
  return ret;
}

bool csGetInputDesc (iEvent *ev, char *buf, bool use_shift)
{
  if (use_shift)
  {
    int mod = 0;
    switch (ev->Type)
    {
      case csevKeyUp:
      case csevKeyDown:
        mod = ev->Key.Modifiers;
        break;

      case csevMouseUp:
      case csevMouseDown:
        mod = ev->Mouse.Modifiers;
        break;

      case csevJoystickUp:
      case csevJoystickDown:
        mod = ev->Joystick.Modifiers;
        break;

      default:
        break;
    }
    for (csKeyMaskDef *mask = KeyMasks; mask->key; mask++)
    {
      if (mod & mask->mask)
      {
        strcpy (buf, mask->key);
        buf = strchr (buf, 0);
      }
    }
  }

  const char *key = NULL;
  switch (ev->Type)
  {
    case csevKeyUp:
    case csevKeyDown:
    {
      for (csKeyCodeDef *k = KeyDefs; k->key; k++)
        if (k->code == ev->Key.Code) key = k->key;
      if (key)
      {
        strcpy (buf, key);
        return true;
      }
      else if (ev->Key.Char < 256 && ev->Key.Char > 0)
      {
        *buf = (char)ev->Key.Char;
        *++buf = 0;
        return true;
      }
    }  break;

    case csevMouseUp:
    case csevMouseDown:
      strcpy (buf, "Mouse");
      sprintf (strchr (buf, 0), "%i", ev->Mouse.Button);
      return true;

    case csevJoystickUp:
    case csevJoystickDown:
      strcpy (buf, "Joystick");
      sprintf (strchr (buf, 0), "%i", ev->Joystick.Button);
      return true;

    case csevMouseMove:
      strcpy (buf, "Mouse");
      buf = strchr (buf, 0);
      if (ev->Mouse.x > ev->Mouse.y) *buf++ = 'X';
      else if (ev->Mouse.x < ev->Mouse.y) *buf++ = 'Y';
      *buf = 0;
      return true;

    case csevJoystickMove:
      strcpy (buf, "Joystick");
      buf = strchr (buf, 0);
      if (ev->Joystick.x > ev->Joystick.y) *buf++ = 'X';
      else if (ev->Joystick.x < ev->Joystick.y) *buf++ = 'Y';
      *buf = 0;
      return true;

    default:
      break;
  }
  return false;
}

bool csGetInputDesc (csEvent &ev, char *buf, bool use_shift)
{
  return csGetInputDesc (&ev, buf, use_shift);
}

bool csGetKeyDesc (int key, int shift, char *buf, bool use_shift)
{
  csEvent ev (0, csevKeyDown,
    key >= CSKEY_FIRST && key <= CSKEY_LAST ? key : 0,
    key < 256 && key > 0 ? 0 : key,
    shift);
  return csGetInputDesc (ev, buf, use_shift);
}

bool csGetMouseDesc (int button, int shift, char *buf, bool use_shift)
{
  csEvent ev (0,
    button == CSAXIS_X || button == CSAXIS_Y ? csevMouseMove : csevMouseDown,
    button == CSAXIS_X ? 1 : 0,
    button == CSAXIS_Y ? 1 : 0,
    button, shift);
  return csGetInputDesc (ev, buf, use_shift);
}

bool csGetJoyDesc (int button, int shift, char *buf, bool use_shift)
{
  csEvent ev (0,
    button == CSAXIS_X || button == CSAXIS_Y ? csevJoystickMove : csevJoystickDown,
    button == CSAXIS_X ? 1 : 0,
    button == CSAXIS_Y ? 1 : 0,
    button, shift);
  return csGetInputDesc (ev, buf, use_shift);
}

<commit_msg>Added "Return" as an alias for "Enter" for string representations of key codes.<commit_after>/*
    Crystal Space input library
    Copyright (C) 2000 by Andrew Zabolotny <bit@eltech.ru>
    Copyright (C) 2002 by Mathew Sutcliffe <oktal@gmx.co.uk>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"
#include "iutil/event.h"
#include "csutil/csevent.h"
#include "csutil/inpnames.h"

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

static struct csKeyCodeDef
{
  const char *key;
  int code;
} KeyDefs [] =
{
  { "Esc",	CSKEY_ESC	},
  { "Enter",	CSKEY_ENTER	},
  { "Return",	CSKEY_ENTER	},
  { "Tab",	CSKEY_TAB	},
  { "Back",	CSKEY_BACKSPACE },
  { "BackSpace",CSKEY_BACKSPACE },
  { "Up",	CSKEY_UP	},
  { "Down",	CSKEY_DOWN	},
  { "Left",	CSKEY_LEFT	},
  { "Right",	CSKEY_RIGHT	},
  { "PgUp",	CSKEY_PGUP	},
  { "PageUp",	CSKEY_PGUP	},
  { "PgDn",	CSKEY_PGDN	},
  { "PageDown",	CSKEY_PGDN	},
  { "Home",	CSKEY_HOME	},
  { "End",	CSKEY_END	},
  { "Ins",	CSKEY_INS	},
  { "Insert",	CSKEY_INS	},
  { "Del",	CSKEY_DEL	},
  { "Delete",	CSKEY_DEL	},
  { "Ctrl",	CSKEY_CTRL	},
  { "Control",	CSKEY_CTRL	},
  { "Alt",	CSKEY_ALT	},
  { "Shift",	CSKEY_SHIFT	},
  { "Center",	CSKEY_CENTER	},
  { "F1",	CSKEY_F1	},
  { "F2",	CSKEY_F2	},
  { "F3",	CSKEY_F3	},
  { "F4",	CSKEY_F4	},
  { "F5",	CSKEY_F5	},
  { "F6",	CSKEY_F6	},
  { "F7",	CSKEY_F7	},
  { "F8",	CSKEY_F8	},
  { "F9",	CSKEY_F9	},
  { "F10",	CSKEY_F10	},
  { "F11",	CSKEY_F11	},
  { "F12",	CSKEY_F12	},
  { "PAD+",	CSKEY_PADPLUS	},
  { "PAD-",	CSKEY_PADMINUS	},
  { "PAD*",	CSKEY_PADMULT	},
  { "PAD/",	CSKEY_PADDIV	},
  { NULL,	0		}
};

static struct csKeyMaskDef
{
  const char *key;
  int mask;
} KeyMasks [] =
{
  { "Ctrl+",	CSMASK_CTRL	},
  { "Alt+",	CSMASK_ALT	},
  { "Shift+",	CSMASK_SHIFT	},
  { NULL,	0		}
};

bool csParseInputDef (const char *name, iEvent* ev, bool use_shift)
{
  int mod = 0;
  bool ismask;
  do
  {
    ismask = false;
    for (csKeyMaskDef *m = KeyMasks; m->key; m++)
      if (! strncasecmp (m->key, name, strlen (m->key)))
      {
        if (use_shift) mod |= m->mask;
        name += strlen (m->key);
        ismask = true;
      }
  } while (ismask);

  if (! strncasecmp (name, "Mouse", 5))
  {
    name += 5;
    if (*name == 'X' || *name == 'x')
      *ev = csEvent (0, csevMouseMove, 1, 0, 0, 0);
    else if (*name == 'Y' || *name == 'y')
      *ev = csEvent (0, csevMouseMove, 0, 1, 0, 0);
    else *ev = csEvent (0, csevMouseDown, 0, 0, atoi (name), mod);
  }
  else if (! strncasecmp (name, "Joystick", 8))
  {
    name += 8;
    if (*name == 'X' || *name == 'x')
      *ev = csEvent (0, csevJoystickMove, 1, 1, 0, 0, 0);
    else if (*name == 'Y' || *name == 'y')
      *ev = csEvent (0, csevJoystickMove, 1, 0, 1, 0, 0);
    else *ev = csEvent (0, csevJoystickDown, 1, 0, 0, atoi (name), mod);
  }
  else
  {
    int code = 0;

    for (csKeyCodeDef *c = KeyDefs; c->key; c++)
      if (! strcasecmp (c->key, name)) { code = c->code; break; }

    if	(code)
      *ev = csEvent (0, csevKeyDown, code, 0, mod);
    else if (strlen (name) != 1)
      return false;
    else
      *ev = csEvent (0, csevKeyDown, 0, (int)*name, mod);
  }
  return true;
}

bool csParseInputDef (const char* name, csEvent& ev, bool use_shift)
{
  return csParseInputDef (name, &ev, use_shift);
}

bool csParseKeyDef (const char *name, int &key, int &shift, bool use_shift)
{
  csEvent ev;
  bool ret = csParseInputDef (name, ev, use_shift);
  if (ret)
  {
    if (ev.Key.Code >= CSKEY_FIRST && ev.Key.Code <= CSKEY_LAST)
      key = ev.Key.Code;
    else if (ev.Key.Char < 256 && ev.Key.Char > 0)
      key = ev.Key.Char;
    else return false;
    shift = ev.Key.Modifiers;
  }
  return ret;
}

bool csParseMouseDef (const char *name, int &button, int &shift, bool use_shift)
{
  csEvent ev;
  bool ret = csParseInputDef (name, ev, use_shift);
  if (ret)
  {
    if (ev.Type == csevMouseMove)
      button = ev.Mouse.x > ev.Mouse.y ? CSAXIS_X : CSAXIS_Y;
    else button = ev.Mouse.Button;
    shift = ev.Mouse.Modifiers;
  }
  return ret;
}

bool csParseJoyDef (const char *name, int &button, int &shift, bool use_shift)
{
  csEvent ev;
  bool ret = csParseInputDef (name, ev, use_shift);
  if (ret)
  {
    if (ev.Type == csevJoystickMove)
      button = ev.Joystick.x > ev.Joystick.y ? CSAXIS_X : CSAXIS_Y;
    else button = ev.Joystick.Button;
    shift = ev.Joystick.Modifiers;
  }
  return ret;
}

bool csGetInputDesc (iEvent *ev, char *buf, bool use_shift)
{
  if (use_shift)
  {
    int mod = 0;
    switch (ev->Type)
    {
      case csevKeyUp:
      case csevKeyDown:
        mod = ev->Key.Modifiers;
        break;

      case csevMouseUp:
      case csevMouseDown:
        mod = ev->Mouse.Modifiers;
        break;

      case csevJoystickUp:
      case csevJoystickDown:
        mod = ev->Joystick.Modifiers;
        break;

      default:
        break;
    }
    for (csKeyMaskDef *mask = KeyMasks; mask->key; mask++)
    {
      if (mod & mask->mask)
      {
        strcpy (buf, mask->key);
        buf = strchr (buf, 0);
      }
    }
  }

  const char *key = NULL;
  switch (ev->Type)
  {
    case csevKeyUp:
    case csevKeyDown:
    {
      for (csKeyCodeDef *k = KeyDefs; k->key; k++)
        if (k->code == ev->Key.Code) key = k->key;
      if (key)
      {
        strcpy (buf, key);
        return true;
      }
      else if (ev->Key.Char < 256 && ev->Key.Char > 0)
      {
        *buf = (char)ev->Key.Char;
        *++buf = 0;
        return true;
      }
    }  break;

    case csevMouseUp:
    case csevMouseDown:
      strcpy (buf, "Mouse");
      sprintf (strchr (buf, 0), "%i", ev->Mouse.Button);
      return true;

    case csevJoystickUp:
    case csevJoystickDown:
      strcpy (buf, "Joystick");
      sprintf (strchr (buf, 0), "%i", ev->Joystick.Button);
      return true;

    case csevMouseMove:
      strcpy (buf, "Mouse");
      buf = strchr (buf, 0);
      if (ev->Mouse.x > ev->Mouse.y) *buf++ = 'X';
      else if (ev->Mouse.x < ev->Mouse.y) *buf++ = 'Y';
      *buf = 0;
      return true;

    case csevJoystickMove:
      strcpy (buf, "Joystick");
      buf = strchr (buf, 0);
      if (ev->Joystick.x > ev->Joystick.y) *buf++ = 'X';
      else if (ev->Joystick.x < ev->Joystick.y) *buf++ = 'Y';
      *buf = 0;
      return true;

    default:
      break;
  }
  return false;
}

bool csGetInputDesc (csEvent &ev, char *buf, bool use_shift)
{
  return csGetInputDesc (&ev, buf, use_shift);
}

bool csGetKeyDesc (int key, int shift, char *buf, bool use_shift)
{
  csEvent ev (0, csevKeyDown,
    key >= CSKEY_FIRST && key <= CSKEY_LAST ? key : 0,
    key < 256 && key > 0 ? 0 : key,
    shift);
  return csGetInputDesc (ev, buf, use_shift);
}

bool csGetMouseDesc (int button, int shift, char *buf, bool use_shift)
{
  csEvent ev (0,
    button == CSAXIS_X || button == CSAXIS_Y ? csevMouseMove : csevMouseDown,
    button == CSAXIS_X ? 1 : 0,
    button == CSAXIS_Y ? 1 : 0,
    button, shift);
  return csGetInputDesc (ev, buf, use_shift);
}

bool csGetJoyDesc (int button, int shift, char *buf, bool use_shift)
{
  csEvent ev (0,
    button == CSAXIS_X || button == CSAXIS_Y ? csevJoystickMove : csevJoystickDown,
    button == CSAXIS_X ? 1 : 0,
    button == CSAXIS_Y ? 1 : 0,
    button, shift);
  return csGetInputDesc (ev, buf, use_shift);
}

<|endoftext|>


<commit_before>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/

#include <osgShadow/ShadowVolume>
#include <osgShadow/ShadowedScene>
#include <osg/Notify>

#include <osg/LightModel>
#include <osg/Depth>
#include <osg/BlendFunc>
#include <osg/Camera>
#include <osg/Stencil>
#include <osg/StencilTwoSided>
#include <osg/CullFace>
#include <osg/Geometry>
#include <osg/ComputeBoundsVisitor>
#include <osg/io_utils>

using namespace osgShadow;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//   ShadowVolume
//
ShadowVolume::ShadowVolume():
    _drawMode(osgShadow::ShadowVolumeGeometry::STENCIL_TWO_SIDED),
    _dynamicShadowVolumes(false)
{
    osg::notify(osg::NOTICE)<<"Warning: osgShadow::ShadowVolume technique in development."<<std::endl;
}

ShadowVolume::ShadowVolume(const ShadowVolume& sv, const osg::CopyOp& copyop):
    ShadowTechnique(sv,copyop),
    _drawMode(sv._drawMode),
    _dynamicShadowVolumes(sv._dynamicShadowVolumes)
{
}

ShadowVolume::~ShadowVolume()
{
}

void ShadowVolume::setDrawMode(osgShadow::ShadowVolumeGeometry::DrawMode drawMode)
{
    if (_drawMode == drawMode) return;

    _drawMode = drawMode;

    dirty();
}

void ShadowVolume::setDynamicShadowVolumes(bool dynamicShadowVolumes)
{
    _dynamicShadowVolumes = dynamicShadowVolumes;
}

void ShadowVolume::init()
{
    if (!_shadowedScene) return;

    // get the bounds of the model.
    osg::ComputeBoundsVisitor cbbv;
    _shadowedScene->osg::Group::traverse(cbbv);

    osg::Vec4 ambient(0.2,0.2,0.2,1.0);
    osg::Vec4 diffuse(0.8,0.8,0.8,1.0);
    osg::Vec4 zero_colour(0.0,0.0,0.0,1.0);

    osg::Vec4 lightpos;
    lightpos.set(0.5f,0.25f,0.8f,0.0f);

    // set up the occluder
    _occluder = new osgShadow::OccluderGeometry;
    _occluder->computeOccluderGeometry(_shadowedScene);
//    cbbv.getPolytope(_occluder->getBoundingPolytope(),0.001);
    cbbv.getBase(_occluder->getBoundingPolytope(),0.001);

    // set up shadow volume
    _shadowVolume = new osgShadow::ShadowVolumeGeometry;
    _shadowVolume->setUseDisplayList(!_dynamicShadowVolumes);
    _occluder->computeShadowVolumeGeometry(lightpos, *_shadowVolume);

    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
    _shadowedScene->addChild(geode.get());
    int shadowVolumeBin = 1000;

    if (_drawMode == osgShadow::ShadowVolumeGeometry::STENCIL_TWO_SIDED)
    {
        osg::notify(osg::NOTICE)<<"STENCIL_TWO_SIDED selected"<<std::endl;

        osg::StateSet* ss_sv1 = geode->getOrCreateStateSet();
        ss_sv1->setRenderBinDetails(shadowVolumeBin, "RenderBin");
        geode->addDrawable(_shadowVolume.get());
    }
    else
    {
        osg::notify(osg::NOTICE)<<"STENCIL_TWO_PASSES selectetd"<<std::endl;

        osg::StateSet* ss_sv1 = geode->getOrCreateStateSet();
        ss_sv1->setRenderBinDetails(shadowVolumeBin, "RenderBin");
        geode->addDrawable(_shadowVolume.get());
    }

    {

        // first group, render the depth buffer + ambient light contribution
        {
            _ss1 = new osg::StateSet;

            osg::LightModel* lm1 = new osg::LightModel;
            lm1->setAmbientIntensity(ambient);
            _ss1->setAttribute(lm1);

            _ambientLight = new osg::Light;
            _ambientLight->setAmbient(ambient);
            _ambientLight->setDiffuse(zero_colour);
            _ss1->setAttributeAndModes(_ambientLight.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);

            _ss1->setMode(GL_LIGHTING, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
        }

        {
            _mainShadowStateSet = new osg::StateSet;

            osg::Depth* depth = new osg::Depth;
            depth->setWriteMask(false);
            depth->setFunction(osg::Depth::LEQUAL);
            _mainShadowStateSet->setAttribute(depth);
            _mainShadowStateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
        }

        {
            _shadowVolumeStateSet = new osg::StateSet;

            osg::Depth* depth = new osg::Depth;
            depth->setWriteMask(false);
            depth->setFunction(osg::Depth::LEQUAL);
            _shadowVolumeStateSet->setAttribute(depth);
            _shadowVolumeStateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);
            _shadowVolumeStateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);

            if (_drawMode == osgShadow::ShadowVolumeGeometry::STENCIL_TWO_SIDED)
            {
                osg::StencilTwoSided* stencil = new osg::StencilTwoSided;
                stencil->setFunction(osg::StencilTwoSided::BACK, osg::StencilTwoSided::ALWAYS,0,~0u);
                stencil->setOperation(osg::StencilTwoSided::BACK, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::DECR_WRAP);
                stencil->setFunction(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::ALWAYS,0,~0u);
                stencil->setOperation(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::INCR_WRAP);

                osg::ColorMask* colourMask = new osg::ColorMask(false, false, false, false);

                _shadowVolumeStateSet->setAttributeAndModes(stencil,osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
                _shadowVolumeStateSet->setAttribute(colourMask, osg::StateAttribute::OVERRIDE);
                _shadowVolumeStateSet->setMode(GL_CULL_FACE,osg::StateAttribute::OFF);

            }
            else
            {
                osg::Stencil* stencil = new osg::Stencil;
                stencil->setFunction(osg::Stencil::ALWAYS,0,~0u);
                stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::KEEP);

                osg::ColorMask* colourMask = new osg::ColorMask(false, false, false, false);

                _shadowVolumeStateSet->setAttributeAndModes(stencil,osg::StateAttribute::ON);
                _shadowVolumeStateSet->setAttribute(colourMask);
                _shadowVolumeStateSet->setMode(GL_CULL_FACE,osg::StateAttribute::ON);
            }
        }

        {
            _shadowedSceneStateSet = new osg::StateSet;

            osg::Depth* depth = new osg::Depth;
            depth->setWriteMask(false);
            depth->setFunction(osg::Depth::LEQUAL);
            _shadowedSceneStateSet->setAttribute(depth);
            _shadowedSceneStateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
            // _shadowedSceneStateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);

            osg::LightModel* lm1 = new osg::LightModel;
            lm1->setAmbientIntensity(zero_colour);
            _shadowedSceneStateSet->setAttribute(lm1);

            _diffuseLight = new osg::Light;
            _diffuseLight->setAmbient(zero_colour);
            _diffuseLight->setDiffuse(diffuse);

            _shadowedSceneStateSet->setMode(GL_LIGHT0, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
            _shadowedSceneStateSet->setAttribute(_diffuseLight.get());

            // set up the stencil ops so that only operator on this mirrors stencil value.
            osg::Stencil* stencil = new osg::Stencil;
            stencil->setFunction(osg::Stencil::EQUAL,0,~0u);
            stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::KEEP);
            _shadowedSceneStateSet->setAttributeAndModes(stencil,osg::StateAttribute::ON);

            osg::BlendFunc* blend = new osg::BlendFunc;
            blend->setFunction(osg::BlendFunc::ONE, osg::BlendFunc::ONE);
            _shadowedSceneStateSet->setAttributeAndModes(blend, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
            // _shadowedSceneStateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
        }

        _ss1->setThreadSafeRefUnref(true);
        _mainShadowStateSet->setThreadSafeRefUnref(true);
        _shadowVolumeStateSet->setThreadSafeRefUnref(true);
        _shadowedSceneStateSet->setThreadSafeRefUnref(true);

    }

    _dirty = false;
}

void ShadowVolume::update(osg::NodeVisitor& nv)
{
    _shadowedScene->osg::Group::traverse(nv);
}

void ShadowVolume::cull(osgUtil::CullVisitor& cv)
{

    osg::ref_ptr<osgUtil::RenderBin> original_bin = cv.getCurrentRenderBin();

    osg::ref_ptr<osgUtil::RenderBin> new_bin = original_bin->find_or_insert(0,"RenderBin");

    cv.setCurrentRenderBin(new_bin.get());

    _shadowedScene->osg::Group::traverse(cv);

    cv.setCurrentRenderBin(original_bin.get());

    osgUtil::RenderBin::RenderBinList::iterator itr =  new_bin->getRenderBinList().find(1000);
    osg::ref_ptr<osgUtil::RenderBin> shadowVolumeBin;
    if (itr != new_bin->getRenderBinList().end())
    {
        shadowVolumeBin = itr->second;

        if (shadowVolumeBin.valid())
        {
            //osg::notify(osg::NOTICE)<<"Found shadow volume bin, now removing it"<<std::endl;
            new_bin->getRenderBinList().erase(itr);
        }
    }

    if (shadowVolumeBin.valid())
    {
        original_bin->setStateSet(_ss1.get());

        osgUtil::RenderStage* orig_rs = cv.getRenderStage();
        osgUtil::RenderStage* new_rs = new osgUtil::RenderStage;
        orig_rs->addPostRenderStage(new_rs);

        new_rs->setViewport(orig_rs->getViewport());
        new_rs->setClearColor(orig_rs->getClearColor());
        new_rs->setClearMask(GL_STENCIL_BUFFER_BIT);
        new_rs->setDrawBuffer(orig_rs->getDrawBuffer());
        new_rs->setReadBuffer(orig_rs->getReadBuffer());
        new_rs->setColorMask(orig_rs->getColorMask());

        osg::Vec4 lightpos;

        osg::ref_ptr<osgUtil::PositionalStateContainer> ps = new osgUtil::PositionalStateContainer;
        new_rs->setPositionalStateContainer(ps.get());

        const osg::Light* selectLight = 0;

        osgUtil::PositionalStateContainer::AttrMatrixList& aml = orig_rs->getPositionalStateContainer()->getAttrMatrixList();
        for(osgUtil::PositionalStateContainer::AttrMatrixList::iterator itr = aml.begin();
            itr != aml.end();
            ++itr)
        {
            const osg::Light* light = dynamic_cast<const osg::Light*>(itr->first.get());
            if (light)
            {
                osg::RefMatrix* matrix = itr->second.get();
                if (matrix) lightpos = light->getPosition() * (*matrix);
                else lightpos = light->getPosition();

                selectLight = light;
            }
            else
            {
                ps->addPositionedAttribute(itr->second.get(), itr->first.get());
            }
        }

        _ambientLight->setPosition(lightpos);

        orig_rs->addPositionedAttribute(0,_ambientLight.get());

        _diffuseLight->setPosition(lightpos);
        if (selectLight)
        {
            _ambientLight->setAmbient(selectLight->getAmbient());

            _diffuseLight->setDiffuse(selectLight->getDiffuse());
            _diffuseLight->setSpecular(selectLight->getSpecular());
            _diffuseLight->setDirection(selectLight->getDirection());
            _diffuseLight->setConstantAttenuation(selectLight->getConstantAttenuation());
            _diffuseLight->setLinearAttenuation(selectLight->getLinearAttenuation());
            _diffuseLight->setQuadraticAttenuation(selectLight->getQuadraticAttenuation());
            _diffuseLight->setSpotExponent(selectLight->getSpotExponent());
            _diffuseLight->setSpotCutoff(selectLight->getSpotCutoff());
        }
        ps->addPositionedAttribute(0, _diffuseLight.get());

        if (_lightpos != lightpos && _dynamicShadowVolumes)
        {
            _lightpos = lightpos;

            osg::Matrix eyeToWorld;
            eyeToWorld.invert(*cv.getModelViewMatrix());

            _occluder->computeShadowVolumeGeometry(lightpos * eyeToWorld, *_shadowVolume);
        }

        if (shadowVolumeBin.valid())
        {
            // new_rs->setStateSet(_mainShadowStateSet.get());
            new_rs->getRenderBinList()[0] = shadowVolumeBin;
            shadowVolumeBin->setStateSet(_shadowVolumeStateSet.get());

            osg::ref_ptr<osgUtil::RenderBin> nested_bin = new_rs->find_or_insert(1,"RenderBin");
            nested_bin->getRenderBinList()[0] = new_bin;
            nested_bin->setStateSet(_shadowedSceneStateSet.get());
        }
    }

}

void ShadowVolume::cleanSceneGraph()
{
    osg::notify(osg::NOTICE)<<className()<<"::cleanSceneGraph()) not implemened yet, but almost."<<std::endl;
}

<commit_msg>Add setting of ShadowVolumeGeometry draw mode<commit_after>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/

#include <osgShadow/ShadowVolume>
#include <osgShadow/ShadowedScene>
#include <osg/Notify>

#include <osg/LightModel>
#include <osg/Depth>
#include <osg/BlendFunc>
#include <osg/Camera>
#include <osg/Stencil>
#include <osg/StencilTwoSided>
#include <osg/CullFace>
#include <osg/Geometry>
#include <osg/ComputeBoundsVisitor>
#include <osg/io_utils>

using namespace osgShadow;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//   ShadowVolume
//
ShadowVolume::ShadowVolume():
    _drawMode(osgShadow::ShadowVolumeGeometry::STENCIL_TWO_SIDED),
    _dynamicShadowVolumes(false)
{
    // _drawMode = osgShadow::ShadowVolumeGeometry::GEOMETRY;

    osg::notify(osg::NOTICE)<<"Warning: osgShadow::ShadowVolume technique in development."<<std::endl;
}

ShadowVolume::ShadowVolume(const ShadowVolume& sv, const osg::CopyOp& copyop):
    ShadowTechnique(sv,copyop),
    _drawMode(sv._drawMode),
    _dynamicShadowVolumes(sv._dynamicShadowVolumes)
{
}

ShadowVolume::~ShadowVolume()
{
}

void ShadowVolume::setDrawMode(osgShadow::ShadowVolumeGeometry::DrawMode drawMode)
{
    if (_drawMode == drawMode) return;

    _drawMode = drawMode;

    dirty();
}

void ShadowVolume::setDynamicShadowVolumes(bool dynamicShadowVolumes)
{
    _dynamicShadowVolumes = dynamicShadowVolumes;
}

void ShadowVolume::init()
{
    if (!_shadowedScene) return;

    // get the bounds of the model.
    osg::ComputeBoundsVisitor cbbv;
    _shadowedScene->osg::Group::traverse(cbbv);

    osg::Vec4 ambient(0.2,0.2,0.2,1.0);
    osg::Vec4 diffuse(0.8,0.8,0.8,1.0);
    osg::Vec4 zero_colour(0.0,0.0,0.0,1.0);

    osg::Vec4 lightpos;
    lightpos.set(0.5f,0.25f,0.8f,0.0f);

    // set up the occluder
    _occluder = new osgShadow::OccluderGeometry;
    _occluder->computeOccluderGeometry(_shadowedScene);
//    cbbv.getPolytope(_occluder->getBoundingPolytope(),0.001);
    cbbv.getBase(_occluder->getBoundingPolytope(),0.001);

    // set up shadow volume
    _shadowVolume = new osgShadow::ShadowVolumeGeometry;
    _shadowVolume->setUseDisplayList(!_dynamicShadowVolumes);
    _shadowVolume->setDrawMode(_drawMode);
    _occluder->computeShadowVolumeGeometry(lightpos, *_shadowVolume);

    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
    _shadowedScene->addChild(geode.get());
    int shadowVolumeBin = 1000;

    if (_drawMode == osgShadow::ShadowVolumeGeometry::STENCIL_TWO_SIDED)
    {
        osg::notify(osg::NOTICE)<<"STENCIL_TWO_SIDED selected"<<std::endl;

        osg::StateSet* ss_sv1 = geode->getOrCreateStateSet();
        ss_sv1->setRenderBinDetails(shadowVolumeBin, "RenderBin");
        geode->addDrawable(_shadowVolume.get());
    }
    else
    {
        osg::notify(osg::NOTICE)<<"STENCIL_TWO_PASSES selecteted"<<std::endl;

        osg::StateSet* ss_sv1 = geode->getOrCreateStateSet();
        ss_sv1->setRenderBinDetails(shadowVolumeBin, "RenderBin");
        geode->addDrawable(_shadowVolume.get());
    }

    {

        // first group, render the depth buffer + ambient light contribution
        {
            _ss1 = new osg::StateSet;

            osg::LightModel* lm1 = new osg::LightModel;
            lm1->setAmbientIntensity(ambient);
            _ss1->setAttribute(lm1);

            _ambientLight = new osg::Light;
            _ambientLight->setAmbient(ambient);
            _ambientLight->setDiffuse(zero_colour);
            _ss1->setAttributeAndModes(_ambientLight.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);

            _ss1->setMode(GL_LIGHTING, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
        }

        {
            _mainShadowStateSet = new osg::StateSet;

            osg::Depth* depth = new osg::Depth;
            depth->setWriteMask(false);
            depth->setFunction(osg::Depth::LEQUAL);
            _mainShadowStateSet->setAttribute(depth);
            _mainShadowStateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
        }

        {
            _shadowVolumeStateSet = new osg::StateSet;

            osg::Depth* depth = new osg::Depth;
            depth->setWriteMask(false);
            depth->setFunction(osg::Depth::LEQUAL);
            _shadowVolumeStateSet->setAttribute(depth);
            _shadowVolumeStateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);
            _shadowVolumeStateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);

            if (_drawMode == osgShadow::ShadowVolumeGeometry::STENCIL_TWO_SIDED)
            {
                osg::StencilTwoSided* stencil = new osg::StencilTwoSided;
                stencil->setFunction(osg::StencilTwoSided::BACK, osg::StencilTwoSided::ALWAYS,0,~0u);
                stencil->setOperation(osg::StencilTwoSided::BACK, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::DECR_WRAP);
                stencil->setFunction(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::ALWAYS,0,~0u);
                stencil->setOperation(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::INCR_WRAP);

                osg::ColorMask* colourMask = new osg::ColorMask(false, false, false, false);

                _shadowVolumeStateSet->setAttributeAndModes(stencil,osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
                _shadowVolumeStateSet->setAttribute(colourMask, osg::StateAttribute::OVERRIDE);
                _shadowVolumeStateSet->setMode(GL_CULL_FACE,osg::StateAttribute::OFF);

            }
            else
            {
                osg::Stencil* stencil = new osg::Stencil;
                stencil->setFunction(osg::Stencil::ALWAYS,0,~0u);
                stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::KEEP);

                osg::ColorMask* colourMask = new osg::ColorMask(false, false, false, false);

                _shadowVolumeStateSet->setAttributeAndModes(stencil,osg::StateAttribute::ON);
                _shadowVolumeStateSet->setAttribute(colourMask);
                _shadowVolumeStateSet->setMode(GL_CULL_FACE,osg::StateAttribute::ON);
            }
        }

        {
            _shadowedSceneStateSet = new osg::StateSet;

            osg::Depth* depth = new osg::Depth;
            depth->setWriteMask(false);
            depth->setFunction(osg::Depth::LEQUAL);
            _shadowedSceneStateSet->setAttribute(depth);
            _shadowedSceneStateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
            // _shadowedSceneStateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);

            osg::LightModel* lm1 = new osg::LightModel;
            lm1->setAmbientIntensity(zero_colour);
            _shadowedSceneStateSet->setAttribute(lm1);

            _diffuseLight = new osg::Light;
            _diffuseLight->setAmbient(zero_colour);
            _diffuseLight->setDiffuse(diffuse);

            _shadowedSceneStateSet->setMode(GL_LIGHT0, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
            _shadowedSceneStateSet->setAttribute(_diffuseLight.get());

            // set up the stencil ops so that only operator on this mirrors stencil value.
            osg::Stencil* stencil = new osg::Stencil;
            stencil->setFunction(osg::Stencil::EQUAL,0,~0u);
            stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::KEEP);
            _shadowedSceneStateSet->setAttributeAndModes(stencil,osg::StateAttribute::ON);

            osg::BlendFunc* blend = new osg::BlendFunc;
            blend->setFunction(osg::BlendFunc::ONE, osg::BlendFunc::ONE);
            _shadowedSceneStateSet->setAttributeAndModes(blend, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
            // _shadowedSceneStateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
        }

        _ss1->setThreadSafeRefUnref(true);
        _mainShadowStateSet->setThreadSafeRefUnref(true);
        _shadowVolumeStateSet->setThreadSafeRefUnref(true);
        _shadowedSceneStateSet->setThreadSafeRefUnref(true);

    }

    _dirty = false;
}

void ShadowVolume::update(osg::NodeVisitor& nv)
{
    _shadowedScene->osg::Group::traverse(nv);
}

void ShadowVolume::cull(osgUtil::CullVisitor& cv)
{

    osg::ref_ptr<osgUtil::RenderBin> original_bin = cv.getCurrentRenderBin();

    osg::ref_ptr<osgUtil::RenderBin> new_bin = original_bin->find_or_insert(0,"RenderBin");

    cv.setCurrentRenderBin(new_bin.get());

    _shadowedScene->osg::Group::traverse(cv);

    cv.setCurrentRenderBin(original_bin.get());

    osgUtil::RenderBin::RenderBinList::iterator itr =  new_bin->getRenderBinList().find(1000);
    osg::ref_ptr<osgUtil::RenderBin> shadowVolumeBin;
    if (itr != new_bin->getRenderBinList().end())
    {
        shadowVolumeBin = itr->second;

        if (shadowVolumeBin.valid())
        {
            //osg::notify(osg::NOTICE)<<"Found shadow volume bin, now removing it"<<std::endl;
            new_bin->getRenderBinList().erase(itr);
        }
    }

    if (shadowVolumeBin.valid())
    {
        original_bin->setStateSet(_ss1.get());

        osgUtil::RenderStage* orig_rs = cv.getRenderStage();
        osgUtil::RenderStage* new_rs = new osgUtil::RenderStage;
        orig_rs->addPostRenderStage(new_rs);

        new_rs->setViewport(orig_rs->getViewport());
        new_rs->setClearColor(orig_rs->getClearColor());
        new_rs->setClearMask(GL_STENCIL_BUFFER_BIT);
        new_rs->setDrawBuffer(orig_rs->getDrawBuffer());
        new_rs->setReadBuffer(orig_rs->getReadBuffer());
        new_rs->setColorMask(orig_rs->getColorMask());

        osg::Vec4 lightpos;

        osg::ref_ptr<osgUtil::PositionalStateContainer> ps = new osgUtil::PositionalStateContainer;
        new_rs->setPositionalStateContainer(ps.get());

        const osg::Light* selectLight = 0;

        osgUtil::PositionalStateContainer::AttrMatrixList& aml = orig_rs->getPositionalStateContainer()->getAttrMatrixList();
        for(osgUtil::PositionalStateContainer::AttrMatrixList::iterator itr = aml.begin();
            itr != aml.end();
            ++itr)
        {
            const osg::Light* light = dynamic_cast<const osg::Light*>(itr->first.get());
            if (light)
            {
                osg::RefMatrix* matrix = itr->second.get();
                if (matrix) lightpos = light->getPosition() * (*matrix);
                else lightpos = light->getPosition();

                selectLight = light;
            }
            else
            {
                ps->addPositionedAttribute(itr->second.get(), itr->first.get());
            }
        }

        _ambientLight->setPosition(lightpos);

        orig_rs->addPositionedAttribute(0,_ambientLight.get());

        _diffuseLight->setPosition(lightpos);
        if (selectLight)
        {
            _ambientLight->setAmbient(selectLight->getAmbient());

            _diffuseLight->setDiffuse(selectLight->getDiffuse());
            _diffuseLight->setSpecular(selectLight->getSpecular());
            _diffuseLight->setDirection(selectLight->getDirection());
            _diffuseLight->setConstantAttenuation(selectLight->getConstantAttenuation());
            _diffuseLight->setLinearAttenuation(selectLight->getLinearAttenuation());
            _diffuseLight->setQuadraticAttenuation(selectLight->getQuadraticAttenuation());
            _diffuseLight->setSpotExponent(selectLight->getSpotExponent());
            _diffuseLight->setSpotCutoff(selectLight->getSpotCutoff());
        }
        ps->addPositionedAttribute(0, _diffuseLight.get());

        if (_lightpos != lightpos && _dynamicShadowVolumes)
        {
            _lightpos = lightpos;

            osg::Matrix eyeToWorld;
            eyeToWorld.invert(*cv.getModelViewMatrix());

            _occluder->computeShadowVolumeGeometry(lightpos * eyeToWorld, *_shadowVolume);
        }

        if (shadowVolumeBin.valid())
        {
            // new_rs->setStateSet(_mainShadowStateSet.get());
            new_rs->getRenderBinList()[0] = shadowVolumeBin;
            shadowVolumeBin->setStateSet(_shadowVolumeStateSet.get());

            osg::ref_ptr<osgUtil::RenderBin> nested_bin = new_rs->find_or_insert(1,"RenderBin");
            nested_bin->getRenderBinList()[0] = new_bin;
            nested_bin->setStateSet(_shadowedSceneStateSet.get());
        }
    }

}

void ShadowVolume::cleanSceneGraph()
{
    osg::notify(osg::NOTICE)<<className()<<"::cleanSceneGraph()) not implemened yet, but almost."<<std::endl;
}

<|endoftext|>


<commit_before>#include "Navigation.h"
#include <fstream>
#include <queue>
// #include <iostream>
// #include <string>
// #include <cstring>
// #include <dirent.h>

using namespace std;

double Node::DNE = 1000000.0;
double Node::LARGE_NUM = 1000.0;

Navigation::Navigation(const char* filename)
{
  inputNodes(filename); //forgot what your format was clayton and don't want to deal with it too much
  if(allNodes.size() > 1) //keep in mind, the output path doesn't include the source
  {
    cout << "from " << allNodes[0].name << " to " << allNodes[allNodes.size()-1].name << endl;
    travelFromSourceToSink(&allNodes[0], &allNodes[allNodes.size()-1]);
  }
}

void Navigation::inputNodes(const char* filename)
{
	ifstream in;
	string inStr;
	int numNeighbors;
	int neighbor;
	int weight;
	int direction;

	in.open(filename);

	if(in.good()){ //if the file was successfully opened
		in >> inStr; //read the number of nodes
		numNodes = atoi(inStr.c_str()); //change the string we read to an int
		for(int i = 0; i < numNodes; i++){ //loop for each node we have
			in >> inStr; //read the name of a node
			Node n(inStr, Node::DNE); //create a new node with nonexistant g value
      		n.parent = NULL;
			allNodes.push_back(n); //put that node in the list of all nodes
		}

		for(int i = 0; i < numNodes; i++){ //loop for each node we have
			in >> inStr; //read the number of neighbors a node has
			numNeighbors = atoi(inStr.c_str());
			for(int j = 0; j < numNeighbors; j++) { //loop for each neighbor of a node
				in >> inStr;
				neighbor = atoi(inStr.c_str()); //read the nodes neighbor
				in >> inStr;
				weight = atoi(inStr.c_str());
				in >> inStr;
				direction = atoi(inStr.c_str());
				// allNodes[i].info[j] = make_tuple(&allNodes[neighbor], weight, direction);
				allNodes[i].neighbors.push_back(&allNodes[neighbor]); //store the node in the list of neighbors
				// in >> inStr; //read the neighbors weight
				allNodes[i].weights.push_back(weight); //assign the weight
				allNodes[i].directions.push_back(direction); //assign the direction we need to go in to reach the neighbor
			}
		}
	}
}

bool Navigation::travelFromSourceToSink(Node* source, Node* sink)
{
  vector<Node*> path;
  //while not yet there...
  bool arrived = false;

  while(!arrived)
  {
    //path from CURRENT place to sink Node                                                  FIX THIS
    path = findPath(source, sink); //should be (current, sink) with current starting at source
    #ifdef DEBUG
    outputPath(path);
    #endif
    arrived = walkPath(path);
  }

  return true; //or false if ???
}

Node* Navigation::getNode(int index)
{
  return &allNodes[index];
}

vector<Node*> Navigation::dbgReconstructPath(Node* current)
{
  vector<Node*> path;

  #ifdef TEST
    return reconstructPath(current);
  #else
    cout << "This function is only for testing." << endl;
  #endif

  return path;
}

vector<Node*> Navigation::dbgFindPath(Node* source, Node* sink)
{
  vector<Node*> path;

  #ifdef TEST
    return findPath(source, sink);
  #else
    cout << "This function is only for testing." << endl;
  #endif

  return path;
}

/*Node Navigation::walkToStartingNode()
{

	//if(OR::atNode()) {
		//return OR::currentNode();
	//}

	//While(!OR::atNode()) {
		//if(OR::straight()) {
			//Roomba::drive(Warp 5, 0);
		//} else {
			//degrees = OR::somethingWithSlopes?()
			//Roomba::drive(0, degrees)
		//}
	//}

	//return OR::currentNode();
}*/

void Navigation::moveForwardUntilSignOrBlockage()
{
  roomba.drive(500, 0); //                              is drive temporary or constant until you drive(0, 0)???????
  while(cam.getfloorsign().empty() && !cam.getpathisblocked())
  {
    cam.update();
  }
  if(!cam.getfloorsign().empty())
  {
    //move forward just a bit more so we're on top of it.
    drive(100, 0); //temp arbitrary numbers
  }
}

bool Navigation::walkPath(const vector<Node*>& path)
{
  //walk the walk using roomba commands
  if(path.empty())
    return false;
  //assume we're on node path[0] and turn towards path[1].

  for(size_t i=1; i<path.size(); ++i)
  {
    bool arrived = false;
    string nodeGoal = path[i]->name;
  	while(!arrived) //is this loop actually doing anything? i.e. does it always only run once?
    {
  		moveForwardUntilSignOrBlockage();
  		if(cam.getpathisblocked())
      {
        cout << "Path is blocked. Turning around." << endl;
  			roomba.drive(0, 180); //turn around
  			//move towards last intersection
        moveForwardUntilSignOrBlockage();                //ASSUMING NO BLOCKAGE HERE

        //update weights where blockage exists
        incrementWeight(path[i-1], path[i]);

  			path = findPath(path[i-1], path[path.size()-1]);
        return walkPath(path);
  		}
      else if(!cam.getfloorsign().empty())
      {
  			arrived = true;
  			//check what direction we need to go
  			//turn
  		}
  	}
  }

  //if blocked, restart pathfinding from current spot.
  return true;
}

vector<Node*> Navigation::findPath(Node* source, Node* sink)
{
  //cout << "findPath" << endl;
  for(size_t i=0; i<allNodes.size(); ++i)
  {
    allNodes[i].g_score = Node::DNE;
    allNodes[i].parent = NULL;
  }

  source->g_score = 0.0;
  //The set of tentative Nodes that need to be evaluated, starting with sink
  queue<Node*> openSet;
  openSet.push(source);

  //while openset is not empty
  while(!openSet.empty())
  {
    //cout << "loop openSet.size() :: " << openSet.size() << endl;
    Node* current = openSet.front();
    // cout << current->name << endl;
    openSet.pop();

    //for each neighbor in current->neighbors
    //cout << "neighbors.size() :: " << current->neighbors.size() << endl;
    for(size_t i=0; i<current->neighbors.size(); ++i)
    {
      Node* neighbor = current->neighbors[i];
      if(neighbor == NULL)
        continue;
      double tempScore = current->g_score + current->weights[i];
      //if neighbor not yet evaluated or better score
      if(neighbor->g_score == Node::DNE || tempScore < neighbor->g_score)
      {
        //if neighbor not yet evaluated
        if(neighbor->g_score == Node::DNE)
          //add neighbor to openset
          openSet.push(neighbor);
        //came_from[neighbor] = current
        neighbor->parent = current;
        //g_score[neighbor] = tentative_g_score
        neighbor->g_score= tempScore;
      }
    }
  }

  return reconstructPath(source, sink);
}

vector<Node*> Navigation::reconstructPath(Node* source, Node* sink)
{
  Node* current = sink;
  vector<Node*> path;
  while(current->parent != NULL)
  {
    path.insert(path.begin(), current);
    current = current->parent;
  }
  path.insert(path.begin(), source);
  return path;
}

void Navigation::incrementWeight(Node* n1, Node* n2)
{
  for(size_t i=0; i<n1->neighbors.size(); ++i)
  {
    if(n1->neighbors[i] == n2)
    {
      n1->weights[i] += Node::LARGE_NUM;
      break;
    }
  }
  for(size_t i=0; i<n2->neighbors.size(); ++i)
  {
    if(n2->neighbors[i] == n1)
    {
      n2->weights[i] += Node::LARGE_NUM;
      break;
    }
  }
}

void Navigation::outputPath(const vector<Node*>& path)
{
  cout << endl << "start path" << endl;
  for(size_t i=0; i<path.size(); ++i)
  {
    cout << "\t" << path[i]->name << endl;
  }
  cout << "end path\n" << endl;
}

void Navigation::outputAllNodes()
{
  for(size_t i=0; i<allNodes.size(); ++i)
  {
    cout << allNodes[i].name << " " << allNodes[i].neighbors.size() << endl;
  }
}

<commit_msg>small fix<commit_after>#include "Navigation.h"
#include <fstream>
#include <queue>
// #include <iostream>
// #include <string>
// #include <cstring>
// #include <dirent.h>

using namespace std;

double Node::DNE = 1000000.0;
double Node::LARGE_NUM = 1000.0;

Navigation::Navigation(const char* filename)
{
  inputNodes(filename); //forgot what your format was clayton and don't want to deal with it too much
  if(allNodes.size() > 1) //keep in mind, the output path doesn't include the source
  {
    cout << "from " << allNodes[0].name << " to " << allNodes[allNodes.size()-1].name << endl;
    travelFromSourceToSink(&allNodes[0], &allNodes[allNodes.size()-1]);
  }
}

void Navigation::inputNodes(const char* filename)
{
	ifstream in;
	string inStr;
	int numNeighbors;
	int neighbor;
	int weight;
	int direction;

	in.open(filename);

	if(in.good()){ //if the file was successfully opened
		in >> inStr; //read the number of nodes
		numNodes = atoi(inStr.c_str()); //change the string we read to an int
		for(int i = 0; i < numNodes; i++){ //loop for each node we have
			in >> inStr; //read the name of a node
			Node n(inStr, Node::DNE); //create a new node with nonexistant g value
      		n.parent = NULL;
			allNodes.push_back(n); //put that node in the list of all nodes
		}

		for(int i = 0; i < numNodes; i++){ //loop for each node we have
			in >> inStr; //read the number of neighbors a node has
			numNeighbors = atoi(inStr.c_str());
			for(int j = 0; j < numNeighbors; j++) { //loop for each neighbor of a node
				in >> inStr;
				neighbor = atoi(inStr.c_str()); //read the nodes neighbor
				in >> inStr;
				weight = atoi(inStr.c_str());
				in >> inStr;
				direction = atoi(inStr.c_str());
				// allNodes[i].info[j] = make_tuple(&allNodes[neighbor], weight, direction);
				allNodes[i].neighbors.push_back(&allNodes[neighbor]); //store the node in the list of neighbors
				// in >> inStr; //read the neighbors weight
				allNodes[i].weights.push_back(weight); //assign the weight
				allNodes[i].directions.push_back(direction); //assign the direction we need to go in to reach the neighbor
			}
		}
	}
}

bool Navigation::travelFromSourceToSink(Node* source, Node* sink)
{
  vector<Node*> path = findPath(source, sink); //should be (current, sink) with current starting at source
  #ifdef DEBUG
  outputPath(path);
  #endif
  return walkPath(path);
}

Node* Navigation::getNode(int index)
{
  return &allNodes[index];
}

vector<Node*> Navigation::dbgReconstructPath(Node* current)
{
  vector<Node*> path;

  #ifdef TEST
    return reconstructPath(current);
  #else
    cout << "This function is only for testing." << endl;
  #endif

  return path;
}

vector<Node*> Navigation::dbgFindPath(Node* source, Node* sink)
{
  vector<Node*> path;

  #ifdef TEST
    return findPath(source, sink);
  #else
    cout << "This function is only for testing." << endl;
  #endif

  return path;
}

/*Node Navigation::walkToStartingNode()
{

	//if(OR::atNode()) {
		//return OR::currentNode();
	//}

	//While(!OR::atNode()) {
		//if(OR::straight()) {
			//Roomba::drive(Warp 5, 0);
		//} else {
			//degrees = OR::somethingWithSlopes?()
			//Roomba::drive(0, degrees)
		//}
	//}

	//return OR::currentNode();
}*/

void Navigation::moveForwardUntilSignOrBlockage()
{
  roomba.drive(500, 0); //                              is drive temporary or constant until you drive(0, 0)???????
  while(cam.getfloorsign().empty() && !cam.getpathisblocked())
  {
    cam.update();
  }
  if(!cam.getfloorsign().empty())
  {
    //move forward just a bit more so we're on top of it.
    drive(100, 0); //temp arbitrary numbers
  }
}

bool Navigation::walkPath(const vector<Node*>& path)
{
  //walk the walk using roomba commands
  if(path.empty())
    return false;
  //assume we're on node path[0] and turn towards path[1].

  for(size_t i=1; i<path.size(); ++i)
  {
    bool arrived = false;
    string nodeGoal = path[i]->name;
  	while(!arrived) //is this loop actually doing anything? i.e. does it always only run once?
    {
  		moveForwardUntilSignOrBlockage();
  		if(cam.getpathisblocked())
      {
        cout << "Path is blocked. Turning around." << endl;
  			roomba.drive(0, 180); //turn around
  			//move towards last intersection
        moveForwardUntilSignOrBlockage();                //ASSUMING NO BLOCKAGE HERE

        //update weights where blockage exists
        incrementWeight(path[i-1], path[i]);

  			path = findPath(path[i-1], path[path.size()-1]);
        return walkPath(path);
  		}
      else if(!cam.getfloorsign().empty())
      {
  			arrived = true;
  			//check what direction we need to go
  			//turn
  		}
  	}
  }

  return true;
}

vector<Node*> Navigation::findPath(Node* source, Node* sink)
{
  //cout << "findPath" << endl;
  for(size_t i=0; i<allNodes.size(); ++i)
  {
    allNodes[i].g_score = Node::DNE;
    allNodes[i].parent = NULL;
  }

  source->g_score = 0.0;
  //The set of tentative Nodes that need to be evaluated, starting with sink
  queue<Node*> openSet;
  openSet.push(source);

  //while openset is not empty
  while(!openSet.empty())
  {
    //cout << "loop openSet.size() :: " << openSet.size() << endl;
    Node* current = openSet.front();
    // cout << current->name << endl;
    openSet.pop();

    //for each neighbor in current->neighbors
    //cout << "neighbors.size() :: " << current->neighbors.size() << endl;
    for(size_t i=0; i<current->neighbors.size(); ++i)
    {
      Node* neighbor = current->neighbors[i];
      if(neighbor == NULL)
        continue;
      double tempScore = current->g_score + current->weights[i];
      //if neighbor not yet evaluated or better score
      if(neighbor->g_score == Node::DNE || tempScore < neighbor->g_score)
      {
        //if neighbor not yet evaluated
        if(neighbor->g_score == Node::DNE)
          //add neighbor to openset
          openSet.push(neighbor);
        //came_from[neighbor] = current
        neighbor->parent = current;
        //g_score[neighbor] = tentative_g_score
        neighbor->g_score= tempScore;
      }
    }
  }

  return reconstructPath(source, sink);
}

vector<Node*> Navigation::reconstructPath(Node* source, Node* sink)
{
  Node* current = sink;
  vector<Node*> path;
  while(current->parent != NULL)
  {
    path.insert(path.begin(), current);
    current = current->parent;
  }
  path.insert(path.begin(), source);
  return path;
}

void Navigation::incrementWeight(Node* n1, Node* n2)
{
  for(size_t i=0; i<n1->neighbors.size(); ++i)
  {
    if(n1->neighbors[i] == n2)
    {
      n1->weights[i] += Node::LARGE_NUM;
      break;
    }
  }
  for(size_t i=0; i<n2->neighbors.size(); ++i)
  {
    if(n2->neighbors[i] == n1)
    {
      n2->weights[i] += Node::LARGE_NUM;
      break;
    }
  }
}

void Navigation::outputPath(const vector<Node*>& path)
{
  cout << endl << "start path" << endl;
  for(size_t i=0; i<path.size(); ++i)
  {
    cout << "\t" << path[i]->name << endl;
  }
  cout << "end path\n" << endl;
}

void Navigation::outputAllNodes()
{
  for(size_t i=0; i<allNodes.size(); ++i)
  {
    cout << allNodes[i].name << " " << allNodes[i].neighbors.size() << endl;
  }
}

<|endoftext|>


<commit_before>#include "AssetConverterSkeleton.hpp"

#include <glm/gtc/quaternion.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <Engine/Geometry/MathFunctions.hpp>
#include <Engine/Animation/Skeleton.hpp>
#include <Utility/Log.hpp>

#ifdef USINGMEMTRACK
#include <MemTrackInclude.hpp>
#endif

AssetConverterSkeleton::AssetConverterSkeleton() {
}

AssetConverterSkeleton::~AssetConverterSkeleton() {
}

bool AssetConverterSkeleton::Convert(const char* filepath, const char* destination, bool isSkeleton) {
    success = true;
    errorString = "";

    const aiScene* aScene = aImporter.ReadFile(filepath, 0);

    bones.clear();
    bones.shrink_to_fit();

    if (!aScene->HasAnimations()) {
        errorString.append("Error: No animation in scene.");
        success = false;

        // Free memory.
        aImporter.FreeScene();
        return false;
    }

    // Push back the bones.
    for (unsigned int i = 0; i < aScene->mMeshes[0]->mNumBones; ++i)
        if (aScene->mMeshes[0]->mBones[i]->mName.C_Str() != aScene->mMeshes[0]->mName.C_Str())
            bones.push_back(aScene->mMeshes[0]->mBones[i]->mName.C_Str());

    currentId = -1;
    SceneRecursive(aScene->mRootNode, -1);

    if (isSkeleton) {
        Animation::Skeleton skeleton;
        for (unsigned int i = 0; i < aScene->mAnimations[0]->mNumChannels; ++i) {
            auto boneIndex = 0;
            for (auto j = 0; j < aScene->mAnimations[0]->mNumChannels; ++j)
                if (aScene->mAnimations[0]->mChannels[j]->mNodeName.C_Str() == bones[i]) {
                    boneIndex = j;
                    break;
                }

            aiNodeAnim* channel = aScene->mAnimations[0]->mChannels[boneIndex];
            Animation::Skeleton::SkeletonBone* bone = new Animation::Skeleton::SkeletonBone;
            bone->parentId = (uint32_t)parents[i];

            // Build bindpose.
            glm::mat4 scaleMatrix(1.f);
            glm::mat4 posMatrix(1.0f);

            glm::quat rot;
            rot.x = channel->mRotationKeys[0].mValue.x;
            rot.y = channel->mRotationKeys[0].mValue.y;
            rot.z = channel->mRotationKeys[0].mValue.z;
            rot.w = channel->mRotationKeys[0].mValue.w;

            glm::mat4 matRot(rot);

            glm::vec3 pos;
            pos.x = channel->mPositionKeys[0].mValue.x;
            pos.y = channel->mPositionKeys[0].mValue.y;
            pos.z = channel->mPositionKeys[0].mValue.z;
            posMatrix = glm::translate(posMatrix, pos);

            glm::vec3 scale(1.f, 1.f, 1.f);
            scaleMatrix = glm::scale(scaleMatrix, scale);

            bone->localTx = posMatrix * (matRot * scaleMatrix);

            skeleton.skeletonBones.push_back(bone);
        }

        // Save to file.
        skeleton.Save((std::string(destination)).c_str());
    } else {
        Animation::AnimationClip::Animation anim;
        anim.numBones = bones.size();
        anim.bones = new Animation::AnimationClip::Bone[aScene->mAnimations[0]->mNumChannels];
        anim.length = (uint32_t)aScene->mAnimations[0]->mChannels[aScene->mAnimations[0]->mChannels[1]->mNumRotationKeys - 1]->mRotationKeys->mTime;

        for (unsigned int i = 0; i < bones.size(); ++i) {
            auto boneIndex = 0;
            for (auto j = 0; j < aScene->mAnimations[0]->mNumChannels; ++j)
                if (aScene->mAnimations[0]->mChannels[j]->mNodeName.C_Str() == bones[i])
                    boneIndex = j;

            aiNodeAnim* channel = aScene->mAnimations[0]->mChannels[boneIndex];
            anim.bones[i].parent = (uint32_t)parents[i];
            anim.bones[i].numRotationKeys = channel->mNumRotationKeys;
            anim.bones[i].rotationKeys = new int32_t[channel->mNumRotationKeys];
            anim.bones[i].rotations = new glm::mat4[channel->mNumRotationKeys];

            // Build keyframes for the bone.
            for (unsigned int j = 0; j < channel->mNumRotationKeys; ++j) {
                anim.bones[i].rotationKeys[j] = channel->mRotationKeys[j].mTime;

                glm::mat4 posMatrix(1.0f);
                glm::mat4 scaleMatrix(1.0f);

                glm::quat rot;
                rot.x = channel->mRotationKeys[j].mValue.x;
                rot.y = channel->mRotationKeys[j].mValue.y;
                rot.z = channel->mRotationKeys[j].mValue.z;
                rot.w = channel->mRotationKeys[j].mValue.w;

                glm::vec3 pos;
                pos.x = channel->mPositionKeys[j].mValue.x;
                pos.y = channel->mPositionKeys[j].mValue.y;
                pos.z = channel->mPositionKeys[j].mValue.z;

                posMatrix = glm::translate(posMatrix, pos);

                glm::vec3 scale(1.f, 1.f, 1.f);
                scaleMatrix = glm::scale(scaleMatrix, scale);

                anim.bones[i].rotations[j] = posMatrix * (glm::mat4(rot) * scaleMatrix);
            }
        }

        // Save.
        std::ofstream file((std::string(destination)).c_str(), std::ios::binary);
        anim.Save(&file);
        file.close();
    }

    // Free memory.
    aImporter.FreeScene();

    return true;
}

bool AssetConverterSkeleton::Success() const {
    return success;
}

const std::string& AssetConverterSkeleton::GetErrorString() {
    return errorString;
}

void AssetConverterSkeleton::SceneRecursive(aiNode* node, int parent) {
    if (!node)
        return;

    int thisId = currentId;

    for (auto i = 0; i < node->mNumChildren; ++i) {
        aiNode* child = node->mChildren[i];
        bool foundBone = false;
        for (auto j = 0; j < bones.size(); ++j)
            if (child->mName.C_Str() == bones[j]) {
                children.push_back(child->mName.C_Str());
                ids.push_back(0);
                ++currentId;
                parents.push_back(-1);
                BoneRecursive(child, 0);
            }

        if (!foundBone)
            SceneRecursive(child, thisId);
    }
}

void AssetConverterSkeleton::BoneRecursive(aiNode* node, int parent) {
    if (!node)
        return;

    int thisId = currentId;

    for (auto i = 0; i < node->mNumChildren; ++i) {
        aiNode* child = node->mChildren[i];
        bool foundBone = false;
        for (auto j = 0; j < bones.size() && !foundBone; ++j) {
            if (child->mName.C_Str() == bones[j]) {
                children.push_back(child->mName.C_Str());
                ids.push_back(thisId);

                for (auto k = 0; k < bones.size(); ++k)
                    if (bones[k] == child->mParent->mName.C_Str()) {
                        parents.push_back(k);
                        break;
                    }

                ++currentId;
                foundBone = true;
                BoneRecursive(child, thisId);
            }
        }

        if (!foundBone)
            return;
    }
}
<commit_msg>Removed bracets.<commit_after>#include "AssetConverterSkeleton.hpp"

#include <glm/gtc/quaternion.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <Engine/Geometry/MathFunctions.hpp>
#include <Engine/Animation/Skeleton.hpp>
#include <Utility/Log.hpp>

#ifdef USINGMEMTRACK
#include <MemTrackInclude.hpp>
#endif

AssetConverterSkeleton::AssetConverterSkeleton() {
}

AssetConverterSkeleton::~AssetConverterSkeleton() {
}

bool AssetConverterSkeleton::Convert(const char* filepath, const char* destination, bool isSkeleton) {
    success = true;
    errorString = "";

    const aiScene* aScene = aImporter.ReadFile(filepath, 0);

    bones.clear();
    bones.shrink_to_fit();

    if (!aScene->HasAnimations()) {
        errorString.append("Error: No animation in scene.");
        success = false;

        // Free memory.
        aImporter.FreeScene();
        return false;
    }

    // Push back the bones.
    for (unsigned int i = 0; i < aScene->mMeshes[0]->mNumBones; ++i)
        if (aScene->mMeshes[0]->mBones[i]->mName.C_Str() != aScene->mMeshes[0]->mName.C_Str())
            bones.push_back(aScene->mMeshes[0]->mBones[i]->mName.C_Str());

    currentId = -1;
    SceneRecursive(aScene->mRootNode, -1);

    if (isSkeleton) {
        Animation::Skeleton skeleton;
        for (unsigned int i = 0; i < aScene->mAnimations[0]->mNumChannels; ++i) {
            auto boneIndex = 0;
            for (auto j = 0; j < aScene->mAnimations[0]->mNumChannels; ++j)
                if (aScene->mAnimations[0]->mChannels[j]->mNodeName.C_Str() == bones[i]) {
                    boneIndex = j;
                    break;
                }

            aiNodeAnim* channel = aScene->mAnimations[0]->mChannels[boneIndex];
            Animation::Skeleton::SkeletonBone* bone = new Animation::Skeleton::SkeletonBone;
            bone->parentId = (uint32_t)parents[i];

            // Build bindpose.
            glm::mat4 scaleMatrix(1.f);
            glm::mat4 posMatrix(1.0f);

            glm::quat rot;
            rot.x = channel->mRotationKeys[0].mValue.x;
            rot.y = channel->mRotationKeys[0].mValue.y;
            rot.z = channel->mRotationKeys[0].mValue.z;
            rot.w = channel->mRotationKeys[0].mValue.w;

            glm::mat4 matRot(rot);

            glm::vec3 pos;
            pos.x = channel->mPositionKeys[0].mValue.x;
            pos.y = channel->mPositionKeys[0].mValue.y;
            pos.z = channel->mPositionKeys[0].mValue.z;
            posMatrix = glm::translate(posMatrix, pos);

            glm::vec3 scale(1.f, 1.f, 1.f);
            scaleMatrix = glm::scale(scaleMatrix, scale);

            bone->localTx = posMatrix * (matRot * scaleMatrix);

            skeleton.skeletonBones.push_back(bone);
        }

        // Save to file.
        skeleton.Save((std::string(destination)).c_str());
    } else {
        Animation::AnimationClip::Animation anim;
        anim.numBones = bones.size();
        anim.bones = new Animation::AnimationClip::Bone[aScene->mAnimations[0]->mNumChannels];
        anim.length = (uint32_t)aScene->mAnimations[0]->mChannels[aScene->mAnimations[0]->mChannels[1]->mNumRotationKeys - 1]->mRotationKeys->mTime;

        for (unsigned int i = 0; i < bones.size(); ++i) {
            auto boneIndex = 0;
            for (auto j = 0; j < aScene->mAnimations[0]->mNumChannels; ++j)
                if (aScene->mAnimations[0]->mChannels[j]->mNodeName.C_Str() == bones[i])
                    boneIndex = j;

            aiNodeAnim* channel = aScene->mAnimations[0]->mChannels[boneIndex];
            anim.bones[i].parent = (uint32_t)parents[i];
            anim.bones[i].numRotationKeys = channel->mNumRotationKeys;
            anim.bones[i].rotationKeys = new int32_t[channel->mNumRotationKeys];
            anim.bones[i].rotations = new glm::mat4[channel->mNumRotationKeys];

            // Build keyframes for the bone.
            for (unsigned int j = 0; j < channel->mNumRotationKeys; ++j) {
                anim.bones[i].rotationKeys[j] = channel->mRotationKeys[j].mTime;

                glm::mat4 posMatrix(1.0f);
                glm::mat4 scaleMatrix(1.0f);

                glm::quat rot;
                rot.x = channel->mRotationKeys[j].mValue.x;
                rot.y = channel->mRotationKeys[j].mValue.y;
                rot.z = channel->mRotationKeys[j].mValue.z;
                rot.w = channel->mRotationKeys[j].mValue.w;

                glm::vec3 pos;
                pos.x = channel->mPositionKeys[j].mValue.x;
                pos.y = channel->mPositionKeys[j].mValue.y;
                pos.z = channel->mPositionKeys[j].mValue.z;

                posMatrix = glm::translate(posMatrix, pos);

                glm::vec3 scale(1.f, 1.f, 1.f);
                scaleMatrix = glm::scale(scaleMatrix, scale);

                anim.bones[i].rotations[j] = posMatrix * (glm::mat4(rot) * scaleMatrix);
            }
        }

        // Save.
        std::ofstream file((std::string(destination)).c_str(), std::ios::binary);
        anim.Save(&file);
        file.close();
    }

    // Free memory.
    aImporter.FreeScene();

    return true;
}

bool AssetConverterSkeleton::Success() const {
    return success;
}

const std::string& AssetConverterSkeleton::GetErrorString() {
    return errorString;
}

void AssetConverterSkeleton::SceneRecursive(aiNode* node, int parent) {
    if (!node)
        return;

    int thisId = currentId;

    for (auto i = 0; i < node->mNumChildren; ++i) {
        aiNode* child = node->mChildren[i];
        bool foundBone = false;
        for (auto j = 0; j < bones.size(); ++j)
            if (child->mName.C_Str() == bones[j]) {
                children.push_back(child->mName.C_Str());
                ids.push_back(0);
                ++currentId;
                parents.push_back(-1);
                BoneRecursive(child, 0);
            }

        if (!foundBone)
            SceneRecursive(child, thisId);
    }
}

void AssetConverterSkeleton::BoneRecursive(aiNode* node, int parent) {
    if (!node)
        return;

    int thisId = currentId;

    for (auto i = 0; i < node->mNumChildren; ++i) {
        aiNode* child = node->mChildren[i];
        bool foundBone = false;
        for (auto j = 0; j < bones.size() && !foundBone; ++j)
            if (child->mName.C_Str() == bones[j]) {
                children.push_back(child->mName.C_Str());
                ids.push_back(thisId);

                for (auto k = 0; k < bones.size(); ++k)
                    if (bones[k] == child->mParent->mName.C_Str()) {
                        parents.push_back(k);
                        break;
                    }

                ++currentId;
                foundBone = true;
                BoneRecursive(child, thisId);
            }

        if (!foundBone)
            return;
    }
}
<|endoftext|>


<commit_before>#include "core/system/components/rendering_component.h"
#include "core/system/gameobject.h"

#include "core/rendering/render_manager.h"
#include "core/rendering/renderable_entity.h"

namespace eversim { namespace core { namespace system {

	rendering_component::rendering_component(
		gameobject* owner, rendering::render_manager& mng, std::string const& texture_name
	)
		: component(owner)
	{
		display = mng.register_entity();
		display->set_Texture(*mng.register_texture(texture_name));
		update_transform();
	}

	void rendering_component::post_physics_update()
	{
		update_transform();
	}

	void rendering_component::update_transform()
	{
		display->set_Position(get_owner().get_position() + offset);
		display->set_Scale(get_owner().get_scale());
		// todo: rotation?!?
	}

}}}
<commit_msg>rendering component now also respects angle of the object<commit_after>#include "core/system/components/rendering_component.h"
#include "core/system/gameobject.h"

#include "core/rendering/render_manager.h"
#include "core/rendering/renderable_entity.h"

#include "core/utility/matrix_helper.h"

#include <glm/gtc/matrix_transform.inl>

namespace eversim { namespace core { namespace system {

	rendering_component::rendering_component(
		gameobject* owner, rendering::render_manager& mng, std::string const& texture_name
	)
		: component(owner)
	{
		display = mng.register_entity();
		display->set_Texture(*mng.register_texture(texture_name));
		offset = -.5f*owner->get_scale();
		update_transform();
	}

	void rendering_component::post_physics_update()
	{
		update_transform();
	}

	void rendering_component::update_transform()
	{
		using namespace glm;
		using namespace utility;

		const auto& obj = get_owner();
		auto M = mat3();

		M = scale(obj.get_scale()) * M;
		M = translation(-offset) * rotation(obj.get_angle()) * translation(offset) * M;
		M = translation(obj.get_position() + offset) * M;

		display->set_M(M);
	}

}}}
<|endoftext|>


<commit_before>#pragma once
#include "thread.h"

namespace mini::threading {

namespace detail {

void
thread_dispatcher(
  thread* thread_instance
  )
{
  thread_instance->thread_procedure();
}

DWORD WINAPI
native_thread_dispatcher(
  LPVOID lpParam
  )
{
  thread_dispatcher(reinterpret_cast<thread*>(lpParam));
  return 0;
}

}

//
// constructors.
//

thread::thread(
  void
  )
  //
  // it's quite important to not use the INVALID_HANDLE_VALUE constant,
  // because the value is same as "current thread" pseudo-handle.
  //
  : _thread_handle(0)
  , _thread_id(0)
{

}

thread::thread(
  thread&& other
  )
  : thread()
{
  swap(other);
}

thread::thread(
  current_thread_tag&
  )
  : _thread_handle(GetCurrentThread())
  , _thread_id(GetCurrentThreadId())
{

}

//
// destructor
//

thread::~thread(
  void
  )
{
  stop();
}

//
// swap.
//

void
thread::swap(
  thread& other
  )
{
  mini::swap(_thread_handle, other._thread_handle);
  mini::swap(_thread_id, other._thread_id);
}

//
// operations.
//

void
thread::start(
  void
  )
{
  if (_thread_id != 0)
  {
    //
    // thread is already running.
    //
    return;
  }

  _thread_handle = CreateThread(
    NULL,                               // default security attributes
    0,                                  // use default stack size
    &detail::native_thread_dispatcher,  // thread function name
    (LPVOID)this,                       // argument to thread function
    0,                                  // use default creation flags
    &_thread_id);                       // returns the thread identifier
}

void
thread::stop(
  void
  )
{
  if (_thread_handle == 0)
  {
    //
    // thread is not running or is already terminated.
    //
    return;
  }

  // bool is_terminated = WaitForSingleObject(_thread_handle, 0) == WAIT_OBJECT_0;

  TerminateThread(_thread_handle, 0);
  CloseHandle(_thread_handle);

  _thread_handle = 0;
  _thread_id = 0;
}

wait_result
thread::join(
  timeout_type timeout
  )
{
  return static_cast<wait_result>(WaitForSingleObject(
    _thread_handle,
    (DWORD)timeout
    ));
}

//
// observers.
//

thread::id
thread::get_id(
  void
  ) const
{
  return _thread_id;
}

bool
thread::is_running(
  void
  ) const
{
  return
    _thread_id != 0 &&
    WaitForSingleObject(_thread_handle, 0) == WAIT_TIMEOUT;
}

//
// static methods.
//

thread
thread::get_current_thread(
  void
  )
{
  return thread(current_thread_tag());
}

void
thread::sleep(
  timeout_type milliseconds
  )
{
  Sleep(milliseconds);
}

//
// virtual methods.
//

void
thread::thread_procedure(
  void
  )
{

}

void
swap(
  thread& lhs,
  thread& rhs
  )
{
  lhs.swap(rhs);
}

}
<commit_msg>fix comment, -1 is current process pseudo-handle<commit_after>#pragma once
#include "thread.h"

namespace mini::threading {

namespace detail {

void
thread_dispatcher(
  thread* thread_instance
  )
{
  thread_instance->thread_procedure();
}

DWORD WINAPI
native_thread_dispatcher(
  LPVOID lpParam
  )
{
  thread_dispatcher(reinterpret_cast<thread*>(lpParam));
  return 0;
}

}

//
// constructors.
//

thread::thread(
  void
  )
  //
  // it's quite important to not use the INVALID_HANDLE_VALUE constant,
  // because the value is same as "current process" pseudo-handle.
  //
  : _thread_handle(0)
  , _thread_id(0)
{

}

thread::thread(
  thread&& other
  )
  : thread()
{
  swap(other);
}

thread::thread(
  current_thread_tag&
  )
  : _thread_handle(GetCurrentThread())
  , _thread_id(GetCurrentThreadId())
{

}

//
// destructor
//

thread::~thread(
  void
  )
{
  stop();
}

//
// swap.
//

void
thread::swap(
  thread& other
  )
{
  mini::swap(_thread_handle, other._thread_handle);
  mini::swap(_thread_id, other._thread_id);
}

//
// operations.
//

void
thread::start(
  void
  )
{
  if (_thread_id != 0)
  {
    //
    // thread is already running.
    //
    return;
  }

  _thread_handle = CreateThread(
    NULL,                               // default security attributes
    0,                                  // use default stack size
    &detail::native_thread_dispatcher,  // thread function name
    (LPVOID)this,                       // argument to thread function
    0,                                  // use default creation flags
    &_thread_id);                       // returns the thread identifier
}

void
thread::stop(
  void
  )
{
  if (_thread_handle == 0)
  {
    //
    // thread is not running or is already terminated.
    //
    return;
  }

  // bool is_terminated = WaitForSingleObject(_thread_handle, 0) == WAIT_OBJECT_0;

  TerminateThread(_thread_handle, 0);
  CloseHandle(_thread_handle);

  _thread_handle = 0;
  _thread_id = 0;
}

wait_result
thread::join(
  timeout_type timeout
  )
{
  return static_cast<wait_result>(WaitForSingleObject(
    _thread_handle,
    (DWORD)timeout
    ));
}

//
// observers.
//

thread::id
thread::get_id(
  void
  ) const
{
  return _thread_id;
}

bool
thread::is_running(
  void
  ) const
{
  return
    _thread_id != 0 &&
    WaitForSingleObject(_thread_handle, 0) == WAIT_TIMEOUT;
}

//
// static methods.
//

thread
thread::get_current_thread(
  void
  )
{
  return thread(current_thread_tag());
}

void
thread::sleep(
  timeout_type milliseconds
  )
{
  Sleep(milliseconds);
}

//
// virtual methods.
//

void
thread::thread_procedure(
  void
  )
{

}

void
swap(
  thread& lhs,
  thread& rhs
  )
{
  lhs.swap(rhs);
}

}
<|endoftext|>