diff --git a/src/definition/VegetationDefinition.cpp b/src/definition/VegetationDefinition.cpp index 2ed1d6f..027e42f 100644 --- a/src/definition/VegetationDefinition.cpp +++ b/src/definition/VegetationDefinition.cpp @@ -29,9 +29,9 @@ void VegetationDefinition::applyPreset(VegetationPreset preset, RandomGenerator clear(); - /*if (preset == VEGETATION_PRESET_TEMPERATE) { + if (preset == VEGETATION_PRESET_TEMPERATE) { layer.applyPreset(VegetationLayerDefinition::VEGETATION_BASIC_TREES, random); layer.setName("Basic tree"); addLayer(layer); - }*/ + } } diff --git a/src/render/opengl/OpenGLVegetationImpostor.cpp b/src/render/opengl/OpenGLVegetationImpostor.cpp index fa31f0c..84b9734 100644 --- a/src/render/opengl/OpenGLVegetationImpostor.cpp +++ b/src/render/opengl/OpenGLVegetationImpostor.cpp @@ -59,12 +59,41 @@ void OpenGLVegetationImpostor::render(OpenGLShaderProgram *program, const OpenGL state->set("impostorTexture", texture); } + // FIXME Deprecated, use renderBatch always + vertices->clearIndexes(); + int index = getIndex(camera_location, instance->getBase()); state->set("offset", instance->getBase()); state->set("size", 2.0 * instance->getSize()); program->draw(vertices, state, index * 4, 4); } +void OpenGLVegetationImpostor::renderBatch(OpenGLShaderProgram *program, + const vector &instances, + const Vector3 &camera_location) { + if (texture_changed) { + texture_changed = false; + state->set("impostorTexture", texture); + } + + // TODO Cache buffers + vector indexes(instances.size() * 5); + int i = 0; + for (auto &instance: instances) { + int index = getIndex(camera_location, instance->getBase()); + for (int j = 0; j < 4; j++) { + indexes[i * 5 + j] = index * 4 + j; + } + indexes[i * 5 + 4] = OPENGL_RESTART_PRIMITIVE_INDEX; + i++; + } + vertices->setIndexes(indexes); + + state->set("offset", VECTOR_UP.scale(10.0)); + state->set("size", 1.0); + program->draw(vertices, state); +} + void OpenGLVegetationImpostor::prepareTexture(const VegetationModelDefinition &model, const Scenery &environment, bool *interrupt) { Scenery scenery; diff --git a/src/render/opengl/OpenGLVegetationImpostor.h b/src/render/opengl/OpenGLVegetationImpostor.h index b8d57fa..5e1ca66 100644 --- a/src/render/opengl/OpenGLVegetationImpostor.h +++ b/src/render/opengl/OpenGLVegetationImpostor.h @@ -3,6 +3,8 @@ #include "opengl_global.h" +#include + namespace paysages { namespace opengl { @@ -23,6 +25,12 @@ class OPENGLSHARED_EXPORT OpenGLVegetationImpostor { */ void render(OpenGLShaderProgram *program, const OpenGLVegetationInstance *instance, const Vector3 &camera_location); + /** + * Render a whole lot of instances using this impostor. + */ + void renderBatch(OpenGLShaderProgram *program, const vector &instances, + const Vector3 &camera_location); + /** * Prepare the texture grid for a given model. */ diff --git a/src/render/opengl/OpenGLVegetationLayer.cpp b/src/render/opengl/OpenGLVegetationLayer.cpp index c9a8a53..fd67c1b 100644 --- a/src/render/opengl/OpenGLVegetationLayer.cpp +++ b/src/render/opengl/OpenGLVegetationLayer.cpp @@ -115,9 +115,10 @@ void OpenGLVegetationLayer::render() { lock_instances->acquire(); // TODO Instanced rendering - for (auto instance : instances) { + /*for (auto instance : instances) { impostor->render(parent->getProgram(), instance, *camera_location); - } + }*/ + impostor->renderBatch(parent->getProgram(), instances, *camera_location); lock_instances->release(); } diff --git a/src/render/opengl/OpenGLVertexArray.cpp b/src/render/opengl/OpenGLVertexArray.cpp index f05dd2c..ea3decd 100644 --- a/src/render/opengl/OpenGLVertexArray.cpp +++ b/src/render/opengl/OpenGLVertexArray.cpp @@ -1,5 +1,6 @@ #include "OpenGLVertexArray.h" +#include #include "OpenGLFunctions.h" #include "Logs.h" #include "Vector3.h" @@ -51,15 +52,32 @@ void OpenGLVertexArray::render(OpenGLFunctions *functions, int start, int count) update(functions); } + assert(start >= 0); + int max_count = indexes.empty() ? vertexcount : indexes.size(); + if (count < 0) { + count = max_count - start; + } + assert(start + count <= max_count); + if (vertexcount and vao) { functions->glBindVertexArray(vao); - functions->glDrawArrays(draw_mode, start, count < 0 ? vertexcount : count); + + if (indexes.empty()) { + functions->glDrawArrays(draw_mode, start, count); + } else { + // TODO Break in sub-ranges if count is too big + functions->glPrimitiveRestartIndex(OPENGL_RESTART_PRIMITIVE_INDEX); + functions->glDrawRangeElements(draw_mode, 0, vertexcount, count, GL_UNSIGNED_SHORT, indexes.data() + start); + } + functions->glBindVertexArray(0); } } void OpenGLVertexArray::setVertexCount(int count) { - if (count != vertexcount) { + if (count >= OPENGL_RESTART_PRIMITIVE_INDEX) { + Logs::error("OpenGL") << "Can't set vertex count higher than " << OPENGL_RESTART_PRIMITIVE_INDEX << endl; + } else if (count != vertexcount) { vertexcount = count; if (count < 1) { count = 1; @@ -101,9 +119,23 @@ void OpenGLVertexArray::copyTo(OpenGLVertexArray *destination) const { memcpy(destination->array_vertex, array_vertex, sizeof(float) * vertexcount * 3); memcpy(destination->array_uv, array_uv, sizeof(float) * vertexcount * 2); } + destination->setIndexes(indexes); destination->changed = true; } +void OpenGLVertexArray::setIndexes(const vector &indexes) { +#ifndef NDEBUG + for (auto index : indexes) { + assert(index < vertexcount or index == OPENGL_RESTART_PRIMITIVE_INDEX); + } +#endif + this->indexes = indexes; +} + +void OpenGLVertexArray::clearIndexes() { + indexes.clear(); +} + void OpenGLVertexArray::update(OpenGLFunctions *functions) { if (not vao) { functions->glGenVertexArrays(1, &vao); diff --git a/src/render/opengl/OpenGLVertexArray.h b/src/render/opengl/OpenGLVertexArray.h index 002c251..c79aa99 100644 --- a/src/render/opengl/OpenGLVertexArray.h +++ b/src/render/opengl/OpenGLVertexArray.h @@ -3,9 +3,13 @@ #include "opengl_global.h" +#include + namespace paysages { namespace opengl { +const unsigned short OPENGL_RESTART_PRIMITIVE_INDEX = 65535; + /** * Vertex arrays storage and binding, to render triangles. * @@ -62,6 +66,21 @@ class OpenGLVertexArray { */ void copyTo(OpenGLVertexArray *destination) const; + /** + * Set the indexes to define the draw order. + * + * Vertex count must have been properly set before calling this. + * + * When this is called, vertices are drawn by specified indexes order, + * instead of their sequential order, thus allowing vertex reuse. + */ + void setIndexes(const vector &indexes); + + /** + * Go back to sequential drawing, after calling setIndexes. + */ + void clearIndexes(); + private: /** * Update the opengl state. @@ -87,6 +106,7 @@ class OpenGLVertexArray { int vertexcount; float *array_vertex; float *array_uv; + vector indexes; }; } } diff --git a/src/render/opengl/shaders/vegetation.frag b/src/render/opengl/shaders/vegetation.frag index 04164fa..7af879c 100644 --- a/src/render/opengl/shaders/vegetation.frag +++ b/src/render/opengl/shaders/vegetation.frag @@ -13,4 +13,6 @@ void main(void) final_color = applyMouseTracking(unprojected, final_color); final_color.a = alpha; + + //final_color = vec4(0, 1, 0, 1); }