nenuzhno-engine_iter1/demos/VolLight/main.cpp

284 lines
6.9 KiB
C++

#include <vector>
#include "graphics/platform_gl.h"
#include "log.h"
#include "engine.h"
#include "button.h"
#include "game/IGame.h"
#include "system/config.h"
#include "resource/ResourceManager.h"
#include "renderer/renderer.h"
#include "renderer/mesh.h"
#include "renderer/material.h"
#include "renderer/model.h"
#include "graphics/texture.h"
#include "graphics/fbo.h"
#include "graphics/glsl_prog.h"
#include "Volumetrics.h"
#include <vec2.hpp>
#include <gtc/random.hpp>
#include <gtc/matrix_transform.hpp>
#include <gtc/type_ptr.hpp>
#include <common.hpp>
#include <geometric.hpp>
using glm::vec2;
using glm::vec3;
using glm::vec4;
using glm::linearRand;
using glm::clamp;
using glm::abs;
using glm::normalize;
using glm::translate;
using glm::scale;
class VolLightGame: public IGame{
public:
VolLightGame(){}
void Created();
void Changed(int w, int h);
void Draw();
const char *GetGamedir(){
return "vol_light";
}
void OnTouch(float tx, float ty, int ta, int tf);
void OnKey(int key, int scancode, int action, int mods);
IRenderer *rend;
ResourceManager *resMan;
ConfigFile cfg;
Camera cam;
Scene scene;
Texture texWhite;
TexMaterial *matWhite;
Volumetrics lightVol;
FrameBufferObject volFBO;
float volScale;
glslProg progVolLight;
int u_lightMtx;
int u_invVPMtx;
int u_lightPosSize;
glslProg progVolLightIn;
int u_lightMtxIn;
int u_invVPMtxIn;
int u_lightPosSizeIn;
Joystick joyL;
KeyJoystick joyM;
int frame;
double oldTime;
};
IGame *CreateGame(){
return new VolLightGame();
}
void VolLightGame::Created(){
Log("VolLight test Created()\n");
resMan = new ResourceManager();
resMan->Init();
rend = CreateRenderer();
rend->Init(RENDERER_GUI|RENDERER_LIGHT|RENDERER_BACKBUFFER, resMan);
uint8_t whiteData[]={255,255,255};
texWhite.Create(1,1);
texWhite.Upload(0,GL_RGB,whiteData);
matWhite = new TexMaterial(&texWhite,true);
progVolLight.CreateFromFile("volLight","volLight");
progVolLight.u_mvpMtx = progVolLight.GetUniformLoc("u_mvpMtx");
progVolLight.u_modelMtx = progVolLight.GetUniformLoc("u_modelMtx");
progVolLight.u_cameraPos = progVolLight.GetUniformLoc("u_cameraPos");
u_lightMtx = progVolLight.GetUniformLoc("u_lightMtx");
u_invVPMtx = progVolLight.GetUniformLoc("u_invVPMtx");
u_lightPosSize = progVolLight.GetUniformLoc("u_lightPosSize");
progVolLight.UniformTex("u_lightDepth",1);
progVolLight.UniformTex("u_sceneDepth",2);
progVolLightIn.CreateFromFile("volLight","volLightIn");
progVolLightIn.u_mvpMtx = progVolLightIn.GetUniformLoc("u_mvpMtx");
progVolLightIn.u_modelMtx = progVolLightIn.GetUniformLoc("u_modelMtx");
progVolLightIn.u_cameraPos = progVolLightIn.GetUniformLoc("u_cameraPos");
u_lightMtxIn = progVolLightIn.GetUniformLoc("u_lightMtx");
u_invVPMtxIn = progVolLightIn.GetUniformLoc("u_invVPMtx");
u_lightPosSizeIn = progVolLightIn.GetUniformLoc("u_lightPosSize");
progVolLightIn.UniformTex("u_lightDepth",1);
progVolLightIn.UniformTex("u_sceneDepth",2);
cfg.Load("config.txt");
Model *mdl = resMan->GetModel(cfg["modelName"].c_str());
mdl->materials[0].mat = matWhite;
scene = Scene();
StaticModel *obj1 = new StaticModel();
obj1->mdl = mdl;
vec3 obj1Pos = cfg.GetVec3("modelPos");
obj1->modelMtx = translate(mat4(1.0f),obj1Pos);
scene.AddObject(obj1);
lightVol.Init(&scene,cfg.GetVec3("lightPos"),cfg.GetVec3("lightTarget"),atof(cfg["lightFOV"].c_str()),
atof(cfg["lightAspect"].c_str()),atof(cfg["lightNear"].c_str()),atof(cfg["lightFar"].c_str()),cfg.GetInt("lightRes"));
volScale = atof(cfg["volScale"].c_str());
volFBO.Create();
volFBO.CreateTexture(64,64,GL_LINEAR);
FrameBufferObject::Unbind();
rend->SetScene(&scene);
cam = Camera();
cam.pos = cfg.GetVec3("cameraPos");
cam.rot = cfg.GetVec3("cameraRot");
cam.UpdateView();
rend->SetCamera(&cam);
rend->debug = cfg["debug"]!="0";
joyL = Joystick(0,0.5,0.5,0.5);
//joyM = Joystick(0.5,0.5,0.5,0.5);
joyM = KeyJoystick(IN_KEY_W,IN_KEY_S,IN_KEY_D,IN_KEY_A);
frame = 0;
oldTime = GetTime();
}
void VolLightGame::Changed(int w, int h){
if(!w||!h)
return;
rend->Resize(w,h);
cam.UpdateProj(80.0f,rend->aspect,0.02f,20.0f);
//cam.SetOrtho(aspect,bScroll.pos);
volFBO.Resize(w*volScale,h*volScale);
frame = 0;
}
void VolLightGame::Draw(){
double startTime = GetTime();
float deltaTime = (startTime-oldTime);
oldTime = startTime;
cam.pos += glm::inverse(glm::mat3(cam.viewMtx))*vec3(joyM.vel.x,0,-joyM.vel.y)*2.0f*deltaTime;
cam.rot += vec3(-joyL.vel.y*rend->aspect,-joyL.vel.x,0)*60.0f*deltaTime;
cam.UpdateView();
rend->Draw();
bool drawVolumetricLight = true;
bool isInsideVolume = lightVol.CheckPoint(cam.pos);
//drawVolumetricLight = !isInsideVolume;
//Add light box to depth
if(drawVolumetricLight){
rend->GetFBO()->Bind();
rend->Set2DMode(false);
glColorMask(0,0,0,0);
//UseProg depth
lightVol.AddToDepth(rend);
glColorMask(1,1,1,1);
rend->GetFBO()->Unbind();
}
#if 0
//display scene depth
rend->Set2DMode(true);
rend->SetModelMtx(mat4(1));
rend->GetFBO()->BindDepthTexture();
rend->DrawRect(0.02,0.02,0.5,0.5);
#else
//prepare depth texture
if(drawVolumetricLight){
if(frame%128==0)
lightVol.Prepare(rend);
//Display light depth
/*lightFBO.BindDepthTexture();
rend->SetModelMtx(mat4(1));
rend->Set2DMode();
rend->DrawRect(0.02,0.02,0.5,0.5);*/
volFBO.Bind();
volFBO.Clear(1);
rend->Set2DMode(false);
if(!isInsideVolume){
glCullFace(GL_FRONT);
rend->UseProg(&progVolLight);
lightVol.Draw(rend,u_lightMtx,u_invVPMtx,u_lightPosSize);
glCullFace(GL_BACK);
}else{
rend->UseProg(&progVolLightIn);
lightVol.Draw(rend,u_lightMtxIn,u_invVPMtxIn,u_lightPosSizeIn);
}
//clean up
glActiveTexture(GL_TEXTURE1);
texWhite.Bind();
glActiveTexture(GL_TEXTURE2);
texWhite.Bind();
glActiveTexture(GL_TEXTURE0);
volFBO.Unbind();
rend->ResetViewport();
//draw effect additive
rend->Set2DMode(true);
glEnable(GL_BLEND);
glBlendFunc(1,1);
volFBO.BindTexture();
rend->DrawRect(0.0,0.0,1.0,1.0);
glDisable(GL_BLEND);
}
texWhite.Bind();
#endif
char temp[256];
snprintf(temp,256,"volumetric light: %s",drawVolumetricLight?"On":"Off");
rend->DrawText(temp,0.02,0.9,0.2*rend->aspect);
frame++;
}
Button::Button(float nx, float ny, float nw, float nh, bool adjust):
x(nx),y(ny),w(nw),h(nh),text(0),active(true),pressed(false)
{
}
Button::Button(float nx, float ny, float nw, float nh, const char *t, bool adjust):
x(nx),y(ny),w(nw),h(nh),text(t),active(true),pressed(false)
{
}
void Button::Update(){}
bool Button::SetUniform(int loc){return false;}
void VolLightGame::OnTouch(float tx, float ty, int ta, int tf){
float x = tx/rend->width;
#ifdef ANDROID
float y = (ty-64)/rend->height;
#else
float y = ty/rend->height;
#endif
if(ta==0){
joyL.Hit(x,y,tf);
joyM.Hit(x,y*rend->aspect,tf);
}else if(ta==1){
joyL.Release(tf);
joyM.Release(tf);
}else if(ta==2){
joyL.Move(x,y,tf);
joyM.Move(x,y*rend->aspect,tf);
}
}
void VolLightGame::OnKey(int key, int scancode, int action, int mods){
joyM.OnKey(key,action);
}