1 #include "lc_global.h"
2 #include "lc_scene.h"
3 #include "lc_context.h"
4 #include "pieceinf.h"
5 #include "lc_texture.h"
6 #include "lc_library.h"
7 #include "lc_application.h"
8 #include "object.h"
9 
lcScene()10 lcScene::lcScene()
11 	: mRenderMeshes(0, 1024), mOpaqueMeshes(0, 1024), mTranslucentMeshes(0, 1024), mInterfaceObjects(0, 1024)
12 {
13 	mActiveSubmodelInstance = nullptr;
14 	mDrawInterface = false;
15 	mShadingMode = lcShadingMode::DefaultLights;
16 	mAllowLOD = true;
17 	mMeshLODDistance = 250.0f;
18 	mHasFadedParts = false;
19 	mPreTranslucentCallback = nullptr;
20 }
21 
Begin(const lcMatrix44 & ViewMatrix)22 void lcScene::Begin(const lcMatrix44& ViewMatrix)
23 {
24 	mViewMatrix = ViewMatrix;
25 	mActiveSubmodelInstance = nullptr;
26 	mPreTranslucentCallback = nullptr;
27 	mRenderMeshes.RemoveAll();
28 	mOpaqueMeshes.RemoveAll();
29 	mTranslucentMeshes.RemoveAll();
30 	mInterfaceObjects.RemoveAll();
31 
32 	const lcPreferences& Preferences = lcGetPreferences();
33 	mHighlightColor = lcVector4FromColor(Preferences.mHighlightNewPartsColor);
34 	mFadeColor = lcVector4FromColor(Preferences.mFadeStepsColor);
35 	mHasFadedParts = false;
36 	mTranslucentFade = mFadeColor.w != 1.0f;
37 }
38 
End()39 void lcScene::End()
40 {
41 	const auto OpaqueMeshCompare = [this](int Index1, int Index2)
42 	{
43 		const lcMesh* Mesh1 = mRenderMeshes[Index1].Mesh;
44 		const lcMesh* Mesh2 = mRenderMeshes[Index2].Mesh;
45 
46 		const int Texture1 = Mesh1->mFlags & lcMeshFlag::HasTexture;
47 		const int Texture2 = Mesh2->mFlags & lcMeshFlag::HasTexture;
48 
49 		if (Texture1 == Texture2)
50 			return Mesh1 < Mesh2;
51 
52 		return Texture1 ? false : true;
53 	};
54 
55 	std::sort(mOpaqueMeshes.begin(), mOpaqueMeshes.end(), OpaqueMeshCompare);
56 
57 	auto TranslucentMeshCompare = [](const lcTranslucentMeshInstance& Mesh1, const lcTranslucentMeshInstance& Mesh2)
58 	{
59 		return Mesh1.Distance > Mesh2.Distance;
60 	};
61 
62 	std::sort(mTranslucentMeshes.begin(), mTranslucentMeshes.end(), TranslucentMeshCompare);
63 }
64 
AddMesh(lcMesh * Mesh,const lcMatrix44 & WorldMatrix,int ColorIndex,lcRenderMeshState State)65 void lcScene::AddMesh(lcMesh* Mesh, const lcMatrix44& WorldMatrix, int ColorIndex, lcRenderMeshState State)
66 {
67 	lcRenderMesh& RenderMesh = mRenderMeshes.Add();
68 
69 	RenderMesh.WorldMatrix = WorldMatrix;
70 	RenderMesh.Mesh = Mesh;
71 	RenderMesh.ColorIndex = ColorIndex;
72 	RenderMesh.State = State;
73 	const float Distance = fabsf(lcMul31(WorldMatrix[3], mViewMatrix).z) - mMeshLODDistance;
74 	RenderMesh.LodIndex = mAllowLOD ? RenderMesh.Mesh->GetLodIndex(Distance) : LC_MESH_LOD_HIGH;
75 
76 	const bool ForceTranslucent = (mTranslucentFade && State == lcRenderMeshState::Faded);
77 	const bool Translucent = lcIsColorTranslucent(ColorIndex) || ForceTranslucent;
78 	const lcMeshFlags Flags = Mesh->mFlags;
79 	mHasFadedParts |= State == lcRenderMeshState::Faded;
80 
81 	if ((Flags & (lcMeshFlag::HasSolid | lcMeshFlag::HasLines)) || ((Flags & lcMeshFlag::HasDefault) && !Translucent))
82 		mOpaqueMeshes.Add(mRenderMeshes.GetSize() - 1);
83 
84 	if ((Flags & lcMeshFlag::HasTranslucent) || ((Flags & lcMeshFlag::HasDefault) && Translucent))
85 	{
86 		const lcMeshLod& Lod = Mesh->mLods[RenderMesh.LodIndex];
87 
88 		for (int SectionIdx = 0; SectionIdx < Lod.NumSections; SectionIdx++)
89 		{
90 			const lcMeshSection* Section = &Lod.Sections[SectionIdx];
91 
92 			if ((Section->PrimitiveType & (LC_MESH_TRIANGLES | LC_MESH_TEXTURED_TRIANGLES)) == 0)
93 				continue;
94 
95 			int SectionColorIndex = Section->ColorIndex;
96 
97 			if (SectionColorIndex == gDefaultColor)
98 				SectionColorIndex = RenderMesh.ColorIndex;
99 
100 			if (!lcIsColorTranslucent(SectionColorIndex) && !ForceTranslucent)
101 				continue;
102 
103 			const lcVector3 Center = (Section->BoundingBox.Min + Section->BoundingBox.Max) / 2;
104 			const float InstanceDistance = fabsf(lcMul31(lcMul31(Center, WorldMatrix), mViewMatrix).z);
105 
106 			lcTranslucentMeshInstance& Instance = mTranslucentMeshes.Add();
107 			Instance.Section = Section;
108 			Instance.Distance = InstanceDistance;
109 			Instance.RenderMeshIndex = mRenderMeshes.GetSize() - 1;
110 		}
111 	}
112 }
113 
DrawDebugNormals(lcContext * Context,const lcMesh * Mesh) const114 void lcScene::DrawDebugNormals(lcContext* Context, const lcMesh* Mesh) const
115 {
116 	const lcVertex* const VertexBuffer = Mesh->GetVertexData();
117 	const lcVertexTextured* const TexturedVertexBuffer = Mesh->GetTexturedVertexData();
118 	lcVector3* const Vertices = (lcVector3*)malloc((Mesh->mNumVertices + Mesh->mNumTexturedVertices) * 2 * sizeof(lcVector3));
119 
120 	for (int VertexIdx = 0; VertexIdx < Mesh->mNumVertices; VertexIdx++)
121 	{
122 		Vertices[VertexIdx * 2] = VertexBuffer[VertexIdx].Position;
123 		Vertices[VertexIdx * 2 + 1] = VertexBuffer[VertexIdx].Position + lcUnpackNormal(VertexBuffer[VertexIdx].Normal);
124 	}
125 
126 	for (int VertexIdx = 0; VertexIdx < Mesh->mNumTexturedVertices; VertexIdx++)
127 	{
128 		Vertices[(Mesh->mNumVertices + VertexIdx) * 2] = TexturedVertexBuffer[VertexIdx].Position;
129 		Vertices[(Mesh->mNumVertices + VertexIdx) * 2 + 1] = TexturedVertexBuffer[VertexIdx].Position + lcUnpackNormal(TexturedVertexBuffer[VertexIdx].Normal);
130 	}
131 
132 	Context->SetVertexBufferPointer(Vertices);
133 	Context->SetVertexFormatPosition(3);
134 	Context->DrawPrimitives(GL_LINES, 0, (Mesh->mNumVertices + Mesh->mNumTexturedVertices) * 2);
135 	free(Vertices);
136 }
137 
DrawOpaqueMeshes(lcContext * Context,bool DrawLit,int PrimitiveTypes,bool DrawFaded,bool DrawNonFaded) const138 void lcScene::DrawOpaqueMeshes(lcContext* Context, bool DrawLit, int PrimitiveTypes, bool DrawFaded, bool DrawNonFaded) const
139 {
140 	if (mOpaqueMeshes.IsEmpty())
141 		return;
142 
143 	lcMaterialType FlatMaterial, TexturedMaterial;
144 
145 	if (DrawLit)
146 	{
147 		FlatMaterial = lcMaterialType::FakeLitColor;
148 		TexturedMaterial = lcMaterialType::FakeLitTextureDecal;
149 	}
150 	else
151 	{
152 		FlatMaterial = lcMaterialType::UnlitColor;
153 		TexturedMaterial = lcMaterialType::UnlitTextureDecal;
154 	}
155 
156 	Context->SetPolygonOffset(lcPolygonOffset::Opaque);
157 
158 	for (const int MeshIndex : mOpaqueMeshes)
159 	{
160 		const lcRenderMesh& RenderMesh = mRenderMeshes[MeshIndex];
161 		const lcMesh* Mesh = RenderMesh.Mesh;
162 		const int LodIndex = RenderMesh.LodIndex;
163 
164 		if (!DrawFaded && RenderMesh.State == lcRenderMeshState::Faded)
165 			continue;
166 
167 		if (!DrawNonFaded && RenderMesh.State != lcRenderMeshState::Faded)
168 			continue;
169 
170 		Context->BindMesh(Mesh);
171 		Context->SetWorldMatrix(RenderMesh.WorldMatrix);
172 
173 		for (int SectionIdx = 0; SectionIdx < Mesh->mLods[LodIndex].NumSections; SectionIdx++)
174 		{
175 			const lcMeshSection* const Section = &Mesh->mLods[LodIndex].Sections[SectionIdx];
176 
177 			if ((Section->PrimitiveType & PrimitiveTypes) == 0)
178 				continue;
179 
180 			int ColorIndex = Section->ColorIndex;
181 
182 			if (Section->PrimitiveType & (LC_MESH_TRIANGLES | LC_MESH_TEXTURED_TRIANGLES))
183 			{
184 				if (ColorIndex == gDefaultColor)
185 					ColorIndex = RenderMesh.ColorIndex;
186 
187 				if (lcIsColorTranslucent(ColorIndex))
188 					continue;
189 
190 				switch (RenderMesh.State)
191 				{
192 				case lcRenderMeshState::Default:
193 				case lcRenderMeshState::Highlighted:
194 					Context->SetColorIndex(ColorIndex);
195 					break;
196 
197 				case lcRenderMeshState::Selected:
198 					Context->SetColorIndexTinted(ColorIndex, LC_COLOR_SELECTED, 0.5f);
199 					break;
200 
201 				case lcRenderMeshState::Focused:
202 					Context->SetColorIndexTinted(ColorIndex, LC_COLOR_FOCUSED, 0.5f);
203 					break;
204 
205 				case lcRenderMeshState::Faded:
206 					if (mTranslucentFade)
207 						continue;
208 					Context->SetColorIndexTinted(ColorIndex, mFadeColor);
209 					break;
210 				}
211 			}
212 			else if (Section->PrimitiveType & (LC_MESH_LINES | LC_MESH_CONDITIONAL_LINES))
213 			{
214 				switch (RenderMesh.State)
215 				{
216 				case lcRenderMeshState::Default:
217 					if (mShadingMode != lcShadingMode::Wireframe)
218 					{
219 						if (ColorIndex != gEdgeColor)
220 							Context->SetColorIndex(ColorIndex);
221 						else
222 							Context->SetEdgeColorIndex(RenderMesh.ColorIndex);
223 					}
224 					else
225 					{
226 						if (ColorIndex == gEdgeColor)
227 							ColorIndex = RenderMesh.ColorIndex;
228 
229 						Context->SetColorIndex(ColorIndex);
230 					}
231 					break;
232 
233 				case lcRenderMeshState::Selected:
234 					Context->SetInterfaceColor(LC_COLOR_SELECTED);
235 					break;
236 
237 				case lcRenderMeshState::Focused:
238 					Context->SetInterfaceColor(LC_COLOR_FOCUSED);
239 					break;
240 
241 				case lcRenderMeshState::Highlighted:
242 					Context->SetColor(mHighlightColor);
243 					break;
244 
245 				case lcRenderMeshState::Faded:
246 					Context->SetEdgeColorIndexTinted(ColorIndex, mFadeColor);
247 					break;
248 				}
249 
250 				if (Section->PrimitiveType == LC_MESH_CONDITIONAL_LINES)
251 				{
252 					int VertexBufferOffset = Mesh->mVertexCacheOffset != -1 ? Mesh->mVertexCacheOffset : 0;
253 					VertexBufferOffset += Mesh->mNumVertices * sizeof(lcVertex) + Mesh->mNumTexturedVertices * sizeof(lcVertexTextured);
254 					const int IndexBufferOffset = Mesh->mIndexCacheOffset != -1 ? Mesh->mIndexCacheOffset : 0;
255 
256 					Context->SetMaterial(lcMaterialType::UnlitColorConditional);
257 					Context->SetVertexFormatConditional(VertexBufferOffset);
258 
259 					Context->DrawIndexedPrimitives(GL_LINES, Section->NumIndices, Mesh->mIndexType, IndexBufferOffset + Section->IndexOffset);
260 
261 					continue;
262 				}
263 			}
264 
265 			lcTexture* const Texture = Section->Texture;
266 			int VertexBufferOffset = Mesh->mVertexCacheOffset != -1 ? Mesh->mVertexCacheOffset : 0;
267 			const int IndexBufferOffset = Mesh->mIndexCacheOffset != -1 ? Mesh->mIndexCacheOffset : 0;
268 
269 			if (!Texture)
270 			{
271 				Context->SetMaterial(FlatMaterial);
272 				Context->SetVertexFormat(VertexBufferOffset, 3, 1, 0, 0, DrawLit);
273 			}
274 			else
275 			{
276 				if (Texture->NeedsUpload())
277 					Texture->Upload(Context);
278 				Context->SetMaterial(TexturedMaterial);
279 				VertexBufferOffset += Mesh->mNumVertices * sizeof(lcVertex);
280 				Context->SetVertexFormat(VertexBufferOffset, 3, 1, 2, 0, DrawLit);
281 				Context->BindTexture2D(Texture->mTexture);
282 			}
283 
284 			const GLenum DrawPrimitiveType = Section->PrimitiveType & (LC_MESH_TRIANGLES | LC_MESH_TEXTURED_TRIANGLES) ? GL_TRIANGLES : GL_LINES;
285 			Context->DrawIndexedPrimitives(DrawPrimitiveType, Section->NumIndices, Mesh->mIndexType, IndexBufferOffset + Section->IndexOffset);
286 		}
287 
288 #ifdef LC_DEBUG_NORMALS
289 		DrawDebugNormals(Context, Mesh);
290 #endif
291 	}
292 
293 	Context->BindTexture2D(0);
294 	Context->SetPolygonOffset(lcPolygonOffset::None);
295 }
296 
DrawTranslucentMeshes(lcContext * Context,bool DrawLit,bool DrawFadePrepass,bool DrawFaded,bool DrawNonFaded) const297 void lcScene::DrawTranslucentMeshes(lcContext* Context, bool DrawLit, bool DrawFadePrepass, bool DrawFaded, bool DrawNonFaded) const
298 {
299 	if (mTranslucentMeshes.IsEmpty())
300 		return;
301 
302 	lcMaterialType FlatMaterial, TexturedMaterial;
303 
304 	if (DrawLit)
305 	{
306 		FlatMaterial = lcMaterialType::FakeLitColor;
307 		TexturedMaterial = lcMaterialType::FakeLitTextureDecal;
308 	}
309 	else
310 	{
311 		FlatMaterial = lcMaterialType::UnlitColor;
312 		TexturedMaterial = lcMaterialType::UnlitTextureDecal;
313 	}
314 
315 	if (!DrawFadePrepass)
316 	{
317 		glEnable(GL_BLEND);
318 		Context->SetDepthWrite(false);
319 	}
320 	else
321 		glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
322 
323 	Context->SetPolygonOffset(lcPolygonOffset::Translucent);
324 
325 	for (const lcTranslucentMeshInstance& MeshInstance : mTranslucentMeshes)
326 	{
327 		const lcRenderMesh& RenderMesh = mRenderMeshes[MeshInstance.RenderMeshIndex];
328 		const lcMesh* Mesh = RenderMesh.Mesh;
329 
330 		if (!DrawFaded && RenderMesh.State == lcRenderMeshState::Faded)
331 			continue;
332 
333 		if (!DrawNonFaded && RenderMesh.State != lcRenderMeshState::Faded)
334 			continue;
335 
336 		Context->BindMesh(Mesh);
337 		Context->SetWorldMatrix(RenderMesh.WorldMatrix);
338 
339 		const lcMeshSection* Section = MeshInstance.Section;
340 
341 		int ColorIndex = Section->ColorIndex;
342 
343 		if (ColorIndex == gDefaultColor)
344 			ColorIndex = RenderMesh.ColorIndex;
345 
346 		if (DrawFadePrepass && lcIsColorTranslucent(ColorIndex))
347 			continue;
348 
349 		switch (RenderMesh.State)
350 		{
351 		case lcRenderMeshState::Default:
352 		case lcRenderMeshState::Highlighted:
353 			Context->SetColorIndex(ColorIndex);
354 			break;
355 
356 		case lcRenderMeshState::Selected:
357 			Context->SetColorIndexTinted(ColorIndex, LC_COLOR_SELECTED, 0.5f);
358 			break;
359 
360 		case lcRenderMeshState::Focused:
361 			Context->SetColorIndexTinted(ColorIndex, LC_COLOR_FOCUSED, 0.5f);
362 			break;
363 
364 		case lcRenderMeshState::Faded:
365 			Context->SetColorIndexTinted(ColorIndex, mFadeColor);
366 			break;
367 		}
368 
369 		lcTexture* const Texture = Section->Texture;
370 		int VertexBufferOffset = Mesh->mVertexCacheOffset != -1 ? Mesh->mVertexCacheOffset : 0;
371 		const int IndexBufferOffset = Mesh->mIndexCacheOffset != -1 ? Mesh->mIndexCacheOffset : 0;
372 
373 		if (!Texture)
374 		{
375 			Context->SetMaterial(FlatMaterial);
376 			Context->SetVertexFormat(VertexBufferOffset, 3, 1, 0, 0, DrawLit);
377 		}
378 		else
379 		{
380 			if (Texture->NeedsUpload())
381 				Texture->Upload(Context);
382 			Context->SetMaterial(TexturedMaterial);
383 			VertexBufferOffset += Mesh->mNumVertices * sizeof(lcVertex);
384 			Context->SetVertexFormat(VertexBufferOffset, 3, 1, 2, 0, DrawLit);
385 			Context->BindTexture2D(Texture->mTexture);
386 		}
387 
388 		const GLenum DrawPrimitiveType = Section->PrimitiveType & (LC_MESH_TRIANGLES | LC_MESH_TEXTURED_TRIANGLES) ? GL_TRIANGLES : GL_LINES;
389 		Context->DrawIndexedPrimitives(DrawPrimitiveType, Section->NumIndices, Mesh->mIndexType, IndexBufferOffset + Section->IndexOffset);
390 
391 #ifdef LC_DEBUG_NORMALS
392 		DrawDebugNormals(Context, Mesh);
393 #endif
394 	}
395 
396 	Context->BindTexture2D(0);
397 	Context->SetPolygonOffset(lcPolygonOffset::None);
398 
399 	if (!DrawFadePrepass)
400 	{
401 		Context->SetDepthWrite(true);
402 		glDisable(GL_BLEND);
403 	}
404 	else
405 		glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
406 }
407 
Draw(lcContext * Context) const408 void lcScene::Draw(lcContext* Context) const
409 {
410 	// TODO: find a better place for these updates
411 	lcGetPiecesLibrary()->UpdateBuffers(Context);
412 
413 	Context->SetViewMatrix(mViewMatrix);
414 
415 	const lcPreferences& Preferences = lcGetPreferences();
416 	const bool DrawLines = Preferences.mDrawEdgeLines && Preferences.mLineWidth > 0.0f;
417 	const bool DrawConditional = Preferences.mDrawConditionalLines && Preferences.mLineWidth > 0.0f;
418 
419 //	lcShadingMode ShadingMode = Preferences.mShadingMode;
420 //	if (ShadingMode == lcShadingMode::Wireframe && !mAllowWireframe)
421 //		ShadingMode = lcShadingMode::Flat;
422 
423 	if (mShadingMode == lcShadingMode::Wireframe)
424 	{
425 		DrawOpaqueMeshes(Context, false, LC_MESH_LINES, true, true);
426 
427 		if (DrawConditional)
428 			DrawOpaqueMeshes(Context, false, LC_MESH_CONDITIONAL_LINES, true, true);
429 
430 		if (mPreTranslucentCallback)
431 			mPreTranslucentCallback();
432 	}
433 	else if (mShadingMode == lcShadingMode::Flat)
434 	{
435 		const int SolidPrimitiveTypes = LC_MESH_TRIANGLES | LC_MESH_TEXTURED_TRIANGLES | (DrawLines ? LC_MESH_LINES : 0);
436 
437 		if (mTranslucentFade && mHasFadedParts)
438 		{
439 			DrawOpaqueMeshes(Context, false, SolidPrimitiveTypes, false, true);
440 
441 			if (mPreTranslucentCallback)
442 				mPreTranslucentCallback();
443 
444 			DrawTranslucentMeshes(Context, false, true, true, false);
445 
446 			if (DrawLines)
447 				DrawOpaqueMeshes(Context, false, LC_MESH_LINES, true, false);
448 
449 			if (DrawConditional)
450 				DrawOpaqueMeshes(Context, false, LC_MESH_CONDITIONAL_LINES, true, false);
451 
452 			DrawTranslucentMeshes(Context, false, false, true, true);
453 		}
454 		else
455 		{
456 			DrawOpaqueMeshes(Context, false, SolidPrimitiveTypes, true, true);
457 
458 			if (DrawConditional)
459 				DrawOpaqueMeshes(Context, false, LC_MESH_CONDITIONAL_LINES, true, true);
460 
461 			if (mPreTranslucentCallback)
462 				mPreTranslucentCallback();
463 
464 			DrawTranslucentMeshes(Context, false, false, true, true);
465 		}
466 	}
467 	else
468 	{
469 		if (mTranslucentFade && mHasFadedParts)
470 		{
471 			DrawOpaqueMeshes(Context, true, LC_MESH_TRIANGLES | LC_MESH_TEXTURED_TRIANGLES, false, true);
472 
473 			if (DrawLines)
474 				DrawOpaqueMeshes(Context, false, LC_MESH_LINES, false, true);
475 
476 			if (DrawConditional)
477 				DrawOpaqueMeshes(Context, false, LC_MESH_CONDITIONAL_LINES, false, true);
478 
479 			if (mPreTranslucentCallback)
480 				mPreTranslucentCallback();
481 
482 			DrawTranslucentMeshes(Context, false, true, true, false);
483 
484 			if (DrawLines)
485 				DrawOpaqueMeshes(Context, false, LC_MESH_LINES, true, false);
486 
487 			if (DrawConditional)
488 				DrawOpaqueMeshes(Context, false, LC_MESH_CONDITIONAL_LINES, true, false);
489 
490 			DrawTranslucentMeshes(Context, true, false, true, true);
491 		}
492 		else
493 		{
494 			if (DrawLines)
495 				DrawOpaqueMeshes(Context, false, LC_MESH_LINES, true, true);
496 
497 			if (DrawConditional)
498 				DrawOpaqueMeshes(Context, false, LC_MESH_CONDITIONAL_LINES, true, true);
499 
500 			DrawOpaqueMeshes(Context, true, LC_MESH_TRIANGLES | LC_MESH_TEXTURED_TRIANGLES, true, true);
501 
502 			if (mPreTranslucentCallback)
503 				mPreTranslucentCallback();
504 
505 			DrawTranslucentMeshes(Context, true, false, true, true);
506 		}
507 	}
508 }
509 
DrawInterfaceObjects(lcContext * Context) const510 void lcScene::DrawInterfaceObjects(lcContext* Context) const
511 {
512 	for (const lcObject* Object : mInterfaceObjects)
513 		Object->DrawInterface(Context, *this);
514 }
515