nenuzhno-engine_iter1/src/renderer/renderer.cpp

546 lines
12 KiB
C++

#include <vector>
using std::vector;
#include <glm.hpp>
#include <gtc/matrix_transform.hpp>
#include <gtc/type_ptr.hpp>
using glm::mat4;
#include "log.h"
#include "renderer/renderer.h"
#include "graphics/platform_gl.h"
#include "graphics/gl_utils.h"
#include "graphics/ArrayBuffer.h"
#include "graphics/glsl_prog.h"
#include "graphics/texture.h"
#include "graphics/fbo.h"
#include "renderer/font.h"
#include "renderer/Model.h"
#include "renderer/mesh.h"
#include "button.h"
#include "engine.h"
#include "renderer/GLES2Renderer.h"
void LogRenderInfo();
IRenderer *CreateRenderer()
{
return new GLES2Renderer();
}
void TexMaterial::Bind(IRenderer *r){
if(tex)
tex->Bind();
}
GLES2Renderer::GLES2Renderer()
{
font = 0;
lighting = 0;
}
void GLES2Renderer::Init(int initFlags,ResourceManager *resMan)
{
flags = initFlags;
Log("Init renderer\n");
LogRenderInfo();
progTex.CreateFromFile("generic", "col_tex");
progTex.u_mvpMtx = progTex.GetUniformLoc("u_mvpMtx");
progTex.u_modelMtx = -1;
progTex.u_color = progTex.GetUniformLoc("u_color");
progTex.Use();
glUniform4f(progTex.u_color,1,1,1,1);
progDepth.CreateFromFile("generic","null");
progDepth.u_mvpMtx = progDepth.GetUniformLoc("u_mvpMtx");
progSkybox.CreateFromFile("skybox","skybox");
progSkybox.u_mvpMtx = progSkybox.GetUniformLoc("u_mvpMtx");
meshCube = LoadMeshFile("cube", true);
GLubyte whiteData[] = {255};
texWhite.Create(1,1);
texWhite.Upload(0, GL_LUMINANCE, whiteData);
if(flags&RENDERER_GUI){
float quadVerts[] ={
1,-1,1,0,
1, 1,1,1,
-1, 1,0,1,
-1,-1,0,0};
vboQuad.Create();
vboQuad.Upload(4*4*4, quadVerts);
if(resMan){
font = new Font();
font->LoadBMFont("sansation",resMan);
}
}
if(flags&RENDERER_LIGHT){
lighting = GetLighting();
lighting->Init(this);
}
if(flags&RENDERER_BACKBUFFER){
backBufferScale = 1;
backFBO.Create();
backFBO.CreateTexture(64,64, GL_LINEAR);
//backFBO.AddDepthBuffer();
backFBO.CreateDepthTexture(64,64);
}
glClearColor(0,0,0,1);
//glClearColor(0.4f,0.4f,0.4f,1);
glUseProgram(0);
modelMtx = glm::mat4(1.0f);
vpMtx = glm::mat4(1.0f);
mvpMtx = glm::mat4(1.0f);
progCur = 0;
debug = false;
drawState = eDSDefault;
CheckGLError("GLES2Renderer::Init", __FILE__, __LINE__);
}
void GLES2Renderer::SetBackBufferScale(float s)
{
if(!(flags&RENDERER_BACKBUFFER)){
return;
}
if(s==backBufferScale)
return;
backBufferScale=s;
backFBO.Resize(width*s,height*s);
}
FrameBufferObject *GLES2Renderer::GetFBO()
{
if(!(flags&RENDERER_BACKBUFFER)){
return NULL;
}
return &backFBO;
}
void GLES2Renderer::Resize(int w, int h)
{
width = w;
height = h;
aspect = w/(float)h;
if(flags&RENDERER_BACKBUFFER){
backFBO.Resize(width*backBufferScale,height*backBufferScale);
}
glViewport(0,0,w,h);
}
void GLES2Renderer::Draw()
{
glBindFramebuffer(GL_FRAMEBUFFER,0);
Clear();
progCur = 0;
UseProg(&progTex);
texWhite.Bind();
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
if(scene){
if(flags&RENDERER_BACKBUFFER){
glBindTexture(GL_TEXTURE_2D,0);
backFBO.Bind();
Clear();
}
if(scene->skyBox){
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
DrawSkyBox(scene->skyBox);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
UseProg(&progTex);
texWhite.Bind();
}
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
UpdateMtx();
if(debug)
debugBBox.clear();
scene->Draw(this);
if(debug){
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
DrawDebugScene();
glEnableVertexAttribArray(2);
}
if(flags&RENDERER_BACKBUFFER){
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, width, height);
mvpMtx = glm::mat4(1.0f);
UseProg(&progTex);
SetColor(1,1,1,1);
backFBO.BindTexture();
glDisable(GL_DEPTH_TEST);
vboQuad.Bind();
glDisableVertexAttribArray(1);
glVertexAttribPointer(0,2,GL_FLOAT,GL_FALSE,16,0);
glVertexAttribPointer(2,2,GL_FLOAT,GL_FALSE,16,(void*)8);
glDrawArrays(GL_TRIANGLE_FAN,0,4);
vboQuad.Unbind();
}
}
glDisableVertexAttribArray(1);
//2d
UseProg(&progTex);
texWhite.Bind();
Set2DMode();
SetColor(1,1,1,1);
glDisable(GL_CULL_FACE);
for(uint32_t i=0;i<buttons.size();i++){
Button *b=buttons[i];
if(b->active&&b->text){
DrawText(b->text,b->x*aspect+0.01,b->y+b->h-0.01,0.5);
}
}
glEnable(GL_BLEND);
glBlendFunc(1,1);
glUniform4f(progTex.u_color,0.3,0.3,0.3,0.3);
for(uint32_t i=0;i<buttons.size();i++){
Button *b=buttons[i];
if(b->active&&b->text){
DrawRect(b->x,b->y,b->w,b->h);
}
}
glUniform4f(progTex.u_color,1,1,1,1);
glDisable(GL_BLEND);
//glUniformMatrix4fv(progTex.u_mvpMtx,1,false,glm::value_ptr(mtx));
CheckGLError("GLES2Renderer::Draw", __FILE__, __LINE__);
}
void GLES2Renderer::RenderDepth(Camera *cam)
{
if(!scene){
return;
}
drawState = eDSDepth;
glEnableVertexAttribArray(0);
UseProg(&progDepth);
glBindTexture(GL_TEXTURE_2D,0);
glEnable(GL_DEPTH_TEST);
vpMtx = cam->projMtx*cam->viewMtx;
mvpMtx = vpMtx*modelMtx;
glUniformMatrix4fv(progCur->u_mvpMtx,1,false,glm::value_ptr(mvpMtx));
scene->Draw(this);
UseProg(&progTex);
texWhite.Bind();
drawState = eDSDefault;
CheckGLError("GLES2Renderer::RenderDepth", __FILE__, __LINE__);
}
void GLES2Renderer::DrawDebugScene()
{
glDisable(GL_DEPTH_TEST);
UseProg(&progTex);
texWhite.Bind();
SetColor(1,0.5,0.2,1);
for(uint32_t i=0; i<debugBBox.size(); i++){
debugBBox_t db = debugBBox[i];
SetModelMtx(db.mtx);
DrawBBox(db.bbox);
}
SetColor(0.5,0.5,1.0,1);
for(uint32_t i=0;i<scene->lights.size(); i++){
LightObject &l=*(scene->lights[i]);
mat4 mtx(1);
SetModelMtx(mtx);
BoundingBox bbox(l.pos-l.radius,l.pos+l.radius);
DrawBBox(&bbox);
bbox = BoundingBox(l.pos-vec3(0.1),l.pos+vec3(0.1));
DrawBBox(&bbox);
}
glEnable(GL_DEPTH_TEST);
CheckGLError("GLES2Renderer::DrawDebugScene", __FILE__, __LINE__);
}
void GLES2Renderer::DrawBBox(BoundingBox *bbox)
{
float r = bbox->max.x;
float l = bbox->min.x;
float u = bbox->max.y;
float d = bbox->min.y;
float f = bbox->max.z;
float b = bbox->min.z;
GLfloat vertices[] =
{
r, d, f,
r, d, b,
l, d, b,
l, d, f,
r, u, f,
r, u, b,
l, u, b,
l, u, f
};
uint8_t inds[] =
{
0,1, 1,2, 2,3, 3,0,
4,5, 5,6, 6,7, 7,4,
0,4, 1,5, 2,6, 3,7
};
//glDisableVertexAttribArray(1);
//glDisableVertexAttribArray(2);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 12, vertices);
glDrawElements(GL_LINES, 24, GL_UNSIGNED_BYTE, inds);
CheckGLError("GLES2Renderer::DrawBBox", __FILE__, __LINE__);
}
void GLES2Renderer::DrawCube()
{
meshCube->Bind();
meshCube->Draw();
meshCube->Unbind();
CheckGLError("GLES2Renderer::DrawCube", __FILE__, __LINE__);
}
void GLES2Renderer::Clear()
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
}
void GLES2Renderer::DrawModel(Model *mdl,const glm::mat4 &mtx)
{
//TODO: render list from vbsp
if(drawState!=eDSDepth && debug)
debugBBox.push_back(debugBBox_t(&mdl->bbox,mtx));
SetModelMtx(mtx);
//TODO: vertexFormat
mdl->vbo.Bind();
/*glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,mdl->vertexStride,0);
if(drawState!=eDSDepth){
glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,mdl->vertexStride,(void*)12);
glVertexAttribPointer(2,2,GL_FLOAT,GL_FALSE,mdl->vertexStride,(void*)24);
}*/
vertAttrib_t &va = mdl->vertexFormat[0];
glVertexAttribPointer(va.id,va.size,va.type,va.norm,va.stride,(void*)va.offset);
if(drawState!=eDSDepth){
for(int i=1; i<mdl->vertexFormat.size; i++){
vertAttrib_t &va = mdl->vertexFormat[i];
glVertexAttribPointer(va.id,va.size,va.type,va.norm,va.stride,(void*)va.offset);
}
}
mdl->vbo.Unbind();
for(int i=0;i<mdl->submeshes.size;i++){
IMaterial *mat = mdl->materials[mdl->submeshes[i].mat].mat;
if(drawState!=eDSDepth && mat){
mat->Bind(this);
if(mat->lit&&lighting){
lighting->SetDirectional();
}else{
UseProg(&progTex);
}
}
//else
// defaultMat->Bind(this);
if(mdl->indexCount){
mdl->ibo.Bind();
glDrawElements(GL_TRIANGLES,mdl->submeshes[i].count,mdl->indexType,(void *)(mdl->submeshes[i].offs*mdl->indexSize));
mdl->ibo.Unbind();
}else{
glDrawArrays(GL_TRIANGLES, mdl->submeshes[i].offs, mdl->submeshes[i].count);
}
//add lights
if(drawState!=eDSDepth && mat && mat->lit&& lighting&& !scene->lights.empty()){
lighting->AddLights(mtx,mdl->submeshes[i]);
}
}
}
void GLES2Renderer::UseProg(glslProg *p){
progCur = p;
if(!p)
return;
p->Use();
glUniformMatrix4fv(progCur->u_mvpMtx,1,false,glm::value_ptr(mvpMtx));
if(progCur->u_modelMtx!=-1)
glUniformMatrix4fv(progCur->u_modelMtx,1,false,glm::value_ptr(modelMtx));
if(progCur->u_cameraPos!=-1){
glUniform3fv(progCur->u_cameraPos, 1, glm::value_ptr(camera->pos));
}
}
void GLES2Renderer::SetScene(Scene *sc){
scene=sc;
if(lighting)
lighting->SetScene(sc);
}
void GLES2Renderer::SetCamera(Camera *cam)
{
camera = cam;
if(lighting)
lighting->SetCamera(cam);
vpMtx = cam->projMtx*cam->viewMtx;
}
void GLES2Renderer::SetModelMtx(const glm::mat4 &mtx)
{
modelMtx = mtx;
mvpMtx = vpMtx*mtx;
glUniformMatrix4fv(progCur->u_mvpMtx,1,false,glm::value_ptr(mvpMtx));
if(progCur->u_modelMtx!=-1)
glUniformMatrix4fv(progCur->u_modelMtx,1,false,glm::value_ptr(mtx));
}
void GLES2Renderer::UpdateMtx()
{
if(camera)
vpMtx = camera->projMtx*camera->viewMtx;
mvpMtx = vpMtx*modelMtx;
glUniformMatrix4fv(progCur->u_mvpMtx,1,false,glm::value_ptr(mvpMtx));
if(progCur->u_modelMtx!=-1)
glUniformMatrix4fv(progCur->u_modelMtx,1,false,glm::value_ptr(modelMtx));
}
void GLES2Renderer::ResetViewport(){
glViewport(0,0,width,height);
}
void GLES2Renderer::Set2DMode(bool m){
if(m){
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
UseProg(&progTex);
glm::mat4 mtx(1.0f);
mtx = glm::translate(mtx,glm::vec3(-1.0,-1.0,0.0));
vpMtx = glm::scale(mtx,glm::vec3(2.0/aspect,2.0f,1.0f));
mvpMtx = vpMtx;
glUniformMatrix4fv(progCur->u_mvpMtx,1,false,glm::value_ptr(mvpMtx));
}else{
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
UpdateMtx();
}
}
void GLES2Renderer::SetColor(float r, float g, float b, float a){
glUniform4f(progCur->u_color,r,g,b,a);
}
void GLES2Renderer::AddButton(Button *b)
{
buttons.push_back(b);
}
void GLES2Renderer::DrawText(const char *t,float x,float y,float s){
if(!font)
return;
UseProg(&progTex);
font->Print(t,x,1-y,s);
texWhite.Bind();
}
void GLES2Renderer::DrawRect(float x, float y, float w, float h){
if(!(flags&RENDERER_GUI)){
EngineError("Renderer::DrawRect without RENDERER_GUI");
return;
}
glm::mat4 mtx(1.0f);
mtx = glm::translate(mtx,glm::vec3(x*2.0-(1-w),-(y*2.0-(1-h)),0));
mtx = glm::scale(mtx,glm::vec3(w,h,1));
glUniformMatrix4fv(progCur->u_mvpMtx,1,false,glm::value_ptr(mtx));
vboQuad.Bind();
glVertexAttribPointer(0,2,GL_FLOAT,GL_FALSE,16,0);
glVertexAttribPointer(2,2,GL_FLOAT,GL_FALSE,16,(void*)8);
glDrawArrays(GL_TRIANGLE_FAN,0,4);
vboQuad.Unbind();
}
void GLES2Renderer::DrawSkyBox(Texture *s){
meshCube->Bind();
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glm::mat4 skyboxViewMtx = camera->viewMtx;
skyboxViewMtx[3] = glm::vec4(0,0,0,1);
glm::mat4 mvpMtx = camera->projMtx * skyboxViewMtx;
UseProg(&progSkybox);
glUniformMatrix4fv(progSkybox.u_mvpMtx,1,GL_FALSE,glm::value_ptr(mvpMtx));
s->Bind();
meshCube->Draw();
meshCube->Unbind();
}
void LogRenderInfo(){
Log("%s %s\n",glGetString(GL_VENDOR),glGetString(GL_RENDERER));
Log("%s\n",glGetString(GL_VERSION));
Log("%s\n",glGetString(GL_SHADING_LANGUAGE_VERSION));
//Log("%s\n",glGetString(GL_EXTENSIONS));
//GLExtensions::Init();
const char *t = (const char*)glGetString(GL_EXTENSIONS);
const char *end = 0;
char ext[256]={0};
int n=0;
while(*t){
end = strstr(t," ");
if(end){
strncpy(ext,t,end-t);
ext[end-t]=0;
}
else
break;
//Log("ext %d: %s\n",n,ext);
t=end+1;
n++;
}
Log("Exts count: %d\n",n);
int rb, gb, bb;
glGetIntegerv(GL_RED_BITS, &rb);
glGetIntegerv(GL_GREEN_BITS, &gb);
glGetIntegerv(GL_BLUE_BITS, &bb);
int bits=-1;
glGetIntegerv(GL_ALPHA_BITS, &bits);
Log( "Color bits: %d %d %d %d\n", rb,gb,bb,bits);
glGetIntegerv(GL_DEPTH_BITS, &bits);
Log( "DEPTH BITS %d\n", bits);
glGetIntegerv(GL_STENCIL_BITS, &bits);
Log( "STENCIL BITS %d\n", bits);
int rfmt=0;
int rtp=0;
glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT,&rfmt);
glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE,&rtp);
Log("Color read format %X, type %X\n",rfmt,rtp);
}