Browse Source

Upload non-world brush models and allow them to be assigned to entities. It's not terribly pretty but it (mostly) works. There still seems to be an issue with texture assignment on subsequent map loads.

console
Nico de Poel 5 years ago
parent
commit
5390483b0b
  1. 10
      Assets/Scripts/Game/Entity.cs
  2. 15
      Assets/Scripts/Game/GameAssets.cs
  3. 26
      Assets/Scripts/Game/GameState.cs
  4. 3
      Assets/Scripts/Modules/GameModule.cs
  5. 8
      Assets/Scripts/Support/AliasModel.cs
  6. 9
      engine/Quake/cl_parse.c

10
Assets/Scripts/Game/Entity.cs

@ -12,6 +12,7 @@ public class Entity
private SkinnedMeshRenderer skinnedMeshRenderer;
private AliasModel aliasModel;
private GameObject brushModel;
private GameObject worldModel;
public Entity(int entityNum)
@ -33,6 +34,8 @@ public class Entity
public void ClearModel()
{
aliasModel = null;
brushModel = null;
worldModel = null;
Object.Destroy(meshFilter);
Object.Destroy(meshRenderer);
@ -52,6 +55,13 @@ public class Entity
UpdateAnimation(0);
}
public void SetBrushModel(GameObject brushModelGO)
{
ClearModel();
brushModel = brushModelGO;
brushModel.transform.SetParent(gameObject.transform);
}
public void SetWorldModel(GameObject worldModelGO)
{
ClearModel();

15
Assets/Scripts/Game/GameAssets.cs

@ -65,6 +65,21 @@ public class GameAssets
brushModels.Add(brushModel);
}
public bool TryGetBrushModel(string name, out BrushModel brushModel)
{
foreach (var model in brushModels)
{
if (model.Name == name)
{
brushModel = model;
return true;
}
}
brushModel = null;
return false;
}
public void SetWorldModel(BrushModel brushModel)
{
worldModel?.Dispose();

26
Assets/Scripts/Game/GameState.cs

@ -30,11 +30,11 @@ public class GameState
// The first sub-model contains all of the static geometry
var subModel = worldModel.GetSubModel(0);
var subModelGO = CreateWorldGameObject(subModel);
var subModelGO = CreateBrushGameObject(subModel);
subModelGO.transform.SetParent(worldGameObject.transform);
}
private GameObject CreateWorldGameObject(BrushModel.SubModel subModel)
private GameObject CreateBrushGameObject(BrushModel.SubModel subModel)
{
var subModelGO = new GameObject(subModel.Name);
@ -104,6 +104,26 @@ public class GameState
entity.SetAliasModel(aliasModel);
}
public void SetEntityBrushModel(int entityNum, string modelName)
{
var entity = GetOrCreateEntity(entityNum);
if (!uq.GameAssets.TryGetBrushModel(modelName, out var brushModel))
{
Debug.LogWarning($"Unknown brush model name: {modelName}");
return;
}
var brushModelGO = new GameObject(brushModel.Name);
for (int i = 0; i < brushModel.SubModelCount; ++i)
{
var subModelGO = CreateBrushGameObject(brushModel.GetSubModel(i));
subModelGO.transform.SetParent(brushModelGO.transform);
}
entity.SetBrushModel(brushModelGO);
}
public void SetEntityWorldModel(int entityNum, int subModelNum)
{
var entity = GetOrCreateEntity(entityNum);
@ -117,7 +137,7 @@ public class GameState
// TODO: these relatively complex world game objects are going to get destroyed and re-created all the time
// as the player moves through the map and moves in and out of range of these entities. This can and should
// be done more efficiently by creating the game objects only once and enabling/disabling them on demand.
var worldModelGO = CreateWorldGameObject(subModel);
var worldModelGO = CreateBrushGameObject(subModel);
entity.SetWorldModel(worldModelGO);
}

3
Assets/Scripts/Modules/GameModule.cs

@ -34,8 +34,7 @@ public partial class GameModule
if (modelName.EndsWith(".bsp"))
{
// TODO: non-world brush model
uq.GameState.GetEntity(entityNum)?.ClearModel();
uq.GameState.SetEntityBrushModel(entityNum, modelName);
return;
}

8
Assets/Scripts/Support/AliasModel.cs

@ -91,6 +91,10 @@ public class AliasModel
ImportGroupFrameAnimations(poseVertices, indices, uvs);
}
/// <summary>
/// Single frame animations are used for dynamically animated entities. The game logic determines which frame is displayed at which time.
/// In Unity we still need to identify groups of frames that form a single animation sequence, so that we can smoothly loop animations when interpolation is enabled.
/// </summary>
private void ImportSingleFrameAnimations(QTriVertex[][] poseVertices, ushort[] indices, Vector2[] uvs)
{
Mesh mesh;
@ -122,6 +126,10 @@ public class AliasModel
animationMeshes.Add((startFrame, mesh));
}
/// <summary>
/// Grouped frame animations are used for entities that animate automatically in an endless cycle, e.g. flames.
/// They are set up once and then the renderer ensures they are updated at a steady rate.
/// </summary>
private void ImportGroupFrameAnimations(QTriVertex[][] poseVertices, ushort[] indices, Vector2[] uvs)
{
for (int frameIdx = 0; frameIdx < header.numFrames; ++frameIdx)

9
engine/Quake/cl_parse.c

@ -393,6 +393,15 @@ void CL_ParseServerInfo (void)
R_NewMap ();
for (i = 1; i < nummodels; i++)
{
if (cl.model_precache[i] == NULL || cl.model_precache[i] == cl.worldmodel || cl.model_precache[i]->type != mod_brush || cl.model_precache[i]->name[0] == '*')
continue;
UQ_GL_UploadBrushModel(cl.model_precache[i]);
CL_KeepaliveMessage();
}
//johnfitz -- clear out string; we don't consider identical
//messages to be duplicates if the map has changed in between
con_lastcenterstring[0] = 0;

Loading…
Cancel
Save