-
-
Save JoshEngebretson/fc08622b25f793fbe422 to your computer and use it in GitHub Desktop.
idTech2 on Urho3D Prototype
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "StringUtils.h" | |
#include "ProcessUtils.h" | |
#include "Context.h" | |
#include "Material.h" | |
#include "Model.h" | |
#include "Geometry.h" | |
#include "VertexBuffer.h" | |
#include "IndexBuffer.h" | |
#include "Technique.h" | |
#include "FileSystem.h" | |
#include "Graphics.h" | |
#include "ResourceCache.h" | |
#include "StaticModel.h" | |
#include "Material.h" | |
#include "AnimatedModel.h" | |
#include "TBESystem.h" | |
// move me | |
#include "Scene.h" | |
#include "Octree.h" | |
#include "Node.h" | |
#include "Camera.h" | |
#include "Zone.h" | |
#include "Renderer.h" | |
#include "RenderPath.h" | |
#include "XMLFile.h" | |
#include "DebugRenderer.h" | |
#include "BillboardSet.h" | |
#include "SkyBox.h" | |
#include "TBEMapModel.h" | |
#include "TBEAliasModel.h" | |
void R_LightPoint (vec3_t p, vec3_t color); | |
extern model_t *r_worldmodel; | |
SharedPtr<Scene> scene_; | |
SharedPtr<Node> cameraNode_; | |
// a surface may be contained in more than one cluster | |
struct RenderCluster | |
{ | |
PODVector<msurface_t*> surfaces; | |
}; | |
static PODVector<Node*> worldNodes; | |
static PODVector<Node*> dynamicLights; | |
static HashMap<msurface_t*, PODVector<Node*> > surfaceNodes; | |
static HashMap<model_t*, Node* > brushNodes; | |
static HashMap<model_t*, PODVector<Node*> > aliasNodes; | |
static Vector<RenderCluster> renderClusters; | |
PODVector<Texture2D*> lightmapTextures; | |
static HashMap<String, SharedPtr<Material> > materialLookup; | |
static HashMap<Material*, PODVector<msurface_t*> > surfaceMap; | |
static float _scale = .1f; | |
static BillboardSet* billboardObject; | |
static bool _castShadows = true; | |
static Material* LoadMaterial(int lightmap, const String& name, msurface_t* surface) | |
{ | |
Context* context = TBESystem::GetGlobalContext(); | |
if (!materialLookup.Contains(name)) | |
{ | |
ResourceCache* cache = context->GetSubsystem<ResourceCache>(); | |
if (name.Find("bluwter") != String::NPOS || name.Find("sewer1") != String::NPOS) | |
{ | |
Texture* texture = surface->texinfo->image->texture; | |
SharedPtr<Material> material = SharedPtr<Material>(cache->GetResource<Material>("Materials/Water.xml")); | |
material->SetTexture(TU_DIFFUSE, texture); | |
material->SetName(name); | |
material->SetShaderParameter("NoiseTiling", .002f); | |
material->SetShaderParameter("NoiseStrength", .04f); | |
if (name.Find("bluwter") != String::NPOS) | |
material->SetShaderParameter("WaterTint", Vector3(0.7f,0.7f,1.0f)); | |
else | |
{ | |
// seem to have issue with 2x water tints? setting green here changes blu water | |
material->SetShaderParameter("WaterTint", Vector3(0.7f,0.7f,1.0f)); | |
} | |
materialLookup.Insert(MakePair(name, material)); | |
} | |
else | |
{ | |
Texture* texture = surface->texinfo->image->texture; | |
SharedPtr<Material> material = SharedPtr<Material>(new Material(context)); | |
Technique* technique; | |
bool trans = surface->texinfo->flags & SURF_TRANS33 || surface->texinfo->flags & SURF_TRANS66; | |
if (!trans) | |
{ | |
technique = cache->GetResource<Technique>("Techniques/DiffLightMap.xml"); | |
} | |
else | |
{ | |
if (lightmap != -1) | |
technique = cache->GetResource<Technique>("Techniques/DiffLightMapAlpha.xml"); | |
else | |
technique = cache->GetResource<Technique>("Techniques/DiffEmissiveAlpha.xml"); | |
material->SetShaderParameter("MatDiffColor", Vector4(1,1,1, surface->texinfo->flags & SURF_TRANS33 ? .33f : .66f)); | |
} | |
material->SetNumTechniques(1); | |
material->SetTechnique(0, technique); | |
material->SetName(name); | |
material->SetTexture(TU_DIFFUSE, texture); | |
if (lightmap != -1 && lightmap < lightmapTextures.Size()) | |
material->SetTexture(TU_EMISSIVE, lightmapTextures[lightmap]); | |
else | |
{ | |
// doesn't have a lightmap, transparency, etc | |
// note from quake 2: the textures are prescaled up for a better lighting range, so scale it back down | |
material->SetTexture(TU_EMISSIVE, texture); | |
Vector4 intensity(.2f,.2f,.2f, surface->texinfo->flags & SURF_TRANS33 ? .33f : .66f); | |
material->SetShaderParameter("MatEmissiveColor", intensity); | |
} | |
materialLookup.Insert(MakePair(name, material)); | |
} | |
} | |
return materialLookup.Find(name)->second_; | |
} | |
static Node* EmitBrushModel(const HashMap<Material*, PODVector<msurface_t*> >& materialMap, bool isWorld = true) | |
{ | |
Context* context = TBESystem::GetGlobalContext(); | |
Vector<Geometry*> submeshes; | |
Vector<Material*> materials; | |
Vector<Vector3> centers; | |
BoundingBox bbox; | |
for (HashMap<Material*, PODVector<msurface_t*> >::ConstIterator i = materialMap.Begin(); i != materialMap.End(); ++i) | |
{ | |
materials.Push(i->first_); | |
const PODVector<msurface_t*>& surfaces = i->second_; | |
// count the vertices and indices | |
int numvertices = 0; | |
int numpolys = 0; | |
for (unsigned i = 0; i < surfaces.Size(); i++) | |
{ | |
const msurface_t* surf = surfaces[i]; | |
glpoly_t* poly = surf->polys; | |
while(poly) | |
{ | |
numvertices += poly->numverts; | |
numpolys += poly->numverts - 2; | |
poly = poly->next; | |
} | |
} | |
SharedPtr<IndexBuffer> ib; | |
SharedPtr<VertexBuffer> vb; | |
// TODO: share vertex buffers | |
vb = new VertexBuffer(context); | |
ib = new IndexBuffer(context); | |
// going to need normal | |
unsigned elementMask = MASK_POSITION | MASK_NORMAL| MASK_TEXCOORD1 | MASK_TEXCOORD2;// | MASK_TANGENT;//; | |
vb->SetSize(numvertices, elementMask); | |
ib->SetSize(numpolys * 3, false); | |
int vcount = 0; | |
float* vertexData = (float *) vb->Lock(0, numvertices); | |
unsigned short* indexData = (unsigned short*) ib->Lock(0, numpolys * 3); | |
Vector3 center = Vector3::ZERO; | |
for (unsigned i = 0; i < surfaces.Size(); i++) | |
{ | |
const msurface_t* surf = surfaces[i]; | |
glpoly_t* poly = surf->polys; | |
// use the plane normal, this will result in faceted lighting | |
// we need to calculate vertex normals properly, however this | |
// is complicated by Quake2's file format not having adjacency info | |
Vector3 normal(surf->plane->normal[0], surf->plane->normal[2], surf->plane->normal[1]); | |
if (surf->flags & SURF_PLANEBACK) | |
normal = -normal; | |
while(poly) | |
{ | |
// copy vertex data into vertex buffer | |
for (int j = 0; j < poly->numverts; j++) | |
{ | |
bbox.Merge(Vector3(poly->verts[j][0] * _scale, poly->verts[j][2] * _scale, poly->verts[j][1] * _scale)); | |
*vertexData++ = poly->verts[j][0] * _scale; // x | |
*vertexData++ = poly->verts[j][2] * _scale; // y | |
*vertexData++ = poly->verts[j][1] * _scale ; // z | |
center.x_ += poly->verts[j][0]; | |
center.y_ += poly->verts[j][2]; | |
center.z_ += poly->verts[j][1]; | |
*vertexData++ = normal.x_; | |
*vertexData++ = normal.y_; | |
*vertexData++ = normal.z_; | |
*vertexData++ = poly->verts[j][3]; // u0 | |
*vertexData++ = poly->verts[j][4]; // v0 | |
*vertexData++ = poly->verts[j][5]; // u1 | |
*vertexData++ = poly->verts[j][6]; // v1 | |
} | |
for (int j = 0; j < poly->numverts - 2; j++) | |
{ | |
*indexData = vcount; indexData++; | |
*indexData = vcount + j + 1; indexData++; | |
*indexData = vcount + j + 2; indexData++; | |
} | |
vcount += poly->numverts; | |
poly = poly->next; } | |
} | |
vb->Unlock(); | |
ib->Unlock(); | |
center /= numpolys * 3; | |
centers.Push(center); | |
Geometry* geom = new Geometry(context); | |
geom->SetIndexBuffer(ib); | |
geom->SetVertexBuffer(0, vb, elementMask); | |
geom->SetDrawRange(TRIANGLE_LIST, 0, numpolys * 3, false); | |
submeshes.Push(geom); | |
} | |
SharedPtr<Model> world(new Model(context)); | |
world->SetNumGeometries(submeshes.Size()); | |
for (unsigned i = 0; i < submeshes.Size(); i++) | |
{ | |
world->SetNumGeometryLodLevels(i, 1); | |
world->SetGeometry(i, 0, submeshes[i]); | |
//world->SetGeometryCenter(i, centers[i]); | |
} | |
world->SetBoundingBox(bbox); | |
Node* worldNode = scene_->CreateChild("World"); | |
StaticModel* worldObject = worldNode->CreateComponent<StaticModel>(); | |
worldObject->SetCastShadows(_castShadows); | |
worldObject->SetModel(world); | |
for (unsigned i = 0; i < materials.Size(); i++) | |
{ | |
worldObject->SetMaterial(i, materials[i]); | |
} | |
if (isWorld) | |
worldNodes.Push(worldNode); | |
// clear for next model | |
surfaceMap.Clear(); | |
return worldNode; | |
} | |
static void MapSurface(msurface_t* surface) | |
{ | |
String name(surface->texinfo->image->texture->GetName()); | |
if (name.Find("trigger") != String::NPOS) | |
return; | |
if (name.Find("sky") != String::NPOS) | |
return; | |
name += "_LM" + String(surface->lightmaptexturenum); | |
SharedPtr<Material> material = SharedPtr<Material>(LoadMaterial(surface->lightmaptexturenum, name, surface)); | |
if (surface->texinfo->numframes > 1) | |
{ | |
material = material->Clone(); | |
} | |
surface->material = material; | |
if (!surfaceMap.Contains(material)) | |
{ | |
surfaceMap.Insert(MakePair(material.Get(), PODVector<msurface_t*>())); | |
} | |
surfaceMap.Find(material)->second_.Push(surface); | |
} | |
void MapModel::Initialize() | |
{ | |
int maxcluster = -1; | |
for (int i = 0; i < r_worldmodel->numleafs; i++) | |
{ | |
if (r_worldmodel->leafs[i].cluster > maxcluster) | |
maxcluster = r_worldmodel->leafs[i].cluster; | |
} | |
renderClusters.Resize(maxcluster + 1); | |
for (int i = 0; i < r_worldmodel->numleafs; i++) | |
{ | |
mleaf_t* leaf = &r_worldmodel->leafs[i]; | |
// cluster 0 holds inline brush surfaces? | |
if (leaf->cluster < 1 || !leaf->nummarksurfaces) | |
continue; | |
RenderCluster& cluster = renderClusters[leaf->cluster]; | |
for (int j = 0; j < leaf->nummarksurfaces; j++) | |
{ | |
msurface_t* surface = leaf->firstmarksurface[j]; | |
if (!cluster.surfaces.Contains(surface)) | |
{ | |
cluster.surfaces.Push(surface); | |
} | |
} | |
} | |
// emit cluster models/nodes | |
for (unsigned i = 0; i < renderClusters.Size(); i++) | |
{ | |
byte* vis = Mod_ClusterPVS (i, r_worldmodel); | |
PODVector<msurface_t*> emitted; | |
int numvis = 0; | |
for (unsigned j = 0; j < renderClusters.Size(); j++) | |
{ | |
if (i == j || vis[j>>3] & (1<<(j&7))) | |
{ | |
for (unsigned k = 0; k < renderClusters[j].surfaces.Size(); k++) | |
{ | |
msurface_t* surf = renderClusters[j].surfaces[k]; | |
// as surfaces can be contained in multiple clusters | |
// the numvis will be slightly higher than the # emitted | |
numvis++; | |
if (!surf->emitted) | |
{ | |
surf->emitted = 1; | |
emitted.Push(surf); | |
} | |
} | |
} | |
} | |
if (emitted.Size()) | |
{ | |
// if we emitted some surfaces for this cluster | |
//printf("Cluster %i emitted %i new surfaces for %i visible\n", i, (int) emitted.Size(), numvis); | |
for (unsigned j = 0; j < emitted.Size(); j++) | |
{ | |
MapSurface(emitted.At(j)); | |
} | |
Node* node = EmitBrushModel(surfaceMap); | |
for (unsigned j = 0; j < emitted.Size(); j++) | |
{ | |
if (!surfaceNodes.Contains(emitted[j])) | |
{ | |
surfaceNodes.Insert(MakePair(emitted[j], PODVector<Node*>())); | |
} | |
PODVector<Node*>& nodes = surfaceNodes.Find(emitted[j])->second_; | |
nodes.Push(node); | |
} | |
} | |
} | |
for (int i = 1; i < r_worldmodel->numsubmodels;i++) | |
{ | |
String modelname = "*"; | |
modelname += i; | |
model_t* model = Mod_ForName((char*) modelname.CString(), qtrue); | |
for (int j = 0; j < model->nummodelsurfaces; j++) | |
{ | |
msurface_t* surf = r_worldmodel->surfaces + model->firstmodelsurface + j; | |
if (surf->emitted) | |
{ | |
ErrorExit("inline brush model already emitted"); | |
} | |
MapSurface(surf); | |
} | |
Node* node = EmitBrushModel(surfaceMap, false); | |
brushNodes.Insert(MakePair(model, node)); | |
} | |
} | |
static void CreateScene() | |
{ | |
Context* context = TBESystem::GetGlobalContext(); | |
ResourceCache* cache = context->GetSubsystem<ResourceCache>(); | |
scene_ = new Scene(context); | |
// Create the Octree component to the scene. This is required before adding any drawable components, or else nothing will | |
// show up. The default octree volume will be from (-1000, -1000, -1000) to (1000, 1000, 1000) in world coordinates; it | |
// is also legal to place objects outside the volume but their visibility can then not be checked in a hierarchically | |
// optimizing manner | |
scene_->CreateComponent<Octree>(); | |
scene_->CreateComponent<DebugRenderer>(); | |
Node* zoneNode = scene_->CreateChild("Zone"); | |
Zone* zone = zoneNode->CreateComponent<Zone>(); | |
// Set same volume as the Octree, set a close bluish fog and some ambient light | |
zone->SetBoundingBox(BoundingBox(Vector3(-10000, -10000, -10000), Vector3(10000, 10000, 10000))); | |
zone->SetAmbientColor(Color(0,0,0)); | |
zone->SetFogStart(10000); | |
zone->SetFogEnd(10000); | |
// Create a directional light to the world so that we can see something. The light scene node's orientation controls the | |
// light direction; we will use the SetDirection() function which calculates the orientation from a forward direction vector. | |
// The light will use default settings (white light, no shadows) | |
//Node* lightNode = scene_->CreateChild("DirectionalLight"); | |
//lightNode->SetDirection(Vector3(0.6f, -1.0f, 0.8f)); // The direction vector does not need to be normalized | |
//Light* light = lightNode->CreateComponent<Light>(); | |
//light->SetLightType(LIGHT_DIRECTIONAL); | |
// Create a scene node for the camera, which we will move around | |
// The camera will use default settings (1000 far clip distance, 45 degrees FOV, set aspect ratio automatically) | |
cameraNode_ = scene_->CreateChild("Camera"); | |
Camera* camera = cameraNode_->CreateComponent<Camera>(); | |
camera->SetFarClip(4096.0f); | |
camera->SetFov(85); | |
//static PODVector<Node*> dynamicLights; | |
for (int i = 0; i < 32; i++) | |
{ | |
// Create a point light to the world so that we can see something. | |
Node* pNode = scene_->CreateChild("Light"); | |
Light* plight = pNode->CreateComponent<Light>(); | |
plight->SetLightType(LIGHT_POINT); | |
plight->SetRange(0.0f); | |
plight->SetColor(Color(1, 1, 1)); | |
plight->SetBrightness(1); | |
plight->SetCastShadows(_castShadows); | |
//plight->SetShadowIntensity(0.5f); | |
// vertex lighting is far cheaper and works pretty well for Quake2 geometry | |
//plight->SetPerVertex(true); | |
dynamicLights.Push(pNode); | |
pNode->SetEnabled(false); | |
} | |
// Set an initial position for the camera scene node above the plane | |
cameraNode_->SetPosition(Vector3(128 * _scale,41* _scale,-320* _scale)); | |
Node* skyNode = scene_->CreateChild("Sky"); | |
skyNode->SetScale(500.0f); // The scale actually does not matter | |
Skybox* skybox = skyNode->CreateComponent<Skybox>(); | |
skybox->SetModel(cache->GetResource<Model>("Models/Box.mdl")); | |
skybox->SetMaterial(cache->GetResource<Material>("Materials/Skybox.xml")); | |
Node* smokeNode = scene_->CreateChild("Particles"); | |
smokeNode->SetPosition(Vector3(0, 0, 0)); | |
billboardObject = smokeNode->CreateComponent<BillboardSet>(); | |
billboardObject->SetNumBillboards(MAX_PARTICLES); | |
billboardObject->SetMaterial(cache->GetResource<Material>("Materials/Smoke.xml")); | |
billboardObject->SetSorted(false); | |
for (unsigned j = 0; j < MAX_PARTICLES; ++j) | |
{ | |
Billboard* bb = billboardObject->GetBillboard(j); | |
bb->size_ = Vector2(0.2f, 0.2f); | |
bb->rotation_ = Random() * 360.0f; | |
bb->enabled_ = false; | |
} | |
// After modifying the billboards, they need to be "commited" so that the BillboardSet updates its internals | |
billboardObject->Commit(); | |
//cameraNode_->SetPosition(Vector3(0, 0, -2000)); | |
Renderer* renderer = context->GetSubsystem<Renderer>(); | |
// Set up a viewport to the Renderer subsystem so that the 3D scene can be seen. We need to define the scene and the camera | |
// at minimum. Additionally we could configure the viewport screen size and the rendering path (eg. forward / deferred) to | |
// use, but now we just use full screen and default render path configured in the engine command line options | |
SharedPtr<Viewport> viewport(new Viewport(context, scene_, cameraNode_->GetComponent<Camera>())); | |
/* | |
SharedPtr<RenderPath> effectRenderPath = viewport->GetRenderPath()->Clone(); | |
effectRenderPath->Append(cache->GetResource<XMLFile>("PostProcess/Blur.xml")); | |
// Make the bloom mixing parameter more pronounced | |
//effectRenderPath->SetShaderParameter("BloomMix", Vector2(1.0f, 1.5f)); | |
//effectRenderPath->SetShaderParameter("BloomThreshold",.2f); | |
viewport->SetRenderPath(effectRenderPath); | |
*/ | |
renderer->SetViewport(0, viewport); | |
} | |
MapModel* MapModel::Generate() | |
{ | |
MapModel* model = new MapModel(); | |
model->Initialize(); | |
return model; | |
} | |
void R_CreateLightmap(int id, int width, int height, unsigned char* data) | |
{ | |
printf("LIGHTMAP: %i %ix%i\n", id, width, height); | |
Context* context = TBESystem::GetGlobalContext(); | |
Texture2D* texture = new Texture2D(context); | |
texture->SetNumLevels(1); | |
texture->SetSize(width, height, Graphics::GetRGBAFormat()); | |
texture->SetData(0, 0, 0, width, height, data); | |
lightmapTextures.Push(texture); | |
} | |
static image_t *R_TextureAnimation (int frame, mtexinfo_t *tex) | |
{ | |
int c; | |
if (!tex->next) | |
return tex->image; | |
c = frame % tex->numframes; | |
while (c) | |
{ | |
tex = tex->next; | |
c--; | |
} | |
return tex->image; | |
} | |
refdef_t r_newrefdef; | |
void R_BuildLightMap (msurface_t *surf, byte *dest, int stride); | |
void R_SetCacheState( msurface_t *surf ); | |
extern unsigned d_8to24table[]; | |
extern "C" | |
{ | |
void R_RenderFrame (refdef_t *fd) | |
{ | |
if (!cameraNode_) | |
return; | |
r_newrefdef = *fd; | |
// optimize this, probably doing too much work | |
for (unsigned i = 0; i < worldNodes.Size(); i++) | |
worldNodes[i]->SetEnabled(false); | |
//printf("%f %f %f\n", fd->vieworg[0], fd->vieworg[1], fd->vieworg[2]); | |
mleaf_t* leaf = Mod_PointInLeaf (fd->vieworg, r_worldmodel); | |
if (leaf->cluster < 0) | |
return; | |
// TODO: factor in areas? | |
//if (fd->areabits) | |
//{ | |
// | |
//} | |
for (HashMap<model_t*, Node *>::Iterator i = brushNodes.Begin(); i != brushNodes.End(); ++i) | |
{ | |
i->second_->SetEnabled(false); | |
} | |
int curLights = 0; | |
for (unsigned i = 0; i < dynamicLights.Size(); i++) | |
{ | |
dynamicLights[i]->SetEnabled(false); | |
} | |
for (int i = 0; i < fd->num_dlights; i++) | |
{ | |
if (i >= dynamicLights.Size()) | |
break; | |
dlight_t* dlight = &fd->dlights[i]; | |
Node* node = dynamicLights.At(i); | |
node->SetEnabled(true); | |
Light* light = node->GetComponent<Light>(); | |
light->SetRange(dlight->intensity * _scale); | |
light->SetColor(Color(dlight->color[0], dlight->color[1], dlight->color[2])); | |
node->SetPosition(Vector3(dlight->origin[0] * _scale, dlight->origin[2] * _scale, dlight->origin[1] * _scale)); | |
} | |
// turn off all alias nodes | |
HashMap<model_t*, PODVector<Node*> >::Iterator aliasItr; | |
for (aliasItr = aliasNodes.Begin(); aliasItr != aliasNodes.End(); aliasItr++) | |
{ | |
PODVector<Node*>& nodes = aliasItr->second_; | |
for (unsigned i = 0; i < nodes.Size(); i++) | |
nodes[i]->SetEnabled(false); | |
} | |
// world animated lights, this only does animation on the world model | |
// and not inline brush models | |
// and it is currenly animating all textures whether they are in visible | |
// or not | |
msurface_t* surf = r_worldmodel->surfaces + r_worldmodel->firstmodelsurface; | |
for (int j = 0; j < r_worldmodel->nummodelsurfaces; j++) | |
{ | |
if ( !(surf->texinfo->flags & (SURF_SKY|SURF_TRANS33|SURF_TRANS66|SURF_WARP ) ) ) | |
{ | |
for ( int maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; maps++ ) | |
{ | |
if ( fd->lightstyles[surf->styles[maps]].white != surf->cached_light[maps] ) | |
{ | |
unsigned temp[128*128]; | |
int smax, tmax; | |
if ( surf->styles[maps] >= 32 || surf->styles[maps] == 0 ) | |
{ | |
smax = (surf->extents[0]>>4)+1; | |
tmax = (surf->extents[1]>>4)+1; | |
R_BuildLightMap( surf, (byte *)temp, smax*4 ); | |
R_SetCacheState( surf ); | |
Texture2D* lightmap = lightmapTextures[surf->lightmaptexturenum]; | |
lightmap->SetData(0, surf->light_s, surf->light_t, smax, tmax, temp); | |
//static int update = 0; | |
//printf("%i Updating Lightmap %i\n", update++, surf->lightmaptexturenum); | |
} | |
} | |
} | |
} | |
if (surf->material && surf->texinfo->numframes) | |
{ | |
image_t* image = R_TextureAnimation(int(TBESystem::GetMilliseconds()/1000.0f), surf->texinfo); | |
if (image->texture) | |
surf->material->SetTexture(TU_DIFFUSE, image->texture); | |
} | |
surf++; | |
} | |
for (int i = 0; i < fd->num_entities; i++) | |
{ | |
entity_t* ent = &fd->entities[i]; | |
model_t* model = (model_t*) ent->model; | |
if (!model) | |
continue; | |
if (model == r_worldmodel) | |
continue; | |
if (model->type == mod_alias) | |
{ | |
aliasItr = aliasNodes.Find(model); | |
if (aliasItr == aliasNodes.End()) | |
{ | |
aliasNodes.Insert(MakePair(model, PODVector<Node*>())); | |
aliasItr = aliasNodes.Find(model); | |
} | |
PODVector<Node*>& nodes = aliasItr->second_; | |
Node* node = NULL; | |
for (unsigned j = 0; j < nodes.Size(); j++) | |
{ | |
if (!nodes.At(j)->IsEnabled()) | |
{ | |
node = nodes.At(j); | |
break; | |
} | |
} | |
if (!node) | |
{ | |
Model* amodel = GetAliasModel(model); | |
node = scene_->CreateChild("AliasModel"); | |
nodes.Push(node); | |
if (!amodel->GetNumMorphs()) | |
{ | |
StaticModel* aliasModel = node->CreateComponent<StaticModel>(); | |
if (ent->flags & RF_WEAPONMODEL || ent->flags & RF_VIEWERMODEL) | |
aliasModel->SetCastShadows(false); | |
else | |
aliasModel->SetCastShadows(_castShadows); | |
aliasModel->SetModel(amodel); | |
aliasModel->SetMaterial(0, model->material->Clone()); | |
} | |
else | |
{ | |
AnimatedModel* aliasModel = node->CreateComponent<AnimatedModel>(); | |
if (ent->flags & RF_WEAPONMODEL || ent->flags & RF_VIEWERMODEL) | |
aliasModel->SetCastShadows(false); | |
else | |
aliasModel->SetCastShadows(_castShadows); | |
aliasModel->SetModel(amodel); | |
aliasModel->SetMaterial(0, model->material->Clone()); | |
} | |
} | |
vec3_t color; | |
color[0] = 1.0f; | |
color[1] = 1.0f; | |
color[2] = 1.0f; | |
if ( !(ent->flags & RF_FULLBRIGHT )) | |
{ | |
// Quake2 has some player lighting hack that goes back to server | |
// from refresh, check into this... | |
int j; | |
R_LightPoint(ent->origin, color); | |
if ( ent->flags & RF_MINLIGHT ) | |
{ | |
for (j=0 ; j<3 ; j++) | |
if (color[j] > 0.1) | |
break; | |
if (j == 3) | |
{ | |
color[0] = 0.1; | |
color[1] = 0.1; | |
color[2] = 0.1; | |
} | |
} | |
if ( ent->flags & RF_GLOW ) | |
{ // bonus items will pulse with time | |
float scale; | |
float min; | |
scale = 0.1 * sin(float(TBESystem::GetMilliseconds())/100.0f); | |
for (j=0 ; j<3 ; j++) | |
{ | |
min = color[j] * 0.8; | |
color[j] += scale; | |
if (color[j] < min) | |
color[j] = min; | |
} | |
} | |
} | |
float alpha = 1.0f; | |
if ( ent->flags & RF_TRANSLUCENT ) | |
{ | |
alpha = ent->alpha; | |
} | |
StaticModel* aliasModel = node->GetComponent<StaticModel>(); | |
if (aliasModel) | |
{ | |
Material* material = aliasModel->GetMaterial(0); | |
material->SetTexture(TU_DIFFUSE, model->skins[ent->skinnum]->texture); | |
material->SetTexture(TU_EMISSIVE, model->skins[ent->skinnum]->texture); | |
material->SetShaderParameter("MatDiffColor", Vector4(1, 1, 1, alpha)); | |
material->SetShaderParameter("MatEmissiveColor", Vector4(color[0], color[1], color[2], alpha)); | |
} | |
else | |
{ | |
AnimatedModel* amodel = node->GetComponent<AnimatedModel>(); | |
amodel->ResetMorphWeights(); | |
if (ent->frame != ent->oldframe && ent->backlerp) | |
{ | |
amodel->SetMorphWeight(String(ent->frame), 1.0f - ent->backlerp); | |
amodel->SetMorphWeight(String(ent->oldframe), ent->backlerp); | |
} | |
else | |
{ | |
amodel->SetMorphWeight(String(ent->frame), 1.0f); | |
} | |
Material* material = amodel->GetMaterial(0); | |
material->SetTexture(TU_DIFFUSE, model->skins[ent->skinnum]->texture); | |
material->SetTexture(TU_EMISSIVE, model->skins[ent->skinnum]->texture); | |
material->SetShaderParameter("MatDiffColor", Vector4(1, 1, 1, alpha)); | |
material->SetShaderParameter("MatEmissiveColor", Vector4(color[0], color[1], color[2], alpha)); | |
} | |
// I am not sure on the pitch and roll signs here, yaw is correct | |
Quaternion q(-ent->angles[2], -ent->angles[1], -ent->angles[0]); | |
node->SetRotation(q); | |
Vector3 curPos(ent->origin[0] * _scale, ent->origin[2] * _scale, ent->origin[1] * _scale); | |
Vector3 prevPos(ent->oldorigin[0] * _scale, ent->oldorigin[2] * _scale, ent->oldorigin[1] * _scale); | |
curPos = prevPos.Lerp(curPos, 1.0f - ent->backlerp); | |
node->SetPosition(curPos); | |
node->SetEnabled(true); | |
} | |
if (model->type == mod_brush) | |
{ | |
msurface_t* surf = model->surfaces + model->firstmodelsurface; | |
for (int j = 0; j < model->nummodelsurfaces; j++) | |
{ | |
if (surf->material && surf->texinfo->numframes) | |
{ | |
image_t* image = R_TextureAnimation(ent->frame, surf->texinfo); | |
surf->material->SetTexture(TU_DIFFUSE, image->texture); | |
} | |
surf++; | |
} | |
Node* node = brushNodes.Find(model)->second_; | |
node->SetEnabled(true); | |
//#define PITCH 0 // up / down | |
//#define YAW 1 // left / right | |
//#define ROLL 2 // fall over | |
// I am not sure on the pitch and roll signs here, yaw is correct | |
Quaternion q(-ent->angles[2], -ent->angles[1], ent->angles[0]); | |
node->SetRotation(q); | |
node->SetPosition(Vector3(ent->origin[0] * _scale, ent->origin[2] * _scale, ent->origin[1] * _scale)); | |
} | |
} | |
byte* vis = Mod_ClusterPVS (leaf->cluster, r_worldmodel); | |
for (unsigned i = 0; i < renderClusters.Size(); i++) | |
{ | |
if (leaf->cluster == i || vis[i>>3] & (1<<(i&7))) | |
{ | |
RenderCluster& cluster = renderClusters.At(i); | |
for (unsigned j = 0; j < cluster.surfaces.Size(); j++) | |
{ | |
PODVector<Node*>& nodes = surfaceNodes.Find(cluster.surfaces[j])->second_; | |
for (unsigned k = 0; k < nodes.Size(); k++) | |
{ | |
if (!nodes[k]->IsEnabled()) | |
nodes[k]->SetEnabled(true); | |
} | |
} | |
} | |
} | |
Quaternion q(fd->viewangles[0], -fd->viewangles[1] + 90, fd->viewangles[2]); | |
cameraNode_->SetPosition(Vector3(fd->vieworg[0] *_scale, fd->vieworg[2] *_scale, fd->vieworg[1] *_scale)); | |
cameraNode_->SetRotation(q); | |
for (int j = 0; j < MAX_PARTICLES; j++) | |
{ | |
} | |
bool anychanged = false; | |
for (int j = 0; j < MAX_PARTICLES; j++) | |
{ | |
Billboard* bb = billboardObject->GetBillboard(j); | |
if (j >= fd->num_particles) | |
{ | |
if (bb->enabled_) | |
{ | |
bb->enabled_ = false; | |
anychanged = true; | |
} | |
continue; | |
} | |
particle_t* p = &fd->particles[j]; | |
bb->position_ = Vector3(p->origin[0] * _scale, p->origin[2] * _scale, p->origin[1] * _scale); | |
unsigned char color[4]; | |
*(int *)color = d_8to24table[p->color]; | |
bb->color_ = Color(float(color[0]) / 255.0f, float(color[1]) / 255.0f, float(color[2]) / 255.0f, p->alpha * .8f); | |
bb->enabled_ = true; | |
anychanged = true; | |
} | |
if (anychanged) | |
billboardObject->Commit(); | |
} | |
} | |
void R_InitMapModel() | |
{ | |
CreateScene(); | |
MapModel::Generate(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment