Files
workinf_Blender_Wasm/blender-5.2.0/extern/opensubdiv-source/examples/glEvalLimit/particles.h
2026-08-12 04:47:48 -04:00

156 lines
4.4 KiB
C++

//
// Copyright 2013 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#ifndef ST_PARTICLES_H
#define ST_PARTICLES_H
#include <opensubdiv/far/topologyRefiner.h>
#include <opensubdiv/far/patchMap.h>
#include <opensubdiv/osd/types.h>
#include <iostream>
//
// In order to emphasize the dynamic nature of the EvalLimit API, where the
// locations can be arbitrarily updated before each evaluation, the glEvalLimit
// example treats each sample as a 'ST particle'.
//
// ST Particles are a simplified parametric-space particle dynamics simulation: each
// particle is assigned a location on the subdivision surface limit that is
// composed of a unique ptex face index, with a local (s,t) parametric pair.
//
// The system also generates an array of parametric velocities (ds, dt) for each
// particle. An Update() function then applies the velocities to the locations and
// moves the points along the parametric space.
//
// Face boundaries are managed using a ptex adjacency table obtained from the
// Far::TopologyRefiner. Every time a particle moves outside of the [0.0f, 1.0f]
// parametric range, a 'warp' function moves it to the neighboring face, or
// bounces it, if the edge happens to be a boundary.
//
// Note: currently the adjacency code does not handle 'diagonal' crossings, nor
// crossings between quad and non-quad faces.
//
class STParticles {
public:
/// \brief Coordinates set on a limit surface
///
struct Position {
Position() { }
/// \brief Constructor
///
/// @param f Ptex face id
///
/// @param x parametric location on face
///
/// @param y parametric location on face
///
Position(int f, float x, float y) : ptexIndex(f), s(x), t(y) { }
int ptexIndex; ///< ptex face index
float s, t; ///< parametric location on face
};
//
// Topology adjacency (borrowed from Ptexture.h)
//
struct FaceInfo {
enum { flag_subface = 8 };
FaceInfo() : adjedges(0), flags(0) {
adjfaces[0] = adjfaces[1] = adjfaces[2] = adjfaces[3] = -1;
}
FaceInfo(int adjfaces_[4], int adjedges_[4], bool isSubface=false) :
flags(isSubface ? flag_subface : 0) {
setadjfaces(adjfaces_[0], adjfaces_[1], adjfaces_[2], adjfaces_[3]);
setadjedges(adjedges_[0], adjedges_[1], adjedges_[2], adjedges_[3]);
}
void setadjfaces(int f0, int f1, int f2, int f3) {
adjfaces[0] = f0;
adjfaces[1] = f1;
adjfaces[2] = f2;
adjfaces[3] = f3;
}
void setadjedges(int e0, int e1, int e2, int e3) {
adjedges = (e0&3) | ((e1&3)<<2) | ((e2&3)<<4) | ((e3&3)<<6);
}
int adjface(int eid) const { return adjfaces[eid]; }
int adjedge(int eid) const { return int((adjedges >> (2*eid)) & 3); }
bool isSubface() const { return (flags & flag_subface) != 0; }
unsigned int adjedges :8,
flags :8;
int adjfaces[4];
};
typedef OpenSubdiv::Far::TopologyRefiner Refiner;
typedef OpenSubdiv::Far::PatchTable PatchTable;
STParticles(Refiner const & refiner, PatchTable const *patchTable,
int nparticles, bool centered=false);
~STParticles();
void Update(float deltaTime);
int GetNumParticles() const {
return (int)_positions.size();
}
void SetSpeed(float speed) {
_speed = std::max(-1.0f, std::min(1.0f, speed));
}
float GetSpeed() const {
return _speed;
}
std::vector<Position> & GetPositions() {
return _positions;
}
std::vector<float> & GetVelocities() {
return _velocities;
}
std::vector<OpenSubdiv::Osd::PatchCoord> GetPatchCoords() const {
return _patchCoords;
}
friend std::ostream & operator << (std::ostream & os, STParticles const & f);
private:
//
// Particle "Dynamics"
//
std::vector<Position> _positions;
std::vector<float> _velocities;
std::vector<OpenSubdiv::Osd::PatchCoord> _patchCoords;
float _speed; // velocity multiplier
int _regFaceSize;
friend std::ostream & operator << (std::ostream & os, FaceInfo const & f);
std::vector<FaceInfo> _adjacency;
OpenSubdiv::Far::PatchMap const *_patchMap;
};
#endif // ST_PARTICLES_H