<commit_before>/*
Copyright (C) 2005-2005 by <NAME>

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 "csgeom/math3d.h"
#include "csgeom/matrix3.h"
#include "csgfx/renderbuffer.h"
#include "csutil/randomgen.h"
#include "iengine/material.h"
#include "igraphic/image.h"

#include "densityfactormap.h"
#include "../engine.h"
#include "meshgen.h"
#include "meshgen_positionmap.h"


CS_PLUGIN_NAMESPACE_BEGIN(Engine)
{

csMeshGeneratorGeometry::csMeshGeneratorGeometry (
  csMeshGenerator* generator) : scfImplementationType (this),
  generator (generator)
{
  colldetID = generator->GetStringSet()->Request ("colldet");
  radius = 0.0f;
  density = 1.0f;
  total_max_dist = 0.0f;
  default_material_factor = 0.0f;
  celldim = 0;
  positions = 0;
  wind_direction = csVector2(0.0f);
  wind_bias = 1.0f;
  wind_speed = 1.0f;
}

csMeshGeneratorGeometry::~csMeshGeneratorGeometry ()
{
}

void csMeshGeneratorGeometry::AddSVToMesh (iMeshWrapper* mesh,  
                                           csShaderVariable* sv) 
{ 
  if (!mesh) return; 
  mesh->GetSVContext()->AddVariable (sv); 
  iSceneNode* sn = mesh->QuerySceneNode (); 
  csRef<iSceneNodeArray> children = sn->GetChildrenArray (); 
  size_t i; 
  for (i = 0 ; i < children->GetSize () ; i++) 
    AddSVToMesh (children->Get (i)->QueryMesh (), sv); 
} 

void csMeshGeneratorGeometry::SetMeshBBox (iMeshWrapper* mesh,  
                                           const csBox3& bbox) 
{ 
  if (!mesh) return; 
  mesh->GetMeshObject()->GetObjectModel()->SetObjectBoundingBox (bbox); 
  // FIXME UGLY UGLY UGLY
  // So the player doesn't collide with the huge mesh bbox. 
 	mesh->GetMeshObject()->GetObjectModel()->SetTriangleData (colldetID, 0); 
  iSceneNode* sn = mesh->QuerySceneNode (); 
  csRef<iSceneNodeArray> children = sn->GetChildrenArray (); 
  size_t i; 
  for (i = 0 ; i < children->GetSize () ; i++) 
    SetMeshBBox (children->Get (i)->QueryMesh (), bbox); 
} 

void csMeshGeneratorGeometry::GetDensityMapFactor (float x, float z,
                                                   float &data)
{
  float factorMapScale = 1.0f;
  if (density_map)
  {
    density_map->SampleFloat (density_map_type, x, z, factorMapScale); 
    factorMapScale *= density_map_factor;  
  }
  data = factorMapScale;

  // Sum up all density factor maps
  if (densityFactorMaps.GetSize() > 0)
  {
    csVector3 worldCoord (x, 0, z);
    float factorMapSum = 0;
    for (size_t i = 0; i < densityFactorMaps.GetSize(); i++)
    {
      factorMapSum += densityFactorMaps[i].first->GetDensity (worldCoord)
	* densityFactorMaps[i].second;
    }    
    
    data *= factorMapSum;
  }
}

void csMeshGeneratorGeometry::SetDensityMap (iTerraFormer* map, float factor, 
                                             const csStringID &type)
{
  density_map = map;
  density_map_factor = factor;
  density_map_type = type;
}

bool csMeshGeneratorGeometry::UseDensityFactorMap (const char* factorMapID,
						   float factor)
{
  DensityFactorMap* factorMap = generator->GetDensityFactorMap (factorMapID);
  if (!factorMap) return false;
  densityFactorMaps.Push (DensityFactorMapScalePair (factorMap, factor));
  return true;
}

void csMeshGeneratorGeometry::AddPositionsFromMap (iTerraFormer* map,
	const csBox2 &region, uint resx, uint resy, float value,
	const csStringID & type)
{
  csRef<iTerraSampler> sampler = map->GetSampler (region, resx, resy);
  float stepx = (region.MaxX () - region.MinX ())/resx;
  float stepy = (region.MaxY () - region.MinY ())/resy;

  const float* map_values = sampler->SampleFloat (type);
  float curx = region.MinX (), cury = region.MinY ();
  for (uint i = 0; i < resx; i++)
  {
    for (uint j = 0; j < resy; j++)
    {
      if (map_values[i*resx + j] == value)
      {
        AddPosition (csVector2 (curx, cury));
      }
      curx += stepx;
    }
    curx = region.MinX ();
    cury += stepy;
  }
}

void csMeshGeneratorGeometry::ResetManualPositions (int new_celldim)
{
  if (celldim == new_celldim)
    return;

  csArray<csVector2> tmp_pos;
  for (int i = 0; i < celldim; i++)
  {
    for (size_t j = 0; j < positions[i].GetSize (); j++)
    {
      tmp_pos.Push (positions[i][j]);
    }
  }

  delete[] positions;

  celldim = new_celldim;
  positions = new csArray<csVector2> [celldim*celldim];

  for (size_t i = 0; i < tmp_pos.GetSize (); i++)
  {
    AddPosition (tmp_pos[i]);
  }
}

void csMeshGeneratorGeometry::AddPosition (const csVector2 &pos)
{
  ResetManualPositions (generator->GetCellCount ());
  positions[generator->GetCellId (pos)].Push (pos);
}

void csMeshGeneratorGeometry::AddDensityMaterialFactor (
  iMaterialWrapper* material, float factor)
{
  csMGDensityMaterialFactor mf;
  mf.material = material;
  mf.factor = factor;
  material_factors.Push (mf);
}

static int CompareGeom (csMGGeom const& m1, csMGGeom const& m2)
{
  if (m1.maxdistance < m2.maxdistance) return -1;
  else if (m1.maxdistance > m2.maxdistance) return 1;
  else return 0;
}

void csMeshGeneratorGeometry::AddFactory (iMeshFactoryWrapper* factory,
                                          float maxdist)
{
  csMGGeom g;
  g.factory = factory;
  g.maxdistance = maxdist;
  g.sqmaxdistance = maxdist * maxdist;
  g.factory->GetMeshObjectFactory ()->SetMixMode (CS_FX_COPY);
  g.mesh = generator->engine->CreateMeshWrapper (g.factory, 0);
  g.mesh->GetFlags ().Set (CS_ENTITY_NOHITBEAM);
  g.mesh->SetZBufModeRecursive (CS_ZBUF_USE); 
  g.windDataVar.AttachNew (new csShaderVariable (generator->varWindData));
  g.windDataVar->SetType (csShaderVariable::VECTOR3);
  g.instancesNumVar.AttachNew (new csShaderVariable (generator->varInstancesNum));
  g.transformVar.AttachNew (new csShaderVariable (generator->varTransform)); 
  g.instanceExtraVar.AttachNew (new csShaderVariable (generator->varInstanceExtra)); 
  AddSVToMesh (g.mesh, g.windDataVar);
  AddSVToMesh (g.mesh, g.instancesNumVar);
  AddSVToMesh (g.mesh, g.transformVar); 
  AddSVToMesh (g.mesh, g.instanceExtraVar); 

  csBox3 bbox;
  bbox.SetSize (csVector3 (maxdist, maxdist, maxdist));
  SetMeshBBox (g.mesh, bbox);

  factories.InsertSorted (g, CompareGeom);

  if (maxdist > total_max_dist) total_max_dist = maxdist;
}

void csMeshGeneratorGeometry::RemoveFactory (size_t idx)
{
  factories.DeleteIndex (idx);
}

void csMeshGeneratorGeometry::SetRadius (float radius)
{
  csMeshGeneratorGeometry::radius = radius;
}

void csMeshGeneratorGeometry::SetDensity (float density)
{
  csMeshGeneratorGeometry::density = density;
}

bool csMeshGeneratorGeometry::AllocMesh (
  int cidx, const csMGCell& cell, float sqdist,
  csMGPosition& pos)
{
  size_t lod = GetLODLevel (sqdist);
  if (lod == csArrayItemNotFound) return false;
  pos.lod = lod;

  csMGGeom& geom = factories[lod];
  size_t i = geom.allPositions.GetSize();
  pos.idInGeometry = i;
  csMGPosition*& newPos = geom.allPositions.GetExtend (i);
  newPos = &pos;
  
  geom.allTransforms.GetExtend (i);
  float fadeOpaqueDist =
    generator->use_alpha_scaling ? generator->alpha_mindist : generator->total_max_dist;
  float fadeDistScale =
    generator->use_alpha_scaling ? generator->alpha_scale : 0;
  geom.allInstanceExtra.GetExtend (i).Set (rng.Get(), fadeOpaqueDist, fadeDistScale);

  geom.dataDirty = true;
  
  return true;
}

void csMeshGeneratorGeometry::MoveMesh (int cidx,
                                        const csMGPosition& pos,
                                        const csVector3& position,
                                        const csMatrix3& matrix)
{
  csMGGeom& geom = factories[pos.lod];
  csVector3 meshpos = geom.mesh->GetMovable ()->GetFullPosition ();
  csVector3 relPos = position - meshpos;
  csMGGeom::Transform& tf = geom.allTransforms[pos.idInGeometry];

  /* Based on makeGLMatrix()
     (Transposition 'inherited' from there ...) */
  tf.m[0] = matrix.m11;
  tf.m[4] = matrix.m12;
  tf.m[8] = matrix.m13;

  tf.m[1] = matrix.m21;
  tf.m[5] = matrix.m22;
  tf.m[9] = matrix.m23;

  tf.m[2] = matrix.m31;
  tf.m[6] = matrix.m32;
  tf.m[10] = matrix.m33;

  tf.m[3] = relPos.x;
  tf.m[7] = relPos.y;
  tf.m[11] = relPos.z;

  geom.dataDirty = true;
}

