Open source Star Ruler 2 source code!
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
#include "scene/mesh_icon_node.h"
|
||||
#include "render/driver.h"
|
||||
#include "render/render_mesh.h"
|
||||
#include "render/spritesheet.h"
|
||||
#include "render/vertexBuffer.h"
|
||||
#include "constants.h"
|
||||
#include "frustum.h"
|
||||
|
||||
namespace scene {
|
||||
|
||||
//Maximum distance away from the camera something can render (according to its scale)
|
||||
const double MaxRenderDistFactor = 8000.0;
|
||||
const double IconRenderDistFactor = 1000.0;
|
||||
const double BothRenderDistFactor = 500.0;
|
||||
bool MeshIconNode::render3DIcons = true;
|
||||
|
||||
MeshIconNode::MeshIconNode(
|
||||
const render::RenderMesh* Mesh, const render::RenderState* Material,
|
||||
const render::SpriteSheet* Sheet, unsigned Index)
|
||||
: mesh(Mesh), material(Material), iconSheet(Sheet), iconIndex(Index) {
|
||||
if(Material->baseMat != render::MAT_Solid || (Sheet && Sheet->material.baseMat != render::MAT_Solid))
|
||||
setFlag(NF_Transparent, true);
|
||||
setFlag(NF_AnimOnlyVisible, true);
|
||||
}
|
||||
|
||||
bool MeshIconNode::preRender(render::RenderDriver& driver) {
|
||||
auto fromCamera = abs_position + (driver.cam_facing * abs_scale) - driver.cam_pos;
|
||||
sortDistance = fromCamera.getLength();
|
||||
|
||||
if(sortDistance > MaxRenderDistFactor * abs_scale || !driver.getViewFrustum().overlaps(abs_position,abs_scale))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
void MeshIconNode::render(render::RenderDriver& driver) {
|
||||
if(render3DIcons) {
|
||||
double scaleMod = pow(abs_scale, 0.3);
|
||||
if(iconSheet) {
|
||||
if(sortDistance > BothRenderDistFactor * scaleMod) {
|
||||
double iconScale = sqrt(sortDistance / abs_scale) * abs_scale * 0.25;
|
||||
|
||||
//Calculate best-fit facing of the 2D sprite (Assuming the sprite is facing +x)
|
||||
auto& cam_facing = driver.cam_facing;
|
||||
auto& cam_up = driver.cam_up;
|
||||
|
||||
double rot;
|
||||
|
||||
vec3d obj_facing = rotation * vec3d::front();
|
||||
double alongDot = cam_facing.dot(obj_facing);
|
||||
|
||||
//If it's facing along the camera vector, we can't get an accurate angle
|
||||
if(alongDot > -0.9999 && alongDot < 0.9999) {
|
||||
obj_facing -= cam_facing * alongDot;
|
||||
obj_facing.normalize();
|
||||
|
||||
vec3d cam_right = cam_facing.cross(cam_up).normalized();
|
||||
rot = acos(cam_right.dot(obj_facing));
|
||||
if(cam_right.cross(cam_facing).dot(obj_facing) < 0)
|
||||
rot = -rot;
|
||||
}
|
||||
else {
|
||||
//Point up when going away, down when coming toward
|
||||
rot = alongDot > 0 ? pi * 0.5 : pi * -0.5;
|
||||
}
|
||||
|
||||
color.a = std::min(1.0, (sortDistance / scaleMod - BothRenderDistFactor) / (IconRenderDistFactor - BothRenderDistFactor));
|
||||
|
||||
Color c = color;
|
||||
|
||||
driver.drawBillboard(abs_position, iconScale,
|
||||
iconSheet->material, iconSheet->getSource(iconIndex), rot, c);
|
||||
|
||||
if(sortDistance > IconRenderDistFactor * scaleMod)
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if(sortDistance > IconRenderDistFactor * scaleMod) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(material->baseMat != render::MAT_Solid)
|
||||
render::renderVertexBuffers();
|
||||
|
||||
driver.setTransformation(transformation);
|
||||
driver.switchToRenderState(*material);
|
||||
mesh->selectLOD(sortDistance / abs_scale)->render();
|
||||
driver.resetTransformation();
|
||||
}
|
||||
|
||||
};
|
||||
Reference in New Issue
Block a user