KlassischeKeplerKriege/game/renderer_polygon_3d/particle_batch.cpp

205 lines
6.1 KiB
C++
Raw Normal View History

#include "particle_batch.hpp"
#include <iostream>
2016-09-28 22:50:14 +00:00
// TODO: use VAO's as soon as this is working
int getDivisorForIndex(int index)
{
return (index == 0) ? 1 : 4;
}
namespace endofthejedi {
2016-09-28 22:50:14 +00:00
ParticleBatch::ParticleBatch(size_t numParticles, float particleSize, float maxAge)
: m_numParticles(numParticles)
, m_particleRadius(particleSize)
2016-09-28 22:50:14 +00:00
, m_maxAge(maxAge)
// 2d quad drawn as a triangle fan
, m_data_quad({
1.0f, -1.0f,
1.0f, 1.0f,
-1.0f, 1.0f,
-1.0f, -1.0f})
{
std::cout<<"[ParticleBatch] create for " << numParticles << " num particles" << std::endl;
2016-09-28 22:50:14 +00:00
m_data_position.resize(m_numParticles);
m_data_velocity.resize(m_numParticles);
m_data_kind.resize(m_numParticles);
m_data_max_age.resize(m_numParticles);
std::string vss_particles =
"#version 120\n"
2016-09-28 22:50:14 +00:00
"attribute vec2 in_vertex;\n"
"attribute vec2 in_position;\n"
"attribute vec2 in_velocity;\n"
"varying vec2 vertex;\n"
"uniform float time;\n"
"uniform float size;\n"
"void main()\n"
"{\n"
2016-09-28 22:50:14 +00:00
" vec2 p = size*in_vertex;\n"
" p += time * in_velocity;\n"
" p += in_position;\n"
" gl_Position = vec4(p, 0.0, 1.0);\n"
" vertex = in_vertex;\n"
"}\n"
;
std::string fss_particles =
"#version 120\n"
2016-09-28 22:50:14 +00:00
"varying vec2 vertex;\n"
"uniform float maxAge;\n"
"uniform float time;\n"
"void main()\n"
"{\n"
2016-09-28 22:50:14 +00:00
//" gl_FragColor = vec4(0.5+0.5*vertex.x, 0.5+0.5*vertex.y, 0.0, 1.0);\n"
" if (length(vertex) > 1.0) {\n"
" discard;\n"
"}\n"
" float decay = time / maxAge;\n"
" gl_FragColor = vec4(1.0/max(1.0, decay), 1.0/max(1.0, 6.0*decay), 0.0, 1.0);\n"
"}\n"
;
m_shader.init();
m_shader.load(vss_particles.c_str(), GL_VERTEX_SHADER);
m_shader.load(fss_particles.c_str(), GL_FRAGMENT_SHADER);
}
ParticleBatch::~ParticleBatch()
{
// TODO: find out if stuff must be deallocated
}
2016-09-28 22:50:14 +00:00
void ParticleBatch::setParticle(size_t index, const glm::vec2 &p, const glm::vec2 &v)
{
if (index >= m_numParticles) {
return;
}
//std::cout<<"[ParticleBatch] setParticle " << index << std::endl;
2016-09-28 22:50:14 +00:00
m_data_position[index] = p;
m_data_velocity[index] = v;
m_data_kind[index] = 0.0;
m_data_max_age[index] = 0.0;
}
void ParticleBatch::bind()
{
//std::cout<<"[ParticleBatch] bind" << std::endl;
2016-09-28 22:50:14 +00:00
for (size_t i=0; i<5; i++) {
//std::cout<<"vbo #" << i << ": " << m_data_vbos[i] << std::endl;
glEnableVertexAttribArray(i);
glBindBuffer(GL_ARRAY_BUFFER, m_data_vbos[i]);
2016-09-28 22:50:14 +00:00
if (i != 0) {
glVertexAttribDivisor(i, getDivisorForIndex(i-1));
}
// TODO: i or index? at first argument?
glVertexAttribPointer(
i,
dataSizeForIndex(i),
GL_FLOAT, // Data is floating point type
GL_FALSE, // No fixed point scaling
0, // stride: no
NULL); // No offset
}
}
void ParticleBatch::upload()
{
2016-09-28 22:50:14 +00:00
std::cout<<"[ParticleBatch] upload to vbo's " << std::endl;
glGenBuffers(4, m_data_vbos); // Generate buffer
for (size_t i=0; i<4; i++) {
2016-09-28 22:50:14 +00:00
size_t bufferDataSize = dataSizeForIndex(i) * m_numParticles * sizeof(float);
glEnableVertexAttribArray(i);
glBindBuffer(GL_ARRAY_BUFFER, m_data_vbos[i]);
// fill buffer with the loaded mesh position data
glBufferData(
2016-09-28 22:50:14 +00:00
GL_ARRAY_BUFFER, // Buffer target
bufferDataSize, // Buffer data size
dataSourceForIndex(i), // Buffer data pointer
GL_STATIC_DRAW); // Usage - Data never changes;
}
}
void ParticleBatch::render()
{
//std::cout<<"[ParticleBatch] render " << std::endl;
m_shader.bind();
2016-09-28 22:50:14 +00:00
glBindAttribLocation(m_shader.program(), 0, "in_vertex");
glBindAttribLocation(m_shader.program(), 1, "in_position");
glBindAttribLocation(m_shader.program(), 2, "in_velocity");
static float time = 0.0f;
time += 1.0/50.0;
2016-09-28 22:50:14 +00:00
glUniform1f(m_shader.location("time"), time);
glUniform1f(m_shader.location("maxAge"), m_maxAge);
glUniform1f(m_shader.location("size"), m_particleRadius);
bind();
2016-09-28 22:50:14 +00:00
//glDrawArrays(GL_TRIANGLE_FAN, 0, 4*m_numParticles);
//glDrawArraysInstanced( GLenum mode, GLint first, GLsizei count, GLsizei primcount);
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, 4*m_numParticles);
#if 0
glBegin(GL_QUADS);
for (size_t index=0; index<m_numParticles; index++) {
for (int i=0; i<4; i++) {
glm::vec2 p = m_data_position[index] + triangles[i];
//glColor3f(1.0, 0.0, 0.0);
glVertex2f(p.x, p.y);
}
}
glEnd();
#endif
}
size_t ParticleBatch::dataSizeForIndex(int i)
{
switch(i) {
case 0:
case 1:
2016-09-28 22:50:14 +00:00
case 2:
return 2;
case 3:
2016-09-28 22:50:14 +00:00
case 4:
return 1;
default:
std::cerr << "bad" << std::endl;
2016-09-28 22:50:14 +00:00
exit(-1);
}
}
void *ParticleBatch::dataSourceForIndex(int i)
{
switch(i) {
2016-09-28 22:50:14 +00:00
case 0: return (void *) m_data_quad.data();
case 1: return (void *) m_data_position.data();
case 2: return (void *) m_data_velocity.data();
case 3: return (void *) m_data_kind.data();
case 4: return (void *) m_data_max_age.data();
default:
std::cerr << "bad" << std::endl;
2016-09-28 22:50:14 +00:00
exit(-1);
}
}
}