void csMeshGeneratorGeometry::SetFadeParams (csMGPosition& p, float opaqueDist, float scale)
{
  csMGGeom& geom = factories[p.lod];
  csMGGeom::InstanceExtra& extra = geom.allInstanceExtra[p.idInGeometry];
  extra.fadeOpaqueDist = opaqueDist;
  extra.fadeDistScale = scale;

  geom.dataDirty = true;
}

void csMeshGeneratorGeometry::SetWindDirection (float x, float z)
{
  wind_direction.x = x;
  wind_direction.y = z;

  for (size_t g = 0; g < factories.GetSize (); ++g)
  {
    csVector2 maxOffset = wind_direction * wind_speed;
    factories[g].windDataVar->SetValue (csVector3(maxOffset.x, maxOffset.y, wind_bias));
  }
}

void csMeshGeneratorGeometry::SetWindBias (float bias)
{
  wind_bias = csClamp (bias, 1.0f, 0.0f);

  for (size_t g = 0; g < factories.GetSize (); ++g)
  {
    csVector2 maxOffset = wind_direction * wind_speed;
    factories[g].windDataVar->SetValue (csVector3(maxOffset.x, maxOffset.y, wind_bias));
  }
}

void csMeshGeneratorGeometry::SetWindSpeed (float speed)
{
  wind_speed = csClamp (speed, FLT_MAX, 0.0f);

  for (size_t g = 0; g < factories.GetSize (); ++g)
  {
    csVector2 maxOffset = wind_direction * wind_speed;
    factories[g].windDataVar->SetValue (csVector3(maxOffset.x, maxOffset.y, wind_bias));
  }
}

