void TransformPositionAll(char *label){
  FILE *fp;

  if((fp = fopen("../plot/Tetra-Triprism.stl", "w"))==NULL){
    printf("ファイルをオープンできません\n");
  } else {
    srand((unsigned)time(NULL));
    prStlProlog(label, fp);
    TransformPosition((char*)"Tetra", fp);
    TransformPosition((char*)"Triprism", fp);
    prStlEpilog(label, fp);
    fclose(fp);
  }

}
Example #2
0
void CBody::Draw(CLensFlare *flare)
{
	TransformPosition();
	if (mainbody)
	{
		ringchain.nextring=ringchain.prevring=&ringchain;
	}
	for (int i=0;i<numsubbodies;i++)
	{
		glPushMatrix();
		subbodies[i].Draw(NULL);
		glPopMatrix();
	}
	if (mainbody)
	{
		if (flare)
			flare->UpdatePos();
	}
	glRotatef((type!=rings?own_rot:orbit_rot),0.0f,0.0f,1.0f);
	if (type!=rings)
	{
		if (textures[3]>0)
			TransformClouds();
		DrawGFX();
	}
	else
	{
		SortNonSolidObject();
	}
	if (mainbody)
	{
		DrawSortedNonSolids();
	}
}
Example #3
0
Light::Light(LightType t, float x, float y, float z, float r, float g, float b, float konst/* =1.0f */, float linear/* =0.0f */, float quad/* =0.0f */)
{
	type = t;
	position = vec3(x, y, z);
	if(t == DIRECTIONAL)
		TransformDirection(position, currMatrix);
	else
		TransformPosition(position, currMatrix);
	color = Color(r, g, b);
	attenuation = vec3(konst, linear, quad);
	if(type == DIRECTIONAL)
		lightDir = glm::normalize(position);
}
Example #4
0
void CPHShell::Activate(const Fmatrix &m0,float dt01,const Fmatrix &m2,bool disable){

	if(isActive())return;
	activate(disable);
//	ELEMENT_I i;
	mXFORM.set(m0);
	//for(i=elements.begin();elements.end() != i;++i){

	//	(*i)->Activate(m0,dt01, m2, disable);
	//}
	
	{		
		ELEMENT_I i=elements.begin(),e=elements.end();
		for(;i!=e;++i)(*i)->Activate(mXFORM,disable);
	}

	{
		JOINT_I i=joints.begin(),e=joints.end();
		for(;i!=e;++i) (*i)->Activate();
	}	
	
	Fmatrix m;
	{
		Fmatrix old_m = mXFORM;//+GetGlobalTransformDynamic update mXFORM;
		GetGlobalTransformDynamic	(&m);
		mXFORM = old_m;
	}
	m.invert();m.mulA_43		(mXFORM);
	TransformPosition(m);
	if(PKinematics())
	{
		SetCallbacks( );
	}

	//bActive=true;
	//bActivating=true;
	m_flags.set(flActive,TRUE);
	m_flags.set(flActivating,TRUE);
	spatial_register();
///////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
	//mXFORM.set(m0);
	//Activate(disable);
	Fvector lin_vel;
	lin_vel.sub(m2.c,m0.c);
	set_LinearVel(lin_vel);
}
Example #5
0
bool CMotionControl::Test(const mm1000_t src[NUM_AXIS],const mm1000_t ofs[NUM_AXIS],mm1000_t dest[NUM_AXIS], bool printOK, std::function<void()> print)
{
	udist_t	to_m[NUM_AXIS];
	mm1000_t toorig[NUM_AXIS];

	memcpy(dest,src,sizeof(toorig));

	bool isError = false;

	if (TransformPosition(src,dest))
	{
		ToMachine(dest, to_m);

		TransformFromMachinePosition(to_m,toorig);

		for (uint8_t i = 0; i < NUM_AXIS && !isError; i++)
			isError = CompareMaxDiff(src[i], toorig[i]);
	}
	else
	{
		isError = true;
	}

	if (printOK || isError)
	{
		DumpArray<mm1000_t, NUM_AXIS>(F("Src"), src, false);
		DumpArray<mm1000_t, NUM_AXIS>(F("Ofs"), ofs, false);
		print();
		DumpArray<mm1000_t, NUM_AXIS>(F(" =>"), dest, false);
		DumpArray<mm1000_t, NUM_AXIS>(F("Back"), toorig, false);

		if (isError)
			printf(" ERROR");

		printf("\n");
	}

	return isError;
}
Example #6
0
void CBody::Predict(int bodyid, bool now, float seconds, float *x, float *y, float *z)
{
	if (mainbody)
		glLoadIdentity();
	if (!now)
		UpdateOrbit(seconds);
	//no glLoadIdentity call, so coords are relative to camera
	TransformPosition();
	if (bodyid==id)
	{
		glPushMatrix();
		glGetFloatv(GL_MODELVIEW_MATRIX,objectmatrix);
		*x=objectmatrix[12]; *y=objectmatrix[13]; *z=objectmatrix[14];
		glPopMatrix();
		return;
	}
	// note: no error checking for incorrect results or protection faults
	int i;
	for (i=0; i<numsubbodies;i++)
		if (subbodies[i].id>bodyid)
			break;
	subbodies[--i].Predict(bodyid,now,seconds,x,y,z);
}
Example #7
0
static void ExportAnimations(ExportContext& Context, FArchive& Ar)
{
	guard(ExportAnimations);

	const CAnimSet* Anim = Context.SkelMesh->Anim;
	int NumBones = Context.SkelMesh->RefSkeleton.Num();

	// Build mesh to anim bone map

	TArray<int> BoneMap;
	BoneMap.Init(-1, NumBones);
	TArray<int> AnimBones;
	AnimBones.Empty(NumBones);

	for (int i = 0; i < NumBones; i++)
	{
		const CSkelMeshBone &B = Context.SkelMesh->RefSkeleton[i];
		for (int j = 0; j < Anim->TrackBoneNames.Num(); j++)
		{
			if (!stricmp(B.Name, Anim->TrackBoneNames[j]))
			{
				BoneMap[i] = j;			// lookup CAnimSet bone by mesh bone index
				AnimBones.Add(i);		// indicate that the bone has animation
				break;
			}
		}
	}

	Ar.Printf(
		"  \"animations\" : [\n"
	);

	int FirstDataIndex = Context.Data.Num();

	// Iterate over all animations
	for (int SeqIndex = 0; SeqIndex < Anim->Sequences.Num(); SeqIndex++)
	{
		const CAnimSequence &Seq = *Anim->Sequences[SeqIndex];

		Ar.Printf(
			"    {\n"
			"      \"name\" : \"%s\",\n",
			*Seq.Name
		);

		struct AnimSampler
		{
			enum ChannelType
			{
				TRANSLATION,
				ROTATION
			};

			int BoneNodeIndex;
			ChannelType Type;
			const CAnimTrack* Track;
		};

		TArray<AnimSampler> Samplers;
		Samplers.Empty(AnimBones.Num() * 2);

		//!! Optimization:
		//!! 1. there will be missing tracks (AnimRotationOnly etc) - drop such samplers
		//!! 2. store all time tracks in a single BufferView, all rotation tracks in another, and all position track in 3rd one - this
		//!!    will reduce amount of BufferViews in json text (combine them by data type)

		// Prepare channels array
		Ar.Printf("      \"channels\" : [\n");
		for (int BoneIndex = 0; BoneIndex < AnimBones.Num(); BoneIndex++)
		{
			int MeshBoneIndex = AnimBones[BoneIndex];
			int AnimBoneIndex = BoneMap[MeshBoneIndex];

			const CAnimTrack* Track = Seq.Tracks[AnimBoneIndex];

			int TranslationSamplerIndex = Samplers.Num();
			AnimSampler* Sampler = new (Samplers) AnimSampler;
			Sampler->Type = AnimSampler::TRANSLATION;
			Sampler->BoneNodeIndex = MeshBoneIndex + FIRST_BONE_NODE;
			Sampler->Track = Track;

			int RotationSamplerIndex = Samplers.Num();
			Sampler = new (Samplers) AnimSampler;
			Sampler->Type = AnimSampler::ROTATION;
			Sampler->BoneNodeIndex = MeshBoneIndex + FIRST_BONE_NODE;
			Sampler->Track = Track;

			// Print glTF information. Not using usual formatting here to make output a little bit more compact.
			Ar.Printf(
				"        { \"sampler\" : %d, \"target\" : { \"node\" : %d, \"path\" : \"%s\" } },\n",
				TranslationSamplerIndex, MeshBoneIndex + FIRST_BONE_NODE, "translation"
			);
			Ar.Printf(
				"        { \"sampler\" : %d, \"target\" : { \"node\" : %d, \"path\" : \"%s\" } }%s\n",
				RotationSamplerIndex, MeshBoneIndex + FIRST_BONE_NODE, "rotation", BoneIndex == AnimBones.Num()-1 ? "" : ","
			);
		}
		Ar.Printf("      ],\n");

		// Prepare samplers
		Ar.Printf("      \"samplers\" : [\n");
		for (int SamplerIndex = 0; SamplerIndex < Samplers.Num(); SamplerIndex++)
		{
			const AnimSampler& Sampler = Samplers[SamplerIndex];

			// Prepare time array
			const TArray<float>* TimeArray = (Sampler.Type == AnimSampler::TRANSLATION) ? &Sampler.Track->KeyPosTime : &Sampler.Track->KeyQuatTime;
			if (TimeArray->Num() == 0)
			{
				// For this situation, use track's time array
				TimeArray = &Sampler.Track->KeyTime;
			}
			int NumKeys = Sampler.Type == (AnimSampler::TRANSLATION) ? Sampler.Track->KeyPos.Num() : Sampler.Track->KeyQuat.Num();

			int TimeBufIndex = Context.Data.AddZeroed();
			BufferData& TimeBuf = Context.Data[TimeBufIndex];
			TimeBuf.Setup(NumKeys, "SCALAR", BufferData::FLOAT, sizeof(float));

			float RateScale = 1.0f / Seq.Rate;
			float LastFrameTime = 0;
			if (TimeArray->Num() == 0 || NumKeys == 1)
			{
				// Fill with equally spaced values
				for (int i = 0; i < NumKeys; i++)
				{
					TimeBuf.Put(i * RateScale);
				}
				LastFrameTime = NumKeys-1;
			}
			else
			{
				for (int i = 0; i < TimeArray->Num(); i++)
				{
					TimeBuf.Put((*TimeArray)[i] * RateScale);
				}
				LastFrameTime = (*TimeArray)[TimeArray->Num()-1];
			}
			// Prepare min/max values for time track, it's required by glTF standard
			TimeBuf.BoundsMin = "[ 0 ]";
			char buf[64];
			appSprintf(ARRAY_ARG(buf), "[ %g ]", LastFrameTime * RateScale);
			TimeBuf.BoundsMax = buf;

			// Try to reuse TimeBuf from previous tracks
			TimeBufIndex = Context.GetFinalIndexForLastBlock(FirstDataIndex);

			// Prepare data
			int DataBufIndex = Context.Data.AddZeroed();
			BufferData& DataBuf = Context.Data[DataBufIndex];
			if (Sampler.Type == AnimSampler::TRANSLATION)
			{
				// Translation track
				DataBuf.Setup(NumKeys, "VEC3", BufferData::FLOAT, sizeof(CVec3));
				for (int i = 0; i < NumKeys; i++)
				{
					CVec3 Pos = Sampler.Track->KeyPos[i];
					TransformPosition(Pos);
					DataBuf.Put(Pos);
				}
			}
			else
			{
				// Rotation track
				DataBuf.Setup(NumKeys, "VEC4", BufferData::FLOAT, sizeof(CQuat));
				for (int i = 0; i < NumKeys; i++)
				{
					CQuat Rot = Sampler.Track->KeyQuat[i];
					TransformRotation(Rot);
					if (Sampler.BoneNodeIndex - FIRST_BONE_NODE == 0)
					{
						Rot.Conjugate();
					}
					DataBuf.Put(Rot);
				}
			}

			// Try to reuse data block as well
			DataBufIndex = Context.GetFinalIndexForLastBlock(FirstDataIndex);

			// Write glTF info
			Ar.Printf(
				"        { \"input\" : %d, \"output\" : %d }%s\n",
				TimeBufIndex, DataBufIndex, SamplerIndex == Samplers.Num()-1 ? "" : ","
			);
		}
		Ar.Printf("      ]\n");

		Ar.Printf("    }%s\n", SeqIndex == Anim->Sequences.Num()-1 ? "" : ",");
	}

	Ar.Printf("  ],\n");

	unguard;
}
Example #8
0
static void ExportSkinData(ExportContext& Context, const CSkelMeshLod& Lod, FArchive& Ar)
{
	guard(ExportSkinData);

	int numBones = Context.SkelMesh->RefSkeleton.Num();

	int MatrixBufIndex = Context.Data.AddZeroed();
	BufferData& MatrixBuf = Context.Data[MatrixBufIndex];
	MatrixBuf.Setup(numBones, "MAT4", BufferData::FLOAT, sizeof(CMat4));

	Ar.Printf(
		"  \"nodes\" : [\n"
		"    {\n"
		"      \"name\" : \"%s\",\n"
		"      \"mesh\" : 0,\n"
		"      \"skin\" : 0,\n"
		"      \"children\" : [ 1 ]\n"
		"    },\n",
		Context.MeshName);

	TArray<CCoords> BoneCoords;
	BoneCoords.AddZeroed(numBones);

	for (int boneIndex = 0; boneIndex < numBones; boneIndex++)
	{
		const CSkelMeshBone& B = Context.SkelMesh->RefSkeleton[boneIndex];

		// Find all children
		TStaticArray<int, 32> children;
		for (int j = 0; j < numBones; j++)
		{
			if (boneIndex == j) continue;
			const CSkelMeshBone& B2 = Context.SkelMesh->RefSkeleton[j];
			if (B2.ParentIndex == boneIndex)
			{
				children.Add(j);
			}
		}

		Ar.Printf(
			"    {\n"
			"      \"name\" : \"%s\",\n",
			*B.Name
		);

		// Write children
		if (children.Num())
		{
			Ar.Printf("      \"children\" : [ %d", children[0]+FIRST_BONE_NODE);
			for (int j = 1; j < children.Num(); j++)
			{
				Ar.Printf(", %d", children[j]+FIRST_BONE_NODE);
			}
			Ar.Printf(" ],\n");
		}

		// Bone transform
		CVec3 bonePos = B.Position;
		CQuat boneRot = B.Orientation;
		if (boneIndex == 0)
		{
			boneRot.Conjugate();
		}

		TransformPosition(bonePos);
		TransformRotation(boneRot);

		Ar.Printf(
			"      \"translation\" : [ %g, %g, %g ],\n"
			"      \"rotation\" : [ %g, %g, %g, %g ]\n",
			bonePos[0], bonePos[1], bonePos[2],
			boneRot.x, boneRot.y, boneRot.z, boneRot.w
		);

		boneRot.w *= -1;

		CCoords& BC = BoneCoords[boneIndex];
		BC.origin = bonePos;
		boneRot.ToAxis(BC.axis);
		if (boneIndex)
		{
			// World coordinate
			BoneCoords[B.ParentIndex].UnTransformCoords(BC, BC);
		}
		CCoords InvCoords;
		InvertCoords(BC, InvCoords);

		CMat4 BC4x4(InvCoords);
		MatrixBuf.Put(BC4x4);

		// Closing brace
		Ar.Printf(
			"    }%s\n",
			boneIndex == (numBones-1) ? "" : ","
		);
	}

	// Close "nodes" array
	Ar.Printf("  ],\n");

	// Make "skins"
	Ar.Printf(
		"  \"skins\" : [\n"
		"    {\n"
		"      \"inverseBindMatrices\" : %d,\n"
		"      \"skeleton\" : 1,\n"
		"      \"joints\" : [",
		MatrixBufIndex
	);
	for (int i = 0; i < numBones; i++)
	{
		if ((i & 31) == 0) Ar.Printf("\n        ");
		Ar.Printf("%d%s", i+FIRST_BONE_NODE, (i == numBones-1) ? "" : ",");
	}
	Ar.Printf(
		"\n"
		"      ]\n"
		"    }\n"
		"  ],\n"
	);

	unguard;
}
Example #9
0
static void ExportSection(ExportContext& Context, const CBaseMeshLod& Lod, const CMeshVertex* Verts, int SectonIndex, FArchive& Ar)
{
	guard(ExportSection);

	int VertexSize = Context.IsSkeletal() ? sizeof(CSkelMeshVertex) : sizeof(CStaticMeshVertex);

	const CMeshSection& S = Lod.Sections[SectonIndex];
	bool bLast = (SectonIndex == Lod.Sections.Num()-1);

	// Remap section indices to local indices
	CIndexBuffer::IndexAccessor_t GetIndex = Lod.Indices.GetAccessor();
	TArray<int> indexRemap; // old vertex index -> new vertex index
	indexRemap.Init(-1, Lod.NumVerts);
	int numLocalVerts = 0;
	int numLocalIndices = S.NumFaces * 3;
	for (int idx = 0; idx < numLocalIndices; idx++)
	{
		int vertIndex = GetIndex(S.FirstIndex + idx);
		if (indexRemap[vertIndex] == -1)
		{
			indexRemap[vertIndex] = numLocalVerts++;
		}
	}

	// Prepare buffers
	int IndexBufIndex = Context.Data.AddZeroed();
	int PositionBufIndex = Context.Data.AddZeroed();
	int NormalBufIndex = Context.Data.AddZeroed();
	int TangentBufIndex = Context.Data.AddZeroed();

	int BonesBufIndex = -1;
	int WeightsBufIndex = -1;
	if (Context.IsSkeletal())
	{
		BonesBufIndex = Context.Data.AddZeroed();
		WeightsBufIndex = Context.Data.AddZeroed();
	}

	int UVBufIndex[MAX_MESH_UV_SETS];
	for (int i = 0; i < Lod.NumTexCoords; i++)
	{
		UVBufIndex[i] = Context.Data.AddZeroed();
	}

	BufferData& IndexBuf = Context.Data[IndexBufIndex];
	BufferData& PositionBuf = Context.Data[PositionBufIndex];
	BufferData& NormalBuf = Context.Data[NormalBufIndex];
	BufferData& TangentBuf = Context.Data[TangentBufIndex];
	BufferData* UVBuf[MAX_MESH_UV_SETS];
	BufferData* BonesBuf = NULL;
	BufferData* WeightsBuf = NULL;

	PositionBuf.Setup(numLocalVerts, "VEC3", BufferData::FLOAT, sizeof(CVec3));
	NormalBuf.Setup(numLocalVerts, "VEC3", BufferData::FLOAT, sizeof(CVec3));
	TangentBuf.Setup(numLocalVerts, "VEC4", BufferData::FLOAT, sizeof(CVec4));
	for (int i = 0; i < Lod.NumTexCoords; i++)
	{
		UVBuf[i] = &Context.Data[UVBufIndex[i]];
		UVBuf[i]->Setup(numLocalVerts, "VEC2", BufferData::FLOAT, sizeof(CMeshUVFloat));
	}

	if (Context.IsSkeletal())
	{
		BonesBuf = &Context.Data[BonesBufIndex];
		WeightsBuf = &Context.Data[WeightsBufIndex];
		BonesBuf->Setup(numLocalVerts, "VEC4", BufferData::UNSIGNED_SHORT, sizeof(uint16)*4);
		WeightsBuf->Setup(numLocalVerts, "VEC4", BufferData::UNSIGNED_BYTE, sizeof(uint32), /*InNormalized=*/ true);
	}

	// Prepare and build indices
	TArray<int> localIndices;
	localIndices.AddUninitialized(numLocalIndices);
	int* pIndex = localIndices.GetData();
	for (int i = 0; i < numLocalIndices; i++)
	{
		*pIndex++ = GetIndex(S.FirstIndex + i);
	}

	if (numLocalVerts <= 65536)
	{
		IndexBuf.Setup(numLocalIndices, "SCALAR", BufferData::UNSIGNED_SHORT, sizeof(uint16));
		for (int idx = 0; idx < numLocalIndices; idx++)
		{
			IndexBuf.Put<uint16>(indexRemap[localIndices[idx]]);
		}
	}
	else
	{
		IndexBuf.Setup(numLocalIndices, "SCALAR", BufferData::UNSIGNED_INT, sizeof(uint32));
		for (int idx = 0; idx < numLocalIndices; idx++)
		{
			IndexBuf.Put<uint32>(indexRemap[localIndices[idx]]);
		}
	}

	// Build reverse index map for fast lookup of vertex by its new index.
	// It maps new vertex index to old vertex index.
	TArray<int> revIndexMap;
	revIndexMap.AddUninitialized(numLocalVerts);
	for (int i = 0; i < indexRemap.Num(); i++)
	{
		int newIndex = indexRemap[i];
		if (newIndex != -1)
		{
			revIndexMap[newIndex] = i;
		}
	}

	// Build vertices
	for (int i = 0; i < numLocalVerts; i++)
	{
		int vertIndex = revIndexMap[i];
		const CMeshVertex& V = VERT(vertIndex);

		CVec3 Position = V.Position;

		CVec4 Normal, Tangent;
		Unpack(Normal, V.Normal);
		Unpack(Tangent, V.Tangent);
		// Unreal (and we are) using normal.w for computing binormal. glTF
		// uses tangent.w for that. Make this value exactly 1.0 of -1.0 to make glTF
		// validator happy.
	#if 0
		// There's some problem: V.Normal.W == 0x80 -> -1.008 instead of -1.0
		if (Normal.w > 1.001 || Normal.w < -1.001)
		{
			appError("%X -> %g\n", V.Normal.Data, Normal.w);
		}
	#endif
		Tangent.w = (Normal.w < 0) ? -1 : 1;

		TransformPosition(Position);
		TransformDirection(Normal);
		TransformDirection(Tangent);

		Normal.Normalize();
		Tangent.Normalize();

		// Fill buffers
		PositionBuf.Put(Position);
		NormalBuf.Put(Normal.xyz);
		TangentBuf.Put(Tangent);
		UVBuf[0]->Put(V.UV);
	}

	// Compute bounds for PositionBuf
	CVec3 Mins, Maxs;
	ComputeBounds((CVec3*)PositionBuf.Data, numLocalVerts, sizeof(CVec3), Mins, Maxs);
	char buf[256];
	appSprintf(ARRAY_ARG(buf), "[ %g, %g, %g ]", VECTOR_ARG(Mins));
	PositionBuf.BoundsMin = buf;
	appSprintf(ARRAY_ARG(buf), "[ %g, %g, %g ]", VECTOR_ARG(Maxs));
	PositionBuf.BoundsMax = buf;

	if (Context.IsSkeletal())
	{
		for (int i = 0; i < numLocalVerts; i++)
		{
			int vertIndex = revIndexMap[i];
			const CMeshVertex& V0 = VERT(vertIndex);
			const CSkelMeshVertex& V = static_cast<const CSkelMeshVertex&>(V0);

			int16 Bones[NUM_INFLUENCES];
			static_assert(NUM_INFLUENCES == 4, "Code designed for 4 influences");
			static_assert(sizeof(Bones) == sizeof(V.Bone), "Unexpected V.Bones size");
			memcpy(Bones, V.Bone, sizeof(Bones));
			for (int j = 0; j < NUM_INFLUENCES; j++)
			{
				// We have INDEX_NONE as list terminator, should replace with something else for glTF
				if (Bones[j] == INDEX_NONE)
				{
					Bones[j] = 0;
				}
			}

			BonesBuf->Put(*(uint64*)&Bones);
			WeightsBuf->Put(V.PackedWeights);
		}
	}

	// Secondary UVs
	for (int uvIndex = 1; uvIndex < Lod.NumTexCoords; uvIndex++)
	{
		BufferData* pBuf = UVBuf[uvIndex];
		const CMeshUVFloat* srcUV = Lod.ExtraUV[uvIndex-1];
		for (int i = 0; i < numLocalVerts; i++)
		{
			int vertIndex = revIndexMap[i];
			pBuf->Put(srcUV[vertIndex]);
		}
	}

	// Write primitive information to json
	Ar.Printf(
		"        {\n"
		"          \"attributes\" : {\n"
		"            \"POSITION\" : %d,\n"
		"            \"NORMAL\" : %d,\n"
		"            \"TANGENT\" : %d,\n",
		PositionBufIndex, NormalBufIndex, TangentBufIndex
	);
	if (Context.IsSkeletal())
	{
		Ar.Printf(
			"            \"JOINTS_0\" : %d,\n"
			"            \"WEIGHTS_0\" : %d,\n",
			BonesBufIndex, WeightsBufIndex
		);
	}
	for (int i = 0; i < Lod.NumTexCoords; i++)
	{
		Ar.Printf(
			"            \"TEXCOORD_%d\" : %d%s\n",
			i, UVBufIndex[i], i < (Lod.NumTexCoords-1) ? "," : ""
		);
	}

	Ar.Printf(
		"          },\n"
		"          \"indices\" : %d,\n"
		"          \"material\" : %d\n"
		"        }%s\n",
		IndexBufIndex, SectonIndex,
		SectonIndex < (Lod.Sections.Num()-1) ? "," : ""
	);

	unguard;
}
Example #10
0
void TransformRay(Ray &ray, const mat4 &matrix)
{
	TransformPosition(ray.origin, matrix);
	TransformDirection(ray.direction, matrix);
	ray.direction = glm::normalize(ray.direction);
}