2013-08-29 11:45:22 +09:00
|
|
|
/*
|
|
|
|
Copyright (c) 2013 yvt
|
|
|
|
|
|
|
|
This file is part of OpenSpades.
|
|
|
|
|
|
|
|
OpenSpades is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
OpenSpades is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
*/
|
2013-08-18 16:18:06 +09:00
|
|
|
|
|
|
|
#include "GLOptimizedVoxelModel.h"
|
|
|
|
#include "GLRenderer.h"
|
|
|
|
#include "GLImage.h"
|
|
|
|
#include "GLProgram.h"
|
|
|
|
#include "GLProgramAttribute.h"
|
|
|
|
#include "GLProgramUniform.h"
|
|
|
|
#include "../Core/Debug.h"
|
|
|
|
#include "GLShadowShader.h"
|
|
|
|
#include "GLDynamicLightShader.h"
|
|
|
|
#include "IGLShadowMapRenderer.h"
|
|
|
|
#include "GLShadowMapShader.h"
|
2014-03-24 23:36:29 +09:00
|
|
|
#include "CellToTriangle.h"
|
2013-08-18 16:18:06 +09:00
|
|
|
#include "../Core/Exception.h"
|
|
|
|
#include <set>
|
|
|
|
#include "../Core/Bitmap.h"
|
|
|
|
#include "../Core/BitmapAtlasGenerator.h"
|
|
|
|
|
|
|
|
namespace spades {
|
|
|
|
namespace draw {
|
2013-09-06 11:44:36 +09:00
|
|
|
void GLOptimizedVoxelModel::PreloadShaders(spades::draw::GLRenderer *renderer) {
|
|
|
|
renderer->RegisterProgram("Shaders/OptimizedVoxelModel.program");
|
|
|
|
renderer->RegisterProgram("Shaders/OptimizedVoxelModelDynamicLit.program");
|
|
|
|
renderer->RegisterProgram("Shaders/OptimizedVoxelModelShadowMap.program");
|
2016-07-16 00:14:59 +09:00
|
|
|
renderer->RegisterImage("Gfx/AmbientOcclusion.png");
|
2013-09-06 11:44:36 +09:00
|
|
|
}
|
2013-08-18 16:18:06 +09:00
|
|
|
GLOptimizedVoxelModel::GLOptimizedVoxelModel(VoxelModel *m,
|
|
|
|
GLRenderer *r){
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
|
|
|
renderer = r;
|
|
|
|
device = r->GetGLDevice();
|
|
|
|
|
|
|
|
BuildVertices(m);
|
|
|
|
GenerateTexture();
|
|
|
|
|
|
|
|
program = renderer->RegisterProgram("Shaders/OptimizedVoxelModel.program");
|
|
|
|
dlightProgram = renderer->RegisterProgram("Shaders/OptimizedVoxelModelDynamicLit.program");
|
|
|
|
shadowMapProgram = renderer->RegisterProgram("Shaders/OptimizedVoxelModelShadowMap.program");
|
2016-07-16 00:14:59 +09:00
|
|
|
aoImage = (GLImage *)renderer->RegisterImage("Gfx/AmbientOcclusion.png");
|
2013-08-18 16:18:06 +09:00
|
|
|
|
|
|
|
|
|
|
|
buffer = device->GenBuffer();
|
|
|
|
device->BindBuffer(IGLDevice::ArrayBuffer, buffer);
|
|
|
|
device->BufferData(IGLDevice::ArrayBuffer,
|
2016-07-15 19:35:09 +09:00
|
|
|
static_cast<IGLDevice::Sizei> (vertices.size() * sizeof(Vertex)),
|
2013-08-18 16:18:06 +09:00
|
|
|
vertices.data(), IGLDevice::StaticDraw);
|
|
|
|
|
|
|
|
idxBuffer = device->GenBuffer();
|
|
|
|
device->BindBuffer(IGLDevice::ArrayBuffer, idxBuffer);
|
|
|
|
device->BufferData(IGLDevice::ArrayBuffer,
|
2016-07-15 19:35:09 +09:00
|
|
|
static_cast<IGLDevice::Sizei> (indices.size() * sizeof(uint32_t)),
|
2013-08-18 16:18:06 +09:00
|
|
|
indices.data(), IGLDevice::StaticDraw);
|
|
|
|
device->BindBuffer(IGLDevice::ArrayBuffer, 0);
|
|
|
|
|
|
|
|
origin = m->GetOrigin();
|
|
|
|
origin -= .5f; // (0,0,0) is center of voxel (0,0,0)
|
|
|
|
|
|
|
|
Vector3 minPos = {0, 0, 0};
|
|
|
|
Vector3 maxPos = {
|
|
|
|
(float)m->GetWidth(), (float)m->GetHeight(), (float)m->GetDepth()
|
|
|
|
};
|
|
|
|
minPos += origin; maxPos += origin;
|
|
|
|
Vector3 maxDiff = {
|
|
|
|
std::max(fabsf(minPos.x), fabsf(maxPos.x)),
|
|
|
|
std::max(fabsf(minPos.y), fabsf(maxPos.y)),
|
|
|
|
std::max(fabsf(minPos.z), fabsf(maxPos.z))
|
|
|
|
};
|
|
|
|
radius = maxDiff.GetLength();
|
|
|
|
|
2013-09-11 13:50:18 +09:00
|
|
|
boundingBox.min = minPos;
|
|
|
|
boundingBox.max = maxPos;
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
// clean up
|
|
|
|
numIndices = (unsigned int)indices.size();
|
|
|
|
std::vector<Vertex>().swap(vertices);
|
|
|
|
std::vector<uint32_t>().swap(indices);
|
|
|
|
}
|
|
|
|
GLOptimizedVoxelModel::~GLOptimizedVoxelModel() {
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
2013-09-14 13:28:19 +09:00
|
|
|
image->Release();
|
2013-08-18 16:18:06 +09:00
|
|
|
device->DeleteBuffer(idxBuffer);
|
|
|
|
device->DeleteBuffer(buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GLOptimizedVoxelModel::GenerateTexture() {
|
|
|
|
BitmapAtlasGenerator atlasGen;
|
|
|
|
std::map<Bitmap *, int> idx;
|
|
|
|
std::vector<IntVector3> poss;
|
|
|
|
for(size_t i = 0; i < bmps.size(); i++){
|
2016-07-15 19:35:09 +09:00
|
|
|
idx[bmps[i]] = static_cast<int> (i);
|
2013-08-18 16:18:06 +09:00
|
|
|
atlasGen.AddBitmap(bmps[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
BitmapAtlasGenerator::Result result = atlasGen.Pack();
|
2013-11-17 00:26:05 +09:00
|
|
|
Handle<Bitmap> bmp(result.bitmap, false);
|
2013-08-18 16:18:06 +09:00
|
|
|
SPAssert(result.items.size() == bmps.size());
|
|
|
|
for(size_t i = 0; i < bmps.size(); i++){
|
2013-09-14 13:28:19 +09:00
|
|
|
bmps[i]->Release();
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
bmps.clear();
|
|
|
|
|
|
|
|
poss.resize(result.items.size());
|
|
|
|
for(size_t i = 0; i < result.items.size(); i++){
|
|
|
|
const BitmapAtlasGenerator::Item& item = result.items[i];
|
|
|
|
int id = idx[item.bitmap];
|
|
|
|
poss[id] = IntVector3::Make(item.x, item.y, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// move vertices' texture coord
|
|
|
|
SPAssert(bmpIndex.size() == vertices.size());
|
|
|
|
for(size_t i = 0; i < bmpIndex.size(); i++){
|
|
|
|
int id = (int)bmpIndex[i];
|
|
|
|
Vertex& v = vertices[i];
|
|
|
|
IntVector3 p = poss[id];
|
|
|
|
v.u += p.x;
|
|
|
|
v.v += p.y;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<uint16_t>().swap(bmpIndex);
|
|
|
|
|
|
|
|
image = static_cast<GLImage *>(renderer->CreateImage(bmp));
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t GLOptimizedVoxelModel::calcAOID(VoxelModel *m,
|
|
|
|
int x, int y, int z,
|
|
|
|
int ux, int uy, int uz,
|
|
|
|
int vx, int vy, int vz){
|
|
|
|
int v = 0;
|
|
|
|
if(m->IsSolid(x - ux, y - uy, z - uz))
|
|
|
|
v |= 1;
|
|
|
|
if(m->IsSolid(x + ux, y + uy, z + uz))
|
|
|
|
v |= 1 << 1;
|
|
|
|
if(m->IsSolid(x - vx, y - vy, z - vz))
|
|
|
|
v |= 1 << 2;
|
|
|
|
if(m->IsSolid(x + vx, y + vy, z + vz))
|
|
|
|
v |= 1 << 3;
|
|
|
|
if(m->IsSolid(x - ux + vx, y - uy + vy, z - uz + vz))
|
|
|
|
v |= 1 << 4;
|
|
|
|
if(m->IsSolid(x - ux - vx, y - uy - vy, z - uz - vz))
|
|
|
|
v |= 1 << 5;
|
|
|
|
if(m->IsSolid(x + ux + vx, y + uy + vy, z + uz + vz))
|
|
|
|
v |= 1 << 6;
|
|
|
|
if(m->IsSolid(x + ux - vx, y + uy - vy, z + uz - vz))
|
|
|
|
v |= 1 << 7;
|
|
|
|
return (uint8_t)v;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class C> static void FreeClear( C & cntr ) {
|
|
|
|
for ( typename C::iterator it = cntr.begin();
|
|
|
|
it != cntr.end(); ++it ) {
|
|
|
|
delete * it;
|
|
|
|
}
|
|
|
|
cntr.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
class GLOptimizedVoxelModel::SliceGenerator {
|
|
|
|
|
|
|
|
public:
|
|
|
|
//0 - air
|
|
|
|
//1 - unprocessed solid
|
|
|
|
//2 - "inside" the processed area, but not connected
|
|
|
|
//3 - found holes
|
|
|
|
uint8_t *slice;
|
|
|
|
int usize, vsize;
|
|
|
|
int minU, maxU, minV, maxV;
|
|
|
|
|
2014-03-24 23:36:29 +09:00
|
|
|
class Model {
|
|
|
|
const uint8_t *slice;
|
|
|
|
int usize, vsize;
|
|
|
|
public:
|
|
|
|
Model(const uint8_t *slice, int usize, int vsize):
|
|
|
|
slice(slice), usize(usize), vsize(vsize) {}
|
|
|
|
inline int GetWidth() { return usize; }
|
|
|
|
inline int GetHeight() { return vsize; }
|
|
|
|
inline bool operator()(int x, int y) const {
|
|
|
|
if(x < 0 || y < 0 || x >= usize || y >= vsize) return false;
|
|
|
|
return slice[x * vsize + y] != 0;
|
|
|
|
}
|
2013-08-18 16:18:06 +09:00
|
|
|
};
|
|
|
|
|
2014-03-24 23:36:29 +09:00
|
|
|
std::unique_ptr<c2t::Trianglulator<Model>> triangulator;
|
2013-08-18 16:18:06 +09:00
|
|
|
|
|
|
|
uint8_t& Slice(int u, int v){
|
|
|
|
SPAssert(u >= 0); SPAssert(v >= 0);
|
|
|
|
SPAssert(u < usize); SPAssert(v < vsize);
|
|
|
|
return slice[u * vsize + v];
|
|
|
|
}
|
|
|
|
uint8_t GetSlice(int u, int v){
|
|
|
|
if(u < 0 || v < 0 || u >= usize || v >= vsize)
|
|
|
|
return 0;
|
|
|
|
return Slice(u, v);
|
|
|
|
}
|
|
|
|
|
2014-03-24 23:36:29 +09:00
|
|
|
std::vector<c2t::Point> ProcessArea() {
|
|
|
|
if(triangulator == nullptr) {
|
|
|
|
triangulator = decltype(triangulator){new c2t::Trianglulator<Model>(Model(slice, usize, vsize))};
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
|
2014-03-24 23:36:29 +09:00
|
|
|
return std::move(triangulator->Triangulate());
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-03-24 23:36:29 +09:00
|
|
|
static IntVector3 ExactPoint(c2t::Point pt){
|
|
|
|
return IntVector3::Make(pt.x, pt.y, 0);
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
static int64_t DoubledTriangleArea(IntVector3 v1, IntVector3 v2, IntVector3 v3) {
|
|
|
|
int64_t x1 = v1.x, y1 = v1.y;
|
|
|
|
int64_t x2 = v2.x, y2 = v2.y;
|
|
|
|
int64_t x3 = v3.x, y3 = v3.y;
|
|
|
|
return (x1 - x3) * (y2 - y1) -
|
|
|
|
(x1 - x2) * (y3 - y1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GLOptimizedVoxelModel::EmitSlice(uint8_t *slice,
|
|
|
|
int usize, int vsize,
|
|
|
|
int sx, int sy, int sz,
|
|
|
|
int ux, int uy, int uz,
|
|
|
|
int vx, int vy, int vz,
|
|
|
|
int mx, int my, int mz,
|
|
|
|
bool flip,
|
|
|
|
VoxelModel *model) {
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
int minU = -1, minV = -1, maxU = -1, maxV = -1;
|
|
|
|
|
|
|
|
for(int u = 0; u < usize; u++){
|
|
|
|
for(int v = 0; v < vsize; v++){
|
|
|
|
if(slice[u * vsize + v]){
|
|
|
|
if(minU == -1 || u < minU) minU = u;
|
|
|
|
if(maxU == -1 || u > maxU) maxU = u;
|
|
|
|
if(minV == -1 || v < minV) minV = v;
|
|
|
|
if(maxV == -1 || v > maxV) maxV = v;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(minU == -1){
|
|
|
|
// no face
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int nx, ny, nz;
|
|
|
|
nx = uy * vz - uz * vy;
|
|
|
|
ny = uz * vx - ux * vz;
|
|
|
|
nz = ux * vy - uy * vx;
|
|
|
|
if(!flip){
|
|
|
|
nx = -nx;
|
|
|
|
ny = -ny;
|
|
|
|
nz = -nz;
|
|
|
|
}
|
|
|
|
|
|
|
|
SliceGenerator generator;
|
|
|
|
generator.slice = slice;
|
|
|
|
generator.usize = usize;
|
|
|
|
generator.vsize = vsize;
|
|
|
|
generator.minU = minU;
|
|
|
|
generator.maxU = maxU;
|
|
|
|
generator.minV = minV;
|
|
|
|
generator.maxV = maxV;
|
|
|
|
|
|
|
|
int tu = minU - 1, tv = minV - 1;
|
|
|
|
int bw = (maxU - minU) + 3, bh = (maxV - minV) + 3;
|
2016-07-15 19:35:09 +09:00
|
|
|
int bId = static_cast<int> (bmps.size());
|
2013-08-18 16:18:06 +09:00
|
|
|
Bitmap *bmp = new Bitmap(bw, bh);
|
|
|
|
bmps.push_back(bmp);
|
|
|
|
{
|
|
|
|
uint32_t *pixels = bmp->GetPixels();
|
|
|
|
IntVector3 p1 = {mx, my, mz};
|
|
|
|
|
|
|
|
IntVector3 uu = {ux, uy, uz};
|
|
|
|
IntVector3 vv = {vx, vy, vz};
|
|
|
|
IntVector3 nn = {nx, ny, nz};
|
|
|
|
|
|
|
|
p1 += uu * tu; p1 += vv * tv;
|
|
|
|
|
|
|
|
for(int y = 0; y < bh; y++){
|
|
|
|
IntVector3 p2 = p1;
|
|
|
|
for(int x = 0; x < bw; x++){
|
|
|
|
IntVector3 p3 = p2;
|
|
|
|
int u = x + tu, v = y + tv;
|
|
|
|
if(u < 0 || v < 0 || u >= usize || v >= vsize ||
|
|
|
|
!slice[u*vsize+v]){
|
|
|
|
if((v >= 0 && v < vsize) && u > 0 && slice[(u-1)*vsize+(v)]){
|
|
|
|
u--;
|
|
|
|
p3 -= uu;
|
|
|
|
}else if((v >= 0 && v < vsize) && u < usize-1 && slice[(u+1)*vsize+(v)]){
|
|
|
|
u++;
|
|
|
|
p3 += uu;
|
|
|
|
}else if((u >= 0 && u < usize) && v > 0 && slice[(u)*vsize+(v-1)]){
|
|
|
|
v--;
|
|
|
|
p3 -= vv;
|
|
|
|
}else if((u >= 0 && u < usize) && v < vsize-1 && slice[(u)*vsize+(v+1)]){
|
|
|
|
v++;
|
|
|
|
p3 += vv;
|
|
|
|
}else if(u > 0 && v > 0 && slice[(u-1)*vsize+(v-1)]){
|
|
|
|
u--; v--;
|
|
|
|
p3 -= uu; p3 -= vv;
|
|
|
|
}else if(u > 0 && v < vsize-1 && slice[(u-1)*vsize+(v+1)]){
|
|
|
|
u--; v++;
|
|
|
|
p3 -= uu; p3 += vv;
|
|
|
|
}else if(u < usize-1 && v > 0 && slice[(u+1)*vsize+(v-1)]){
|
|
|
|
u++; v--;
|
|
|
|
p3 += uu; p3 -= vv;
|
|
|
|
}else if(u < usize-1 && v < vsize-1 && slice[(u+1)*vsize+(v+1)]){
|
|
|
|
u++; v++;
|
|
|
|
p3 += uu; p3 += vv;
|
|
|
|
}else{
|
|
|
|
*(pixels++) = 0x00ff00ff;
|
|
|
|
p2 += uu;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SPAssert(model->IsSolid(p3.x, p3.y, p3.z));
|
|
|
|
uint32_t col = model->GetColor(p3.x, p3.y, p3.z);
|
|
|
|
|
|
|
|
col &= 0xffffff;
|
|
|
|
|
|
|
|
// add AOID
|
|
|
|
p3 += nn;
|
|
|
|
SPAssert(!model->IsSolid(p3.x, p3.y, p3.z));
|
|
|
|
uint8_t aoId = calcAOID(model,
|
|
|
|
p3.x, p3.y, p3.z,
|
|
|
|
ux, uy, uz,
|
|
|
|
vx, vy, vz);
|
|
|
|
col |= ((uint8_t)aoId) << 24;
|
|
|
|
|
|
|
|
*(pixels++) = col;
|
|
|
|
|
|
|
|
p2 += uu;
|
|
|
|
}
|
|
|
|
|
|
|
|
p1 += vv;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: optimize scan range
|
2014-03-24 23:36:29 +09:00
|
|
|
auto polys = std::move(generator.ProcessArea());
|
|
|
|
for(std::size_t i = 0; i < polys.size(); i += 3) {
|
|
|
|
uint32_t idx = (uint32_t)vertices.size();
|
|
|
|
IntVector3 pt1 = ExactPoint(polys[i + 0]);
|
|
|
|
IntVector3 pt2 = ExactPoint(polys[i + 1]);
|
|
|
|
IntVector3 pt3 = ExactPoint(polys[i + 2]);
|
|
|
|
|
|
|
|
// degenerate triangle
|
|
|
|
if(DoubledTriangleArea(pt1, pt2, pt3) == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
Vertex vtx;
|
|
|
|
vtx.nx = nx; vtx.ny = ny; vtx.nz = nz;
|
|
|
|
|
|
|
|
vtx.x = sx + (int)pt1.x * ux + (int)pt1.y * vx;
|
|
|
|
vtx.y = sy + (int)pt1.x * uy + (int)pt1.y * vy;
|
|
|
|
vtx.z = sz + (int)pt1.x * uz + (int)pt1.y * vz;
|
|
|
|
vtx.u = (int)pt1.x - tu;
|
|
|
|
vtx.v = (int)pt1.y - tv;
|
|
|
|
vertices.push_back(vtx);
|
|
|
|
|
|
|
|
vtx.x = sx + (int)pt2.x * ux + (int)pt2.y * vx;
|
|
|
|
vtx.y = sy + (int)pt2.x * uy + (int)pt2.y * vy;
|
|
|
|
vtx.z = sz + (int)pt2.x * uz + (int)pt2.y * vz;
|
|
|
|
vtx.u = (int)pt2.x - tu;
|
|
|
|
vtx.v = (int)pt2.y - tv;
|
|
|
|
vertices.push_back(vtx);
|
|
|
|
|
|
|
|
vtx.x = sx + (int)pt3.x * ux + (int)pt3.y * vx;
|
|
|
|
vtx.y = sy + (int)pt3.x * uy + (int)pt3.y * vy;
|
|
|
|
vtx.z = sz + (int)pt3.x * uz + (int)pt3.y * vz;
|
|
|
|
vtx.u = (int)pt3.x - tu;
|
|
|
|
vtx.v = (int)pt3.y - tv;
|
|
|
|
vertices.push_back(vtx);
|
|
|
|
|
|
|
|
if(!flip){
|
|
|
|
indices.push_back(idx+2);
|
|
|
|
indices.push_back(idx+1);
|
|
|
|
indices.push_back(idx);
|
|
|
|
|
|
|
|
}else{
|
|
|
|
indices.push_back(idx);
|
|
|
|
indices.push_back(idx+1);
|
|
|
|
indices.push_back(idx+2);
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
2014-03-24 23:36:29 +09:00
|
|
|
bmpIndex.push_back(bId);
|
|
|
|
bmpIndex.push_back(bId);
|
|
|
|
bmpIndex.push_back(bId);
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void GLOptimizedVoxelModel::BuildVertices(spades::VoxelModel *model) {
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
|
|
|
SPAssert(vertices.empty());
|
|
|
|
SPAssert(indices.empty());
|
|
|
|
|
|
|
|
int w = model->GetWidth();
|
|
|
|
int h = model->GetHeight();
|
|
|
|
int d = model->GetDepth();
|
|
|
|
|
|
|
|
std::vector<uint8_t> slice;
|
|
|
|
|
|
|
|
// x-slice
|
|
|
|
slice.resize(h * d);
|
|
|
|
std::fill(slice.begin(), slice.end(), 0);
|
|
|
|
for(int x = 0; x < w; x++){
|
|
|
|
for(int y = 0; y < h; y++){
|
|
|
|
for(int z = 0; z < d; z++){
|
|
|
|
uint8_t& s = slice[y * d + z];
|
|
|
|
if(x == 0)
|
|
|
|
s = model->IsSolid(x, y, z) ? 1 : 0;
|
|
|
|
else
|
|
|
|
s = (model->IsSolid(x, y, z) &&
|
|
|
|
!model->IsSolid(x - 1, y, z))
|
|
|
|
? 1 : 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EmitSlice(slice.data(), h, d,
|
|
|
|
x, 0, 0,
|
|
|
|
0, 1, 0,
|
|
|
|
0, 0, 1,
|
|
|
|
x, 0, 0,
|
|
|
|
false,
|
|
|
|
model);
|
|
|
|
|
|
|
|
for(int y = 0; y < h; y++){
|
|
|
|
for(int z = 0; z < d; z++){
|
|
|
|
uint8_t& s = slice[y * d + z];
|
|
|
|
if(x == w - 1)
|
|
|
|
s = model->IsSolid(x, y, z) ? 1 : 0;
|
|
|
|
else
|
|
|
|
s = (model->IsSolid(x, y, z) &&
|
|
|
|
!model->IsSolid(x + 1, y, z))
|
|
|
|
? 1 : 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EmitSlice(slice.data(), h, d,
|
|
|
|
x + 1, 0, 0,
|
|
|
|
0, 1, 0,
|
|
|
|
0, 0, 1,
|
|
|
|
x, 0, 0,
|
|
|
|
true,
|
|
|
|
model);
|
|
|
|
}
|
|
|
|
|
|
|
|
// y-slice
|
|
|
|
slice.resize(w * d);
|
|
|
|
std::fill(slice.begin(), slice.end(), 0);
|
|
|
|
for(int y = 0; y < h; y++){
|
|
|
|
for(int x = 0; x < w; x++){
|
|
|
|
for(int z = 0; z < d; z++){
|
|
|
|
uint8_t& s = slice[x * d + z];
|
|
|
|
if(y == 0)
|
|
|
|
s = model->IsSolid(x, y, z) ? 1 : 0;
|
|
|
|
else
|
|
|
|
s = (model->IsSolid(x, y, z) &&
|
|
|
|
!model->IsSolid(x, y - 1, z))
|
|
|
|
? 1 : 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EmitSlice(slice.data(), w, d,
|
|
|
|
0, y, 0,
|
|
|
|
1, 0, 0,
|
|
|
|
0, 0, 1,
|
|
|
|
0, y, 0,
|
|
|
|
true,
|
|
|
|
model);
|
|
|
|
|
|
|
|
for(int x = 0; x < w; x++){
|
|
|
|
for(int z = 0; z < d; z++){
|
|
|
|
uint8_t& s = slice[x * d + z];
|
|
|
|
if(y == h - 1)
|
|
|
|
s = model->IsSolid(x, y, z) ? 1 : 0;
|
|
|
|
else
|
|
|
|
s = (model->IsSolid(x, y, z) &&
|
|
|
|
!model->IsSolid(x, y + 1, z))
|
|
|
|
? 1 : 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EmitSlice(slice.data(), w, d,
|
|
|
|
0, y + 1, 0,
|
|
|
|
1, 0, 0,
|
|
|
|
0, 0, 1,
|
|
|
|
0, y, 0,
|
|
|
|
false,
|
|
|
|
model);
|
|
|
|
}
|
|
|
|
|
|
|
|
// z-slice
|
|
|
|
slice.resize(w * h);
|
|
|
|
std::fill(slice.begin(), slice.end(), 0);
|
|
|
|
for(int z = 0; z < d; z++){
|
|
|
|
for(int x = 0; x < w; x++){
|
|
|
|
for(int y = 0; y < h; y++){
|
|
|
|
uint8_t& s = slice[x * h + y];
|
|
|
|
if(z == 0)
|
|
|
|
s = model->IsSolid(x, y, z) ? 1 : 0;
|
|
|
|
else
|
|
|
|
s = (model->IsSolid(x, y, z) &&
|
|
|
|
!model->IsSolid(x, y, z - 1))
|
|
|
|
? 1 : 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EmitSlice(slice.data(), w, h,
|
|
|
|
0, 0, z,
|
|
|
|
1, 0, 0,
|
|
|
|
0, 1, 0,
|
|
|
|
0, 0, z,
|
|
|
|
false,
|
|
|
|
model);
|
|
|
|
|
|
|
|
for(int x = 0; x < w; x++){
|
|
|
|
for(int y = 0; y < h; y++){
|
|
|
|
uint8_t& s = slice[x * h + y];
|
|
|
|
if(z == d - 1)
|
|
|
|
s = model->IsSolid(x, y, z) ? 1 : 0;
|
|
|
|
else
|
|
|
|
s = (model->IsSolid(x, y, z) &&
|
|
|
|
!model->IsSolid(x, y, z + 1))
|
|
|
|
? 1 : 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EmitSlice(slice.data(), w, h,
|
|
|
|
0, 0, z + 1,
|
|
|
|
1, 0, 0,
|
|
|
|
0, 1, 0,
|
|
|
|
0, 0, z,
|
|
|
|
true,
|
|
|
|
model);
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("%d vertices emit\n", (int)indices.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
void GLOptimizedVoxelModel::RenderShadowMapPass(std::vector<client::ModelRenderParam> params) {
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
|
|
|
device->Enable(IGLDevice::CullFace, true);
|
|
|
|
device->Enable(IGLDevice::DepthTest, true);
|
|
|
|
|
|
|
|
shadowMapProgram->Use();
|
|
|
|
|
|
|
|
static GLShadowMapShader shadowMapShader;
|
|
|
|
shadowMapShader(renderer, shadowMapProgram, 0);
|
|
|
|
|
|
|
|
static GLProgramUniform modelOrigin("modelOrigin");
|
|
|
|
modelOrigin(shadowMapProgram);
|
|
|
|
modelOrigin.SetValue(origin.x, origin.y, origin.z);
|
|
|
|
|
|
|
|
// setup attributes
|
|
|
|
static GLProgramAttribute positionAttribute("positionAttribute");
|
|
|
|
static GLProgramAttribute normalAttribute("normalAttribute");
|
|
|
|
|
|
|
|
positionAttribute(shadowMapProgram);
|
|
|
|
normalAttribute(shadowMapProgram);
|
|
|
|
|
|
|
|
device->BindBuffer(IGLDevice::ArrayBuffer, buffer);
|
|
|
|
device->VertexAttribPointer(positionAttribute(),
|
|
|
|
4, IGLDevice::UnsignedByte,
|
|
|
|
false, sizeof(Vertex),
|
|
|
|
(void *)0);
|
|
|
|
if(normalAttribute() != -1){
|
|
|
|
device->VertexAttribPointer(normalAttribute(),
|
|
|
|
3, IGLDevice::Byte,
|
|
|
|
false, sizeof(Vertex),
|
|
|
|
(void *)8);
|
|
|
|
}
|
|
|
|
device->BindBuffer(IGLDevice::ArrayBuffer, 0);
|
|
|
|
|
|
|
|
device->EnableVertexAttribArray(positionAttribute(), true);
|
|
|
|
if(normalAttribute() != -1)
|
|
|
|
device->EnableVertexAttribArray(normalAttribute(), true);
|
|
|
|
|
|
|
|
device->BindBuffer(IGLDevice::ElementArrayBuffer, idxBuffer);
|
|
|
|
|
|
|
|
for(size_t i = 0; i < params.size(); i++){
|
|
|
|
const client::ModelRenderParam& param = params[i];
|
|
|
|
|
|
|
|
// frustrum cull
|
|
|
|
float rad = radius;
|
|
|
|
rad *= param.matrix.GetAxis(0).GetLength();
|
|
|
|
|
|
|
|
if(param.depthHack)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if(!renderer->GetShadowMapRenderer()->SphereCull(param.matrix.GetOrigin(),
|
|
|
|
rad)){
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
Matrix4 modelMatrix = param.matrix;
|
|
|
|
|
|
|
|
static GLProgramUniform modelMatrixU("modelMatrix");
|
|
|
|
modelMatrixU(shadowMapProgram);
|
|
|
|
modelMatrixU.SetValue(modelMatrix);
|
|
|
|
|
|
|
|
modelMatrix.m[12] = 0.f;
|
|
|
|
modelMatrix.m[13] = 0.f;
|
|
|
|
modelMatrix.m[14] = 0.f;
|
|
|
|
static GLProgramUniform modelNormalMatrix("modelNormalMatrix");
|
|
|
|
modelNormalMatrix(shadowMapProgram);
|
|
|
|
modelNormalMatrix.SetValue(modelMatrix);
|
|
|
|
|
|
|
|
device->DrawElements(IGLDevice::Triangles,
|
|
|
|
numIndices,
|
|
|
|
IGLDevice::UnsignedInt,
|
|
|
|
(void *)0);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
device->BindBuffer(IGLDevice::ElementArrayBuffer, 0);
|
|
|
|
|
|
|
|
|
|
|
|
device->EnableVertexAttribArray(positionAttribute(), false);
|
|
|
|
if(normalAttribute() != -1)
|
|
|
|
device->EnableVertexAttribArray(normalAttribute(), false);
|
|
|
|
|
|
|
|
device->ActiveTexture(0);
|
|
|
|
device->BindTexture(IGLDevice::Texture2D, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GLOptimizedVoxelModel::RenderSunlightPass(std::vector<client::ModelRenderParam> params) {
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
2013-09-04 22:11:39 +09:00
|
|
|
bool mirror = renderer->IsRenderingMirror();
|
2013-08-18 16:18:06 +09:00
|
|
|
|
|
|
|
device->ActiveTexture(0);
|
|
|
|
aoImage->Bind(IGLDevice::Texture2D);
|
|
|
|
device->TexParamater(IGLDevice::Texture2D,
|
|
|
|
IGLDevice::TextureMinFilter,
|
|
|
|
IGLDevice::Linear);
|
|
|
|
|
|
|
|
device->ActiveTexture(1);
|
|
|
|
image->Bind(IGLDevice::Texture2D);
|
|
|
|
device->TexParamater(IGLDevice::Texture2D,
|
|
|
|
IGLDevice::TextureMinFilter,
|
|
|
|
IGLDevice::Nearest);
|
|
|
|
device->TexParamater(IGLDevice::Texture2D,
|
|
|
|
IGLDevice::TextureMagFilter,
|
|
|
|
IGLDevice::Nearest);
|
|
|
|
|
|
|
|
device->Enable(IGLDevice::CullFace, true);
|
|
|
|
device->Enable(IGLDevice::DepthTest, true);
|
|
|
|
|
|
|
|
program->Use();
|
|
|
|
|
|
|
|
static GLShadowShader shadowShader;
|
|
|
|
shadowShader(renderer, program, 2);
|
|
|
|
|
|
|
|
static GLProgramUniform fogDistance("fogDistance");
|
|
|
|
fogDistance(program);
|
|
|
|
fogDistance.SetValue(renderer->GetFogDistance());
|
|
|
|
|
|
|
|
static GLProgramUniform fogColor("fogColor");
|
|
|
|
fogColor(program);
|
2013-08-22 20:02:17 +09:00
|
|
|
Vector3 fogCol = renderer->GetFogColorForSolidPass();
|
2013-08-18 16:18:06 +09:00
|
|
|
fogCol *= fogCol; // linearize
|
|
|
|
fogColor.SetValue(fogCol.x, fogCol.y, fogCol.z);
|
|
|
|
|
|
|
|
static GLProgramUniform aoUniform("ambientOcclusionTexture");
|
|
|
|
aoUniform(program);
|
|
|
|
aoUniform.SetValue(0);
|
|
|
|
|
|
|
|
static GLProgramUniform modelOrigin("modelOrigin");
|
|
|
|
modelOrigin(program);
|
|
|
|
modelOrigin.SetValue(origin.x, origin.y, origin.z);
|
|
|
|
|
|
|
|
static GLProgramUniform texScale("texScale");
|
|
|
|
texScale(program);
|
|
|
|
texScale.SetValue(1.f / image->GetWidth(),
|
|
|
|
1.f / image->GetHeight());
|
|
|
|
|
|
|
|
static GLProgramUniform modelTexture("modelTexture");
|
|
|
|
modelTexture(program);
|
|
|
|
modelTexture.SetValue(1);
|
|
|
|
|
|
|
|
static GLProgramUniform sunLightDirection("sunLightDirection");
|
|
|
|
sunLightDirection(program);
|
|
|
|
Vector3 sunPos = MakeVector3(0, -1, -1);
|
|
|
|
sunPos = sunPos.Normalize();
|
|
|
|
sunLightDirection.SetValue(sunPos.x, sunPos.y, sunPos.z);
|
2016-11-06 22:15:37 +09:00
|
|
|
|
|
|
|
static GLProgramUniform viewOriginVector("viewOriginVector");
|
|
|
|
viewOriginVector(program);
|
|
|
|
const auto &viewOrigin = renderer->GetSceneDef().viewOrigin;
|
|
|
|
viewOriginVector.SetValue(viewOrigin.x, viewOrigin.y, viewOrigin.z);
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
// setup attributes
|
|
|
|
static GLProgramAttribute positionAttribute("positionAttribute");
|
|
|
|
static GLProgramAttribute textureCoordAttribute("textureCoordAttribute");
|
|
|
|
static GLProgramAttribute normalAttribute("normalAttribute");
|
|
|
|
|
|
|
|
positionAttribute(program);
|
|
|
|
textureCoordAttribute(program);
|
|
|
|
normalAttribute(program);
|
|
|
|
|
|
|
|
device->BindBuffer(IGLDevice::ArrayBuffer, buffer);
|
|
|
|
device->VertexAttribPointer(positionAttribute(),
|
|
|
|
4, IGLDevice::UnsignedByte,
|
|
|
|
false, sizeof(Vertex),
|
|
|
|
(void *)0);
|
|
|
|
device->VertexAttribPointer(textureCoordAttribute(),
|
|
|
|
2, IGLDevice::UnsignedShort,
|
|
|
|
false, sizeof(Vertex),
|
|
|
|
(void *)4);
|
|
|
|
device->VertexAttribPointer(normalAttribute(),
|
|
|
|
3, IGLDevice::Byte,
|
|
|
|
false, sizeof(Vertex),
|
|
|
|
(void *)8);
|
|
|
|
device->BindBuffer(IGLDevice::ArrayBuffer, 0);
|
|
|
|
|
|
|
|
device->EnableVertexAttribArray(positionAttribute(), true);
|
|
|
|
device->EnableVertexAttribArray(textureCoordAttribute(), true);
|
|
|
|
device->EnableVertexAttribArray(normalAttribute(), true);
|
|
|
|
|
|
|
|
device->BindBuffer(IGLDevice::ElementArrayBuffer, idxBuffer);
|
|
|
|
|
|
|
|
for(size_t i = 0; i < params.size(); i++){
|
|
|
|
const client::ModelRenderParam& param = params[i];
|
|
|
|
|
2013-09-04 22:11:39 +09:00
|
|
|
if(mirror && param.depthHack)
|
|
|
|
continue;
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
// frustrum cull
|
|
|
|
float rad = radius;
|
|
|
|
rad *= param.matrix.GetAxis(0).GetLength();
|
|
|
|
if(!renderer->SphereFrustrumCull(param.matrix.GetOrigin(),
|
|
|
|
rad)){
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static GLProgramUniform customColor("customColor");
|
|
|
|
customColor(program);
|
|
|
|
customColor.SetValue(param.customColor.x, param.customColor.y, param.customColor.z);
|
|
|
|
|
|
|
|
|
|
|
|
Matrix4 modelMatrix = param.matrix;
|
|
|
|
static GLProgramUniform projectionViewModelMatrix("projectionViewModelMatrix");
|
|
|
|
projectionViewModelMatrix(program);
|
|
|
|
projectionViewModelMatrix.SetValue(renderer->GetProjectionViewMatrix() * modelMatrix);
|
|
|
|
|
|
|
|
static GLProgramUniform viewModelMatrix("viewModelMatrix");
|
|
|
|
viewModelMatrix(program);
|
|
|
|
viewModelMatrix.SetValue(renderer->GetViewMatrix() * modelMatrix);
|
|
|
|
|
|
|
|
static GLProgramUniform modelMatrixU("modelMatrix");
|
|
|
|
modelMatrixU(program);
|
|
|
|
modelMatrixU.SetValue(modelMatrix);
|
|
|
|
|
|
|
|
modelMatrix.m[12] = 0.f;
|
|
|
|
modelMatrix.m[13] = 0.f;
|
|
|
|
modelMatrix.m[14] = 0.f;
|
|
|
|
static GLProgramUniform modelNormalMatrix("modelNormalMatrix");
|
|
|
|
modelNormalMatrix(program);
|
|
|
|
modelNormalMatrix.SetValue(modelMatrix);
|
|
|
|
|
|
|
|
if(param.depthHack){
|
|
|
|
device->DepthRange(0.f, 0.1f);
|
|
|
|
}
|
|
|
|
|
|
|
|
device->DrawElements(IGLDevice::Triangles,
|
|
|
|
numIndices,
|
|
|
|
IGLDevice::UnsignedInt,
|
|
|
|
(void *)0);
|
|
|
|
if(param.depthHack){
|
|
|
|
device->DepthRange(0.f, 1.f);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
device->BindBuffer(IGLDevice::ElementArrayBuffer, 0);
|
|
|
|
|
|
|
|
|
|
|
|
device->EnableVertexAttribArray(positionAttribute(), false);
|
|
|
|
device->EnableVertexAttribArray(textureCoordAttribute(), false);
|
|
|
|
device->EnableVertexAttribArray(normalAttribute(), false);
|
|
|
|
|
|
|
|
device->ActiveTexture(1);
|
|
|
|
device->BindTexture(IGLDevice::Texture2D, 0);
|
|
|
|
device->ActiveTexture(0);
|
|
|
|
device->BindTexture(IGLDevice::Texture2D, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GLOptimizedVoxelModel::RenderDynamicLightPass(std::vector<client::ModelRenderParam> params, std::vector<GLDynamicLight> lights) {
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
2013-09-04 22:11:39 +09:00
|
|
|
bool mirror = renderer->IsRenderingMirror();
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
device->ActiveTexture(0);
|
|
|
|
aoImage->Bind(IGLDevice::Texture2D);
|
|
|
|
device->TexParamater(IGLDevice::Texture2D,
|
|
|
|
IGLDevice::TextureMinFilter,
|
|
|
|
IGLDevice::Linear);
|
|
|
|
|
|
|
|
device->ActiveTexture(1);
|
|
|
|
image->Bind(IGLDevice::Texture2D);
|
|
|
|
device->TexParamater(IGLDevice::Texture2D,
|
|
|
|
IGLDevice::TextureMinFilter,
|
|
|
|
IGLDevice::Nearest);
|
|
|
|
device->TexParamater(IGLDevice::Texture2D,
|
|
|
|
IGLDevice::TextureMagFilter,
|
|
|
|
IGLDevice::Nearest);
|
|
|
|
|
|
|
|
device->Enable(IGLDevice::CullFace, true);
|
|
|
|
device->Enable(IGLDevice::DepthTest, true);
|
|
|
|
|
|
|
|
dlightProgram->Use();
|
|
|
|
|
|
|
|
static GLDynamicLightShader dlightShader;
|
|
|
|
|
|
|
|
static GLProgramUniform fogDistance("fogDistance");
|
|
|
|
fogDistance(dlightProgram);
|
|
|
|
fogDistance.SetValue(renderer->GetFogDistance());
|
|
|
|
|
|
|
|
static GLProgramUniform modelOrigin("modelOrigin");
|
|
|
|
modelOrigin(dlightProgram);
|
|
|
|
modelOrigin.SetValue(origin.x, origin.y, origin.z);
|
|
|
|
|
|
|
|
|
|
|
|
static GLProgramUniform texScale("texScale");
|
|
|
|
texScale(dlightProgram);
|
|
|
|
texScale.SetValue(1.f / image->GetWidth(),
|
|
|
|
1.f / image->GetHeight());
|
|
|
|
|
|
|
|
static GLProgramUniform modelTexture("modelTexture");
|
|
|
|
modelTexture(dlightProgram);
|
|
|
|
modelTexture.SetValue(1);
|
2016-11-06 22:15:37 +09:00
|
|
|
|
|
|
|
static GLProgramUniform viewOriginVector("viewOriginVector");
|
|
|
|
viewOriginVector(dlightProgram);
|
|
|
|
const auto &viewOrigin = renderer->GetSceneDef().viewOrigin;
|
|
|
|
viewOriginVector.SetValue(viewOrigin.x, viewOrigin.y, viewOrigin.z);
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
// setup attributes
|
|
|
|
static GLProgramAttribute positionAttribute("positionAttribute");
|
|
|
|
static GLProgramAttribute textureCoordAttribute("textureCoordAttribute");
|
|
|
|
static GLProgramAttribute normalAttribute("normalAttribute");
|
|
|
|
|
|
|
|
positionAttribute(dlightProgram);
|
|
|
|
textureCoordAttribute(dlightProgram);
|
|
|
|
normalAttribute(dlightProgram);
|
|
|
|
|
|
|
|
device->BindBuffer(IGLDevice::ArrayBuffer, buffer);
|
|
|
|
device->VertexAttribPointer(positionAttribute(),
|
|
|
|
4, IGLDevice::UnsignedByte,
|
|
|
|
false, sizeof(Vertex),
|
|
|
|
(void *)0);
|
|
|
|
device->VertexAttribPointer(textureCoordAttribute(),
|
|
|
|
2, IGLDevice::UnsignedShort,
|
|
|
|
false, sizeof(Vertex),
|
|
|
|
(void *)4);
|
|
|
|
device->VertexAttribPointer(normalAttribute(),
|
|
|
|
3, IGLDevice::Byte,
|
|
|
|
false, sizeof(Vertex),
|
|
|
|
(void *)8);
|
|
|
|
device->BindBuffer(IGLDevice::ArrayBuffer, 0);
|
|
|
|
|
|
|
|
device->EnableVertexAttribArray(positionAttribute(), true);
|
|
|
|
device->EnableVertexAttribArray(textureCoordAttribute(), true);
|
|
|
|
device->EnableVertexAttribArray(normalAttribute(), true);
|
|
|
|
|
|
|
|
device->BindBuffer(IGLDevice::ElementArrayBuffer, idxBuffer);
|
|
|
|
|
|
|
|
for(size_t i = 0; i < params.size(); i++){
|
|
|
|
const client::ModelRenderParam& param = params[i];
|
|
|
|
|
2013-09-04 22:11:39 +09:00
|
|
|
if(mirror && param.depthHack)
|
|
|
|
continue;
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
// frustrum cull
|
|
|
|
float rad = radius;
|
|
|
|
rad *= param.matrix.GetAxis(0).GetLength();
|
|
|
|
if(!renderer->SphereFrustrumCull(param.matrix.GetOrigin(),
|
|
|
|
rad)){
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static GLProgramUniform customColor("customColor");
|
|
|
|
customColor(dlightProgram);
|
|
|
|
customColor.SetValue(param.customColor.x, param.customColor.y, param.customColor.z);
|
|
|
|
|
|
|
|
|
|
|
|
Matrix4 modelMatrix = param.matrix;
|
|
|
|
static GLProgramUniform projectionViewModelMatrix("projectionViewModelMatrix");
|
|
|
|
projectionViewModelMatrix(dlightProgram);
|
|
|
|
projectionViewModelMatrix.SetValue(renderer->GetProjectionViewMatrix() * modelMatrix);
|
|
|
|
|
|
|
|
static GLProgramUniform viewModelMatrix("viewModelMatrix");
|
|
|
|
viewModelMatrix(dlightProgram);
|
|
|
|
viewModelMatrix.SetValue(renderer->GetViewMatrix() * modelMatrix);
|
|
|
|
|
|
|
|
static GLProgramUniform modelMatrixU("modelMatrix");
|
|
|
|
modelMatrixU(dlightProgram);
|
|
|
|
modelMatrixU.SetValue(modelMatrix);
|
|
|
|
|
|
|
|
modelMatrix.m[12] = 0.f;
|
|
|
|
modelMatrix.m[13] = 0.f;
|
|
|
|
modelMatrix.m[14] = 0.f;
|
|
|
|
static GLProgramUniform modelNormalMatrix("modelNormalMatrix");
|
|
|
|
modelNormalMatrix(dlightProgram);
|
|
|
|
modelNormalMatrix.SetValue(modelMatrix);
|
|
|
|
|
|
|
|
if(param.depthHack){
|
|
|
|
device->DepthRange(0.f, 0.1f);
|
|
|
|
}
|
|
|
|
for(size_t i = 0; i < lights.size(); i++){
|
|
|
|
if(!GLDynamicLightShader::SphereCull(lights[i],
|
|
|
|
param.matrix.GetOrigin(), rad))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
dlightShader(renderer, dlightProgram, lights[i], 2);
|
|
|
|
|
|
|
|
device->DrawElements(IGLDevice::Triangles,
|
|
|
|
numIndices,
|
|
|
|
IGLDevice::UnsignedInt,
|
|
|
|
(void *)0);
|
|
|
|
}
|
|
|
|
if(param.depthHack){
|
|
|
|
device->DepthRange(0.f, 1.f);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
device->BindBuffer(IGLDevice::ElementArrayBuffer, 0);
|
|
|
|
|
|
|
|
|
|
|
|
device->EnableVertexAttribArray(positionAttribute(), false);
|
|
|
|
device->EnableVertexAttribArray(textureCoordAttribute(), false);
|
|
|
|
device->EnableVertexAttribArray(normalAttribute(), false);
|
|
|
|
|
|
|
|
device->ActiveTexture(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|