void csMeshGeneratorGeometry::FreeMesh (int cidx, csMGPosition& pos)
{
  csMGGeom& geom = factories[pos.lod];
  
  size_t index = pos.idInGeometry;
  geom.allPositions.DeleteIndexFast (index);
  geom.allTransforms.DeleteIndexFast (index);
  geom.allInstanceExtra.DeleteIndexFast (index);
  geom.dataDirty = true;
  if (index < geom.allPositions.GetSize())
  {
    csMGPosition*& newPos = geom.allPositions[index];
    newPos->idInGeometry = index;
  }
}

void csMeshGeneratorGeometry::FinishUpdate ()
{
  size_t lod;
  for (lod = 0 ; lod < factories.GetSize () ; lod++)
  {
    csMGGeom& geom = factories[lod];
    if (geom.allPositions.GetSize() == 0)
    {
      // No instances
      geom.mesh->GetMovable()->ClearSectors ();
    }
    else
    {
      if (geom.mesh->GetMovable ()->GetSectors()->GetCount() == 0)
      {
	geom.mesh->GetMovable ()->SetSector (generator->GetSector ()); 
      }
      
      geom.instancesNumVar->SetValue (int (geom.allPositions.GetSize()));

      /* Update buffers
         (Compare capacity instead of size so a buffer is kept if the number of
         elements changes only slightly.) */
      bool updateTransformData = geom.dataDirty;
      if (!geom.transformBuffer
	|| (geom.transformBuffer->GetElementCount() != geom.allTransforms.Capacity()))
      {
	geom.transformBuffer = csRenderBuffer::CreateRenderBuffer (geom.allTransforms.Capacity(),
								   CS_BUF_STREAM, CS_BUFCOMP_FLOAT,
								   sizeof (csMGGeom::Transform) / sizeof(float));
	geom.transformVar->SetValue (geom.transformBuffer);
	updateTransformData = true;
      }
      if (updateTransformData) geom.transformBuffer->SetData (geom.allTransforms.GetArray());

      bool updateExtraData = geom.dataDirty;
      if (!geom.instanceExtraBuffer
	|| (geom.instanceExtraBuffer->GetElementCount() != geom.allInstanceExtra.Capacity()))
      {
	geom.instanceExtraBuffer = csRenderBuffer::CreateRenderBuffer (geom.allInstanceExtra.Capacity(),
								       CS_BUF_STREAM, CS_BUFCOMP_FLOAT,
								       sizeof (csMGGeom::InstanceExtra) / sizeof(float));
	geom.instanceExtraVar->SetValue (geom.instanceExtraBuffer);
	updateExtraData = true;
      }
      if (updateExtraData) geom.instanceExtraBuffer->SetData (geom.allInstanceExtra.GetArray());

      geom.dataDirty = false;
    }
    geom.mesh->GetMovable ()->UpdateMove ();
  }
}

