mirror of
https://github.com/love2d/love.git
synced 2026-08-16 16:20:42 +02:00
e03c763215
--HG-- branch : minor
217 lines
6.0 KiB
C++
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
|