You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

335 lines
9.7 KiB

/*
* Copyright (c) 2010-2015 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#if !defined(OPENGL_ES) || OPENGL_ES==1
#include "painterogl1.h"
#include <framework/graphics/graphics.h>
PainterOGL1 *g_painterOGL1 = nullptr;
PainterOGL1::PainterOGL1()
{
m_matrixMode = GL_PROJECTION;
resetState();
}
void PainterOGL1::refreshState()
{
PainterOGL::refreshState();
updateGlColor();
updateGlMatrixMode();
updateGlTransformMatrix();
updateGlProjectionMatrix();
updateGlTextureMatrix();
updateGlTextureState();
}
void PainterOGL1::bind()
{
PainterOGL::bind();
// vertex and texture coord arrays are always enabled
// to avoid massive enable/disables, thus improving frame rate
if(g_graphics.canUseDrawArrays())
glEnableClientState(GL_VERTEX_ARRAY);
}
void PainterOGL1::unbind()
{
if(g_graphics.canUseDrawArrays())
glDisableClientState(GL_VERTEX_ARRAY);
}
void PainterOGL1::drawCoords(CoordsBuffer& coordsBuffer, DrawMode drawMode)
{
int vertexCount = coordsBuffer.getVertexCount();
if(vertexCount == 0)
return;
bool textured = coordsBuffer.getTextureCoordCount() != 0 && m_texture;
// skip drawing of empty textures
if(textured && m_texture->isEmpty())
return;
if(textured != m_textureEnabled) {
m_textureEnabled = textured;
updateGlTextureState();
}
// GDI Generic driver has this bug
if(g_graphics.hasScissorBug())
updateGlClipRect();
// use vertex arrays if possible, much faster
if(g_graphics.canUseDrawArrays()) {
// update coords buffer hardware caches if enabled
coordsBuffer.updateCaches();
bool hardwareCached = coordsBuffer.isHardwareCached();
// only set texture coords arrays when needed
if(textured) {
if(hardwareCached) {
coordsBuffer.getHardwareTextureCoordArray()->bind();
glTexCoordPointer(2, GL_FLOAT, 0, nullptr);
} else
glTexCoordPointer(2, GL_FLOAT, 0, coordsBuffer.getTextureCoordArray());
}
// set vertex array
if(hardwareCached) {
coordsBuffer.getHardwareVertexArray()->bind();
glVertexPointer(2, GL_FLOAT, 0, nullptr);
} else
glVertexPointer(2, GL_FLOAT, 0, coordsBuffer.getVertexArray());
if(hardwareCached)
HardwareBuffer::unbind(HardwareBuffer::VertexBuffer);
// draw the element in coords buffers
if(drawMode == Triangles)
glDrawArrays(GL_TRIANGLES, 0, vertexCount);
else if(drawMode == TriangleStrip)
glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexCount);
}
#ifndef OPENGL_ES
else {
int verticesSize = vertexCount*2;
float *vertices = coordsBuffer.getVertexArray();
float *texCoords = coordsBuffer.getTextureCoordArray();
// use glBegin/glEnd, this is not available in OpenGL ES
// and is considered much slower then glDrawArrays,
// but this code is executed in really old graphics cards
if(drawMode == Triangles)
glBegin(GL_TRIANGLES);
else if(drawMode == TriangleStrip)
glBegin(GL_TRIANGLE_STRIP);
for(int i=0;i<verticesSize;i+=2) {
if(textured)
glTexCoord2f(texCoords[i], texCoords[i+1]);
glVertex2f(vertices[i], vertices[i+1]);
}
glEnd();
}
#endif
}
void PainterOGL1::drawFillCoords(CoordsBuffer& coordsBuffer)
{
setTexture(nullptr);
drawCoords(coordsBuffer);
}
void PainterOGL1::drawTextureCoords(CoordsBuffer& coordsBuffer, const TexturePtr& texture)
{
if(texture->isEmpty())
return;
setTexture(texture.get());
drawCoords(coordsBuffer);
}
void PainterOGL1::drawTexturedRect(const Rect& dest, const TexturePtr& texture, const Rect& src)
{
if(dest.isEmpty() || src.isEmpty() || texture->isEmpty())
return;
setTexture(texture.get());
m_coordsBuffer.clear();
m_coordsBuffer.addQuad(dest, src);
drawCoords(m_coordsBuffer, TriangleStrip);
}
void PainterOGL1::drawUpsideDownTexturedRect(const Rect& dest, const TexturePtr& texture, const Rect& src)
{
if(dest.isEmpty() || src.isEmpty() || texture->isEmpty())
return;
setTexture(texture.get());
m_coordsBuffer.clear();
m_coordsBuffer.addUpsideDownQuad(dest, src);
drawCoords(m_coordsBuffer, TriangleStrip);
}
void PainterOGL1::drawRepeatedTexturedRect(const Rect& dest, const TexturePtr& texture, const Rect& src)
{
if(dest.isEmpty() || src.isEmpty() || texture->isEmpty())
return;
setTexture(texture.get());
m_coordsBuffer.clear();
m_coordsBuffer.addRepeatedRects(dest, src);
drawCoords(m_coordsBuffer);
}
void PainterOGL1::drawFilledRect(const Rect& dest)
{
if(dest.isEmpty())
return;
setTexture(nullptr);
m_coordsBuffer.clear();
m_coordsBuffer.addRect(dest);
drawCoords(m_coordsBuffer);
}
void PainterOGL1::drawFilledTriangle(const Point& a, const Point& b, const Point& c)
{
if(a == b || a == c || b == c)
return;
setTexture(nullptr);
m_coordsBuffer.clear();
m_coordsBuffer.addTriangle(a, b, c);
drawCoords(m_coordsBuffer);
}
void PainterOGL1::drawBoundingRect(const Rect& dest, int innerLineWidth)
{
if(dest.isEmpty() || innerLineWidth == 0)
return;
setTexture(nullptr);
m_coordsBuffer.clear();
m_coordsBuffer.addBoudingRect(dest, innerLineWidth);
drawCoords(m_coordsBuffer);
}
void PainterOGL1::setMatrixMode(PainterOGL1::MatrixMode matrixMode)
{
if(m_matrixMode == matrixMode)
return;
m_matrixMode = matrixMode;
updateGlMatrixMode();
}
void PainterOGL1::setTransformMatrix(const Matrix3& transformMatrix)
{
m_transformMatrix = transformMatrix;
if(g_painter == this)
updateGlTransformMatrix();
}
void PainterOGL1::setProjectionMatrix(const Matrix3& projectionMatrix)
{
m_projectionMatrix = projectionMatrix;
if(g_painter == this)
updateGlProjectionMatrix();
}
void PainterOGL1::setTextureMatrix(const Matrix3& textureMatrix)
{
// avoid re-updating texture matrix
if(m_textureMatrix == textureMatrix)
return;
m_textureMatrix = textureMatrix;
updateGlTextureMatrix();
}
void PainterOGL1::setColor(const Color& color)
{
if(m_color == color)
return;
m_color = color;
updateGlColor();
}
void PainterOGL1::setOpacity(float opacity)
{
if(m_opacity == opacity)
return;
m_opacity = opacity;
updateGlColor();
}
void PainterOGL1::updateGlColor()
{
glColor4f(m_color.rF(), m_color.gF(), m_color.bF(), m_color.aF() * m_opacity);
}
void PainterOGL1::updateGlMatrixMode()
{
glMatrixMode(m_matrixMode);
}
void PainterOGL1::updateGlTransformMatrix()
{
float glTransformMatrix[] = {
m_transformMatrix(1,1), m_transformMatrix(1,2), 0.0f, m_transformMatrix(1,3),
m_transformMatrix(2,1), m_transformMatrix(2,2), 0.0f, m_transformMatrix(2,3),
0.0f, 0.0f, 1.0f, 0.0f,
m_transformMatrix(3,1), m_transformMatrix(3,2), 0.0f, m_transformMatrix(3,3),
};
setMatrixMode(MatrixTransform);
glLoadMatrixf(glTransformMatrix);
}
void PainterOGL1::updateGlProjectionMatrix()
{
float glProjectionMatrix[] = {
m_projectionMatrix(1,1), m_projectionMatrix(1,2), 0.0f, m_projectionMatrix(1,3),
m_projectionMatrix(2,1), m_projectionMatrix(2,2), 0.0f, m_projectionMatrix(2,3),
0.0f, 0.0f, 1.0f, 0.0f,
m_projectionMatrix(3,1), m_projectionMatrix(3,2), 0.0f, m_projectionMatrix(3,3),
};
setMatrixMode(MatrixProjection);
glLoadMatrixf(glProjectionMatrix);
}
void PainterOGL1::updateGlTextureMatrix()
{
float glTextureMatrix[] = {
m_textureMatrix(1,1), m_textureMatrix(1,2), 0.0f, 0.0f,
m_textureMatrix(2,1), m_textureMatrix(2,2), 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
m_textureMatrix(3,1), m_textureMatrix(3,2), 0.0f, m_textureMatrix(3,3),
};
setMatrixMode(MatrixTexture);
glLoadMatrixf(glTextureMatrix);
}
void PainterOGL1::updateGlTextureState()
{
if(m_textureEnabled) {
glEnable(GL_TEXTURE_2D);
if(g_graphics.canUseDrawArrays())
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
} else {
glDisable(GL_TEXTURE_2D);
if(g_graphics.canUseDrawArrays())
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
}
#endif