size_t csMeshGeneratorGeometry::GetLODLevel (float sqdist)
{
  size_t i;
  for (i = 0 ; i < factories.GetSize () ; i++)
  {
    csMGGeom& geom = factories[i];
    if (sqdist <= geom.sqmaxdistance)
    {
      return i;
    }
  }
  return csArrayItemNotFound;
}

bool csMeshGeneratorGeometry::IsRightLOD (float sqdist, size_t current_lod)
{
  // With only one lod level we are always right.
  if (factories.GetSize () <= 1) return true;
  if (current_lod == 0)
    return (sqdist <= factories[0].sqmaxdistance);
  else
    return (sqdist <= factories[current_lod].sqmaxdistance) &&
    (sqdist > factories[current_lod-1].sqmaxdistance);
}

void csMeshGeneratorGeometry::UpdatePosition (const csVector3& pos) 
{ 
  for (size_t f = 0; f < factories.GetSize(); f++) 
  { 
    factories[f].mesh->GetMovable()->SetPosition (pos); 
  } 
} 

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

csMeshGenerator::csMeshGenerator (csEngine* engine) : 
  scfImplementationType (this), total_max_dist (-1.0f), minRadius(-1.0f),
  use_density_scaling (false), use_alpha_scaling (false),
  last_pos (0, 0, 0), setup_cells (false),
  cell_dim (50), inuse_blocks (0), inuse_blocks_last (0),
  max_blocks (100), engine (engine)
{
  cells = new csMGCell [cell_dim * cell_dim];

  for (size_t i = 0 ; i < size_t (max_blocks) ; i++)<commit_msg>Fixed a bug in meshgen where I forgot to initialize a variable.<commit_after>/*
Copyright (C) 2005-2005 by <NAME>

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 "csgeom/math3d.h"
#include "csgeom/matrix3.h"
#include "csgfx/renderbuffer.h"
#include "csutil/randomgen.h"
#include "iengine/material.h"
#include "igraphic/image.h"

#include "densityfactormap.h"
#include "../engine.h"
#include "meshgen.h"
#include "meshgen_positionmap.h"


CS_PLUGIN_NAMESPACE_BEGIN(Engine)
{

csMeshGeneratorGeometry::csMeshGeneratorGeometry (
  csMeshGenerator* generator) : scfImplementationType (this),
  generator (generator)
{
  colldetID = generator->GetStringSet()->Request ("colldet");
  radius = 0.0f;
  density = 1.0f;
  total_max_dist = 0.0f;
  default_material_factor = 0.0f;
  celldim = 0;
  positions = 0;
  wind_direction = csVector2(0.0f);
  wind_bias = 1.0f;
  wind_speed = 1.0f;
}

csMeshGeneratorGeometry::~csMeshGeneratorGeometry ()
{
}

void csMeshGeneratorGeometry::AddSVToMesh (iMeshWrapper* mesh,  
                                           csShaderVariable* sv) 
{ 
  if (!mesh) return; 
  mesh->GetSVContext()->AddVariable (sv); 
  iSceneNode* sn = mesh->QuerySceneNode (); 
  csRef<iSceneNodeArray> children = sn->GetChildrenArray (); 
  size_t i; 
  for (i = 0 ; i < children->GetSize () ; i++) 
    AddSVToMesh (children->Get (i)->QueryMesh (), sv); 
} 

void csMeshGeneratorGeometry::SetMeshBBox (iMeshWrapper* mesh,  
                                           const csBox3& bbox) 
{ 
  if (!mesh) return; 
  mesh->GetMeshObject()->GetObjectModel()->SetObjectBoundingBox (bbox); 
  // FIXME UGLY UGLY UGLY
  // So the player doesn't collide with the huge mesh bbox. 
 	mesh->GetMeshObject()->GetObjectModel()->SetTriangleData (colldetID, 0); 
  iSceneNode* sn = mesh->QuerySceneNode (); 
  csRef<iSceneNodeArray> children = sn->GetChildrenArray (); 
  size_t i; 
  for (i = 0 ; i < children->GetSize () ; i++) 
    SetMeshBBox (children->Get (i)->QueryMesh (), bbox); 
} 

void csMeshGeneratorGeometry::GetDensityMapFactor (float x, float z,
                                                   float &data)
{
  float factorMapScale = 1.0f;
  if (density_map)
  {
    density_map->SampleFloat (density_map_type, x, z, factorMapScale); 
    factorMapScale *= density_map_factor;  
  }
  data = factorMapScale;

  // Sum up all density factor maps
  if (densityFactorMaps.GetSize() > 0)
  {
    csVector3 worldCoord (x, 0, z);
    float factorMapSum = 0;
    for (size_t i = 0; i < densityFactorMaps.GetSize(); i++)
    {
      factorMapSum += densityFactorMaps[i].first->GetDensity (worldCoord)
	* densityFactorMaps[i].second;
    }    
    
    data *= factorMapSum;
  }
}

void csMeshGeneratorGeometry::SetDensityMap (iTerraFormer* map, float factor, 
                                             const csStringID &type)
{
  density_map = map;
  density_map_factor = factor;
  density_map_type = type;
}

bool csMeshGeneratorGeometry::UseDensityFactorMap (const char* factorMapID,
						   float factor)
{
  DensityFactorMap* factorMap = generator->GetDensityFactorMap (factorMapID);
  if (!factorMap) return false;
  densityFactorMaps.Push (DensityFactorMapScalePair (factorMap, factor));
  return true;
}

void csMeshGeneratorGeometry::AddPositionsFromMap (iTerraFormer* map,
	const csBox2 &region, uint resx, uint resy, float value,
	const csStringID & type)
{
  csRef<iTerraSampler> sampler = map->GetSampler (region, resx, resy);
  float stepx = (region.MaxX () - region.MinX ())/resx;
  float stepy = (region.MaxY () - region.MinY ())/resy;

  const float* map_values = sampler->SampleFloat (type);
  float curx = region.MinX (), cury = region.MinY ();
  for (uint i = 0; i < resx; i++)
  {
    for (uint j = 0; j < resy; j++)
    {
      if (map_values[i*resx + j] == value)
      {
        AddPosition (csVector2 (curx, cury));
      }
      curx += stepx;
    }
    curx = region.MinX ();
    cury += stepy;
  }
}

void csMeshGeneratorGeometry::ResetManualPositions (int new_celldim)
{
  if (celldim == new_celldim)
    return;

  csArray<csVector2> tmp_pos;
  for (int i = 0; i < celldim; i++)
  {
    for (size_t j = 0; j < positions[i].GetSize (); j++)
    {
      tmp_pos.Push (positions[i][j]);
    }
  }

  delete[] positions;

  celldim = new_celldim;
  positions = new csArray<csVector2> [celldim*celldim];

  for (size_t i = 0; i < tmp_pos.GetSize (); i++)
  {
    AddPosition (tmp_pos[i]);
  }
}

void csMeshGeneratorGeometry::AddPosition (const csVector2 &pos)
{
  ResetManualPositions (generator->GetCellCount ());
  positions[generator->GetCellId (pos)].Push (pos);
}

void csMeshGeneratorGeometry::AddDensityMaterialFactor (
  iMaterialWrapper* material, float factor)
{
  csMGDensityMaterialFactor mf;
  mf.material = material;
  mf.factor = factor;
  material_factors.Push (mf);
}

static int CompareGeom (csMGGeom const& m1, csMGGeom const& m2)
{
  if (m1.maxdistance < m2.maxdistance) return -1;
  else if (m1.maxdistance > m2.maxdistance) return 1;
  else return 0;
}

void csMeshGeneratorGeometry::AddFactory (iMeshFactoryWrapper* factory,
                                          float maxdist)
{
  csMGGeom g;
  g.factory = factory;
  g.maxdistance = maxdist;
  g.sqmaxdistance = maxdist * maxdist;
  g.factory->GetMeshObjectFactory ()->SetMixMode (CS_FX_COPY);
  g.mesh = generator->engine->CreateMeshWrapper (g.factory, 0);
  g.mesh->GetFlags ().Set (CS_ENTITY_NOHITBEAM);
  g.mesh->SetZBufModeRecursive (CS_ZBUF_USE); 
  g.windDataVar.AttachNew (new csShaderVariable (generator->varWindData));
  g.windDataVar->SetType (csShaderVariable::VECTOR3);
  g.instancesNumVar.AttachNew (new csShaderVariable (generator->varInstancesNum));
  g.transformVar.AttachNew (new csShaderVariable (generator->varTransform)); 
  g.instanceExtraVar.AttachNew (new csShaderVariable (generator->varInstanceExtra)); 
  AddSVToMesh (g.mesh, g.windDataVar);
  AddSVToMesh (g.mesh, g.instancesNumVar);
  AddSVToMesh (g.mesh, g.transformVar); 
  AddSVToMesh (g.mesh, g.instanceExtraVar); 

  csBox3 bbox;
  bbox.SetSize (csVector3 (maxdist, maxdist, maxdist));
  SetMeshBBox (g.mesh, bbox);

  factories.InsertSorted (g, CompareGeom);

  if (maxdist > total_max_dist) total_max_dist = maxdist;
}

void csMeshGeneratorGeometry::RemoveFactory (size_t idx)
{
  factories.DeleteIndex (idx);
}

void csMeshGeneratorGeometry::SetRadius (float radius)
{
  csMeshGeneratorGeometry::radius = radius;
}

void csMeshGeneratorGeometry::SetDensity (float density)
{
  csMeshGeneratorGeometry::density = density;
}

bool csMeshGeneratorGeometry::AllocMesh (
  int cidx, const csMGCell& cell, float sqdist,
  csMGPosition& pos)
{
  size_t lod = GetLODLevel (sqdist);
  if (lod == csArrayItemNotFound) return false;
  pos.lod = lod;

  csMGGeom& geom = factories[lod];
  size_t i = geom.allPositions.GetSize();
  pos.idInGeometry = i;
  csMGPosition*& newPos = geom.allPositions.GetExtend (i);
  newPos = &pos;
  
  geom.allTransforms.GetExtend (i);
  float fadeOpaqueDist =
    generator->use_alpha_scaling ? generator->alpha_mindist : generator->total_max_dist;
  float fadeDistScale =
    generator->use_alpha_scaling ? generator->alpha_scale : 0;
  geom.allInstanceExtra.GetExtend (i).Set (rng.Get(), fadeOpaqueDist, fadeDistScale);

  geom.dataDirty = true;
  
  return true;
}

void csMeshGeneratorGeometry::MoveMesh (int cidx,
                                        const csMGPosition& pos,
                                        const csVector3& position,
                                        const csMatrix3& matrix)
{
  csMGGeom& geom = factories[pos.lod];
  csVector3 meshpos = geom.mesh->GetMovable ()->GetFullPosition ();
  csVector3 relPos = position - meshpos;
  csMGGeom::Transform& tf = geom.allTransforms[pos.idInGeometry];

  /* Based on makeGLMatrix()
     (Transposition 'inherited' from there ...) */
  tf.m[0] = matrix.m11;
  tf.m[4] = matrix.m12;
  tf.m[8] = matrix.m13;

  tf.m[1] = matrix.m21;
  tf.m[5] = matrix.m22;
  tf.m[9] = matrix.m23;

  tf.m[2] = matrix.m31;
  tf.m[6] = matrix.m32;
  tf.m[10] = matrix.m33;

  tf.m[3] = relPos.x;
  tf.m[7] = relPos.y;
  tf.m[11] = relPos.z;

  geom.dataDirty = true;
}

