Files
love/src/modules/graphics/opengl/Mesh.cpp
T
Alex Szpakowski e03c763215 Fix love.graphics.drawLayer.
--HG--
branch : minor
2017-05-20 15:37:29 -03:00

217 lines
6.0 KiB
C++

/**
* Copyright (c) 2006-2017 LOVE Development Team
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
// LOVE
#include "Mesh.h"
#include "common/Exception.h"
#include "Shader.h"
#include "graphics/Graphics.h"
// C++
#include <algorithm>
#include <limits>
namespace love
{
namespace graphics
{
namespace opengl
{
Mesh::Mesh(graphics::Graphics *gfx, const std::vector<AttribFormat> &vertexformat, const void *data, size_t datasize, DrawMode drawmode, vertex::Usage usage)
: love::graphics::Mesh(gfx, vertexformat, data, datasize, drawmode, usage)
{
}
Mesh::Mesh(graphics::Graphics *gfx, const std::vector<AttribFormat> &vertexformat, int vertexcount, DrawMode drawmode, vertex::Usage usage)
: love::graphics::Mesh(gfx, vertexformat, vertexcount, drawmode, usage)
{
}
Mesh::Mesh(graphics::Graphics *gfx, const std::vector<Vertex> &vertices, DrawMode drawmode, vertex::Usage usage)
: Mesh(gfx, getDefaultVertexFormat(), &vertices[0], vertices.size() * sizeof(Vertex), drawmode, usage)
{
}
Mesh::Mesh(graphics::Graphics *gfx, int vertexcount, DrawMode drawmode, vertex::Usage usage)
: Mesh(gfx, getDefaultVertexFormat(), vertexcount, drawmode, usage)
{
}
Mesh::~Mesh()
{
}
int Mesh::bindAttributeToShaderInput(int attributeindex, const std::string &inputname)
{
const AttribFormat &format = vertexFormat[attributeindex];
GLint attriblocation = -1;
// If the attribute is one of the LOVE-defined ones, use the constant
// attribute index for it, otherwise query the index from the shader.
VertexAttribID builtinattrib;
if (vertex::getConstant(inputname.c_str(), builtinattrib))
attriblocation = (GLint) builtinattrib;
else if (Shader::current)
attriblocation = ((Shader *) Shader::current)->getAttribLocation(inputname);
// The active shader might not use this vertex attribute name.
if (attriblocation < 0)
return attriblocation;
// Make sure the buffer isn't mapped (sends data to GPU if needed.)
vbo->unmap();
gl.bindBuffer(BUFFER_VERTEX, (GLuint) vbo->getHandle());
const void *gloffset = BUFFER_OFFSET(getAttributeOffset(attributeindex));
GLenum datatype = getGLDataType(format.type);
GLboolean normalized = (datatype == GL_UNSIGNED_BYTE);
glVertexAttribPointer(attriblocation, format.components, datatype, normalized, (GLsizei) vertexStride, gloffset);
return attriblocation;
}
void Mesh::drawInstanced(love::graphics::Graphics *gfx, const love::Matrix4 &m, int instancecount)
{
if (vertexCount <= 0 || instancecount <= 0)
return;
if (instancecount > 1 && !gl.isInstancingSupported())
throw love::Exception("Instancing is not supported on this system.");
gfx->flushStreamDraws();
if (Shader::isDefaultActive())
Shader::attachDefault(Shader::STANDARD_DEFAULT);
if (Shader::current && texture.get())
Shader::current->checkMainTexture(texture);
OpenGL::TempDebugGroup debuggroup("Mesh draw");
uint32 enabledattribs = 0;
uint32 instancedattribs = 0;
for (const auto &attrib : attachedAttributes)
{
if (!attrib.second.enabled)
continue;
love::graphics::Mesh *mesh = attrib.second.mesh;
int location = mesh->bindAttributeToShaderInput(attrib.second.index, attrib.first);
if (location >= 0)
{
uint32 bit = 1u << (uint32) location;
enabledattribs |= bit;
if (attrib.second.step == STEP_PER_INSTANCE)
instancedattribs |= bit;
}
}
// Not supported on all platforms or GL versions, I believe.
if (!(enabledattribs & ATTRIBFLAG_POS))
throw love::Exception("Mesh must have an enabled VertexPosition attribute to be drawn.");
gl.useVertexAttribArrays(enabledattribs, instancedattribs);
gl.bindTextureToUnit(texture, 0, false);
Graphics::TempTransform transform(gfx, m);
gl.prepareDraw();
if (useIndexBuffer && ibo && elementCount > 0)
{
// Use the custom vertex map (index buffer) to draw the vertices.
gl.bindBuffer(BUFFER_INDEX, (GLuint) ibo->getHandle());
// Make sure the index buffer isn't mapped (sends data to GPU if needed.)
ibo->unmap();
int start = std::min(std::max(0, rangeStart), (int) elementCount - 1);
int count = (int) elementCount;
if (rangeCount > 0)
count = std::min(count, rangeCount);
count = std::min(count, (int) elementCount - start);
size_t elementsize = vertex::getIndexDataSize(elementDataType);
const void *indices = BUFFER_OFFSET(start * elementsize);
GLenum type = OpenGL::getGLIndexDataType(elementDataType);
if (count > 0)
gl.drawElements(getGLDrawMode(drawMode), count, type, indices, instancecount);
}
else
{
int start = std::min(std::max(0, rangeStart), (int) vertexCount - 1);
int count = (int) vertexCount;
if (rangeCount > 0)
count = std::min(count, rangeCount);
count = std::min(count, (int) vertexCount - start);
// Normal non-indexed drawing (no custom vertex map.)
if (count > 0)
gl.drawArrays(getGLDrawMode(drawMode), start, count, instancecount);
}
}
GLenum Mesh::getGLDrawMode(DrawMode mode)
{
switch (mode)
{
case DRAWMODE_FAN:
return GL_TRIANGLE_FAN;
case DRAWMODE_STRIP:
return GL_TRIANGLE_STRIP;
case DRAWMODE_TRIANGLES:
default:
return GL_TRIANGLES;
case DRAWMODE_POINTS:
return GL_POINTS;
}
}
GLenum Mesh::getGLDataType(DataType type)
{
switch (type)
{
case DATA_BYTE:
return GL_UNSIGNED_BYTE;
case DATA_FLOAT:
return GL_FLOAT;
default:
return 0;
}
}
} // opengl
} // graphics
} // love