#include <CoreAPI.h>
static const char* backup = "data/Temp/TreesGenerator.json";
static const char *LeafsPath = "UserPrefs/ToolsSettings/Leafs/";
const char* GeneratorID = "TreesGenerator";
class TreesGenerator : public SculptGenerator{
public:
TreesGenerator() {
defaults();
collision.setUnit(8);
}
virtual const char* GetID() {
return GeneratorID;
}
void defaults() {
sign = 1;
noiseAmpliicator = 1.2;
chunkLengthAmplificator = 1.3;
overallDensity = 1.0;
radiusDecrement = 0.75;
gravity = 0.05;
transition = 4;
start_transition = 0;
ends_distortion = 0.125;
Level0_branches = 1;
Level0_Randomness = 1;
Level0_StartBranchesLevel = 0;
Level0_Proportions = 1;
GrowUpStrength = 1;
BranchesRandomness = 1;
BranchesStartAngle = 100;
BranchesEndAngle = 0;
BranchesProportions = 1;
MinimalBranchRadius = 0.9;
MakeRoots = true;
RootsRandomness = 1;
RootsLength = 1;
RootsComplexity = 0.5;
RootsCount = 8;
TreeGenSeed = 0;
RootsStartGrowHeight = 0.05;
addLeafs = true;
addNarrowTrunks = false;
LeafsScale = 1;
LeafsDensity = 1;
LeafsScattering = 1;
LeafsColor1 = 0xFF8BA055;
LeafsColor2 = 0xFF519E2A;
LeafsType = 0;
pLeafsType = -1;
UpdateLeafsEnum();
}
const char* leafsEnum() {
return "LEAFSTYPES";
}
void UpdateLeafsEnum() {
utils::clearEnum(leafsEnum());
io::ListFolders(LeafsPath, FL);
for (auto& s : FL) {
s.RemoveFilePath();
utils::addEnumValue(leafsEnum(), s);
}
}
const char* GetLeafName() {
return utils::getEnumValueByIndex(leafsEnum(), LeafsType);
}
float GrowUpStrength;
float sign;
float noiseAmpliicator;
float chunkLengthAmplificator;
float overallDensity;
float radiusDecrement;
float gravity;
float transition;
float start_transition;
float ends_distortion;
float Level0_Randomness;
int Level0_branches;
float Level0_StartBranchesLevel;
float Level0_Proportions;
float BranchesRandomness;
float BranchesStartAngle;
float BranchesEndAngle;
float BranchesProportions;
float MinimalBranchRadius;
bool MakeRoots;
float RootsRandomness;
float RootsLength;
float RootsComplexity;
float RootsStartGrowHeight;
int RootsCount;
int TreeGenSeed;
bool addLeafs;
bool addNarrowTrunks;
int pLeafsType;
int LeafsType;
float LeafsScale;
float LeafsDensity;
float LeafsScattering;
DWORD LeafsColor1;
DWORD LeafsColor2;
bool bfCulling;
void RandomizeTree() {
TreeGenSeed = rand();
NotifyChanges();
}
void SaveTreePreset() {
if(io::saveFileDialog("*.tree",fn)) {
WriteToFile(fn);
}
}
void LoadTreePreset() {
if (io::openFileDialog("*.tree", fn)) {
defaults();
ReadFromFile(fn);
}
NotifyChanges();
}
virtual const char* getDefaultObjectName() {
return "Tree";
}
SERIALIZE() {
FUNCTION_CALL(CreateNewObject,"CreateNewTree");
if (getObject()) {
FSLIDER(overallDensity, "overallDensity", 0, 2, 100, 0);
FSLIDER(GrowUpStrength, "GrowUpStrength", -5, 5, 100, 0);
SLIDER(Level0_branches, "Level0_branches", 1, 8);
FSLIDER(Level0_Randomness, "Level0_Randomness", 0, 3, 100, 0);
FSLIDER(Level0_StartBranchesLevel, "Level0_StartBranchesLevel", 0, 0.8, 100, 0);
FSLIDER(Level0_Proportions, "Level0_Proportions", 0, 3, 100, 0);
DELIMITER;
FSLIDER(BranchesProportions, "BranchesProportions", 0, 3, 100, 0);
FSLIDER(radiusDecrement, "radiusDecrement", 0, 0.85, 100, 0);
FSLIDER(BranchesRandomness, "BranchesRandomness", 0, 3, 100, 0);
FSLIDER(BranchesStartAngle, "BranchesStartAngle", 30, 160, 1, 0);
FSLIDER(BranchesEndAngle, "BranchesEndAngle", 30, 160, 1, 0);
FSLIDER(MinimalBranchRadius, "MinimalBranchRadius", 0.5, 2, 1, 0);
DELIMITER;
REG_AUTO(MakeRoots);
if (MakeRoots) {
FSLIDER(RootsRandomness, "RootsRandomness", 0, 3, 100, 0);
FSLIDER(RootsLength, "RootsLength", 0, 3, 100, 0);
FSLIDER(RootsComplexity, "RootsComplexity", 0, 2, 100, 0);
FSLIDER(RootsStartGrowHeight, "RootsStartGrowHeight", 0, 0.5, 100, 0);
SLIDER(RootsCount, "RootsCount", 2, 16);
}
DELIMITER;
REG_AUTO(addLeafs);
FSLIDER(LeafsScale, "LeafsScale", 0.1, 4, 100, 0);
FSLIDER(LeafsDensity, "LeafsDensity", 0.1, 4, 100, 0);
FSLIDER(LeafsScattering, "LeafsScattering", 0.1, 4, 100, 0);
REG_AUTO(LeafsColor1);
REG_AUTO(LeafsColor2);
if (FolderToRemove.Length()) {
UI_LAYOUT("1[]");
REG_DROPLIST(LeafsType, "LeafsType", "LEAFSTYPES");
ICON_BUTTON("delete", removeLeafFolder, "REMOVELEAF_HINT");
}else {
REG_DROPLIST(LeafsType, "LeafsType", "LEAFSTYPES");
}
FUNCTION_CALL(AddLeafsType);
if(bfCulling) {
TEXTMSG2("TurnOffCulling");
if (hash)*hash << 1.0f;
}
DELIMITER;
UI_LAYOUT("1[]");
REG_AUTO(TreeGenSeed);
FUNCTION_CALL(RandomizeTree, "{maticon dice}");
UI_LAYOUT("2");
FUNCTION_CALL(SaveTreePreset);
FUNCTION_CALL(LoadTreePreset);
FUNCTION_CALL(Generate, "GenerateTreeInGoodQuality");
REG_AUTO(TransformObject);
if(TransformObject) {
NOHASH{
REG_AUTO(Transform);
}
}
if (hash)*hash << utils::getEnumValuesCount(leafsEnum());
}
}
void Process() override {
bfCulling = ui::getOption("BackfaceCulling") == "true";
if(LeafsType !=pLeafsType) {
pLeafsType = LeafsType;
FolderToRemove.Clear();
if (utils::getEnumValuesCount(leafsEnum()) > 1) {
str name = utils::getEnumValueByIndex(leafsEnum(), LeafsType);
str fn = LeafsPath + name +
"/";
io::convertToWritablePath(&fn);
io::ListFiles(fn, "*.*", FL, false);
if (FL.Count()) {
FolderToRemove = fn;
}
}
}
SculptGenerator::Process();
}
void removeLeafFolder() {
if (utils::getEnumValuesCount(leafsEnum()) > 1) {
if (
dialog().
text(
"SureRemoveLeaf").yes().no().show() == 1) {
io::removeFolder(FolderToRemove);
pLeafsType = -1;
UpdateLeafsEnum();
if (LeafsType >= utils::getEnumValuesCount(leafsEnum())) {
LeafsType = utils::getEnumValuesCount(leafsEnum()) - 1;
}
NotifyChanges();
}
}
}
void AddLeafsType() {
if (io::openFileDialog("*.png;*.tga", fn)) {
str name = fn.GetFileName();
str ext = name.GetFileExtension();
name.RemoveFileExtension();
str dest = LeafsPath + name +
"/color." + ext;
while(io::fileExists(dest)) {
name += "_";
name += str::ToString(abs(int(GetTickCount())) % 1000);
dest = LeafsPath + name + "/color." + ext;
}
UpdateLeafsEnum();
LeafsType = utils::getEnumValueIndex(leafsEnum(), name);
NotifyChanges();
}
}
float checkVoxelsCollision(
Volume& v,
const vec3& pos,
float radius) {
return collision.
collides(pos, radius).LengthSq() > 0;
}
void create(
int level,
Volume v,
vec3 start,
vec3 start_direction,
vec3 direction,
float radius,
float rdiff,
float relative_length,
float randomness) {
vec3 N = start_direction.GetOrthonormal();
int npoints = 20;
float L = radius * relative_length / npoints;
if (sign < 0)L *= RootsLength;
else if (level == 0)L *= Level0_Proportions;
else L *= BranchesProportions;
float best_cost = FLT_MAX;
ort.MakeOrthonormalTo(start_direction);
float random_level = randomness;
if (sign < 0)random_level *= RootsRandomness;
else if (level == 0)random_level *= Level0_Randomness;
else random_level *= BranchesRandomness;
float this_transition = transition;
float this_start_transition = start_transition;
if(level == 0 && sign > 0) {
this_transition = 0;
this_start_transition = 1;
}
int nattempts = (level == 0 && Level0_branches <= 1) && sign > 0 ? 1 : 30;
for (int k = 0; k < nattempts; k++) {
direction = dir0;
mat4 rot = level > 0 ? mat4::RotationAt(start0, start_direction, comms::cMath::Rand(0, 360)) : mat4::Identity;
direction.TransformNormal(rot);
start = start0 + ort * rdiff;
vec3 out = start0 + ort * (rdiff + radius);
start.TransformCoordinate(rot);
out.TransformCoordinate(rot);
float cost = 0;
vec3 dir = start_direction;
for (int i = 0; i < npoints; i++) {
float r = radius * (npoints - i) / npoints;
if (start.y * sign < 0)cost -= start.y * 1000 * sign;
current.Add(start);
cost += checkVoxelsCollision(v, start, r * 1.2);
float t = float(i) * this_transition / npoints + this_start_transition;
if (t > 1)t = 1;
dir = start_direction * (1 - t) + direction * t;
start += L * dir;
direction.y += gravity;
direction += vec3::RandNormal() * random_level * (1.0 + float(i) * ends_distortion / 20);
direction.Normalize();
}
if (cost < best_cost) {
best_cost = cost;
best = current;
best_out = out + start_direction * radius * 2;
}
}
auto addleaf = [&](
const vec3& pt,
const vec3& dir) {
forLeafs.Add(std::pair(pt, (dir + Vector3D::RandNormal()).ToNormal()));
};
const int nsub = int((addNarrowTrunks ? 4 : 32) * LeafsDensity);
for (int i = 0; i < best.Count(); i++) {
float r = radius * (npoints + 1 - i) / (npoints + 1);
int ip = i - 1;
int in = i + 1;
if (ip < 0)ip = 0;
if (in > best.Count() - 1)in = best.Count() - 1;
vec3 d = (best[in] - best[ip]).ToNormal();
if (r > MinimalBranchRadius) {
N.MakeOrthonormalTo(d);
}
if(addLeafs && sign > 0 && r<MinimalBranchRadius*3) {
addleaf(best[i],d);
if (i < best.Count() - 1) {
for (int k = 1; k < nsub; k++) {
addleaf((best[i + 1] * k + best[i]*(nsub-k)) / nsub, d);
}
}
}
}
if (level == 0 && sign > 0) {
mainTrunk.Clear();
mainTrunk.Add(
vec4(a->SpacePos, a->Radius));
}
}
int ns = int(radius * overallDensity / 1.2);
if (sign < 0)ns = int(radius * RootsComplexity / 1.2);
if (ns > 0) {
randomGrow(level + 1, v, cu, m, best_out, ns, relative_length, randomness);
}
}
void randomGrow(
int level,
Volume v,
Curve& cu,
Mesh& m,
vec3 outPos,
int count,
float relative_length,
float randomness) {
for (int i = 0; i < count; i++) {
if (nr > 8) {
int p0 = Level0_StartBranchesLevel * nr;
if (p0 < 1)p0 = 1;
if (level > 1 || sign < 0)p0 = 1;
int s = nr / 16;
int p = p0 + i * (nr - p0 - 4) / count;
if (a && !checkVoxelsCollision(v, a->SpacePos, a->Radius * 1.1)) {
pts.Add(p);
}
}
}
for (int i = 0; i < nr; i++) {
}
summ += m;
if (BranchesEndAngle < BranchesStartAngle)std::swap(BranchesEndAngle, BranchesStartAngle);
if (p0 && p0->Radius > 1) {
float r = p0->Radius;
if (sign > 0)r *= 2;
else r *= 1.25;
relaxSpheres.Add(
vec4(outPos, r));
}
for(int i=0;i<pts.Count();i++){
int p = pts[i];
vec3 dir = (a_next->SpacePos - a_prev->SpacePos).ToNormal();
vec3 N = a_curr->TempNormal;
vec3 pos = a_curr->SpacePos;
mat4 rot = mat4::RotationAt(pos, dir, comms::cMath::Rand(0, 360));
float ang = float(BranchesStartAngle + comms::cMath::Rand01() * (BranchesEndAngle - BranchesStartAngle)) * comms::cMath::Pi / 180;
float _cos = cos(ang);
vec3 tdir = (dir * cos(ang) + N * sin(ang)).ToNormal();
tdir.TransformNormal(rot);
create(level + 1, v, pos, dir, tdir
, a_curr->Radius * radiusDecrement
, a_curr->Radius * (1.0f - radiusDecrement)
, relative_length * chunkLengthAmplificator, randomness * noiseAmpliicator);
}
}
if(leafs.Volume().valid()) {
leafs.
Volume().clearNoUndo();
}
else leafs = parent.
addChild(
"Leafs");
vec4 v40 = utils::dwordToVec4(LeafsColor1);
vec4 v41 = utils::dwordToVec4(LeafsColor2);
v41 -= v40;
str leafName =
str(LeafsPath) + GetLeafName() +
"/color.png";
int w = im.GetWidth();
int h = im.GetHeight();
if (w > 0 && h > 0) {
int minX = w - 1;
int maxX = 0;
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
auto pix = im.GetPixelRgba8(x, y);
if (pix.a > 0) {
minX = std::min(x, minX);
maxX = std::max(x, maxX);
}
}
}
float u0 = float(minX) / w;
float u1 = float(maxX) / w;
float dx1 = 1.0f - u0 * 2.0f;
float dx2 = u1 * 2.0f - 1.0f;
if (leafs.Volume().vo()) {
leafs.Volume().toSurface();
auto& pos = lf.
geometry()->GetPositions();
auto& vcol = lf.
geometry()->GetVertexColor();
auto& tpos = smallTrunks.
geometry()->GetPositions();
auto& traw = smallTrunks.
geometry()->GetRaw();
auto quad = [&](
const vec3& start,
const vec3& dir) {
Vector3D ort;
do {
ort = Vector3D::RandNormal();
ort -= dir * ort.dot(dir);
if (ort.Length() > 0.1) {
ort.Normalize();
break;
}
} while (true);
ort *= LeafsScale * 3;
Vector3D dd = dir * 6 * LeafsScale;
int ps = pos.Count();
pos.Add(start + ort * dx2);
pos.Add(start + ort * dx2 + dd);
pos.Add(start - ort * dx1 + dd);
pos.Add(start - ort * dx1);
coat::vec4 vc = v40 + v41 * comms::cMath::Rand01();
DWORD CL = utils::vec4ToDword(vc);
if (CL == 0xFF808080)CL = 0xFF818181;
if (CL == 0xFFFFFFFF)CL = 0xFFFEFEfE;
vcol.Add(CL, 4);
raw.Add(
vec3i(ps, ps, -1));
raw.Add(
vec3i(ps + 1, ps + 1, -1));
raw.Add(
vec3i(ps + 2, ps + 2, -1));
raw.Add(
vec3i(ps + 3, ps + 3, -1));
};
auto rode = [&](
const vec3& start,
const vec3& end,
float r1,
float r2) {
float L = dir.Length();
if (L > 0) {
dir /= L;
auto ort = dir.GetOrthonormalPair();
int nbase = 6;
const float da = cMath::Pi * 2 / nbase;
int p0 = tpos.Count();
for (int i = 0; i < nbase; i++) {
float ang = i * da;
vec3 dd = ort.first * cos(ang) + ort.second * sin(ang);
tpos.Add(start + dd * r1);
tpos.Add(end + dd * r2);
int in = (i + 1) % nbase;
in *= 2;
int ic = i * 2;
traw.Add(cVec3i(4, 0, 0));
traw.Add(cVec3i(p0 + ic, -1, -1));
traw.Add(cVec3i(p0 + ic + 1, -1, -1));
traw.Add(cVec3i(p0 + in + 1, -1, -1));
traw.Add(cVec3i(p0 + in, -1, -1));
}
}
};
lf.
geometry()->GetMaterials()[0].Tex[0].FileName = leafName;
float r = 3 * LeafsScale;
float r2 = r/3;
if(addNarrowTrunks) {
smallTrunks.
geometry()->SetDefaultObjMtl();
if (addNarrowTrunks) {
for (auto& a : forLeafs) {
vec3 lp = a.first + a.second * comms::cMath::Rand01() * LeafsScale * 16 * LeafsScattering;
rode(a.first, lp, MinimalBranchRadius / 1.5, MinimalBranchRadius / 4);
quad(lp, (lp - a.first).ToNormal());
}
}
}
else {
for (auto& a : forLeafs) {
for (int k = 0; k < 8; k++) {
vec3 lp = a.first + a.second * comms::cMath::Rand01() * LeafsScale * 16 * LeafsScattering;
vec3 c = lp + a.second * r;
if (!collision.
collides(c, r2).LengthSq()) {
quad(lp, a.second);
break;
}
}
}
}
leafs.Volume().clear();
leafs.Volume().mergeMeshWithTexture(lf);
leafs.Volume().vo()->RenderJustFacture = true;
}
}
return leafs;
}
void generate(
Volume v,
bool Preview) {
forLeafs.Clear();
comms::cMath::Randomize(TreeGenSeed);
relaxSpheres.Clear();
mainTrunk.Clear();
Save(t, this);
gravity = 0.05 * GrowUpStrength;
for (int i = 0; i < Level0_branches; i++) {
create(0, v, vec3::Zero, vec3::AxisY, vec3::AxisY, 20, 0, 20, 0.2);
}
if (MakeRoots && RootsCount && mainTrunk.Count() > 4) {
overallDensity *= 0.7;
sign = -10;
gravity = 0.01;
transition = 2;
start_transition = 0.15;
ends_distortion = 2.0;
int a0 = 360 / RootsCount;
for (int r = 0; r < RootsCount; r++) {
ax *= mat3::Rotation(vec3::AxisY, r * a0 + comms::cMath::Rand(-45, 45));
ax.Normalize();
int n0 = mainTrunk.Count() / 30 + 1;
int g = n0 + int(RootsStartGrowHeight * comms::cMath::Rand(0, mainTrunk.Count() - n0 - 2));
vec3 d = (mainTrunk[g - 1].ToVec3() - mainTrunk[g + 1].ToVec3()).ToNormal();
float rad = mainTrunk[g].w;
create(0, v, mainTrunk[g].ToVec3(), d, ax, rad * 0.6, rad * 0.4, 20, 0.2);
}
defaults();
Load(t, this);
}
}
for (int k = 0; k < relaxSpheres.Count(); k++) {
v.
relaxGpu(relaxSpheres[k].ToVec3(), relaxSpheres[k].w * 2, 1);
}
}
virtual void GeneratePreview() {
auto v = t.Volume();
auto setShader = [](
Volume v) {
v.
setFloatShaderProperty(
"Textures scale", 1.0);
v.setFloatShaderProperty("Bumpness", 4.0);
v.setFloatShaderProperty("Gloss", 0.4);
v.setFloatShaderProperty("Side rotation [1]", comms::cMath::Rad(0.0f));
v.setFloatShaderProperty("Side rotation [2]", comms::cMath::Rad(90.0f));
v.
setColorShaderProperty(
"Color", 0xFF935B38);
v.setColorShaderProperty("Cavity color", 0xFF2F1D12);
v.setColorShaderProperty("Bulge color", 0xFF51331D);
v.
setBoolShaderProperty(
"Flat shading",
false);
};
setShader(v);
if (addLeafs && addNarrowTrunks) {
trunks.Volume().toSurface();
auto vt = trunks.Volume();
setShader(vt);
}
generate(t.Volume(), true);
if (addLeafs) {
auto l = generateLeafs(s);
if (addNarrowTrunks) {
trunks.Volume().mergeMesh(smallTrunks);
}
}
WriteToFile(backup);
};
virtual void GenerateFinalObject() {
if (s.Volume().valid()) {
generate(t.Volume(), true);
for (int k = 0; k < relaxSpheres.Count(); k++) {
v.
relaxGpu(relaxSpheres[k].ToVec3(), relaxSpheres[k].w * 2, 1);
}
if (addLeafs) {
auto l = generateLeafs(s);
}
}
}
};
EXPORT_EXTENSION(TreesGenerator) {
TreesGenerator* tg = new TreesGenerator;
tg->ReadFromFile(backup);
VoxelExtension::Register(tg);
}
Definition CoreAPI.h:3141
void add(const Vector3D &p, const Vector3D &normal, float Radius)
add the point to the curve without the direct options the tangents
int pointsCount()
get the base points cout in the curve
OneSelPoint * point(int idx)
get the base point pointer
int renderPointsCount()
returns the visual points count. Visual points used to render the curve in the viewport as set of str...
void updatePoints()
update the visual points if need. Use this function if you cahnge the curve. Change the multiple para...
void tubeToMesh(Mesh &mesh, bool hemisphere)
create the solid tube around the curve using the points radius
OneSelPoint * renderPoint(int idx)
returns the visual point reference
The image references. Look the cImage for the list of allowed operations.
Definition CoreAPI.h:1310
bool Read(const char *name)
Read the image from the file.
The mesh reference.
Definition CoreAPI.h:418
comms::cMeshContainer * geometry()
The low-level mesh reference allows to create, operate over individual faces, vertices,...
The scene element, like sculpt object or curve.
Definition CoreAPI.h:1638
void selectOne() const
unselect all similar elements and select this one
SceneElement findInSubtree(const char *name) const
find the element in subtree by name
SceneElement child(int index) const
returns child element by index
mat4 getTransform() const
get the scene element transform
void removeSubtree() const
remove the whole subtree
int childCount() const
returns the child elements count
const SceneElement & setTransform(const mat4 &Transform) const
Set the transform matrix.
SceneElement addChild(const char *name) const
add the child element of the same nature
The class intended to place spheres in space and identify if there are spheres around....
Definition CoreAPI.h:3344
int addSphere(const vec3 &p, float radius)
add the sphere into the space
void clear()
remove all spheres
vec3 collides(const vec3 &p, float radius)
check if sphere intersects other spheres in the space
The class allows to operate over voxels/surface on the relatively low-level.
Definition CoreAPI.h:1953
void clearNoUndo()
Clear quickly, without affecting the Undo queue.
void relaxGpu(const vec3 ¢er, float Radius, float degree)
fast voxel-based relax within the sphere with the gradual falloff. It works only in voxel mode.
void mergeMesh(Mesh &mesh, const mat4 &transform=mat4::Identity, BoolOpType op=BOOL_MERGE)
merge the mesh into scene
void toVoxels()
turn to voxels, auto-voxelize
void assignShader(const char *shaderName)
set the shader for the Volume
void toSurface()
turn to surface mode, the triangles will be tangentially relaxed
the rich dialog. You may customize it, show your custom parameters and custom buttons.
Definition CoreAPI.h:3821
dialog & dontShowAgainCheckbox()
show the checkbox "Don't show again". If user checks if the dialog will net be shown next time and sh...
dialog & ok()
add Ok button
int show()
Show the dialog. This is usually the last command in the chain.
dialog & text(const char *id)
pass the header text of the dialog
static void copyFile(const char *src, const char *dest)
copy the file from src to dest. If the src or dest is relative, it is relative to the documents folde...
text primitive
Definition CorePrimAPI.h:1735
static bool cmd(const char *id, std::function< void()> process_in_modal_dialog=0)
execute some action in UI as if you pressed on some control
The UV API. The mesh is taken from the current room. If paint or UV rooms is active,...
Definition CoreAPI.h:4691
The coat namespace used for most 3DCoat API calls except low-level internal structures.
Definition CoreAPI.h:43
comms::cVec3 vec3
3D - float vector, see the cVec3
Definition CoreAPI.h:50
comms::cVec4 vec4
4D - float vector, see the cVec4
Definition CoreAPI.h:47
comms::cVec2 vec2
2D - vector, see the cVec2
Definition CoreAPI.h:56
comms::cMat4 mat4
4x4 float matrix, see the cMat4
Definition CoreAPI.h:59
comms::cVec3i vec3i
3D - int vector, see the cVec3i
Definition CoreAPI.h:53
comms::cList< X > list
the array template, see cList
Definition CoreAPI.h:70
comms::cStr str
the string that is compatible with the 3DCoat engine, see the cStr
Definition CoreAPI.h:67