void csMeshGeneratorGeometry::SetFadeParams (csMGPosition& p, float opaqueDist, float scale)
{
  csMGGeom& geom = factories[p.lod];
  csMGGeom::InstanceExtra& extra = geom.allInstanceExtra[p.idInGeometry];
  extra.fadeOpaqueDist = opaqueDist;
  extra.fadeDistScale = scale;

  geom.dataDirty = true;
}

void csMeshGeneratorGeometry::SetWindDirection (float x, float z)
{
  wind_direction.x = x;
  wind_direction.y = z;

  for (size_t g = 0; g < factories.GetSize (); ++g)
  {
    csVector2 maxOffset = wind_direction * wind_speed;
    factories[g].windDataVar->SetValue (csVector3(maxOffset.x, maxOffset.y, wind_bias));
  }
}

void csMeshGeneratorGeometry::SetWindBias (float bias)
{
  wind_bias = csClamp (bias, 1.0f, 0.0f);

  for (size_t g = 0; g < factories.GetSize (); ++g)
  {
    csVector2 maxOffset = wind_direction * wind_speed;
    factories[g].windDataVar->SetValue (csVector3(maxOffset.x, maxOffset.y, wind_bias));
  }
}

void csMeshGeneratorGeometry::SetWindSpeed (float speed)
{
  wind_speed = csClamp (speed, FLT_MAX, 0.0f);

  for (size_t g = 0; g < factories.GetSize (); ++g)
  {
    csVector2 maxOffset = wind_direction * wind_speed;
    factories[g].windDataVar->SetValue (csVector3(maxOffset.x, maxOffset.y, wind_bias));
  }
}

