/******************************************************************************/
#include "stdafx.h"
#include "../../../../../data/enum/_enums.h"
/******************************************************************************/
//One Way to do a render to texture mirror. It's not 100% correct but pretty close
//Feel free to edit the code and try to fix any issues you might be able to solve.
/******************************************************************************/
Viewport viewport[2];
Camera camera [2];
Flt mirrorCamDist;
Vec2 fov;
Mesh box ,
ball;
Image rtt ; // Render Target Tetxture (of IMAGE_RT mode)
MaterialPtr mirrorMat;
bool mirrorInRange = true;
Camera desired_camera; // create a helper desired camera
/******************************************************************************/
// Player
/******************************************************************************/
STRUCT(Player , Game::Chr)
//{
virtual Bool update();
};
/******************************************************************************/
// MIRROR
/******************************************************************************/
struct MirrorObject : Game::Static // Extend
{
virtual void create (Game::ObjParams &obj); // extend creation to include accessing item type
virtual Bool update ( ); // extend updating to include bomb explosion, and 'mesh_overlay' update
virtual UInt drawPrepare( ); // extend drawing to include request for the RM_OVERLAY mode
// io
virtual void save(File &f); // extend saving to include members saving
virtual Bool load(File &f); // extend loading to include members loading
MirrorObject();
};
/******************************************************************************/
Game::ObjMemx<MirrorObject> Mirrors;
Game::ObjMemx< Player> Players;
/******************************************************************************/
/******************************************************************************/
Bool Player::update()
{
if(action)
{
if(Kb.b(KB_W) || Kb.b(KB_S) || Kb.b(KB_A) || Kb.b(KB_D) || Kb.b(KB_Q) || Kb.b(KB_E))actionBreak();
}
if(!action)
{
// turn & move
input.turn.x=Kb.b(KB_Q)-Kb.b(KB_E);
input.turn.y=Kb.b(KB_T)-Kb.b(KB_G);
input.move.x=Kb.b(KB_D)-Kb.b(KB_A);
input.move.z=Kb.b(KB_W)-Kb.b(KB_S);
input.move.y=Kb.b(KB_SPACE)-Kb.b(KB_LSHIFT);
// dodge, crouch, walk, jump
input.dodge = Kb.bd(KB_D)-Kb.bd(KB_A);
input.crouch= Kb.b (KB_LSHIFT);
input.walk = Kb.b (KB_LCTRL );
input.jump =(Kb.bp(KB_SPACE ) ? 3.5f : 0);
}
return super::update();
}
/******************************************************************************/
// MIRROR
/******************************************************************************/
MirrorObject::MirrorObject()
{
}
/******************************************************************************/
void MirrorObject::create(Game::ObjParams &obj)
{
super::create(obj);
//Change the diffuse for mirrrors material to the rtt image
this->mesh->parts[0].material()->base_0 = &rtt; // draw texture
this->mesh->parts[0].material()->validate();
}
/******************************************************************************/
Bool MirrorObject::update()
{
return __super::update();
}
/******************************************************************************/
UInt MirrorObject::drawPrepare()
{
Matrix matrix=matrixScaled();
if(Frustum(mesh->box, matrix))
{
mirrorInRange = true; //Render the mirror image
Matrix mirrorMatrix = desired_camera.matrix; //Create a mirrorMatrix and use desired_camera.matrix for its base
Vec cameraTarget = desired_camera.matrix.pos; //target pos
cameraTarget = Mirror(mirrorMatrix.pos,pos(),matrix.x); //mirror camera target on x axis
cameraTarget = Mirror(cameraTarget,pos(),Vec(0,1,0)); //mirror camera target on world up axis
Vec cameraPos = desired_camera.matrix.pos; //camera pos
cameraPos = Mirror(mirrorMatrix.pos,pos(),this->matrix().z); //mirror camera pos on z axis
camera[1].setFromAt(cameraPos-matrix.z,pos()); //set mirror cameras position and target
Flt CamDist = Dist(camera[1].at,camera[1].matrix.pos); //Check distance between camera pos and target
//Calculate the fov angles accoring to width and height of the actor box and camera distance
Flt a = (actor.box().w()/2)/CamDist;fov.x = Tan(a)*2;
Flt b = (actor.box().h()/2)/CamDist;fov.y = Tan(b)*2;
mirrorCamDist = CamDist; //set the distance for clipping
//Draw mesh normally
MaterialLock=material(); mesh->draw(matrix);
MaterialLock=NULL;
return true;
}else return false;
}
/******************************************************************************/
void MirrorObject::save(File &f)
{
super::save(f);
}
Bool MirrorObject::load(File &f)
{
if(super::load(f))
{
this->mesh->parts[0].material()->base_0 = &rtt; // draw texture
this->mesh->parts[0].material()->validate();
}
return false;
}
//Just creating a mirror object and mesh
void createMirror()
{
Game::ObjParams &obj=*Game::Objs("obj/mirror/0.obj"); // get barrel object parameters
Game::Obj *tmpObj = Game::World.objCreateNear(obj,Matrix(obj.scale(),Players[0].pos()-Vec(0,0,1))); // create new object at (16,8,16) position and give objects default scaling
}
/******************************************************************************/
// MAIN
/******************************************************************************/
void InitPre()
{
App.name("Camera Collisions");
App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE;
DataPath("../data");
Paks.add("engine.pak");
D.full(true).sync(true).ambPower(0.3f).hpRt(true);
}
/******************************************************************************/
Bool Init()
{
// initialize cameras
camera[0].setSpherical(Vec(0,0,0), 0, 0, 0, 3);
camera[1].setSpherical(Vec(0,0,0), 0, 0, 0, 3);
Physics.create(CSS_NONE,true,"../Installation/PhysX");
Sky .atmospheric();
Sun.image=Images("gfx/sky/sun.gfx"); Sun.light_color=1-D.ambColor();
// create the world
Game::World.init()
.setObjType(Mirrors,OBJ_STATIC) //Use mirrors instead of static objects
.setObjType(Players,OBJ_PLAYER)
.New("world/sample.world");
return true;
}
/******************************************************************************/
void Shut()
{
}
void UpdateCamera()
{
//I used third person camera from the camera collision tutorial
if(Players.elms())
{
// first setup the desired camera as in the previous tutorials
desired_camera.yaw -=Ms.d().x; // update camera yaw angle according to mouse delta x
desired_camera.pitch+=Ms.d().y; // update camera pitch angle according to mouse delta y
Clamp(desired_camera.pitch,-PI_2,PI_4); // clamp to possible camera pitch angle
desired_camera.dist=Max(1.0f,desired_camera.dist*ScaleFactor(Ms.wheel()*-0.2f)); // update camera distance according to mouse wheel
desired_camera.at =Players[0].pos();
desired_camera.setSpherical(); // set as spherical from current values, this will set the camera's matrix (desired_camera.matrix)
// now what we'll do is cast a small sized Ball from starting position to target camera destination
// we'll stop the ball at first contact point, and set camera at that place
// create a helper ball which will be used for collision detection
Ball ball(0.1f, desired_camera.at); // we place it at starting point (where the camera is looking at)
// now we'll move the ball in the direction where the camera should be
Physics.move(ball, desired_camera.matrix.pos-ball.pos); // use physics movement to move the ball as far as it can go without any collisions
// now the ball.pos is located at either maximum movement distance or at nearest collision point
// having ball's position we can now set the final camera position
camera[0].setPosDir(ball.pos, desired_camera.matrix.z, desired_camera.matrix.y); // we'll use 'desired_camera.matrix' directions which were set in 'setSpherical' camera method
camera[0].updateVelocities().set(); // update camera velocities and activate it
}
}
/******************************************************************************/
Bool Update()
{
Game::World.update(Cam.at);
UpdateCamera();
if(Kb.bp(KB_M)) // on space
createMirror(); //Create the mirror to the sample world
if(Kb.bp(KB_ESC))return false;
return true;
}
/******************************************************************************/
void Render()
{
Game::World.draw(); //draw world
}
void RenderToTexture()
{
Int tex_size=256; //Texture size
camera[1].set(); //Enable secondary camera used for mirrors
Flt tmpFov = D.viewFov(); // remember old fov before rendering
D.viewFrom(mirrorCamDist+0.1); //change viewport clipping accoring to distance. add a little extra just incase.
D.viewFov(fov.x,FOV_X); //get fov from object calculations
D.viewFov(fov.y,FOV_Y); //get fov from object calculations
// create the Render Target Texture if it hasn't been created yet
if(!rtt.is())rtt.create(tex_size,tex_size,1,IMAGE_B8G8R8A8,IMAGE_RT,1);
// render to texture
Bool super_sample=false; // optionally use super sampling to enable anti-aliasing at the cost of greater viewport size
Int render_size =Min(D.x(), D.y(), tex_size*(super_sample ? 2 : 1)); // calculate rendering viewport size
D.viewRect(&RectI(0,0,render_size,render_size)); // set new viewport
Renderer.dest_rt=&rtt; // specify custom render target
Renderer(Render); // perform rendering
Renderer.dest_rt=NULL; // disable custom render target
D.viewRect(NULL); // Restore full viewport
D.viewFrom(0.01f); // Restore clipping
D.viewFov(tmpFov); // Restore fov
camera[0].set(); //Restore main camera
}
/******************************************************************************/
void Draw()
{
//*********************Mirrors in game*****************************///
RenderToTexture(); //Render to texture
mirrorInRange = false; //restore range check
//*********************Mirrors in game*****************************///
// render normally
Renderer(Render);
}
/******************************************************************************/