void csMeshGeneratorGeometry::FreeMesh (int cidx, csMGPosition& pos)
{
  csMGGeom& geom = factories[pos.lod];
  
  size_t index = pos.idInGeometry;
  geom.allPositions.DeleteIndexFast (index);
  geom.allTransforms.DeleteIndexFast (index);
  geom.allInstanceExtra.DeleteIndexFast (index);
  geom.dataDirty = true;
  if (index < geom.allPositions.GetSize())
  {
    csMGPosition*& newPos = geom.allPositions[index];
    newPos->idInGeometry = index;
  }
}

void csMeshGeneratorGeometry::FinishUpdate ()
{
  size_t lod;
  for (lod = 0 ; lod < factories.GetSize () ; lod++)
  {
    csMGGeom& geom = factories[lod];
    if (geom.allPositions.GetSize() == 0)
    {
      // No instances
      geom.mesh->GetMovable()->ClearSectors ();
    }
    else
    {
      if (geom.mesh->GetMovable ()->GetSectors()->GetCount() == 0)
      {
	geom.mesh->GetMovable ()->SetSector (generator->GetSector ()); 
      }
      
      geom.instancesNumVar->SetValue (int (geom.allPositions.GetSize()));

      /* Update buffers
         (Compare capacity instead of size so a buffer is kept if the number of
         elements changes only slightly.) */
      bool updateTransformData = geom.dataDirty;
      if (!geom.transformBuffer
	|| (geom.transformBuffer->GetElementCount() != geom.allTransforms.Capacity()))
      {
	geom.transformBuffer = csRenderBuffer::CreateRenderBuffer (geom.allTransforms.Capacity(),
								   CS_BUF_STREAM, CS_BUFCOMP_FLOAT,
								   sizeof (csMGGeom::Transform) / sizeof(float));
	geom.transformVar->SetValue (geom.transformBuffer);
	updateTransformData = true;
      }
      if (updateTransformData) geom.transformBuffer->SetData (geom.allTransforms.GetArray());

      bool updateExtraData = geom.dataDirty;
      if (!geom.instanceExtraBuffer
	|| (geom.instanceExtraBuffer->GetElementCount() != geom.allInstanceExtra.Capacity()))
      {
	geom.instanceExtraBuffer = csRenderBuffer::CreateRenderBuffer (geom.allInstanceExtra.Capacity(),
								       CS_BUF_STREAM, CS_BUFCOMP_FLOAT,
								       sizeof (csMGGeom::InstanceExtra) / sizeof(float));
	geom.instanceExtraVar->SetValue (geom.instanceExtraBuffer);
	updateExtraData = true;
      }
      if (updateExtraData) geom.instanceExtraBuffer->SetData (geom.allInstanceExtra.GetArray());

      geom.dataDirty = false;
    }
    geom.mesh->GetMovable ()->UpdateMove ();
  }
}

size_t csMeshGeneratorGeometry::GetLODLevel (float sqdist)
{
  size_t i;
  for (i = 0 ; i < factories.GetSize () ; i++)
  {
    csMGGeom& geom = factories[i];
    if (sqdist <= geom.sqmaxdistance)
    {
      return i;
    }
  }
  return csArrayItemNotFound;
}

bool csMeshGeneratorGeometry::IsRightLOD (float sqdist, size_t current_lod)
{
  // With only one lod level we are always right.
  if (factories.GetSize () <= 1) return true;
  if (current_lod == 0)
    return (sqdist <= factories[0].sqmaxdistance);
  else
    return (sqdist <= factories[current_lod].sqmaxdistance) &&
    (sqdist > factories[current_lod-1].sqmaxdistance);
}

void csMeshGeneratorGeometry::UpdatePosition (const csVector3& pos) 
{ 
  for (size_t f = 0; f < factories.GetSize(); f++) 
  { 
    factories[f].mesh->GetMovable()->SetPosition (pos); 
  } 
} 

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

csMeshGenerator::csMeshGenerator (csEngine* engine) : 
  scfImplementationType (this), total_max_dist (-1.0f), minRadius(-1.0f),
  use_density_scaling (false), use_alpha_scaling (false),
  last_pos (0, 0, 0), setup_cells (false),
  cell_dim (50), inuse_blocks (0), inuse_blocks_last (0),
  max_blocks (100), engine (engine)
{
  default_density_factor = 1.0f;

  cells = new csMGCell [cell_dim * cell_dim];

  for (size_t i = 0 ; i < size_t (max_blocks) ; i++)
{'fraction_non_alphanumeric': 0.1294477188386815, 'fraction_numerical': 0.010769118824128647, 'mean_word_length': 3.537306041597887, 'pattern_counts': {'":': 0, '<': 57, '<?xml version=': 0, '>': 159, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 26, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2961814', 'n_tokens_mistral': 9688, 'n_tokens_neox': 9239, 'n_words': 2084}