3527 lines
123 KiB
C++
3527 lines
123 KiB
C++
![]() |
/**********************************************************************
|
||
|
|
||
|
Filename : GRendererOGLImpl.cpp
|
||
|
Content : OpenGL Sample renderer implementation
|
||
|
Created :
|
||
|
Authors : Andrew Reisse, Michael Antonov, TU
|
||
|
|
||
|
Copyright : (c) 2001-2006 Scaleform Corp. All Rights Reserved.
|
||
|
|
||
|
Notes :
|
||
|
|
||
|
Licensees may use this file in accordance with the valid Scaleform
|
||
|
Commercial License Agreement provided with the software.
|
||
|
|
||
|
This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
|
||
|
THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR ANY PURPOSE.
|
||
|
|
||
|
**********************************************************************/
|
||
|
|
||
|
#include "GImage.h"
|
||
|
#include "GAtomic.h"
|
||
|
|
||
|
#if defined(GFC_OS_WIN32)
|
||
|
#include <windows.h>
|
||
|
#endif
|
||
|
|
||
|
#include "GRendererOGL.h"
|
||
|
#include "GRendererCommonImpl.h"
|
||
|
|
||
|
#include <string.h> // for memset()
|
||
|
|
||
|
#ifdef GFC_OS_PS3
|
||
|
#include <PSGL/psgl.h>
|
||
|
#include <PSGL/psglu.h>
|
||
|
#include <cell/fs/cell_fs_file_api.h>
|
||
|
#include <sys/paths.h>
|
||
|
#elif defined(GFC_OS_MAC)
|
||
|
#include <OpenGL/OpenGL.h>
|
||
|
#include <OpenGL/gl.h>
|
||
|
#include <OpenGL/glu.h>
|
||
|
#elif defined(GFC_OS_WIN32)
|
||
|
#include <gl/gl.h>
|
||
|
#include <gl/glu.h>
|
||
|
#include "glext.h"
|
||
|
#define GFC_GL_RUNTIME_LINK(x) wglGetProcAddress(x)
|
||
|
|
||
|
#elif defined(GFC_OS_ANDROID)
|
||
|
#include <GLES/gl.h>
|
||
|
#include <GLES/glext.h>
|
||
|
#elif defined(GFC_OS_IPHONE)
|
||
|
#include <OpenGLES/ES1/gl.h>
|
||
|
#include <OpenGLES/ES1/glext.h>
|
||
|
#define GFC_ZBUFFER_MASKING
|
||
|
#define GFC_GL_NO_STAGE_CONSTANTS
|
||
|
#define GFC_GL_NO_TEX_UPDATE
|
||
|
|
||
|
#else
|
||
|
|
||
|
// Use GLX to link gl extensions at runtime; comment out if not using GLX
|
||
|
#define GFC_GLX_RUNTIME_LINK
|
||
|
|
||
|
#ifdef GFC_GLX_RUNTIME_LINK
|
||
|
#define GLX_GLXEXT_PROTOTYPES
|
||
|
#include <GL/glx.h>
|
||
|
#include <GL/glxext.h>
|
||
|
#define GFC_GL_RUNTIME_LINK(x) glXGetProcAddressARB((const GLubyte*) (x))
|
||
|
#else
|
||
|
#define GL_GLEXT_PROTOTYPES
|
||
|
#endif
|
||
|
|
||
|
#include <GL/gl.h>
|
||
|
#include <GL/glu.h>
|
||
|
#include <GL/glext.h>
|
||
|
#endif
|
||
|
|
||
|
#if defined(GL_VERSION_ES_CM_1_0)
|
||
|
#define GL_FUNC_ADD GL_FUNC_ADD_OES
|
||
|
#define GL_FUNC_REVERSE_SUBTRACT GL_FUNC_REVERSE_SUBTRACT_OES
|
||
|
|
||
|
// Unsupported features
|
||
|
#define GL_MIN GL_FUNC_ADD_OES
|
||
|
#define GL_MAX GL_FUNC_ADD_OES
|
||
|
|
||
|
#define GFC_GL_NO_TEXGEN
|
||
|
|
||
|
#if defined(GL_VERSION_ES_CM_1_1)
|
||
|
#define GL_ARB_texture_env_combine
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
#if defined(GL_ARB_texture_env_combine) && !defined(GL_SRC0_RGB)
|
||
|
#define GL_SRC0_RGB GL_SOURCE0_RGB
|
||
|
#define GL_SRC1_RGB GL_SOURCE1_RGB
|
||
|
#define GL_SRC2_RGB GL_SOURCE2_RGB
|
||
|
#define GL_SRC0_ALPHA GL_SOURCE0_ALPHA
|
||
|
#define GL_SRC1_ALPHA GL_SOURCE1_ALPHA
|
||
|
#define GL_SRC2_ALPHA GL_SOURCE2_ALPHA
|
||
|
#endif
|
||
|
|
||
|
// ***** Classes implemented
|
||
|
class GRendererOGLImpl;
|
||
|
class GTextureOGLImpl;
|
||
|
|
||
|
|
||
|
// Define this macro if mask should be implemented through
|
||
|
// z-buffer instead of stencil. Will overwrite z-buffer contents.
|
||
|
// #define GFC_ZBUFFER_MASKING
|
||
|
|
||
|
|
||
|
// Pixel shaders
|
||
|
enum PixelShaderType
|
||
|
{
|
||
|
PS_None = 0,
|
||
|
PS_TextTexture,
|
||
|
PS_TextTextureColor,
|
||
|
PS_TextTextureColorMultiply,
|
||
|
PS_TextTextureYUV,
|
||
|
PS_TextTextureYUVMultiply,
|
||
|
PS_TextTextureYUVA,
|
||
|
PS_TextTextureYUVAMultiply,
|
||
|
PS_CxformTexture,
|
||
|
PS_CxformTextureMultiply,
|
||
|
|
||
|
PS_CxformGouraud,
|
||
|
PS_CxformGouraudNoAddAlpha,
|
||
|
PS_CxformGouraudTexture,
|
||
|
PS_Cxform2Texture,
|
||
|
|
||
|
// Multiplies - must come in same order as other gourauds
|
||
|
PS_CxformGouraudMultiply,
|
||
|
PS_CxformGouraudMultiplyNoAddAlpha,
|
||
|
PS_CxformGouraudMultiplyTexture,
|
||
|
PS_CxformMultiply2Texture,
|
||
|
|
||
|
// premultiplied alpha
|
||
|
PS_AcTextTexture,
|
||
|
PS_AcTextTextureColor,
|
||
|
PS_AcTextTextureColorMultiply,
|
||
|
PS_AcTextTextureYUV,
|
||
|
PS_AcTextTextureYUVMultiply,
|
||
|
PS_AcTextTextureYUVA,
|
||
|
PS_AcTextTextureYUVAMultiply,
|
||
|
PS_AcCxformTexture,
|
||
|
PS_AcCxformTextureMultiply,
|
||
|
|
||
|
PS_AcCxformGouraud,
|
||
|
PS_AcCxformGouraudNoAddAlpha,
|
||
|
PS_AcCxformGouraudTexture,
|
||
|
PS_AcCxform2Texture,
|
||
|
|
||
|
PS_AcCxformGouraudMultiply,
|
||
|
PS_AcCxformGouraudMultiplyNoAddAlpha,
|
||
|
PS_AcCxformGouraudMultiplyTexture,
|
||
|
PS_AcCxformMultiply2Texture,
|
||
|
|
||
|
PS_Count,
|
||
|
PS_AcOffset = PS_AcCxformTexture-PS_CxformTexture,
|
||
|
};
|
||
|
|
||
|
/* *** Fixed Function Pipeline Support Notes
|
||
|
|
||
|
Some shader behavior can be replicated with fixed
|
||
|
function pipeline texture stages. However, there a number of FF limitations that
|
||
|
make this challenging or impossible.
|
||
|
|
||
|
Specifically:
|
||
|
|
||
|
1. Cxforms are supported as long as 3 texture units and GL_COMBINE are available.
|
||
|
If only 2 texture units, Blend_Multiply and Blend_Darken won't be correct.
|
||
|
Without GL_COMBINE, only the modulate portion is supported.
|
||
|
|
||
|
2. EdgeAA is difficult to support due to their being only one
|
||
|
color per vertex (secondary color is not usable for texture combines).
|
||
|
NoAddAlpha and 2Texture versions could be supported, but there are no Cap
|
||
|
flags for that. A complex use of lookup tables in textures might work for all cases,
|
||
|
but is not implemented.
|
||
|
|
||
|
*/
|
||
|
|
||
|
|
||
|
// ***** GTextureOGLImpl implementation
|
||
|
|
||
|
|
||
|
// GTextureOGLImpl declaration
|
||
|
class GTextureOGLImpl : public GTextureOGL
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
// Renderer
|
||
|
GRendererOGLImpl * pRenderer;
|
||
|
// GL texture id
|
||
|
GLuint TextureId;
|
||
|
GLenum TextureFmt, TextureData;
|
||
|
bool DeleteTexture;
|
||
|
#ifdef GFC_GL_NO_ALPHA_TEXTURES
|
||
|
bool IsAlpha;
|
||
|
#endif
|
||
|
SInt TexWidth, TexHeight;
|
||
|
GLubyte ** TexData;
|
||
|
SInt Mipmaps;
|
||
|
|
||
|
GTextureOGLImpl(GRendererOGLImpl *prenderer);
|
||
|
~GTextureOGLImpl();
|
||
|
|
||
|
// Obtains the renderer that create TextureInfo
|
||
|
virtual GRenderer* GetRenderer() const;
|
||
|
virtual bool IsDataValid() const;
|
||
|
|
||
|
// Creates a texture based on parameters
|
||
|
bool InitTextureAlpha(GImageBase* pim);
|
||
|
|
||
|
virtual bool InitTexture(UInt texID, bool deleteTexture);
|
||
|
virtual bool InitTexture(GImageBase* pim, UInt usage = Usage_Wrap);
|
||
|
virtual bool InitDynamicTexture(int width, int height, GImage::ImageFormat format, int mipmaps, UInt usage);
|
||
|
virtual void Update(int level, int n, const UpdateRect *rects, const GImageBase *pim);
|
||
|
|
||
|
virtual int Map(int level, int n, MapRect* maps, int flags);
|
||
|
virtual bool Unmap(int level, int n, MapRect* maps, int flags);
|
||
|
|
||
|
// Helper function
|
||
|
// Creates a texture id ans sets filter parameters
|
||
|
void InitTextureId(GLint minFilter);
|
||
|
// Releases texture and clears vals
|
||
|
virtual void ReleaseTextureId();
|
||
|
|
||
|
// Remove texture from renderer, notifies of renderer destruction
|
||
|
void RemoveFromRenderer();
|
||
|
|
||
|
virtual UInt GetNativeTexture() const { return TextureId; }
|
||
|
|
||
|
virtual int IsYUVTexture() { return 0; }
|
||
|
virtual void Bind(int stage, GRenderer::BitmapWrapMode WrapMode, GRenderer::BitmapSampleMode SampleMode, bool useMipmaps);
|
||
|
};
|
||
|
|
||
|
class GTextureOGLImplYUV : public GTextureOGLImpl
|
||
|
{
|
||
|
public:
|
||
|
GLuint TextureUVA[3];
|
||
|
|
||
|
GTextureOGLImplYUV(GRendererOGLImpl *prenderer) : GTextureOGLImpl(prenderer)
|
||
|
{ TextureUVA[0] = TextureUVA[1] = TextureUVA[2] = 0; }
|
||
|
~GTextureOGLImplYUV();
|
||
|
|
||
|
virtual bool InitTexture(UInt, SInt, SInt, bool) { return 0; }
|
||
|
virtual bool InitTexture(GImageBase*, UInt) { return 0; }
|
||
|
virtual void Update(int, int, const UpdateRect *, const GImageBase *) { }
|
||
|
|
||
|
virtual bool InitDynamicTexture(int width, int height, GImage::ImageFormat format, int mipmaps, UInt usage);
|
||
|
virtual int Map(int level, int n, MapRect* maps, int flags);
|
||
|
virtual bool Unmap(int level, int n, MapRect* maps, int flags);
|
||
|
|
||
|
virtual void ReleaseTextureId();
|
||
|
|
||
|
virtual int IsYUVTexture() { return TextureUVA[2] ? 2 : 1; }
|
||
|
virtual void Bind(int stage, GRenderer::BitmapWrapMode WrapMode, GRenderer::BitmapSampleMode SampleMode, bool useMipmaps);
|
||
|
};
|
||
|
|
||
|
|
||
|
#if (GFC_BYTE_ORDER == GFC_BIG_ENDIAN) && !defined(GFC_OS_PS3)
|
||
|
#define SWAPCOLOR(color) ((color >> 24) | ((color >> 8) & 0xff00) | ((color & 0xff00) << 8) | ((color & 0xff) << 24))
|
||
|
#else
|
||
|
#define SWAPCOLOR(color) color
|
||
|
#endif
|
||
|
|
||
|
// Vertex buffer structure used for glyphs.
|
||
|
struct GGlyphVertex
|
||
|
{
|
||
|
float x,y,z,w;
|
||
|
float u,v;
|
||
|
GColor color;
|
||
|
|
||
|
void SetVertex2D(float xx, float yy, float uu, float vv, GColor c)
|
||
|
{
|
||
|
x = xx; y = yy; u = uu; v = vv;
|
||
|
color.Raw = SWAPCOLOR(c.Raw);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
class GBufferNode : public GRendererNode, public GNewOverrideBase<GStat_Default_Mem>
|
||
|
{
|
||
|
public:
|
||
|
GLuint buffer;
|
||
|
GRenderer::CachedData *pcache;
|
||
|
|
||
|
GBufferNode() : GRendererNode() { buffer = 0; pcache = 0; }
|
||
|
GBufferNode(GBufferNode *p, GRenderer::CachedData *d) : GRendererNode(p) { buffer = 0; pcache = d; }
|
||
|
};
|
||
|
|
||
|
// ***** Renderer Implementation
|
||
|
|
||
|
|
||
|
class GRendererOGLImpl : public GRendererOGL
|
||
|
{
|
||
|
public:
|
||
|
// Some renderer state.
|
||
|
|
||
|
bool Initialized;
|
||
|
SInt RenderMode;
|
||
|
|
||
|
// Output size.
|
||
|
Float DisplayWidth;
|
||
|
Float DisplayHeight;
|
||
|
GRectF DisplayRect;
|
||
|
|
||
|
GRenderer::Matrix UserMatrix;
|
||
|
GRenderer::Matrix CurrentMatrix;
|
||
|
GRenderer::Cxform CurrentCxform;
|
||
|
|
||
|
#ifndef GFC_NO_3D
|
||
|
bool Is3DStateSet, IsProjMatrixSet;
|
||
|
GMatrix3D UserViewMatrix, ProjMatrix;
|
||
|
const GMatrix3D* pWorldMatrix;
|
||
|
#endif
|
||
|
|
||
|
// Link list of all allocated textures
|
||
|
GRendererNode Textures;
|
||
|
GLock TexturesLock;
|
||
|
|
||
|
// Statistics
|
||
|
Stats RenderStats;
|
||
|
// Video memory
|
||
|
GMemoryStat TextureVMem;
|
||
|
GMemoryStat BufferVMem;
|
||
|
// Counts
|
||
|
GCounterStat TextureUploadCnt;
|
||
|
GCounterStat TextureUpdateCnt;
|
||
|
GCounterStat DPLineCnt;
|
||
|
GCounterStat DPTriangleCnt;
|
||
|
GCounterStat LineCnt;
|
||
|
GCounterStat TriangleCnt;
|
||
|
GCounterStat MaskCnt;
|
||
|
GCounterStat FilterCnt;
|
||
|
|
||
|
// Vertex data pointer
|
||
|
GBufferNode BufferObjects;
|
||
|
const void* pVertexData;
|
||
|
const void* pIndexData;
|
||
|
GLuint VertexArray, IndexArray;
|
||
|
VertexFormat VertexFmt;
|
||
|
GLenum IndexFmt;
|
||
|
|
||
|
// Stencil counter - for increment/decrement compares.
|
||
|
SInt StencilCounter;
|
||
|
bool DrawingMask;
|
||
|
|
||
|
// Current sample mode
|
||
|
BitmapSampleMode SampleMode;
|
||
|
|
||
|
typedef GArrayConstPolicy<0, 4, true> NeverShrinkPolicy;
|
||
|
typedef GArrayLH<BlendType, GStat_Default_Mem, NeverShrinkPolicy> BlendModeStackType;
|
||
|
|
||
|
// Current blend mode
|
||
|
BlendType BlendMode;
|
||
|
BlendModeStackType BlendModeStack;
|
||
|
|
||
|
// Buffer used to pass along glyph vertices
|
||
|
enum { GlyphVertexBufferSize = 6 * 48 };
|
||
|
GGlyphVertex GlyphVertexBuffer[GlyphVertexBufferSize];
|
||
|
|
||
|
// Linked list used for buffer cache testing, otherwise holds no data.
|
||
|
CacheNode CacheList;
|
||
|
|
||
|
SInt CurrentShader;
|
||
|
|
||
|
GLint MaxTexUnits;
|
||
|
bool UseCombine, UseBuffers, UseAcBlend;
|
||
|
bool UseShaders;
|
||
|
SInt TexNonPower2;
|
||
|
|
||
|
#ifdef GFC_GL_RUNTIME_LINK
|
||
|
// Extensions
|
||
|
PFNGLBLENDEQUATIONPROC p_glBlendEquation;
|
||
|
PFNGLBLENDFUNCSEPARATEPROC p_glBlendFuncSeparate;
|
||
|
PFNGLDRAWRANGEELEMENTSPROC p_glDrawRangeElements;
|
||
|
PFNGLMULTITEXCOORD4FVPROC p_glMultiTexCoord4fv;
|
||
|
PFNGLCLIENTACTIVETEXTUREPROC p_glClientActiveTexture;
|
||
|
PFNGLACTIVETEXTUREPROC p_glActiveTexture;
|
||
|
PFNGLENABLEVERTEXATTRIBARRAYPROC p_glEnableVertexAttribArray;
|
||
|
PFNGLDISABLEVERTEXATTRIBARRAYPROC p_glDisableVertexAttribArray;
|
||
|
PFNGLVERTEXATTRIBPOINTERPROC p_glVertexAttribPointer;
|
||
|
PFNGLVERTEXATTRIB4FPROC p_glVertexAttrib4f;
|
||
|
PFNGLDELETEOBJECTARBPROC p_glDeleteObjectARB;
|
||
|
PFNGLCREATESHADEROBJECTARBPROC p_glCreateShaderObjectARB;
|
||
|
PFNGLSHADERSOURCEARBPROC p_glShaderSourceARB;
|
||
|
PFNGLCOMPILESHADERARBPROC p_glCompileShaderARB;
|
||
|
PFNGLCREATEPROGRAMOBJECTARBPROC p_glCreateProgramObjectARB;
|
||
|
PFNGLATTACHOBJECTARBPROC p_glAttachObjectARB;
|
||
|
PFNGLLINKPROGRAMARBPROC p_glLinkProgramARB;
|
||
|
PFNGLUSEPROGRAMOBJECTARBPROC p_glUseProgramObjectARB;
|
||
|
PFNGLGETOBJECTPARAMETERIVARBPROC p_glGetObjectParameterivARB;
|
||
|
PFNGLGETINFOLOGARBPROC p_glGetInfoLogARB;
|
||
|
PFNGLGETUNIFORMLOCATIONARBPROC p_glGetUniformLocationARB;
|
||
|
PFNGLUNIFORM4FARBPROC p_glUniform4fARB;
|
||
|
PFNGLUNIFORM1IARBPROC p_glUniform1iARB;
|
||
|
|
||
|
PFNGLGENPROGRAMSARBPROC p_glGenProgramsARB;
|
||
|
PFNGLDELETEPROGRAMSARBPROC p_glDeleteProgramsARB;
|
||
|
PFNGLPROGRAMSTRINGARBPROC p_glProgramStringARB;
|
||
|
PFNGLBINDPROGRAMARBPROC p_glBindProgramARB;
|
||
|
PFNGLPROGRAMENVPARAMETER4DARBPROC p_glProgramLocalParameter4dARB;
|
||
|
PFNGLGENBUFFERSARBPROC p_glGenBuffers;
|
||
|
PFNGLDELETEBUFFERSARBPROC p_glDeleteBuffers;
|
||
|
PFNGLBINDBUFFERARBPROC p_glBindBuffer;
|
||
|
PFNGLBUFFERDATAARBPROC p_glBufferData;
|
||
|
|
||
|
PFNGLCOMPRESSEDTEXIMAGE2DPROC p_glCompressedTexImage2D;
|
||
|
|
||
|
void glBlendEquation (GLenum e) const { if (p_glBlendEquation) p_glBlendEquation (e); }
|
||
|
void glBlendFuncSeparate (GLenum sc, GLenum dc, GLenum sa, GLenum da) const
|
||
|
{
|
||
|
if (p_glBlendFuncSeparate)
|
||
|
p_glBlendFuncSeparate (sc,dc,sa,da);
|
||
|
else
|
||
|
::glBlendFunc (sc, dc);
|
||
|
}
|
||
|
void glDrawRangeElements (GLenum p, GLuint s, GLuint e, GLsizei c, GLenum t, const void *a) const
|
||
|
{
|
||
|
// Disabled because some drivers crash (rarely) when it is used
|
||
|
|
||
|
//if (p_glDrawRangeElements) p_glDrawRangeElements(p,s,e,c,t,a);
|
||
|
//else
|
||
|
glDrawElements(p,c,t,a);
|
||
|
GUNUSED2(s,e);
|
||
|
}
|
||
|
void glMultiTexCoord4fv(GLenum e, const GLfloat *v) const { p_glMultiTexCoord4fv(e,v); }
|
||
|
void glActiveTexture(GLenum e) const { if (p_glActiveTexture) p_glActiveTexture(e); }
|
||
|
void glClientActiveTexture(GLenum e) const { if (p_glClientActiveTexture) p_glClientActiveTexture(e); }
|
||
|
void glEnableVertexAttribArrayARB(GLuint i) const { if (p_glEnableVertexAttribArray) p_glEnableVertexAttribArray(i); }
|
||
|
void glDisableVertexAttribArrayARB(GLuint i) const { if (p_glDisableVertexAttribArray) p_glDisableVertexAttribArray(i); }
|
||
|
void glVertexAttribPointerARB(GLuint i, GLint c, GLenum t, GLboolean n, GLsizei s, const GLvoid *a) const
|
||
|
{
|
||
|
if (p_glVertexAttribPointer)
|
||
|
p_glVertexAttribPointer(i,c,t,n,s,a);
|
||
|
}
|
||
|
void glVertexAttrib4fARB(GLuint i, GLfloat a, GLfloat b, GLfloat c, GLfloat d) { p_glVertexAttrib4f(i,a,b,c,d); }
|
||
|
void glDeleteObjectARB (GLhandleARB o) const { if (p_glDeleteObjectARB) p_glDeleteObjectARB(o); }
|
||
|
|
||
|
GLhandleARB glCreateShaderObjectARB (GLenum t) const { if (p_glCreateShaderObjectARB) return p_glCreateShaderObjectARB(t); }
|
||
|
void glShaderSourceARB (GLhandleARB s, GLsizei n, const GLcharARB* *t, const GLint *l) const { p_glShaderSourceARB(s,n,t,l); }
|
||
|
|
||
|
void glCompileShaderARB (GLhandleARB s) const { p_glCompileShaderARB(s); }
|
||
|
GLhandleARB glCreateProgramObjectARB (void) const { if (p_glCreateProgramObjectARB) return p_glCreateProgramObjectARB(); }
|
||
|
void glAttachObjectARB (GLhandleARB o, GLhandleARB s) const { p_glAttachObjectARB(o,s); }
|
||
|
void glLinkProgramARB (GLhandleARB o) const { p_glLinkProgramARB(o); }
|
||
|
void glUseProgramObjectARB (GLhandleARB o) const { if (p_glUseProgramObjectARB) p_glUseProgramObjectARB(o); }
|
||
|
void glGetObjectParameterivARB (GLhandleARB o, GLenum e, GLint *v) const { p_glGetObjectParameterivARB(o,e,v); }
|
||
|
void glGetInfoLogARB (GLhandleARB o, GLsizei m, GLsizei *l, GLcharARB *t) const
|
||
|
{
|
||
|
if (p_glGetInfoLogARB)
|
||
|
p_glGetInfoLogARB (o,m,l,t);
|
||
|
}
|
||
|
|
||
|
GLint glGetUniformLocationARB (GLhandleARB o, const GLcharARB *n) const { return p_glGetUniformLocationARB(o,n); }
|
||
|
void glUniform4fARB (GLint i, GLfloat a, GLfloat b, GLfloat c, GLfloat d) const { p_glUniform4fARB(i,a,b,c,d); }
|
||
|
void glUniform1iARB (GLint i, GLint a) const { p_glUniform1iARB(i,a); }
|
||
|
|
||
|
void glProgramStringARB (GLenum t, GLenum f, GLsizei l, const GLvoid *s) const { p_glProgramStringARB(t,f,l,s); }
|
||
|
void glBindProgramARB (GLenum t, GLuint o) const { p_glBindProgramARB(t,o); }
|
||
|
void glDeleteProgramsARB (GLsizei n, const GLuint *o) const { p_glDeleteProgramsARB(n,o); }
|
||
|
void glGenProgramsARB (GLsizei n, GLuint *o) const { p_glGenProgramsARB(n,o); }
|
||
|
void glProgramLocalParameter4dARB (GLenum t, GLuint i, GLdouble x, GLdouble y, GLdouble z, GLdouble w) const
|
||
|
{
|
||
|
p_glProgramLocalParameter4dARB(t, i, x,y,z,w);
|
||
|
}
|
||
|
void glGenBuffers(GLsizei n, GLuint *o) { p_glGenBuffers(n,o); }
|
||
|
void glDeleteBuffers(GLsizei n, GLuint *o) { p_glDeleteBuffers(n,o); }
|
||
|
void glBindBuffer(GLenum t, GLuint b) { if (p_glBindBuffer) p_glBindBuffer(t,b); }
|
||
|
void glBufferData(GLenum t, GLsizeiptr s, const GLvoid *p, GLenum u) { p_glBufferData(t,s,p,u);}
|
||
|
|
||
|
void glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data)
|
||
|
{
|
||
|
if (p_glCompressedTexImage2D)
|
||
|
p_glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data);
|
||
|
else
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(1, "GRendererOGL texture creation failed - glCompressedTexImage2D ext not available");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
void glBlendEquation (GLenum e) const
|
||
|
{
|
||
|
#ifdef GL_VERSION_ES_CM_1_0
|
||
|
#ifdef GL_OES_blend_subtract
|
||
|
::glBlendEquationOES (e);
|
||
|
#endif
|
||
|
#else
|
||
|
::glBlendEquation (e);
|
||
|
#endif
|
||
|
}
|
||
|
void glActiveTexture(GLenum e) const { ::glActiveTexture(e); }
|
||
|
|
||
|
#ifndef GFC_OS_PS3
|
||
|
void glDrawRangeElements (GLenum p, GLuint s, GLuint e, GLsizei c, GLenum t, const void *a) const
|
||
|
{
|
||
|
glDrawElements(p,c,t,a);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
void glBlendFuncSeparate (GLenum sc, GLenum dc, GLenum sa, GLenum da) const
|
||
|
{
|
||
|
#ifdef GL_ARB_blend_func_separate
|
||
|
::glBlendFuncSeparate(sc,dc,sa,da);
|
||
|
#else
|
||
|
glBlendFunc(sc,dc);
|
||
|
#endif
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// all OGL calls should be done on the main thread, but textures can be released from
|
||
|
// different threads so we collect system resources and release them on the main thread
|
||
|
GArrayLH<GLuint> ResourceReleasingQueue;
|
||
|
GLock ResourceReleasingQueueLock;
|
||
|
|
||
|
// this method is called from GTextureXXX destructor to put a system resource into releasing queue
|
||
|
void AddResourceForReleasing(GLuint textureId)
|
||
|
{
|
||
|
if (textureId == 0) return;
|
||
|
GLock::Locker guard(&ResourceReleasingQueueLock);
|
||
|
ResourceReleasingQueue.PushBack(textureId);
|
||
|
}
|
||
|
|
||
|
// this method is called from GetTexture, EndDisplay and destructor to actually release
|
||
|
// collected system resources
|
||
|
void ReleaseQueuedResources()
|
||
|
{
|
||
|
GLock::Locker guard(&ResourceReleasingQueueLock);
|
||
|
for (UInt i = 0; i < ResourceReleasingQueue.GetSize(); ++i)
|
||
|
glDeleteTextures(1, &ResourceReleasingQueue[i]);
|
||
|
ResourceReleasingQueue.Clear();
|
||
|
}
|
||
|
|
||
|
// ****
|
||
|
|
||
|
GRendererOGLImpl()
|
||
|
{
|
||
|
Initialized = 0;
|
||
|
|
||
|
SampleMode = Sample_Linear;
|
||
|
RenderMode = 0;
|
||
|
pVertexData = 0;
|
||
|
pIndexData = 0;
|
||
|
VertexFmt = Vertex_None;
|
||
|
IndexFmt = GL_UNSIGNED_SHORT;
|
||
|
|
||
|
#ifndef GFC_NO_3D
|
||
|
pWorldMatrix = 0;
|
||
|
Is3DStateSet = 0;
|
||
|
#endif
|
||
|
|
||
|
StencilCounter = 0;
|
||
|
|
||
|
// Glyph buffer z, w components are always 0 and 1.
|
||
|
UInt i;
|
||
|
for(i = 0; i < GlyphVertexBufferSize; i++)
|
||
|
{
|
||
|
GlyphVertexBuffer[i].z = 0.0f;
|
||
|
GlyphVertexBuffer[i].w = 1.0f;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
~GRendererOGLImpl()
|
||
|
{
|
||
|
Clear();
|
||
|
}
|
||
|
|
||
|
void Clear()
|
||
|
{
|
||
|
// Remove/notify all textures
|
||
|
{
|
||
|
GLock::Locker guard(&TexturesLock);
|
||
|
while (Textures.pFirst != &Textures)
|
||
|
((GTextureOGLImpl*)Textures.pFirst)->RemoveFromRenderer();
|
||
|
}
|
||
|
|
||
|
CacheList.ReleaseList();
|
||
|
|
||
|
for (GRendererNode *p = BufferObjects.pFirst; p; )
|
||
|
{
|
||
|
GBufferNode *pn = (GBufferNode*)p;
|
||
|
#ifdef GL_ARB_vertex_buffer_object
|
||
|
if (pn->buffer)
|
||
|
glDeleteBuffers(1, &pn->buffer);
|
||
|
#endif
|
||
|
if (pn->pcache)
|
||
|
pn->pcache->ReleaseDataByRenderer();
|
||
|
p = p->pNext;
|
||
|
if (p == BufferObjects.pLast)
|
||
|
p->pNext = 0;
|
||
|
if (pn != &BufferObjects)
|
||
|
delete pn;
|
||
|
}
|
||
|
BufferObjects.pFirst = NULL;
|
||
|
ReleaseQueuedResources();
|
||
|
}
|
||
|
|
||
|
void ReleaseResources()
|
||
|
{
|
||
|
Clear();
|
||
|
}
|
||
|
|
||
|
|
||
|
// Utility. Mutates *width, *height and *data to create the
|
||
|
// next mip level.
|
||
|
static void MakeNextMiplevel(int* width, int* height, UByte* data, GLenum format = GL_ALPHA)
|
||
|
{
|
||
|
GASSERT(width);
|
||
|
GASSERT(height);
|
||
|
GASSERT(data);
|
||
|
GASSERT_ON_RENDERER_MIPMAP_GEN;
|
||
|
|
||
|
int newW = *width >> 1;
|
||
|
int newH = *height >> 1;
|
||
|
if (newW < 1) newW = 1;
|
||
|
if (newH < 1) newH = 1;
|
||
|
|
||
|
if (newW * 2 != *width || newH * 2 != *height)
|
||
|
{
|
||
|
// Image can not be shrunk Along (at least) one
|
||
|
// of its dimensions, so no need to do
|
||
|
// resampling. Technically we should, but
|
||
|
// it's pretty useless at this point. Just
|
||
|
// change the image dimensions and leave the
|
||
|
// existing pixels.
|
||
|
}
|
||
|
else if (format == GL_ALPHA || format == GL_LUMINANCE)
|
||
|
{
|
||
|
// Resample. Simple average 2x2 --> 1, in-place.
|
||
|
for (int j = 0; j < newH; j++)
|
||
|
{
|
||
|
UByte* out = ((UByte*) data) + j * newW;
|
||
|
UByte* in = ((UByte*) data) + (j << 1) * *width;
|
||
|
for (int i = 0; i < newW; i++)
|
||
|
{
|
||
|
int a = (*(in + 0) + *(in + 1) + *(in + 0 + *width) + *(in + 1 + *width));
|
||
|
*(out) = UByte(a >> 2);
|
||
|
out++;
|
||
|
in += 2;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Resample. Simple average 2x2 --> 1, in-place.
|
||
|
for (int j = 0; j < newH; j++)
|
||
|
{
|
||
|
UByte* out = ((UByte*) data) + j * (4 * newW);
|
||
|
UByte* in = ((UByte*) data) + (j << 1) * (4 * *width);
|
||
|
for (int i = 0; i < newW; i++)
|
||
|
{
|
||
|
int r,g,b,a;
|
||
|
r = ( *(in + 0) + *(in + 4) + *(in + 0 + (*width * 4)) + *(in + 4 + (*width * 4)) );
|
||
|
g = ( *(in + 1) + *(in + 5) + *(in + 1 + (*width * 4)) + *(in + 5 + (*width * 4)) );
|
||
|
b = ( *(in + 2) + *(in + 6) + *(in + 2 + (*width * 4)) + *(in + 6 + (*width * 4)) );
|
||
|
a = ( *(in + 3) + *(in + 7) + *(in + 3 + (*width * 4)) + *(in + 7 + (*width * 4)) );
|
||
|
out[0] = UByte(r >> 2);
|
||
|
out[1] = UByte(g >> 2);
|
||
|
out[2] = UByte(b >> 2);
|
||
|
out[3] = UByte(a >> 2);
|
||
|
out += 4;
|
||
|
in += 8;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Set parameters to reflect the new size
|
||
|
*width = newW;
|
||
|
*height = newH;
|
||
|
}
|
||
|
|
||
|
virtual void DisableShaders () { }
|
||
|
virtual void SetPixelShader (PixelShaderType ps, SInt pass = 0) { GUNUSED2(ps,pass); }
|
||
|
virtual void ApplyPShaderCxform(const Cxform &cxform) const { GUNUSED(cxform); }
|
||
|
virtual bool SetVertexProgram (VertexFormat vf, SInt numtex) { GUNUSED2(vf,numtex); return 0; }
|
||
|
virtual void SetVertexProgState () { }
|
||
|
virtual void SetTexgenState (SInt stageIndex, const FillTexture& fill) { GUNUSED2(stageIndex,fill); }
|
||
|
virtual void VertexAttribArray (SInt attr, GLint size, GLenum type, GLboolean norm, GLsizei stride, GLvoid* array)
|
||
|
{
|
||
|
#ifdef GL_VERSION_ES_1_1
|
||
|
glClientActiveTexture(GL_TEXTURE1);
|
||
|
|
||
|
#else
|
||
|
GUNUSED4(attr,size,type,norm); GUNUSED2(stride,array);
|
||
|
#endif
|
||
|
}
|
||
|
virtual void DisableVertexAttribArrays () { }
|
||
|
|
||
|
// Fill helper function:
|
||
|
// Applies fill texture by setting it to the specified stage, initializing samplers and vertex constants
|
||
|
virtual void ApplyFillTexture(const FillTexture &fill, UInt stageIndex, bool useVS = 0)
|
||
|
{
|
||
|
GASSERT (fill.pTexture != 0);
|
||
|
if (fill.pTexture == 0) return; // avoid crash in release build
|
||
|
|
||
|
GTextureOGLImpl* ptexture = ((GTextureOGLImpl*)fill.pTexture);
|
||
|
|
||
|
ptexture->Bind(stageIndex, fill.WrapMode, fill.SampleMode, 1);
|
||
|
|
||
|
if (useVS)
|
||
|
SetTexgenState (stageIndex, fill);
|
||
|
else
|
||
|
{
|
||
|
// Set up the bitmap GRenderer::Matrix for texgen.
|
||
|
const GRenderer::Matrix& m = fill.TextureMatrix;
|
||
|
|
||
|
#ifndef GFC_GL_NO_TEXGEN
|
||
|
Float p[4] = { 0, 0, 0, 0 };
|
||
|
|
||
|
glEnable(GL_TEXTURE_GEN_S);
|
||
|
glEnable(GL_TEXTURE_GEN_T);
|
||
|
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
|
||
|
p[0] = m.M_[0][0];
|
||
|
p[1] = m.M_[0][1];
|
||
|
p[3] = m.M_[0][2];
|
||
|
glTexGenfv(GL_S, GL_OBJECT_PLANE, p);
|
||
|
|
||
|
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
|
||
|
p[0] = m.M_[1][0];
|
||
|
p[1] = m.M_[1][1];
|
||
|
p[3] = m.M_[1][2];
|
||
|
glTexGenfv(GL_T, GL_OBJECT_PLANE, p);
|
||
|
#else
|
||
|
// Use position as texcoord, then transform with texture matrix.
|
||
|
Float tm[16];
|
||
|
|
||
|
tm[0] = m.M_[0][0];
|
||
|
tm[4] = m.M_[0][1];
|
||
|
tm[8] = 0.0f;
|
||
|
tm[12] = m.M_[0][2];
|
||
|
|
||
|
tm[1] = m.M_[1][0];
|
||
|
tm[5] = m.M_[1][1];
|
||
|
tm[9] = 0.0f;
|
||
|
tm[13] = m.M_[1][2];
|
||
|
|
||
|
tm[2] = tm[3] = tm[6] = tm[7] = tm[11] = tm[14] = 0.0f;
|
||
|
tm[10] = tm[15] = 1.0f;
|
||
|
|
||
|
glMatrixMode(GL_TEXTURE);
|
||
|
glLoadMatrixf(tm);
|
||
|
glMatrixMode(GL_MODELVIEW);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
glActiveTexture(GL_TEXTURE0);
|
||
|
}
|
||
|
|
||
|
class GFxFillStyle
|
||
|
{
|
||
|
public:
|
||
|
enum FillMode
|
||
|
{
|
||
|
FM_None,
|
||
|
FM_Color,
|
||
|
FM_Bitmap,
|
||
|
FM_Gouraud
|
||
|
};
|
||
|
|
||
|
FillMode Mode;
|
||
|
GouraudFillType GouraudType;
|
||
|
GColor Color;
|
||
|
FillTexture Fill, Fill2;
|
||
|
|
||
|
GRenderer::Cxform BitmapColorTransform;
|
||
|
bool HasNonzeroAdditiveCxform, HasMultiplyCxform;
|
||
|
|
||
|
GFxFillStyle()
|
||
|
{
|
||
|
Mode = FM_None;
|
||
|
GouraudType = GFill_Color;
|
||
|
Fill.pTexture = 0;
|
||
|
Fill2.pTexture = 0;
|
||
|
HasNonzeroAdditiveCxform = false;
|
||
|
}
|
||
|
|
||
|
// Push our style into OpenGL.
|
||
|
void Apply(GRendererOGLImpl *prenderer) const
|
||
|
{
|
||
|
GASSERT(Mode != FM_None);
|
||
|
|
||
|
prenderer->DisableShaders();
|
||
|
|
||
|
if (prenderer->MaxTexUnits)
|
||
|
{
|
||
|
prenderer->glActiveTexture(GL_TEXTURE1);
|
||
|
glDisable(GL_TEXTURE_2D);
|
||
|
if (prenderer->MaxTexUnits >= 4)
|
||
|
{
|
||
|
prenderer->glActiveTexture(GL_TEXTURE2);
|
||
|
glDisable(GL_TEXTURE_2D);
|
||
|
prenderer->glActiveTexture(GL_TEXTURE3);
|
||
|
glDisable(GL_TEXTURE_2D);
|
||
|
}
|
||
|
prenderer->glActiveTexture(GL_TEXTURE0);
|
||
|
}
|
||
|
|
||
|
if (Mode == FM_Color)
|
||
|
{
|
||
|
prenderer->ApplyColor(Color, (prenderer->UseAcBlend == 0) && (prenderer->RenderMode & GViewport::View_AlphaComposite));
|
||
|
|
||
|
if ((Color.GetAlpha() == 0xFF) && (prenderer->BlendMode <= Blend_Normal))
|
||
|
glDisable(GL_BLEND);
|
||
|
else
|
||
|
glEnable(GL_BLEND);
|
||
|
|
||
|
glDisable(GL_TEXTURE_2D);
|
||
|
}
|
||
|
else if (Mode == FM_Bitmap)
|
||
|
{
|
||
|
if (Fill.pTexture == NULL)
|
||
|
{
|
||
|
glDisable(GL_TEXTURE_2D);
|
||
|
|
||
|
if ((Color.GetAlpha() == 0xFF) && (prenderer->BlendMode <= Blend_Normal))
|
||
|
glDisable(GL_BLEND);
|
||
|
else
|
||
|
glEnable(GL_BLEND);
|
||
|
|
||
|
prenderer->ApplyColor(Color, (prenderer->UseAcBlend == 0) && (prenderer->RenderMode & GViewport::View_AlphaComposite));
|
||
|
}
|
||
|
else if (prenderer->UseShaders)
|
||
|
{
|
||
|
glEnable(GL_BLEND);
|
||
|
|
||
|
if (prenderer->BlendMode == Blend_Multiply || prenderer->BlendMode == Blend_Darken)
|
||
|
prenderer->SetPixelShader(PS_CxformTextureMultiply);
|
||
|
else
|
||
|
prenderer->SetPixelShader(PS_CxformTexture);
|
||
|
|
||
|
prenderer->ApplyFillTexture(Fill, 0);
|
||
|
prenderer->ApplyPShaderCxform(BitmapColorTransform);
|
||
|
}
|
||
|
#ifdef GL_ARB_texture_env_combine
|
||
|
else if (prenderer->MaxTexUnits >= 2 && prenderer->UseCombine)
|
||
|
{
|
||
|
glEnable(GL_BLEND);
|
||
|
prenderer->ApplyFillTexture(Fill, 0);
|
||
|
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||
|
glColor4f(BitmapColorTransform.M_[0][0],
|
||
|
BitmapColorTransform.M_[1][0],
|
||
|
BitmapColorTransform.M_[2][0],
|
||
|
BitmapColorTransform.M_[3][0]);
|
||
|
|
||
|
Float sca[4] = {
|
||
|
BitmapColorTransform.M_[0][1] / 255.0f,
|
||
|
BitmapColorTransform.M_[1][1] / 255.0f,
|
||
|
BitmapColorTransform.M_[2][1] / 255.0f,
|
||
|
BitmapColorTransform.M_[3][1] / 255.0f };
|
||
|
|
||
|
if (((prenderer->RenderMode & GViewport::View_AlphaComposite) ||
|
||
|
prenderer->BlendMode == Blend_Multiply || prenderer->BlendMode == Blend_Darken)
|
||
|
&& prenderer->MaxTexUnits >= 3)
|
||
|
{
|
||
|
prenderer->glActiveTexture(GL_TEXTURE2);
|
||
|
glEnable(GL_TEXTURE_2D);
|
||
|
glBindTexture(GL_TEXTURE_2D, ((GTextureOGLImpl*)Fill.pTexture)->TextureId);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_PREVIOUS);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
|
||
|
#ifdef GFC_GL_NO_STAGE_CONSTANTS
|
||
|
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, sca);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
prenderer->glActiveTexture(GL_TEXTURE1);
|
||
|
glEnable(GL_TEXTURE_2D);
|
||
|
glBindTexture(GL_TEXTURE_2D, ((GTextureOGLImpl*)Fill.pTexture)->TextureId);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_ADD);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_CONSTANT);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
|
||
|
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, sca);
|
||
|
prenderer->glActiveTexture(GL_TEXTURE0);
|
||
|
}
|
||
|
#endif
|
||
|
else // modulate part of transform (add in second pass with combine and <2 tex units only)
|
||
|
{
|
||
|
glEnable(GL_BLEND);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||
|
prenderer->ApplyFillTexture(Fill, 0);
|
||
|
|
||
|
glColor4f(BitmapColorTransform.M_[0][0],
|
||
|
BitmapColorTransform.M_[1][0],
|
||
|
BitmapColorTransform.M_[2][0],
|
||
|
BitmapColorTransform.M_[3][0]);
|
||
|
}
|
||
|
}
|
||
|
else if (Mode == FM_Gouraud)
|
||
|
{
|
||
|
if (!prenderer->UseShaders)
|
||
|
{
|
||
|
#ifdef GL_ARB_texture_env_combine
|
||
|
GASSERT(Fill.pTexture == NULL);
|
||
|
GTextureOGLImpl *pDummyTex = NULL;
|
||
|
if (prenderer->Textures.pFirst)
|
||
|
pDummyTex = (GTextureOGLImpl*)prenderer->Textures.pFirst;
|
||
|
|
||
|
glEnable(GL_BLEND);
|
||
|
int stage;
|
||
|
|
||
|
if (HasNonzeroAdditiveCxform)
|
||
|
{
|
||
|
stage = HasMultiplyCxform ? 1 : 0;
|
||
|
}
|
||
|
else
|
||
|
stage = 0;
|
||
|
|
||
|
if (prenderer->VertexFmt == Vertex_XY16iCF32)
|
||
|
{
|
||
|
GASSERT(0);
|
||
|
}
|
||
|
|
||
|
#ifdef GFC_GL_NO_STAGE_CONSTANTS
|
||
|
if (stage)
|
||
|
stage--;
|
||
|
else
|
||
|
#endif
|
||
|
if (HasNonzeroAdditiveCxform)
|
||
|
{
|
||
|
// cxform add
|
||
|
Float sca[4] = {
|
||
|
BitmapColorTransform.M_[0][1] / 255.0f,
|
||
|
BitmapColorTransform.M_[1][1] / 255.0f,
|
||
|
BitmapColorTransform.M_[2][1] / 255.0f,
|
||
|
BitmapColorTransform.M_[3][1] / 255.0f };
|
||
|
|
||
|
prenderer->glActiveTexture(GL_TEXTURE0 + stage);
|
||
|
glEnable(GL_TEXTURE_2D);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_ADD);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_CONSTANT);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
|
||
|
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, sca);
|
||
|
stage--;
|
||
|
prenderer->glActiveTexture(GL_TEXTURE0 + stage);
|
||
|
}
|
||
|
|
||
|
GASSERT(stage == 0);
|
||
|
if (HasMultiplyCxform)
|
||
|
{
|
||
|
// cxform multiply
|
||
|
Float scm[4] = {
|
||
|
BitmapColorTransform.M_[0][0],
|
||
|
BitmapColorTransform.M_[1][0],
|
||
|
BitmapColorTransform.M_[2][0],
|
||
|
BitmapColorTransform.M_[3][0] };
|
||
|
|
||
|
glEnable(GL_TEXTURE_2D);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PRIMARY_COLOR);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PRIMARY_COLOR);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_CONSTANT);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
|
||
|
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, scm);
|
||
|
}
|
||
|
else if (!HasNonzeroAdditiveCxform)
|
||
|
{
|
||
|
glDisable(GL_TEXTURE_2D);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||
|
}
|
||
|
#endif
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
PixelShaderType shader = PS_None;
|
||
|
bool useVS = prenderer->SetVertexProgram(prenderer->VertexFmt,
|
||
|
GouraudType == GFill_2Texture || GouraudType == GFill_2TextureColor ? 2 : 1);
|
||
|
|
||
|
// No texture: generate color-shaded triangles.
|
||
|
if (Fill.pTexture == NULL)
|
||
|
{
|
||
|
glEnable(GL_BLEND);
|
||
|
|
||
|
if (prenderer->VertexFmt == Vertex_XY16iC32)
|
||
|
{
|
||
|
// Cxform Alpha Add can not be non-zero is this state because
|
||
|
// cxform blend equations can not work correctly.
|
||
|
// If we hit this assert, it means Vertex_XY16iCF32 should have been used.
|
||
|
//GASSERT (BitmapColorTransform.M_[3][1] < 1.0f);
|
||
|
|
||
|
shader = PS_CxformGouraudNoAddAlpha;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
shader = PS_CxformGouraud;
|
||
|
}
|
||
|
}
|
||
|
// We have a textured or multi-textured gouraud case.
|
||
|
else
|
||
|
{
|
||
|
glEnable(GL_BLEND);
|
||
|
|
||
|
if ((GouraudType == GFill_1TextureColor) ||
|
||
|
(GouraudType == GFill_1Texture))
|
||
|
{
|
||
|
shader = PS_CxformGouraudTexture;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
shader = PS_Cxform2Texture;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ((prenderer->BlendMode == Blend_Multiply) ||
|
||
|
(prenderer->BlendMode == Blend_Darken) )
|
||
|
{
|
||
|
shader = (PixelShaderType)(shader + (PS_CxformGouraudMultiply - PS_CxformGouraud));
|
||
|
|
||
|
// For indexing to work, these should hold:
|
||
|
GCOMPILER_ASSERT( (PS_Cxform2Texture - PS_CxformGouraud) ==
|
||
|
(PS_CxformMultiply2Texture - PS_CxformGouraudMultiply));
|
||
|
GCOMPILER_ASSERT( (PS_CxformGouraudMultiply - PS_CxformGouraud) ==
|
||
|
(PS_Cxform2Texture - PS_CxformGouraud + 1) );
|
||
|
}
|
||
|
prenderer->SetPixelShader(shader);
|
||
|
prenderer->ApplyPShaderCxform(BitmapColorTransform);
|
||
|
|
||
|
if (Fill.pTexture)
|
||
|
{
|
||
|
prenderer->ApplyFillTexture(Fill, 0, useVS);
|
||
|
if (useVS) prenderer->SetTexgenState (0, Fill);
|
||
|
|
||
|
if (Fill2.pTexture &&
|
||
|
((GouraudType == GFill_2TextureColor) ||
|
||
|
(GouraudType == GFill_2Texture)))
|
||
|
{
|
||
|
prenderer->ApplyFillTexture(Fill2, 1, useVS);
|
||
|
if (useVS) prenderer->SetTexgenState (1, Fill2);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Return true if we need to do a second pass to make
|
||
|
// a valid color.
|
||
|
bool NeedsSecondPass(GRendererOGLImpl *prenderer) const
|
||
|
{
|
||
|
if (Mode == FM_Bitmap && prenderer->UseCombine && prenderer->MaxTexUnits < 2)
|
||
|
{
|
||
|
return HasNonzeroAdditiveCxform;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Set OpenGL state for a necessary second pass.
|
||
|
void ApplySecondPass() const
|
||
|
{
|
||
|
// The additive color also seems to be modulated by the texture. So,
|
||
|
// maybe we can fake this in one pass using using the mean value of
|
||
|
// the colors: c0*t+c1*t = ((c0+c1)/2) * t*2
|
||
|
// not sure what the alpha component of the color is for.
|
||
|
|
||
|
#ifdef GL_ARB_texture_env_combine
|
||
|
glEnable(GL_BLEND);
|
||
|
|
||
|
glColor4f(
|
||
|
BitmapColorTransform.M_[0][1] / 255.0f,
|
||
|
BitmapColorTransform.M_[1][1] / 255.0f,
|
||
|
BitmapColorTransform.M_[2][1] / 255.0f,
|
||
|
BitmapColorTransform.M_[3][1] / 255.0f
|
||
|
);
|
||
|
|
||
|
glEnable(GL_TEXTURE_2D);
|
||
|
|
||
|
// Alpha needs to come from texture.
|
||
|
// Add-color needs to come from above.
|
||
|
// Need to use COMBINE functions (GL 1.4 +).
|
||
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); // not GL_MODULATE
|
||
|
glTexEnvf(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PRIMARY_COLOR);
|
||
|
glTexEnvf(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
|
||
|
glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
|
||
|
glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
|
||
|
|
||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void CleanupSecondPass(GRendererOGLImpl *pRenderer) const
|
||
|
{
|
||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||
|
pRenderer->glBlendEquation(GL_FUNC_ADD);
|
||
|
|
||
|
// Restore modulate.
|
||
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||
|
}
|
||
|
|
||
|
|
||
|
void Disable() { Mode = FM_None; Fill.pTexture = 0; }
|
||
|
|
||
|
void SetColor(GColor color) { Mode = FM_Color; Color = color; }
|
||
|
|
||
|
void SetCxform(const Cxform& colorTransform)
|
||
|
{
|
||
|
BitmapColorTransform = colorTransform;
|
||
|
|
||
|
if ( BitmapColorTransform.M_[0][1] > 1.0f ||
|
||
|
BitmapColorTransform.M_[1][1] > 1.0f ||
|
||
|
BitmapColorTransform.M_[2][1] > 1.0f ||
|
||
|
BitmapColorTransform.M_[3][1] > 1.0f )
|
||
|
HasNonzeroAdditiveCxform = true;
|
||
|
else
|
||
|
HasNonzeroAdditiveCxform = false;
|
||
|
|
||
|
if ( BitmapColorTransform.M_[0][0] ||
|
||
|
BitmapColorTransform.M_[1][0] ||
|
||
|
BitmapColorTransform.M_[2][0] ||
|
||
|
BitmapColorTransform.M_[3][0])
|
||
|
HasMultiplyCxform = true;
|
||
|
else
|
||
|
HasMultiplyCxform = false;
|
||
|
}
|
||
|
|
||
|
void SetBitmap(const FillTexture* pft, const Cxform& colorTransform)
|
||
|
{
|
||
|
Mode = FM_Bitmap;
|
||
|
Fill = *pft;
|
||
|
Color = GColor(0xFFFFFFFF);
|
||
|
|
||
|
SetCxform(colorTransform);
|
||
|
}
|
||
|
|
||
|
// Sets the interpolated color/texture fill style used for shapes with EdgeAA.
|
||
|
// The specified textures are applied to vertices {0, 1, 2} of each triangle based
|
||
|
// on factors of Complex vertex. Any or all subsequent pointers can be NULL, in which case
|
||
|
// texture is not applied and vertex colors used instead.
|
||
|
void SetGouraudFill(GouraudFillType gfill,
|
||
|
const FillTexture *ptexture0,
|
||
|
const FillTexture *ptexture1,
|
||
|
const FillTexture *ptexture2, const Cxform& colorTransform)
|
||
|
{
|
||
|
|
||
|
// Texture2 is not yet used.
|
||
|
if (ptexture0 || ptexture1 || ptexture2)
|
||
|
{
|
||
|
const FillTexture *p = ptexture0;
|
||
|
if (!p) p = ptexture1;
|
||
|
|
||
|
SetBitmap(p, colorTransform);
|
||
|
// Used in 2 texture mode
|
||
|
if (ptexture1)
|
||
|
Fill2 = *ptexture1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetCxform(colorTransform);
|
||
|
Fill.pTexture = 0;
|
||
|
}
|
||
|
|
||
|
Mode = GFxFillStyle::FM_Gouraud;
|
||
|
GouraudType = gfill;
|
||
|
}
|
||
|
|
||
|
bool IsValid() const { return Mode != FM_None; }
|
||
|
bool UsesTextures() const { return Fill.pTexture != 0; }
|
||
|
};
|
||
|
|
||
|
|
||
|
// Style state.
|
||
|
enum StyleIndex
|
||
|
{
|
||
|
FILL_STYLE = 0,
|
||
|
LINE_STYLE,
|
||
|
STYLE_COUNT
|
||
|
};
|
||
|
GFxFillStyle CurrentStyles[STYLE_COUNT];
|
||
|
|
||
|
|
||
|
// Given an image, returns a Pointer to a GTexture struct
|
||
|
// that can later be passed to FillStyleX_bitmap(), to set a
|
||
|
// bitmap fill style.
|
||
|
GTextureOGL* CreateTexture()
|
||
|
{
|
||
|
ReleaseQueuedResources();
|
||
|
GLock::Locker guard(&TexturesLock);
|
||
|
return new GTextureOGLImpl(this);
|
||
|
}
|
||
|
|
||
|
GTextureOGL* CreateTextureYUV()
|
||
|
{
|
||
|
if (!UseShaders)
|
||
|
return NULL;
|
||
|
|
||
|
ReleaseQueuedResources();
|
||
|
GLock::Locker guard(&TexturesLock);
|
||
|
return new GTextureOGLImplYUV(this);
|
||
|
}
|
||
|
|
||
|
// Helper function to query renderer capabilities.
|
||
|
bool GetRenderCaps(RenderCaps *pcaps)
|
||
|
{
|
||
|
if (!Initialized)
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(1, "GRendererOGL::GetRenderCaps fails - video mode not set");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
pcaps->CapBits = Cap_Index16 | Cap_Index32 | Cap_NestedMasks;
|
||
|
pcaps->BlendModes = (1<<Blend_None) | (1<<Blend_Normal) |
|
||
|
(1<<Blend_Multiply) | (1<<Blend_Lighten) | (1<<Blend_Darken) |
|
||
|
(1<<Blend_Add) | (1<<Blend_Subtract);
|
||
|
pcaps->VertexFormats= (1<<Vertex_None) | (1<<Vertex_XY16i) | (1<<Vertex_XY16iC32);
|
||
|
|
||
|
if (UseShaders)
|
||
|
{
|
||
|
pcaps->CapBits |= Cap_CxformAdd | Cap_FillGouraud | Cap_FillGouraudTex;
|
||
|
pcaps->VertexFormats |= (1<<Vertex_XY16iCF32);
|
||
|
}
|
||
|
else if (UseCombine)
|
||
|
{
|
||
|
#ifdef GFC_GL_NO_STAGE_CONSTANTS
|
||
|
pcaps->CapBits |= Cap_FillGouraud;
|
||
|
pcaps->VertexFormats |= (1<<Vertex_XY16iCF32);
|
||
|
#else
|
||
|
pcaps->CapBits |= Cap_CxformAdd;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
GLint maxTextureSize = 64;
|
||
|
glGetIntegerv (GL_MAX_TEXTURE_SIZE, &maxTextureSize);
|
||
|
pcaps->MaxTextureSize = maxTextureSize;
|
||
|
|
||
|
if (TexNonPower2 >= 2)
|
||
|
pcaps->CapBits |= Cap_TexNonPower2 | Cap_TexNonPower2Wrap | Cap_TexNonPower2Mip;
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
GRenderTarget* CreateRenderTarget()
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void SetDisplayRenderTarget(GRenderTarget* prt, bool setstate = 1)
|
||
|
{
|
||
|
GUNUSED(prt);
|
||
|
GUNUSED(setstate);
|
||
|
}
|
||
|
|
||
|
void PushRenderTarget(const GRectF& frameRect, GRenderTarget* prt)
|
||
|
{
|
||
|
GUNUSED(frameRect);
|
||
|
GUNUSED(prt);
|
||
|
}
|
||
|
|
||
|
void PopRenderTarget()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
GTextureOGL* PushTempRenderTarget(const GRectF& frameRect, UInt targetW, UInt targetH, bool wantStencil = 0)
|
||
|
{
|
||
|
GUNUSED(frameRect);
|
||
|
GUNUSED(targetW);
|
||
|
GUNUSED(targetH);
|
||
|
GUNUSED(wantStencil);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
UInt CheckFilterSupport(const BlurFilterParams& params)
|
||
|
{
|
||
|
GUNUSED(params);
|
||
|
return 0;
|
||
|
}
|
||
|
void DrawBlurRect(GTexture* psrcin, const GRectF& insrcrect, const GRectF& indestrect, const BlurFilterParams& params, bool islast)
|
||
|
{
|
||
|
GUNUSED(psrcin);
|
||
|
GUNUSED(insrcrect);
|
||
|
GUNUSED(indestrect);
|
||
|
GUNUSED(params);
|
||
|
GUNUSED(islast);
|
||
|
}
|
||
|
|
||
|
void DrawColorMatrixRect(GTexture* psrcin, const GRectF& insrcrect, const GRectF& destrect, const Float *matrix, bool islast)
|
||
|
{
|
||
|
GUNUSED(psrcin);
|
||
|
GUNUSED(insrcrect);
|
||
|
GUNUSED(destrect);
|
||
|
GUNUSED(matrix);
|
||
|
GUNUSED(islast);
|
||
|
}
|
||
|
|
||
|
// Set up to render a full frame from a movie and fills the
|
||
|
// background. Sets up necessary transforms, to scale the
|
||
|
// movie to fit within the given dimensions. Call
|
||
|
// EndDisplay() when you're done.
|
||
|
//
|
||
|
// The Rectangle (viewportX0, viewportY0,
|
||
|
// viewportX0 + viewportWidth, viewportY0 + viewportHeight)
|
||
|
// defines the window coordinates taken up by the movie.
|
||
|
//
|
||
|
// The Rectangle (x0, y0, x1, y1) defines the pixel
|
||
|
// coordinates of the movie that correspond to the viewport bounds.
|
||
|
void BeginDisplay(
|
||
|
GColor backgroundColor, const GViewport &viewport,
|
||
|
Float x0, Float x1, Float y0, Float y1)
|
||
|
|
||
|
{
|
||
|
RenderMode = viewport.Flags;
|
||
|
|
||
|
BlendModeStack.Clear();
|
||
|
BlendModeStack.Reserve(16);
|
||
|
BlendMode = Blend_None;
|
||
|
ApplyBlendMode(BlendMode);
|
||
|
|
||
|
DisplayWidth = fabsf(x1 - x0);
|
||
|
DisplayHeight = fabsf(y1 - y0);
|
||
|
DisplayRect = GRectF(x0,y0,x1,y1);
|
||
|
|
||
|
if (0 == (viewport.Flags & GViewport::View_NoSetState))
|
||
|
{
|
||
|
glViewport(viewport.Left, viewport.BufferHeight-viewport.Top-viewport.Height,
|
||
|
viewport.Width, viewport.Height);
|
||
|
|
||
|
if (viewport.Flags & GViewport::View_UseScissorRect)
|
||
|
{
|
||
|
glEnable(GL_SCISSOR_TEST);
|
||
|
glScissor(viewport.ScissorLeft, viewport.BufferHeight-viewport.ScissorTop-viewport.ScissorHeight,
|
||
|
viewport.ScissorWidth, viewport.ScissorHeight);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
glDisable(GL_SCISSOR_TEST);
|
||
|
}
|
||
|
|
||
|
glMatrixMode(GL_PROJECTION);
|
||
|
glPushMatrix();
|
||
|
glLoadIdentity();
|
||
|
}
|
||
|
|
||
|
glMatrixMode(GL_MODELVIEW);
|
||
|
glPushMatrix();
|
||
|
glLoadIdentity();
|
||
|
|
||
|
#if defined(GFC_OS_PS3) || defined(GL_VERSION_ES_CM_1_0)
|
||
|
if (viewport.Flags & GViewport::View_IsRenderTexture)
|
||
|
glOrthof(x0, x1, y0, y1, -1, 1);
|
||
|
else
|
||
|
glOrthof(x0, x1, y1, y0, -1, 1);
|
||
|
#else
|
||
|
if (viewport.Flags & GViewport::View_IsRenderTexture)
|
||
|
glOrtho(x0, x1, y0, y1, -1, 1);
|
||
|
else
|
||
|
glOrtho(x0, x1, y1, y0, -1, 1);
|
||
|
#endif
|
||
|
|
||
|
#ifndef GFC_NO_3D
|
||
|
Is3DStateSet = 0;
|
||
|
IsProjMatrixSet = 0;
|
||
|
pWorldMatrix = 0;
|
||
|
#endif
|
||
|
|
||
|
glDisable(GL_CULL_FACE);
|
||
|
|
||
|
// No lighting or depth testing.
|
||
|
glDisable(GL_DEPTH_TEST);
|
||
|
glDisable(GL_LIGHTING);
|
||
|
glDisable(GL_STENCIL_TEST);
|
||
|
glDisable(GL_ALPHA_TEST);
|
||
|
glStencilMask(0xffffffff);
|
||
|
|
||
|
glEnable(GL_BLEND);
|
||
|
|
||
|
for (int i = 0; i < MaxTexUnits; i++)
|
||
|
{
|
||
|
glActiveTexture(GL_TEXTURE0 + i);
|
||
|
glDisable(GL_TEXTURE_2D);
|
||
|
}
|
||
|
glActiveTexture(GL_TEXTURE0);
|
||
|
glClientActiveTexture(GL_TEXTURE0);
|
||
|
|
||
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||
|
|
||
|
#ifdef GL_ARB_vertex_buffer_object
|
||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||
|
#endif
|
||
|
|
||
|
DisableShaders();
|
||
|
|
||
|
// Sample Mode
|
||
|
SampleMode = Sample_Linear;
|
||
|
|
||
|
BlendMode = Blend_Normal;
|
||
|
|
||
|
// Stencil counter starts out at 0.
|
||
|
StencilCounter = 0;
|
||
|
DrawingMask = 0;
|
||
|
|
||
|
// Clear the background, if background color has alpha > 0.
|
||
|
if (backgroundColor.GetAlpha() > 0)
|
||
|
{
|
||
|
// Draw a big quad.
|
||
|
if (backgroundColor.GetAlpha() == 0xFF)
|
||
|
glDisable(GL_BLEND);
|
||
|
else
|
||
|
glEnable(GL_BLEND);
|
||
|
|
||
|
ApplyColor(backgroundColor, (UseAcBlend == 0) && (RenderMode & GViewport::View_AlphaComposite));
|
||
|
|
||
|
GLfloat bgVertBuffer[12];
|
||
|
bgVertBuffer[0] = x0; bgVertBuffer[1] = y0;
|
||
|
bgVertBuffer[2] = x1; bgVertBuffer[3] = y0;
|
||
|
bgVertBuffer[4] = x0; bgVertBuffer[5] = y1;
|
||
|
bgVertBuffer[6] = x1; bgVertBuffer[7] = y1;
|
||
|
|
||
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||
|
glVertexPointer(2, GL_FLOAT, 0, bgVertBuffer);
|
||
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifndef GFC_NO_3D
|
||
|
virtual void SetPerspective3D(const GMatrix3D &projMatIn)
|
||
|
{
|
||
|
ProjMatrix = projMatIn;
|
||
|
IsProjMatrixSet = 0;
|
||
|
}
|
||
|
|
||
|
virtual void SetView3D(const GMatrix3D &viewMatIn)
|
||
|
{
|
||
|
UserViewMatrix = GMatrix3D(UserMatrix) * viewMatIn;
|
||
|
}
|
||
|
|
||
|
virtual void SetWorld3D(const GMatrix3D *pWorldMatIn)
|
||
|
{
|
||
|
pWorldMatrix = pWorldMatIn;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// Clean up after rendering a frame. Client program is still
|
||
|
// responsible for calling glSwapBuffers() or whatever.
|
||
|
void EndDisplay()
|
||
|
{
|
||
|
if (0 == (RenderMode & GViewport::View_NoSetState))
|
||
|
{
|
||
|
glMatrixMode(GL_PROJECTION);
|
||
|
glPopMatrix();
|
||
|
}
|
||
|
|
||
|
glMatrixMode(GL_MODELVIEW);
|
||
|
glPopMatrix();
|
||
|
ReleaseQueuedResources();
|
||
|
}
|
||
|
|
||
|
|
||
|
// Set the current transform for mesh & line-strip rendering.
|
||
|
void SetMatrix(const GRenderer::Matrix& m)
|
||
|
{
|
||
|
CurrentMatrix = m;
|
||
|
}
|
||
|
|
||
|
void SetUserMatrix(const GRenderer::Matrix& m)
|
||
|
{
|
||
|
UserMatrix = m;
|
||
|
}
|
||
|
|
||
|
// Set the current color transform for mesh & line-strip rendering.
|
||
|
void SetCxform(const GRenderer::Cxform& cx)
|
||
|
{
|
||
|
CurrentCxform = cx;
|
||
|
}
|
||
|
|
||
|
struct BlendModeDesc
|
||
|
{
|
||
|
GLenum op, src, dest;
|
||
|
};
|
||
|
|
||
|
struct BlendModeDescAlpha
|
||
|
{
|
||
|
GLenum op, srcc, srca, destc, desta;
|
||
|
};
|
||
|
|
||
|
void ApplyBlendMode(BlendType mode)
|
||
|
{
|
||
|
static BlendModeDesc modes[15] =
|
||
|
{
|
||
|
{ GL_FUNC_ADD, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, // None
|
||
|
{ GL_FUNC_ADD, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, // Normal
|
||
|
{ GL_FUNC_ADD, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, // Layer
|
||
|
|
||
|
{ GL_FUNC_ADD, GL_DST_COLOR, GL_ZERO }, // Multiply
|
||
|
// (For multiply, should src be pre-multiplied by its inverse alpha?)
|
||
|
|
||
|
{ GL_FUNC_ADD, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, // Screen *??
|
||
|
|
||
|
{ GL_MAX, GL_SRC_ALPHA, GL_ONE }, // Lighten
|
||
|
{ GL_MIN, GL_SRC_ALPHA, GL_ONE }, // Darken
|
||
|
|
||
|
{ GL_FUNC_ADD, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, // Difference *??
|
||
|
|
||
|
{ GL_FUNC_ADD, GL_SRC_ALPHA, GL_ONE }, // Add
|
||
|
{ GL_FUNC_REVERSE_SUBTRACT, GL_SRC_ALPHA, GL_ONE }, // Subtract
|
||
|
|
||
|
{ GL_FUNC_ADD, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, // Invert *??
|
||
|
|
||
|
{ GL_FUNC_ADD, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, // Alpha *??
|
||
|
{ GL_FUNC_ADD, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, // Erase *??
|
||
|
{ GL_FUNC_ADD, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, // Overlay *??
|
||
|
{ GL_FUNC_ADD, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, // HardLight *??
|
||
|
};
|
||
|
|
||
|
// Blending into alpha textures with premultiplied colors
|
||
|
static BlendModeDescAlpha acmodes[15] =
|
||
|
{
|
||
|
{ GL_FUNC_ADD, GL_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, // None
|
||
|
{ GL_FUNC_ADD, GL_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, // Normal
|
||
|
{ GL_FUNC_ADD, GL_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, // Layer
|
||
|
|
||
|
{ GL_FUNC_ADD, GL_DST_COLOR, GL_DST_ALPHA, GL_ZERO, GL_ZERO }, // Multiply
|
||
|
|
||
|
{ GL_FUNC_ADD, GL_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, // Screen *??
|
||
|
|
||
|
{ GL_MAX, GL_SRC_ALPHA, GL_SRC_ALPHA, GL_ONE, GL_ONE }, // Lighten *??
|
||
|
{ GL_MIN, GL_SRC_ALPHA, GL_SRC_ALPHA, GL_ONE, GL_ONE }, // Darken *??
|
||
|
|
||
|
{ GL_FUNC_ADD, GL_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, // Difference
|
||
|
|
||
|
{ GL_FUNC_ADD, GL_SRC_ALPHA, GL_ZERO, GL_ONE, GL_ONE }, // Add
|
||
|
{ GL_FUNC_REVERSE_SUBTRACT, GL_SRC_ALPHA, GL_ZERO, GL_ONE, GL_ONE }, // Subtract
|
||
|
|
||
|
{ GL_FUNC_ADD, GL_SRC_ALPHA, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, // Invert *??
|
||
|
|
||
|
{ GL_FUNC_ADD, GL_ZERO, GL_ZERO, GL_ONE, GL_ONE }, // Alpha *??
|
||
|
{ GL_FUNC_ADD, GL_ZERO, GL_ZERO, GL_ONE, GL_ONE }, // Erase *??
|
||
|
{ GL_FUNC_ADD, GL_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, // Overlay *??
|
||
|
{ GL_FUNC_ADD, GL_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, // HardLight *??
|
||
|
};
|
||
|
|
||
|
// For debug build
|
||
|
GASSERT(((UInt) mode) < 15);
|
||
|
// For release
|
||
|
if (((UInt) mode) >= 15)
|
||
|
mode = Blend_None;
|
||
|
|
||
|
if (RenderMode & GViewport::View_AlphaComposite)
|
||
|
{
|
||
|
if (UseAcBlend)
|
||
|
{
|
||
|
glBlendFuncSeparate(acmodes[mode].srcc, acmodes[mode].destc, acmodes[mode].srca, acmodes[mode].desta);
|
||
|
glBlendEquation(acmodes[mode].op);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
glBlendFunc(modes[mode].src == GL_SRC_ALPHA ? GL_ONE : modes[mode].src, modes[mode].dest);
|
||
|
glBlendEquation(modes[mode].op);
|
||
|
if (!DrawingMask)
|
||
|
{
|
||
|
if (BlendMode == Blend_Add)
|
||
|
glColorMask(1,1,1,0);
|
||
|
else
|
||
|
glColorMask(1,1,1,1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
glBlendFunc(modes[mode].src, modes[mode].dest);
|
||
|
glBlendEquation(modes[mode].op);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Pushes a Blend mode onto renderer.
|
||
|
virtual void PushBlendMode(BlendType mode)
|
||
|
{
|
||
|
// Blend modes need to be applied cumulatively, ideally through an extra RT texture.
|
||
|
// If the nested clip has a "Multiply" effect, and its parent has an "Add", the result
|
||
|
// of Multiply should be written to a buffer, and then used in Add.
|
||
|
|
||
|
// For now we only simulate it on one level -> we apply the last effect on top of stack.
|
||
|
// (Note that the current "top" element is BlendMode, it is not actually stored on stack).
|
||
|
// Although incorrect, this will at least ensure that parent's specified effect
|
||
|
// will be applied to children.
|
||
|
|
||
|
BlendModeStack.PushBack(BlendMode);
|
||
|
|
||
|
if ((mode > Blend_Layer) && (BlendMode != mode))
|
||
|
{
|
||
|
BlendMode = mode;
|
||
|
ApplyBlendMode(BlendMode);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Pops a blend mode, restoring it to the previous one.
|
||
|
virtual void PopBlendMode()
|
||
|
{
|
||
|
if (BlendModeStack.GetSize() != 0)
|
||
|
{
|
||
|
// Find the next top interesting mode.
|
||
|
BlendType newBlendMode = Blend_None;
|
||
|
|
||
|
for (SInt i = (SInt)BlendModeStack.GetSize()-1; i>=0; i--)
|
||
|
if (BlendModeStack[i] > Blend_Layer)
|
||
|
{
|
||
|
newBlendMode = BlendModeStack[i];
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
BlendModeStack.PopBack();
|
||
|
|
||
|
if (newBlendMode != BlendMode)
|
||
|
{
|
||
|
BlendMode = newBlendMode;
|
||
|
ApplyBlendMode(BlendMode);
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Stack was empty..
|
||
|
GFC_DEBUG_WARNING(1, "GRendererGL::PopBlendMode - blend mode stack is empty");
|
||
|
}
|
||
|
|
||
|
|
||
|
void ApplySampleMode(BitmapWrapMode wrapMode, BitmapSampleMode mode, bool useMipmaps)
|
||
|
{
|
||
|
GLint filter = (mode == Sample_Point) ?
|
||
|
GL_NEAREST :
|
||
|
(useMipmaps ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
|
||
|
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (filter == GL_NEAREST) ? GL_NEAREST : GL_LINEAR);
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
|
||
|
|
||
|
if (wrapMode == Wrap_Clamp)
|
||
|
{
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GASSERT(wrapMode == Wrap_Repeat);
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// multiply current GRenderer::Matrix with GL GRenderer::Matrix
|
||
|
void ApplyMatrix(const GRenderer::Matrix& m1, bool bUse3D = true)
|
||
|
{
|
||
|
#ifndef GFC_NO_3D
|
||
|
if (bUse3D && pWorldMatrix)
|
||
|
{
|
||
|
if (!Is3DStateSet)
|
||
|
{
|
||
|
glMatrixMode(GL_PROJECTION);
|
||
|
glLoadMatrixf(ProjMatrix);
|
||
|
glMatrixMode(GL_MODELVIEW);
|
||
|
Is3DStateSet = 1;
|
||
|
}
|
||
|
else if (!IsProjMatrixSet)
|
||
|
{
|
||
|
glMatrixMode(GL_PROJECTION);
|
||
|
glLoadMatrixf(ProjMatrix);
|
||
|
glMatrixMode(GL_MODELVIEW);
|
||
|
}
|
||
|
GMatrix3D m3D (m1);
|
||
|
glLoadMatrixf(UserViewMatrix);
|
||
|
glMultMatrixf(*pWorldMatrix);
|
||
|
glMultMatrixf(m3D);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (Is3DStateSet)
|
||
|
{
|
||
|
glMatrixMode(GL_PROJECTION);
|
||
|
glLoadIdentity();
|
||
|
glMatrixMode(GL_MODELVIEW);
|
||
|
Is3DStateSet = 0;
|
||
|
IsProjMatrixSet = 0;
|
||
|
}
|
||
|
#else
|
||
|
{
|
||
|
#endif
|
||
|
GRenderer::Matrix m(UserMatrix);
|
||
|
m.Prepend(m1);
|
||
|
|
||
|
Float mat[16];
|
||
|
memset(&mat[0], 0, sizeof(mat));
|
||
|
mat[0] = m.M_[0][0];
|
||
|
mat[1] = m.M_[1][0];
|
||
|
mat[4] = m.M_[0][1];
|
||
|
mat[5] = m.M_[1][1];
|
||
|
mat[10] = 1;
|
||
|
mat[12] = m.M_[0][2];
|
||
|
mat[13] = m.M_[1][2];
|
||
|
mat[15] = 1;
|
||
|
glMultMatrixf(mat);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Set the given color.
|
||
|
void ApplyColor(const GColor c, int alpha = 0)
|
||
|
{
|
||
|
if (alpha ||
|
||
|
(BlendMode == Blend_Multiply) ||
|
||
|
(BlendMode == Blend_Darken))
|
||
|
{
|
||
|
const float alpha = c.GetAlpha() * (1.0f / 65025.0f);
|
||
|
glColor4f(c.GetRed() * alpha, c.GetGreen() * alpha, c.GetBlue() * alpha,
|
||
|
c.GetAlpha() * (1.0f / 255.0f));
|
||
|
}
|
||
|
else
|
||
|
glColor4ub(c.GetRed(), c.GetGreen(), c.GetBlue(), c.GetAlpha());
|
||
|
}
|
||
|
|
||
|
// Don't fill on the {0 == left, 1 == right} side of a path.
|
||
|
void FillStyleDisable()
|
||
|
{
|
||
|
CurrentStyles[FILL_STYLE].Disable();
|
||
|
}
|
||
|
// Don't draw a line on this path.
|
||
|
void LineStyleDisable()
|
||
|
{
|
||
|
CurrentStyles[LINE_STYLE].Disable();
|
||
|
}
|
||
|
|
||
|
// Set fill style for the left interior of the shape. If
|
||
|
// enable is false, turn off fill for the left interior.
|
||
|
void FillStyleColor(GColor color)
|
||
|
{
|
||
|
CurrentStyles[FILL_STYLE].SetColor(CurrentCxform.Transform(color));
|
||
|
}
|
||
|
|
||
|
// Set the line style of the shape. If enable is false, turn
|
||
|
// off lines for following curve segments.
|
||
|
void LineStyleColor(GColor color)
|
||
|
{
|
||
|
CurrentStyles[LINE_STYLE].SetColor(CurrentCxform.Transform(color));
|
||
|
}
|
||
|
|
||
|
void FillStyleBitmap(const FillTexture *pfill)
|
||
|
{
|
||
|
CurrentStyles[FILL_STYLE].SetBitmap(pfill, CurrentCxform);
|
||
|
}
|
||
|
|
||
|
// Sets the interpolated color/texture fill style used for shapes with EdgeAA.
|
||
|
void FillStyleGouraud(GouraudFillType gfill,
|
||
|
const FillTexture *ptexture0,
|
||
|
const FillTexture *ptexture1,
|
||
|
const FillTexture *ptexture2)
|
||
|
{
|
||
|
CurrentStyles[FILL_STYLE].SetGouraudFill(gfill, ptexture0, ptexture1, ptexture2, CurrentCxform);
|
||
|
}
|
||
|
|
||
|
void SetVertexData(const void* pvertices, int numVertices, VertexFormat vf, CacheProvider *pcache)
|
||
|
{
|
||
|
pVertexData = pvertices;
|
||
|
VertexFmt = vf;
|
||
|
VertexArray = 0;
|
||
|
|
||
|
#ifdef GL_ARB_vertex_buffer_object
|
||
|
if (pcache && UseBuffers)
|
||
|
{
|
||
|
CachedData *pcd = pcache->GetCachedData(this);
|
||
|
if (pcd)
|
||
|
{
|
||
|
VertexArray = ((GBufferNode*)pcd->GetRendererData())->buffer;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
GLsizeiptr size;
|
||
|
switch (vf)
|
||
|
{
|
||
|
case Vertex_XY16i: size = 2 * sizeof(GLshort); break;
|
||
|
case Vertex_XY32f: size = 2 * sizeof(GLfloat); break;
|
||
|
case Vertex_XY16iC32: size = 2 * sizeof(GLshort) + 4; break;
|
||
|
case Vertex_XY16iCF32: size = 2 * sizeof(GLshort) + 8; break;
|
||
|
default: return;
|
||
|
}
|
||
|
|
||
|
GBufferNode *pva;
|
||
|
pcd = pcache->CreateCachedData(Cached_Vertex,this,0);
|
||
|
|
||
|
if (!pcd->GetRendererData())
|
||
|
{
|
||
|
GLsizeiptr vasize = (size * numVertices + 15) & ~15;
|
||
|
pva = new GBufferNode(&BufferObjects, pcd);
|
||
|
pcd->SetRendererData(pva);
|
||
|
glGenBuffers(1, &pva->buffer);
|
||
|
|
||
|
glBindBuffer(GL_ARRAY_BUFFER, pva->buffer);
|
||
|
glBufferData(GL_ARRAY_BUFFER, vasize, pvertices, GL_STATIC_DRAW);
|
||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||
|
|
||
|
VertexArray = pva->buffer;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
// Test cache buffer management support.
|
||
|
CacheList.VerifyCachedData( this, pcache, CacheNode::Buffer_Vertex, (pvertices!=0),
|
||
|
numVertices, (((pvertices!=0)&&numVertices) ? *((SInt16*)pvertices) : 0) );
|
||
|
}
|
||
|
|
||
|
void SetIndexData(const void* pindices, int numIndices, IndexFormat idxf, CacheProvider *pcache)
|
||
|
{
|
||
|
pIndexData = pindices;
|
||
|
IndexArray = 0;
|
||
|
switch(idxf)
|
||
|
{
|
||
|
case Index_None: IndexFmt = 0; break;
|
||
|
case Index_16: IndexFmt = GL_UNSIGNED_SHORT; break;
|
||
|
case Index_32:
|
||
|
#ifdef GL_UNSIGNED_INT
|
||
|
IndexFmt = GL_UNSIGNED_INT;
|
||
|
#else
|
||
|
GFC_DEBUG_WARNING(1, "GL_UNSIGNED_INT not supported, no 32-bit indices.");
|
||
|
#endif
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
#ifdef GL_ARB_vertex_buffer_object
|
||
|
if (pcache && UseBuffers)
|
||
|
{
|
||
|
CachedData *pcd = pcache->GetCachedData(this);
|
||
|
if (pcd)
|
||
|
{
|
||
|
IndexArray = ((GBufferNode*)pcd->GetRendererData())->buffer;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
GLsizeiptr size;
|
||
|
switch (idxf)
|
||
|
{
|
||
|
case Index_16: size = sizeof(GLshort); break;
|
||
|
case Index_32: size = sizeof(GLint); break;
|
||
|
default: return;
|
||
|
}
|
||
|
|
||
|
GBufferNode *pva;
|
||
|
pcd = pcache->CreateCachedData(Cached_Index,this,0);
|
||
|
|
||
|
if (!pcd->GetRendererData())
|
||
|
{
|
||
|
pva = new GBufferNode(&BufferObjects, pcd);
|
||
|
pcd->SetRendererData(pva);
|
||
|
glGenBuffers(1, &pva->buffer);
|
||
|
|
||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, pva->buffer);
|
||
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size * numIndices, pindices, GL_STATIC_DRAW);
|
||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||
|
|
||
|
IndexArray = pva->buffer;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// Test cache buffer management support.
|
||
|
CacheList.VerifyCachedData( this, pcache, CacheNode::Buffer_Index, (pindices!=0),
|
||
|
numIndices, (((pindices!=0)&&numIndices) ? *((SInt16*)pindices) : 0) );
|
||
|
}
|
||
|
|
||
|
void ReleaseCachedData(CachedData *pdata, CachedDataType type)
|
||
|
{
|
||
|
// Releases cached data that was allocated from the cache providers.
|
||
|
CacheList.ReleaseCachedData(pdata, type);
|
||
|
|
||
|
#ifdef GL_ARB_vertex_buffer_object
|
||
|
if (pdata->GetRendererData())
|
||
|
{
|
||
|
GBufferNode *pn = (GBufferNode*)pdata->GetRendererData();
|
||
|
glDeleteBuffers(1, &pn->buffer);
|
||
|
pn->RemoveNode();
|
||
|
delete pn;
|
||
|
pdata->SetRendererData(0);
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
void DrawIndexedTriList(int baseVertexIndex, int minVertexIndex, int numVertices,
|
||
|
int startIndex, int triangleCount)
|
||
|
{
|
||
|
GUNUSED2(minVertexIndex, numVertices);
|
||
|
|
||
|
if (!pVertexData || !pIndexData || !IndexFmt) // Must have vertex data.
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(!pVertexData, "GRendererOGL::DrawIndexedTriList failed, vertex data not specified");
|
||
|
GFC_DEBUG_WARNING(!pIndexData, "GRendererOGL::DrawIndexedTriList failed, index data not specified");
|
||
|
GFC_DEBUG_WARNING(!IndexFmt, "GRendererOGL::DrawIndexedTriList failed, index buffer format not specified");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Set up current style.
|
||
|
CurrentStyles[FILL_STYLE].Apply(this);
|
||
|
|
||
|
glMatrixMode(GL_MODELVIEW);
|
||
|
glPushMatrix();
|
||
|
ApplyMatrix(CurrentMatrix);
|
||
|
|
||
|
SetVertexProgState(); // for Cg matrices
|
||
|
|
||
|
const void* pindices = (UByte*)(IndexArray ? 0 : pIndexData) + startIndex *
|
||
|
((IndexFmt == GL_UNSIGNED_SHORT) ? sizeof(UInt16) : sizeof(UInt32));
|
||
|
const void *pVertexBase = pVertexData;
|
||
|
|
||
|
#ifdef GL_ARB_vertex_buffer_object
|
||
|
if (VertexArray)
|
||
|
{
|
||
|
glBindBuffer(GL_ARRAY_BUFFER, VertexArray);
|
||
|
pVertexBase = 0;
|
||
|
}
|
||
|
if (IndexArray)
|
||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexArray);
|
||
|
#endif
|
||
|
|
||
|
// Send the tris to OpenGL
|
||
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||
|
|
||
|
// Gouraud colors
|
||
|
if (VertexFmt == Vertex_XY16iC32)
|
||
|
{
|
||
|
glVertexPointer(2, GL_SHORT, sizeof(VertexXY16iC32),
|
||
|
((UByte*)pVertexBase) + baseVertexIndex * sizeof(VertexXY16iC32));
|
||
|
glEnableClientState(GL_COLOR_ARRAY);
|
||
|
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof (VertexXY16iC32),
|
||
|
((UByte*)pVertexBase) + baseVertexIndex * sizeof(VertexXY16iC32) + 2 * sizeof(UInt16));
|
||
|
|
||
|
#ifdef GFC_GL_NO_TEXGEN
|
||
|
if (CurrentStyles[FILL_STYLE].Fill.pTexture)
|
||
|
{
|
||
|
glTexCoordPointer(2, GL_SHORT, sizeof(VertexXY16iC32),
|
||
|
((UByte*)pVertexBase) + baseVertexIndex * sizeof(VertexXY16iC32));
|
||
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
else if (VertexFmt == Vertex_XY16iCF32)
|
||
|
{
|
||
|
glVertexPointer(2, GL_SHORT, sizeof(VertexXY16iCF32),
|
||
|
((UByte*)pVertexBase) + baseVertexIndex * sizeof(VertexXY16iCF32));
|
||
|
|
||
|
glEnableClientState(GL_COLOR_ARRAY);
|
||
|
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof (VertexXY16iCF32),
|
||
|
((UByte*)pVertexBase) + baseVertexIndex * sizeof(VertexXY16iCF32) + 2 * sizeof(UInt16));
|
||
|
|
||
|
VertexAttribArray (0, 4, GL_UNSIGNED_BYTE, 1, sizeof (VertexXY16iCF32),
|
||
|
((UByte*)pVertexBase) + baseVertexIndex * sizeof(VertexXY16iCF32) + 2 * sizeof(UInt16) + 4);
|
||
|
|
||
|
#ifdef GFC_GL_NO_TEXGEN
|
||
|
if (CurrentStyles[FILL_STYLE].Fill.pTexture)
|
||
|
{
|
||
|
glTexCoordPointer(2, GL_SHORT, sizeof(VertexXY16iCF32),
|
||
|
((UByte*)pVertexBase) + baseVertexIndex * sizeof(VertexXY16iCF32));
|
||
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
glVertexPointer(2, GL_SHORT, sizeof(SInt16) * 2,
|
||
|
((UByte*)pVertexBase) + baseVertexIndex * 2 * sizeof(SInt16));
|
||
|
|
||
|
#ifdef GFC_GL_NO_TEXGEN
|
||
|
if (CurrentStyles[FILL_STYLE].Fill.pTexture)
|
||
|
{
|
||
|
glTexCoordPointer(2, GL_SHORT, sizeof(SInt16) * 2,
|
||
|
((UByte*)pVertexBase) + baseVertexIndex * 2 * sizeof(SInt16));
|
||
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
glDrawRangeElements(GL_TRIANGLES, minVertexIndex,
|
||
|
numVertices-1, 3*triangleCount, IndexFmt, pindices);
|
||
|
|
||
|
RenderStats.Triangles += triangleCount;
|
||
|
RenderStats.Primitives++;
|
||
|
|
||
|
DPTriangleCnt.AddCount(1);
|
||
|
TriangleCnt.AddCount(triangleCount);
|
||
|
if (CurrentStyles[FILL_STYLE].NeedsSecondPass(this))
|
||
|
{
|
||
|
CurrentStyles[FILL_STYLE].ApplySecondPass();
|
||
|
glDrawRangeElements(GL_TRIANGLES, minVertexIndex,
|
||
|
numVertices-1, 3*triangleCount, IndexFmt, pindices);
|
||
|
CurrentStyles[FILL_STYLE].CleanupSecondPass(this);
|
||
|
|
||
|
RenderStats.Triangles += triangleCount;
|
||
|
RenderStats.Primitives++;
|
||
|
|
||
|
DPTriangleCnt.AddCount(1);
|
||
|
TriangleCnt.AddCount(triangleCount);
|
||
|
}
|
||
|
|
||
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||
|
glDisableClientState(GL_COLOR_ARRAY);
|
||
|
DisableVertexAttribArrays ();
|
||
|
#ifdef GFC_GL_NO_TEXGEN
|
||
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||
|
#endif
|
||
|
|
||
|
#ifdef GL_ARB_vertex_buffer_object
|
||
|
if (VertexArray) glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||
|
if (IndexArray) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||
|
#endif
|
||
|
|
||
|
glPopMatrix();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
// Draw the line strip formed by the sequence of Points.
|
||
|
void DrawLineStrip(int baseVertexIndex, int lineCount)
|
||
|
{
|
||
|
if (!pVertexData) // Must have vertex data.
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(!pVertexData, "GRendererOGL::DrawLineStrip failed, vertex data not specified");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Set up current style.
|
||
|
CurrentStyles[LINE_STYLE].Apply(this);
|
||
|
|
||
|
glMatrixMode(GL_MODELVIEW);
|
||
|
glPushMatrix();
|
||
|
ApplyMatrix(CurrentMatrix);
|
||
|
|
||
|
const void *pVertexBase = pVertexData;
|
||
|
|
||
|
#ifdef GL_ARB_vertex_buffer_object
|
||
|
if (VertexArray)
|
||
|
{
|
||
|
glBindBuffer(GL_ARRAY_BUFFER, VertexArray);
|
||
|
pVertexBase = 0;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// Send the line-strip to OpenGL
|
||
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||
|
glVertexPointer(2, GL_SHORT, sizeof(SInt16) * 2,
|
||
|
((UByte*)pVertexBase) + baseVertexIndex * 2 * sizeof(SInt16));
|
||
|
glDrawArrays(GL_LINE_STRIP, 0, lineCount + 1);
|
||
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||
|
|
||
|
RenderStats.Lines += lineCount;
|
||
|
RenderStats.Primitives++;
|
||
|
|
||
|
DPLineCnt.AddCount(1);
|
||
|
LineCnt.AddCount(lineCount);
|
||
|
|
||
|
#ifdef GL_ARB_vertex_buffer_object
|
||
|
if (VertexArray) glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||
|
#endif
|
||
|
glPopMatrix();
|
||
|
}
|
||
|
|
||
|
|
||
|
// Draw a set of rectangles textured with the given bitmap, with the given color.
|
||
|
// Apply given transform; ignore any currently set transforms.
|
||
|
//
|
||
|
// Intended for textured glyph rendering.
|
||
|
void DrawBitmaps(BitmapDesc* pbitmapList, int listSize, int startIndex, int count,
|
||
|
const GTexture* pti, const Matrix& m,
|
||
|
CacheProvider *pcache)
|
||
|
{
|
||
|
if (!pbitmapList || !pti)
|
||
|
return;
|
||
|
|
||
|
// Test cache buffer management support.
|
||
|
// Optimized implementation could use this spot to set vertex buffer and/or initialize offset in it.
|
||
|
// Note that since bitmap lists are usually short, it would be a good idea to combine many of them
|
||
|
// into one buffer, instead of creating individual buffers for each pbitmapList data instance.
|
||
|
CacheList.VerifyCachedData( this, pcache, CacheNode::Buffer_BitmapList, (pbitmapList!=0),
|
||
|
listSize, (((pbitmapList!=0)&&listSize) ? ((SInt)pbitmapList->Coords.Left) : 0) );
|
||
|
|
||
|
glEnable(GL_BLEND);
|
||
|
DisableShaders();
|
||
|
bool IsAlpha =
|
||
|
#ifdef GFC_GL_NO_ALPHA_TEXTURES
|
||
|
((GTextureOGLImpl*)pti)->IsAlpha;
|
||
|
#else
|
||
|
((GTextureOGLImpl*)pti)->TextureFmt == GL_ALPHA;
|
||
|
#endif
|
||
|
|
||
|
if (MaxTexUnits)
|
||
|
{
|
||
|
glActiveTexture(GL_TEXTURE3);
|
||
|
glDisable(GL_TEXTURE_2D);
|
||
|
glActiveTexture(GL_TEXTURE2);
|
||
|
glDisable(GL_TEXTURE_2D);
|
||
|
|
||
|
if (UseShaders)
|
||
|
{
|
||
|
glActiveTexture(GL_TEXTURE0);
|
||
|
|
||
|
if (((GTextureOGLImpl*)pti)->IsYUVTexture() == 1)
|
||
|
{
|
||
|
IsAlpha = 0;
|
||
|
if (BlendMode == Blend_Multiply || BlendMode == Blend_Darken)
|
||
|
SetPixelShader(PS_TextTextureYUVMultiply);
|
||
|
else
|
||
|
SetPixelShader(PS_TextTextureYUV);
|
||
|
}
|
||
|
else if (((GTextureOGLImpl*)pti)->IsYUVTexture() == 2)
|
||
|
{
|
||
|
IsAlpha = 0;
|
||
|
if (BlendMode == Blend_Multiply || BlendMode == Blend_Darken)
|
||
|
SetPixelShader(PS_TextTextureYUVAMultiply);
|
||
|
else
|
||
|
SetPixelShader(PS_TextTextureYUVA);
|
||
|
}
|
||
|
else if (IsAlpha)
|
||
|
SetPixelShader(PS_TextTexture);
|
||
|
else if (BlendMode == Blend_Multiply || BlendMode == Blend_Darken)
|
||
|
SetPixelShader(PS_TextTextureColorMultiply);
|
||
|
else
|
||
|
SetPixelShader(PS_TextTextureColor);
|
||
|
}
|
||
|
#ifdef GL_ARB_texture_env_combine
|
||
|
else if (UseCombine)
|
||
|
{
|
||
|
glActiveTexture(GL_TEXTURE1);
|
||
|
|
||
|
if (!IsAlpha && (MaxTexUnits >= (RenderMode & GViewport::View_AlphaComposite) ? 3 : 2))
|
||
|
{
|
||
|
Float sca[4] = {
|
||
|
CurrentCxform.M_[0][1] / 255.0f,
|
||
|
CurrentCxform.M_[1][1] / 255.0f,
|
||
|
CurrentCxform.M_[2][1] / 255.0f,
|
||
|
CurrentCxform.M_[3][1] / 255.0f };
|
||
|
|
||
|
glEnable(GL_TEXTURE_2D);
|
||
|
glBindTexture(GL_TEXTURE_2D, ((GTextureOGLImpl*)pti)->TextureId);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_ADD);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_CONSTANT);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
|
||
|
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, sca);
|
||
|
glActiveTexture(GL_TEXTURE2);
|
||
|
|
||
|
if ((BlendMode == Blend_Multiply || BlendMode == Blend_Darken)
|
||
|
&& MaxTexUnits >= 4)
|
||
|
{
|
||
|
Float sc1[4] = {1.0f, 1.0f, 1.0f, 1.0f};
|
||
|
|
||
|
glEnable(GL_TEXTURE_2D);
|
||
|
glBindTexture(GL_TEXTURE_2D, ((GTextureOGLImpl*)pti)->TextureId);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_INTERPOLATE);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_CONSTANT);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_PREVIOUS);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_ALPHA, GL_PREVIOUS);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, GL_SRC_ALPHA);
|
||
|
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, sc1);
|
||
|
if (RenderMode & GViewport::View_AlphaComposite)
|
||
|
glActiveTexture(GL_TEXTURE3);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (RenderMode & GViewport::View_AlphaComposite && !UseAcBlend)
|
||
|
{
|
||
|
glEnable(GL_TEXTURE_2D);
|
||
|
glBindTexture(GL_TEXTURE_2D, ((GTextureOGLImpl*)pti)->TextureId);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_PREVIOUS);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
|
||
|
}
|
||
|
|
||
|
glActiveTexture(GL_TEXTURE0);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||
|
}
|
||
|
else
|
||
|
#endif
|
||
|
{
|
||
|
// only multiply part of cxform supported for 4 color textures
|
||
|
glActiveTexture(GL_TEXTURE0);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
((GTextureOGLImpl*)pti)->Bind(0, Wrap_Clamp, Sample_Linear, IsAlpha);
|
||
|
|
||
|
#ifndef GFC_GL_NO_TEXGEN
|
||
|
glDisable(GL_TEXTURE_GEN_S);
|
||
|
glDisable(GL_TEXTURE_GEN_T);
|
||
|
#else
|
||
|
glMatrixMode(GL_TEXTURE);
|
||
|
glLoadIdentity();
|
||
|
#endif
|
||
|
|
||
|
// Custom matrix per call.
|
||
|
glMatrixMode(GL_MODELVIEW);
|
||
|
glPushMatrix();
|
||
|
ApplyMatrix(m);
|
||
|
|
||
|
SInt ibitmap = 0, ivertex = 0;
|
||
|
GCOMPILER_ASSERT((GlyphVertexBufferSize%6) == 0);
|
||
|
|
||
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||
|
glVertexPointer(4, GL_FLOAT, sizeof(GGlyphVertex), GlyphVertexBuffer);
|
||
|
glTexCoordPointer(2, GL_FLOAT, sizeof(GGlyphVertex), ((UByte*)GlyphVertexBuffer) + sizeof(Float)*4);
|
||
|
|
||
|
if (IsAlpha)
|
||
|
{
|
||
|
glEnableClientState(GL_COLOR_ARRAY);
|
||
|
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(GGlyphVertex), &GlyphVertexBuffer[0].color);
|
||
|
}
|
||
|
|
||
|
if (UseShaders)
|
||
|
{
|
||
|
ApplyPShaderCxform(CurrentCxform);
|
||
|
while (ibitmap < count)
|
||
|
{
|
||
|
for(ivertex = 0; (ivertex < GlyphVertexBufferSize) && (ibitmap<count); ibitmap++, ivertex+= 6)
|
||
|
{
|
||
|
BitmapDesc & bd = pbitmapList[ibitmap + startIndex];
|
||
|
GGlyphVertex* pv = GlyphVertexBuffer + ivertex;
|
||
|
|
||
|
// Triangle 1.
|
||
|
pv[0].SetVertex2D(bd.Coords.Left, bd.Coords.Top, bd.TextureCoords.Left, bd.TextureCoords.Top, bd.Color);
|
||
|
pv[1].SetVertex2D(bd.Coords.Right, bd.Coords.Top, bd.TextureCoords.Right, bd.TextureCoords.Top, bd.Color);
|
||
|
pv[2].SetVertex2D(bd.Coords.Left, bd.Coords.Bottom, bd.TextureCoords.Left, bd.TextureCoords.Bottom, bd.Color);
|
||
|
// Triangle 2.
|
||
|
pv[3].SetVertex2D(bd.Coords.Left, bd.Coords.Bottom, bd.TextureCoords.Left, bd.TextureCoords.Bottom, bd.Color);
|
||
|
pv[4].SetVertex2D(bd.Coords.Right, bd.Coords.Top, bd.TextureCoords.Right, bd.TextureCoords.Top, bd.Color);
|
||
|
pv[5].SetVertex2D(bd.Coords.Right, bd.Coords.Bottom,bd.TextureCoords.Right, bd.TextureCoords.Bottom, bd.Color);
|
||
|
}
|
||
|
|
||
|
// Draw the generated triangles.
|
||
|
if (ivertex)
|
||
|
{
|
||
|
glDrawArrays(GL_TRIANGLES, 0, ivertex);
|
||
|
RenderStats.Primitives++;
|
||
|
DPTriangleCnt.AddCount(1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (!IsAlpha) // cxform multiply done in first modulate stage
|
||
|
glColor4f(CurrentCxform.M_[0][0], CurrentCxform.M_[1][0], CurrentCxform.M_[2][0], CurrentCxform.M_[3][0]);
|
||
|
|
||
|
GRenderer::Cxform cxform(CurrentCxform);
|
||
|
if (!IsAlpha)
|
||
|
cxform.M_[0][1] = cxform.M_[1][1] = cxform.M_[2][1] = cxform.M_[3][1] = 0;
|
||
|
|
||
|
while (ibitmap < count)
|
||
|
{
|
||
|
for(ivertex = 0; (ivertex < GlyphVertexBufferSize) && (ibitmap<count); ibitmap++, ivertex+= 6)
|
||
|
{
|
||
|
BitmapDesc & bd = pbitmapList[ibitmap + startIndex];
|
||
|
GGlyphVertex* pv = GlyphVertexBuffer + ivertex;
|
||
|
|
||
|
GColor c1 = cxform.Transform(bd.Color);
|
||
|
GColor Color (c1.GetRed() | (c1.GetGreen() << 8) | (c1.GetBlue() << 16) | (c1.GetAlpha() << 24));
|
||
|
|
||
|
// Triangle 1.
|
||
|
pv[0].SetVertex2D(bd.Coords.Left, bd.Coords.Top, bd.TextureCoords.Left, bd.TextureCoords.Top, Color);
|
||
|
pv[1].SetVertex2D(bd.Coords.Right, bd.Coords.Top, bd.TextureCoords.Right, bd.TextureCoords.Top, Color);
|
||
|
pv[2].SetVertex2D(bd.Coords.Left, bd.Coords.Bottom, bd.TextureCoords.Left, bd.TextureCoords.Bottom, Color);
|
||
|
// Triangle 2.
|
||
|
pv[3].SetVertex2D(bd.Coords.Left, bd.Coords.Bottom, bd.TextureCoords.Left, bd.TextureCoords.Bottom, Color);
|
||
|
pv[4].SetVertex2D(bd.Coords.Right, bd.Coords.Top, bd.TextureCoords.Right, bd.TextureCoords.Top, Color);
|
||
|
pv[5].SetVertex2D(bd.Coords.Right, bd.Coords.Bottom,bd.TextureCoords.Right, bd.TextureCoords.Bottom, Color);
|
||
|
}
|
||
|
|
||
|
// Draw the generated triangles.
|
||
|
if (ivertex)
|
||
|
{
|
||
|
glDrawArrays(GL_TRIANGLES, 0, ivertex);
|
||
|
RenderStats.Primitives++;
|
||
|
DPTriangleCnt.AddCount(1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||
|
glDisableClientState(GL_COLOR_ARRAY);
|
||
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||
|
RenderStats.Triangles += count * 2;
|
||
|
TriangleCnt.AddCount(count * 2);
|
||
|
|
||
|
#ifdef GL_ARB_texture_env_combine
|
||
|
if (UseCombine && ((RenderMode & GViewport::View_AlphaComposite) || !IsAlpha))
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||
|
#endif
|
||
|
|
||
|
glPopMatrix();
|
||
|
}
|
||
|
|
||
|
void BeginSubmitMask(SubmitMaskMode maskMode)
|
||
|
{
|
||
|
DrawingMask = 1;
|
||
|
glColorMask(0,0,0,0); // disable framebuffer writes
|
||
|
|
||
|
#ifndef GFC_ZBUFFER_MASKING
|
||
|
glEnable(GL_STENCIL_TEST);
|
||
|
|
||
|
switch(maskMode)
|
||
|
{
|
||
|
case Mask_Clear:
|
||
|
glClearStencil(0);
|
||
|
glClear(GL_STENCIL_BUFFER_BIT);
|
||
|
glStencilFunc(GL_ALWAYS, 1, 1); // Always pass, 1 bit plane, 1 as mask
|
||
|
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); //
|
||
|
StencilCounter = 1;
|
||
|
break;
|
||
|
|
||
|
case Mask_Increment:
|
||
|
glStencilFunc(GL_EQUAL, StencilCounter, 0xFF);
|
||
|
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
|
||
|
StencilCounter++;
|
||
|
break;
|
||
|
|
||
|
case Mask_Decrement:
|
||
|
glStencilFunc(GL_EQUAL, StencilCounter, 0xFF);
|
||
|
glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
|
||
|
StencilCounter--;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
glEnable(GL_DEPTH_TEST); // enable the depth test and the depth write
|
||
|
glDepthMask(GL_TRUE);
|
||
|
|
||
|
if (maskMode == Mask_Clear)
|
||
|
{
|
||
|
#if defined(GL_VERSION_ES_CM_1_0)
|
||
|
glClearDepthf(1.0); // clear the depth buffer to the farthest value
|
||
|
#else
|
||
|
glClearDepth(1.0); // clear the depth buffer to the farthest value
|
||
|
#endif
|
||
|
glClear(GL_DEPTH_BUFFER_BIT);
|
||
|
glDepthFunc(GL_ALWAYS); // always write on the depth buffer
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Don't modify buffer for increment/decrement.
|
||
|
glDepthFunc(GL_NEVER);
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
RenderStats.Masks++;
|
||
|
MaskCnt.AddCount(1);
|
||
|
}
|
||
|
|
||
|
void EndSubmitMask()
|
||
|
{
|
||
|
DrawingMask = 0;
|
||
|
glColorMask(1,1,1,1); // Enable frame-buffer writes
|
||
|
|
||
|
#ifndef GFC_ZBUFFER_MASKING
|
||
|
// We draw only where the (stencil == StencilCounter); i.e. where the mask was drawn.
|
||
|
// Don't change the stencil buffer
|
||
|
glStencilFunc(GL_EQUAL, StencilCounter, 0xFF);
|
||
|
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
||
|
#else
|
||
|
glEnable(GL_DEPTH_TEST); // Enable the depth test and the depth write
|
||
|
glDepthMask(GL_FALSE);
|
||
|
glDepthFunc(GL_EQUAL); // We draw only where the mask was drawn with whatever depth is assumed by your driver.
|
||
|
// According to the spec, this should be 0.0. If it is 1.0, change the clear depth above.
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void DisableMask()
|
||
|
{
|
||
|
#ifndef GFC_ZBUFFER_MASKING
|
||
|
glDisable(GL_STENCIL_TEST);
|
||
|
StencilCounter = 0;
|
||
|
#else
|
||
|
glDisable(GL_DEPTH_TEST);
|
||
|
glDepthMask(GL_FALSE);
|
||
|
glDepthFunc(GL_LEQUAL);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
virtual void GetRenderStats(Stats *pstats, bool resetStats)
|
||
|
{
|
||
|
if (pstats)
|
||
|
memcpy(pstats, &RenderStats, sizeof(Stats));
|
||
|
if (resetStats)
|
||
|
RenderStats.Clear();
|
||
|
}
|
||
|
|
||
|
virtual void GetStats(GStatBag* pbag, bool reset)
|
||
|
{
|
||
|
if (pbag)
|
||
|
{
|
||
|
pbag->Add(GStatRender_Texture_VMem, &TextureVMem);
|
||
|
pbag->Add(GStatRender_Buffer_VMem, &BufferVMem);
|
||
|
|
||
|
pbag->Add(GStatRender_TextureUpload_Cnt, &TextureUploadCnt);
|
||
|
pbag->Add(GStatRender_TextureUpdate_Cnt, &TextureUpdateCnt);
|
||
|
|
||
|
pbag->Add(GStatRender_DP_Line_Cnt, &DPLineCnt);
|
||
|
pbag->Add(GStatRender_DP_Triangle_Cnt, &DPTriangleCnt);
|
||
|
pbag->Add(GStatRender_Line_Cnt, &LineCnt);
|
||
|
pbag->Add(GStatRender_Triangle_Cnt, &TriangleCnt);
|
||
|
pbag->Add(GStatRender_Mask_Cnt, &MaskCnt);
|
||
|
pbag->Add(GStatRender_Filter_Cnt, &FilterCnt);
|
||
|
}
|
||
|
|
||
|
if (reset)
|
||
|
{
|
||
|
TextureUploadCnt.Reset();
|
||
|
TextureUpdateCnt.Reset();
|
||
|
|
||
|
DPLineCnt.Reset();
|
||
|
DPTriangleCnt.Reset();
|
||
|
LineCnt.Reset();
|
||
|
TriangleCnt.Reset();
|
||
|
MaskCnt.Reset();
|
||
|
FilterCnt.Reset();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static bool CheckExtension (const char *exts, const char *name)
|
||
|
{
|
||
|
const char *p = strstr(exts, name);
|
||
|
return (p && (p[strlen(name)] == 0 || p[strlen(name)] == ' '));
|
||
|
}
|
||
|
|
||
|
// Specify pixel format (?)
|
||
|
// (we can also get it from the window)
|
||
|
// Specify OpenGL context ?
|
||
|
virtual bool SetDependentVideoMode()
|
||
|
{
|
||
|
if (Initialized)
|
||
|
return 1;
|
||
|
|
||
|
#ifdef GFC_GL_RUNTIME_LINK
|
||
|
p_glBlendEquation = (PFNGLBLENDEQUATIONPROC) GFC_GL_RUNTIME_LINK ("glBlendEquation");
|
||
|
p_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC) GFC_GL_RUNTIME_LINK ("glBlendFuncSeparate");
|
||
|
p_glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC) GFC_GL_RUNTIME_LINK("glDrawRangeElements");
|
||
|
p_glMultiTexCoord4fv = (PFNGLMULTITEXCOORD4FVPROC) GFC_GL_RUNTIME_LINK("glMultiTexCoord4fv");
|
||
|
p_glActiveTexture = (PFNGLACTIVETEXTUREPROC) GFC_GL_RUNTIME_LINK("glActiveTexture");
|
||
|
p_glClientActiveTexture = (PFNGLCLIENTACTIVETEXTUREPROC) GFC_GL_RUNTIME_LINK("glClientActiveTexture");
|
||
|
p_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC) GFC_GL_RUNTIME_LINK("glEnableVertexAttribArrayARB");
|
||
|
p_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC) GFC_GL_RUNTIME_LINK("glDisableVertexAttribArrayARB");
|
||
|
p_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC) GFC_GL_RUNTIME_LINK("glVertexAttribPointerARB");
|
||
|
p_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC) GFC_GL_RUNTIME_LINK("glVertexAttrib4fARB");
|
||
|
p_glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC) GFC_GL_RUNTIME_LINK ("glDeleteObjectARB");
|
||
|
p_glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) GFC_GL_RUNTIME_LINK ("glCreateShaderObjectARB");
|
||
|
p_glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) GFC_GL_RUNTIME_LINK ("glShaderSourceARB");
|
||
|
p_glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) GFC_GL_RUNTIME_LINK ("glCompileShaderARB");
|
||
|
p_glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) GFC_GL_RUNTIME_LINK ("glCreateProgramObjectARB");
|
||
|
p_glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) GFC_GL_RUNTIME_LINK ("glAttachObjectARB");
|
||
|
p_glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) GFC_GL_RUNTIME_LINK ("glLinkProgramARB");
|
||
|
p_glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC) GFC_GL_RUNTIME_LINK ("glUseProgramObjectARB");
|
||
|
p_glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC) GFC_GL_RUNTIME_LINK ("glGetInfoLogARB");
|
||
|
p_glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) GFC_GL_RUNTIME_LINK ("glGetUniformLocationARB");
|
||
|
p_glUniform4fARB = (PFNGLUNIFORM4FARBPROC) GFC_GL_RUNTIME_LINK ("glUniform4fARB");
|
||
|
p_glUniform1iARB = (PFNGLUNIFORM1IARBPROC) GFC_GL_RUNTIME_LINK ("glUniform1iARB");
|
||
|
p_glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) GFC_GL_RUNTIME_LINK("glGetObjectParameterivARB");
|
||
|
p_glProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC) GFC_GL_RUNTIME_LINK ("glProgramStringARB");
|
||
|
p_glBindProgramARB = (PFNGLBINDPROGRAMARBPROC) GFC_GL_RUNTIME_LINK ("glBindProgramARB");
|
||
|
p_glProgramLocalParameter4dARB = (PFNGLPROGRAMENVPARAMETER4DARBPROC) GFC_GL_RUNTIME_LINK ("glProgramLocalParameter4dARB");
|
||
|
p_glGenProgramsARB = (PFNGLGENPROGRAMSARBPROC) GFC_GL_RUNTIME_LINK("glGenProgramsARB");
|
||
|
p_glDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC) GFC_GL_RUNTIME_LINK("glDeleteProgramsARB");
|
||
|
p_glGenBuffers = (PFNGLGENBUFFERSARBPROC) GFC_GL_RUNTIME_LINK("glGenBuffersARB");
|
||
|
p_glDeleteBuffers = (PFNGLDELETEBUFFERSARBPROC) GFC_GL_RUNTIME_LINK("glDeleteBuffersARB");
|
||
|
p_glBindBuffer = (PFNGLBINDBUFFERARBPROC) GFC_GL_RUNTIME_LINK("glBindBufferARB");
|
||
|
p_glBufferData = (PFNGLBUFFERDATAARBPROC) GFC_GL_RUNTIME_LINK("glBufferDataARB");
|
||
|
p_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC) GFC_GL_RUNTIME_LINK("glCompressedTexImage2D");
|
||
|
#endif
|
||
|
|
||
|
UseShaders = 0;
|
||
|
UseBuffers = 0;
|
||
|
UseCombine = 0;
|
||
|
UseAcBlend = 0;
|
||
|
|
||
|
const char *glexts = (const char *) glGetString(GL_EXTENSIONS);
|
||
|
|
||
|
MaxTexUnits = 0;
|
||
|
glGetIntegerv(GL_MAX_TEXTURE_UNITS, &MaxTexUnits);
|
||
|
if (MaxTexUnits <= 1)
|
||
|
MaxTexUnits = 0;
|
||
|
#ifdef GL_ARB_texture_env_combine
|
||
|
UseCombine = CheckExtension(glexts, "GL_ARB_texture_env_combine");
|
||
|
#endif
|
||
|
UseAcBlend = CheckExtension(glexts, "GL_EXT_blend_func_separate");
|
||
|
//UseBuffers = CheckExtension(glexts, "GL_ARB_vertex_buffer_object");
|
||
|
|
||
|
#ifdef GL_UNPACK_ALIGNMENT
|
||
|
TexNonPower2 = CheckExtension(glexts, "GL_ARB_texture_non_power_of_two") ? 2 : 0;
|
||
|
#else
|
||
|
TexNonPower2 = 0;
|
||
|
#endif
|
||
|
|
||
|
#if defined(GL_VERSION_ES_CM_1_1)
|
||
|
UseCombine = 1;
|
||
|
#endif
|
||
|
|
||
|
Initialized = 1;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
// Returns back to original mode (cleanup)
|
||
|
virtual bool ResetVideoMode()
|
||
|
{
|
||
|
ReleaseQueuedResources();
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
virtual DisplayStatus CheckDisplayStatus() const
|
||
|
{
|
||
|
return Initialized ? DisplayStatus_Ok : DisplayStatus_NoModeSet;
|
||
|
}
|
||
|
|
||
|
inline void SetCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data)
|
||
|
{
|
||
|
glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data);
|
||
|
}
|
||
|
|
||
|
}; // end class GRendererOGLImpl
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
// ***** GTextureOGL implementation
|
||
|
|
||
|
GTextureOGLImpl::GTextureOGLImpl(GRendererOGLImpl *prenderer)
|
||
|
: GTextureOGL(&prenderer->Textures)
|
||
|
{
|
||
|
pRenderer = prenderer;
|
||
|
TextureId = 0;
|
||
|
TexData = 0;
|
||
|
Mipmaps = 0;
|
||
|
}
|
||
|
|
||
|
GTextureOGLImpl::~GTextureOGLImpl()
|
||
|
{
|
||
|
ReleaseTextureId();
|
||
|
if (!pRenderer)
|
||
|
return;
|
||
|
GLock::Locker guard(&pRenderer->TexturesLock);
|
||
|
if (pFirst)
|
||
|
RemoveNode();
|
||
|
}
|
||
|
|
||
|
// Obtains the renderer that create TextureInfo
|
||
|
GRenderer* GTextureOGLImpl::GetRenderer() const
|
||
|
{ return pRenderer; }
|
||
|
bool GTextureOGLImpl::IsDataValid() const
|
||
|
{ return (TextureId > 0); }
|
||
|
|
||
|
// Remove texture from renderer, notifies renderer destruction
|
||
|
void GTextureOGLImpl::RemoveFromRenderer()
|
||
|
{
|
||
|
pRenderer = 0;
|
||
|
if (AddRef_NotZero())
|
||
|
{
|
||
|
ReleaseTextureId();
|
||
|
CallHandlers(ChangeHandler::Event_RendererReleased);
|
||
|
if (pNext) // We may have been released by user
|
||
|
RemoveNode();
|
||
|
Release();
|
||
|
} else {
|
||
|
if (pNext) // We may have been released by user
|
||
|
RemoveNode();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Creates a texture id ans sets filter parameters, initializes Width/Height
|
||
|
void GTextureOGLImpl::InitTextureId(GLint minFilter)
|
||
|
{
|
||
|
// Create the texture.
|
||
|
glEnable(GL_TEXTURE_2D);
|
||
|
glGenTextures(1, (GLuint*)&TextureId);
|
||
|
glBindTexture(GL_TEXTURE_2D, TextureId);
|
||
|
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
|
||
|
|
||
|
DeleteTexture = 1;
|
||
|
}
|
||
|
|
||
|
// Releases texture and clears values
|
||
|
void GTextureOGLImpl::ReleaseTextureId()
|
||
|
{
|
||
|
if (TextureId > 0)
|
||
|
{
|
||
|
if (DeleteTexture)
|
||
|
{
|
||
|
if (pRenderer)
|
||
|
pRenderer->AddResourceForReleasing(TextureId);
|
||
|
else
|
||
|
glDeleteTextures(1, &TextureId);
|
||
|
}
|
||
|
TextureId = 0;
|
||
|
}
|
||
|
|
||
|
if (TexData)
|
||
|
{
|
||
|
for (int i = 0; i < Mipmaps; i++)
|
||
|
{
|
||
|
if (TexData[i])
|
||
|
GFREE(TexData[i]);
|
||
|
}
|
||
|
GFREE(TexData);
|
||
|
TexData = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Forward declarations for sampling/mipmaps
|
||
|
static void SoftwareResample(int bytesPerPixel, int srcWidth, int srcHeight, int srcPitch, UByte* psrcData, int dstWidth, int dstHeight);
|
||
|
|
||
|
|
||
|
bool GTextureOGLImpl::InitTexture(UInt texID, bool deleteTexture)
|
||
|
{
|
||
|
ReleaseTextureId();
|
||
|
|
||
|
if (texID)
|
||
|
{
|
||
|
TextureId = texID;
|
||
|
DeleteTexture = deleteTexture;
|
||
|
}
|
||
|
|
||
|
CallHandlers(ChangeHandler::Event_DataChange);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
bool GTextureOGLImpl::InitDynamicTexture(int width, int height, GImage::ImageFormat format, int mipmaps, UInt usage)
|
||
|
{
|
||
|
GLint internalFormat=0, texFormat=0;
|
||
|
GLint datatype = GL_UNSIGNED_BYTE;
|
||
|
GLuint bpp = 0;
|
||
|
//bool resample = 0;
|
||
|
|
||
|
ReleaseTextureId();
|
||
|
#ifdef GFC_GL_NO_ALPHA_TEXTURES
|
||
|
IsAlpha = 0;
|
||
|
#endif
|
||
|
|
||
|
if (format == GImage::Image_ARGB_8888)
|
||
|
{
|
||
|
bpp = 4;
|
||
|
texFormat = GL_RGBA;
|
||
|
#if defined(GFC_OS_WIN32) && defined(GL_BGRA)
|
||
|
internalFormat = (usage & Usage_Map) ? GL_BGRA : GL_RGBA;
|
||
|
#else
|
||
|
internalFormat = GL_RGBA;
|
||
|
#endif
|
||
|
#ifdef GFC_OS_PS3
|
||
|
datatype = GL_UNSIGNED_INT_8_8_8_8;
|
||
|
#endif
|
||
|
}
|
||
|
else if (format == GImage::Image_RGB_888)
|
||
|
{
|
||
|
bpp = 3;
|
||
|
texFormat = GL_RGB;
|
||
|
#if defined(GFC_OS_WIN32) && defined(GL_BGR)
|
||
|
internalFormat = (usage & Usage_Map) ? GL_BGR : GL_RGB;
|
||
|
#else
|
||
|
internalFormat = GL_RGB;
|
||
|
#endif
|
||
|
#ifdef GFC_OS_PS3
|
||
|
datatype = GL_UNSIGNED_INT_8_8_8_8;
|
||
|
#endif
|
||
|
}
|
||
|
else if (format == GImage::Image_A_8)
|
||
|
{
|
||
|
#ifdef GFC_GL_NO_ALPHA_TEXTURES
|
||
|
if (usage & Usage_Update)
|
||
|
{
|
||
|
IsAlpha = 1;
|
||
|
texFormat = GL_RGBA;
|
||
|
internalFormat = GL_RGBA;
|
||
|
#ifdef GFC_OS_PS3
|
||
|
datatype = GL_UNSIGNED_INT_8_8_8_8;
|
||
|
#endif
|
||
|
}
|
||
|
else
|
||
|
#endif
|
||
|
{
|
||
|
internalFormat = GL_ALPHA;
|
||
|
texFormat = GL_ALPHA;
|
||
|
bpp = 1;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
GASSERT(0);
|
||
|
|
||
|
InitTextureId(GL_LINEAR);
|
||
|
TextureFmt = internalFormat;
|
||
|
TextureData = datatype;
|
||
|
TexWidth = width;
|
||
|
TexHeight = height;
|
||
|
Mipmaps = mipmaps+1;
|
||
|
|
||
|
|
||
|
glTexImage2D(GL_TEXTURE_2D, 0, texFormat, width, height, 0, internalFormat, datatype, 0);
|
||
|
|
||
|
#ifndef GL_VERSION_ES_CM_1_0
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mipmaps);
|
||
|
#endif
|
||
|
|
||
|
#ifdef GL_VERSION_ES_CM_1_0
|
||
|
GFC_DEBUG_WARNING(mipmaps && (width > 1 || height > 1),
|
||
|
"GRendererOGL: updatable texture created with incomplete mipmaps");
|
||
|
#endif
|
||
|
|
||
|
#ifdef GFC_GL_NO_TEX_UPDATE
|
||
|
usage |= Usage_Map;
|
||
|
#endif
|
||
|
|
||
|
if (usage & Usage_Map)
|
||
|
{
|
||
|
TexData = (GLubyte**)GALLOC(sizeof(GLubyte*) * Mipmaps, GStat_Default_Mem);
|
||
|
TexData[0] = (GLubyte*)GALLOC(bpp * TexWidth * TexHeight, GStat_Default_Mem);
|
||
|
memset(TexData[0], 255, bpp * TexWidth * TexHeight);
|
||
|
}
|
||
|
|
||
|
for (int i = 0; i < mipmaps; i++)
|
||
|
{
|
||
|
width >>= 1;
|
||
|
height >>= 1;
|
||
|
if (width < 1)
|
||
|
width = 1;
|
||
|
if (height < 1)
|
||
|
height = 1;
|
||
|
glTexImage2D(GL_TEXTURE_2D, i+1, texFormat, width, height, 0, internalFormat, datatype, 0);
|
||
|
|
||
|
if (usage & Usage_Map)
|
||
|
{
|
||
|
TexData[i+1] = (GLubyte*)GALLOC(bpp * width * height, GStat_Default_Mem);
|
||
|
memset(TexData[i+1], 255, bpp * width * height);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CallHandlers(ChangeHandler::Event_DataChange);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
// NOTE: This function destroys pim's data in the process of making mipmaps.
|
||
|
bool GTextureOGLImpl::InitTexture(GImageBase* pim, UInt usage)
|
||
|
{
|
||
|
// Delete old data
|
||
|
ReleaseTextureId();
|
||
|
if (!pim)
|
||
|
{
|
||
|
// Kill texture
|
||
|
CallHandlers(ChangeHandler::Event_DataChange);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
// Determine format
|
||
|
UInt bytesPerPixel=0;
|
||
|
GLint internalFormat=0;
|
||
|
GLint datatype = GL_UNSIGNED_BYTE;
|
||
|
bool resample = 0;
|
||
|
|
||
|
if (pim->Format == GImage::Image_ARGB_8888)
|
||
|
{
|
||
|
bytesPerPixel = 4;
|
||
|
internalFormat = GL_RGBA;
|
||
|
#ifdef GFC_OS_PS3
|
||
|
datatype = GL_UNSIGNED_INT_8_8_8_8;
|
||
|
#endif
|
||
|
}
|
||
|
else if (pim->Format == GImage::Image_RGB_888)
|
||
|
{
|
||
|
bytesPerPixel = 3;
|
||
|
internalFormat = GL_RGB;
|
||
|
#ifdef GFC_OS_PS3
|
||
|
datatype = GL_UNSIGNED_INT_8_8_8_8;
|
||
|
resample = 1;
|
||
|
#endif
|
||
|
}
|
||
|
else if (pim->Format == GImage::Image_A_8)
|
||
|
{
|
||
|
return InitTextureAlpha(pim);
|
||
|
}
|
||
|
#ifdef GL_COMPRESSED_RGB_S3TC_DXT1_EXT
|
||
|
else if (pim->Format == GImage::Image_DXT1)
|
||
|
{
|
||
|
bytesPerPixel = 1;
|
||
|
internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
|
||
|
}
|
||
|
else if (pim->Format == GImage::Image_DXT3)
|
||
|
{
|
||
|
bytesPerPixel = 1;
|
||
|
internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
|
||
|
}
|
||
|
else if (pim->Format == GImage::Image_DXT5)
|
||
|
{
|
||
|
bytesPerPixel = 1;
|
||
|
internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
||
|
}
|
||
|
#endif
|
||
|
else
|
||
|
{ // Unsupported format
|
||
|
GASSERT(0);
|
||
|
}
|
||
|
|
||
|
#ifdef GFC_GL_NO_ALPHA_TEXTURES
|
||
|
IsAlpha = 0;
|
||
|
#endif
|
||
|
|
||
|
// Create the texture.
|
||
|
InitTextureId(GL_LINEAR);
|
||
|
TextureFmt = internalFormat;
|
||
|
TextureData = datatype;
|
||
|
|
||
|
UInt w = pim->Width;
|
||
|
UInt h = pim->Height;
|
||
|
|
||
|
if (pRenderer->TexNonPower2 < ((usage & Usage_Wrap) ? 2 : 1))
|
||
|
{
|
||
|
w = 1; while (w < pim->Width) { w <<= 1; }
|
||
|
h = 1; while (h < pim->Height) { h <<= 1; }
|
||
|
}
|
||
|
TexWidth = w;
|
||
|
TexHeight = h;
|
||
|
|
||
|
if (!pim->IsDataCompressed() && (w != pim->Width || h != pim->Height || resample))
|
||
|
{
|
||
|
GASSERT_ON_RENDERER_RESAMPLING;
|
||
|
#ifndef GL_VERSION_ES_CM_1_0
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||
|
#endif
|
||
|
|
||
|
// Faster/simpler software bilinear rescale.
|
||
|
SoftwareResample(bytesPerPixel, pim->Width, pim->Height, pim->Pitch, pim->pData, w, h);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Use original image directly.
|
||
|
UInt level = 0;
|
||
|
UInt mipW, mipH, mipPitch;
|
||
|
do
|
||
|
{
|
||
|
const UByte* pdata = pim->GetMipMapLevelData(level, &mipW, &mipH, &mipPitch);
|
||
|
if (pdata == 0) //????
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(1, "GRendererOGL: can't find mipmap level in texture");
|
||
|
break;
|
||
|
}
|
||
|
if (pim->IsDataCompressed())
|
||
|
{
|
||
|
pRenderer->SetCompressedTexImage2D(GL_TEXTURE_2D, level, internalFormat, mipW, mipH, 0,
|
||
|
GImage::GetMipMapLevelSize(pim->Format, mipW, mipH), pdata);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (mipPitch == mipW * bytesPerPixel)
|
||
|
{
|
||
|
glTexImage2D(GL_TEXTURE_2D, level, internalFormat, mipW, mipH, 0, internalFormat, datatype, pdata);
|
||
|
}
|
||
|
#ifdef GL_UNPACK_ALIGNMENT
|
||
|
else if (mipPitch == ((3 + mipW * bytesPerPixel) & ~3))
|
||
|
{
|
||
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
||
|
glTexImage2D(GL_TEXTURE_2D, level, internalFormat, mipW, mipH, 0, internalFormat, datatype, pdata);
|
||
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||
|
}
|
||
|
#endif
|
||
|
else
|
||
|
{
|
||
|
GASSERT(0);
|
||
|
}
|
||
|
}
|
||
|
} while(++level < pim->MipMapCount);
|
||
|
|
||
|
#ifdef GL_VERSION_ES_CM_1_0
|
||
|
GFC_DEBUG_WARNING(level > 1 && (mipW > 1 || mipH > 1),
|
||
|
"GRendererOGL: texture with incomplete mipmaps");
|
||
|
#else
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level-1);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
CallHandlers(ChangeHandler::Event_DataChange);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
bool GTextureOGLImpl::InitTextureAlpha(GImageBase* pim)
|
||
|
{
|
||
|
GASSERT(pim);
|
||
|
int width = pim->Width;
|
||
|
int height = pim->Height;
|
||
|
UByte* data = pim->pData;
|
||
|
|
||
|
bool retVal = 1;
|
||
|
// Delete old data
|
||
|
ReleaseTextureId();
|
||
|
if (!data)
|
||
|
{
|
||
|
// Kill texture
|
||
|
empty_texture:
|
||
|
CallHandlers(ChangeHandler::Event_DataChange);
|
||
|
return retVal;
|
||
|
}
|
||
|
|
||
|
GASSERT(width > 0);
|
||
|
GASSERT(height > 0);
|
||
|
|
||
|
InitTextureId(GL_LINEAR_MIPMAP_LINEAR);
|
||
|
// Copy data to avoid destruction
|
||
|
#ifdef GFC_GL_NO_ALPHA_TEXTURES
|
||
|
IsAlpha = 1;
|
||
|
UByte *pnewData = (UByte*)GALLOC(width * height * 4, GStat_Default_Mem);
|
||
|
if (!pnewData)
|
||
|
{
|
||
|
retVal = 0;
|
||
|
ReleaseTextureId();
|
||
|
goto empty_texture;
|
||
|
}
|
||
|
|
||
|
int len = width * height * 4;
|
||
|
for( int i = 0, j = 0; i < len; i += 4, j++ )
|
||
|
{
|
||
|
pnewData[i] = 255;
|
||
|
pnewData[i+1] = 255;
|
||
|
pnewData[i+2] = 255;
|
||
|
pnewData[i+3] = data[j];
|
||
|
}
|
||
|
#else
|
||
|
UByte *pnewData = 0;
|
||
|
if (pim->MipMapCount <= 1)
|
||
|
{
|
||
|
pnewData = (UByte*)GALLOC(width * height, GStat_Default_Mem);
|
||
|
if (!pnewData)
|
||
|
{
|
||
|
retVal = 0;
|
||
|
ReleaseTextureId();
|
||
|
goto empty_texture;
|
||
|
}
|
||
|
memcpy(pnewData, data, width*height);
|
||
|
}
|
||
|
else
|
||
|
pnewData = data;
|
||
|
#endif
|
||
|
|
||
|
#ifdef GFC_BUILD_DEBUG
|
||
|
if (pRenderer->TexNonPower2 < 2)
|
||
|
{
|
||
|
// must use power-of-two dimensions
|
||
|
int w = 1; while (w < width) { w <<= 1; }
|
||
|
int h = 1; while (h < height) { h <<= 1; }
|
||
|
GASSERT(w == width);
|
||
|
GASSERT(h == height);
|
||
|
}
|
||
|
#endif // DEBUG
|
||
|
|
||
|
#ifdef GFC_GL_NO_ALPHA_TEXTURES
|
||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, pnewData);
|
||
|
|
||
|
// Build mips.
|
||
|
int level = 1;
|
||
|
while (width > 1 || height > 1)
|
||
|
{
|
||
|
GRendererOGLImpl::MakeNextMiplevel(&width, &height, pnewData, GL_RGBA);
|
||
|
glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, pnewData);
|
||
|
level++;
|
||
|
}
|
||
|
TextureFmt = GL_RGBA;
|
||
|
TextureData = GL_UNSIGNED_INT_8_8_8_8;
|
||
|
#else
|
||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pnewData);
|
||
|
|
||
|
int level = 1;
|
||
|
if (pim->MipMapCount <= 1)
|
||
|
{
|
||
|
// Build mips.
|
||
|
while (width > 1 || height > 1)
|
||
|
{
|
||
|
GRendererOGLImpl::MakeNextMiplevel(&width, &height, pnewData);
|
||
|
glTexImage2D(GL_TEXTURE_2D, level, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pnewData);
|
||
|
level++;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
while(level < int(pim->MipMapCount))
|
||
|
{
|
||
|
UInt mipW, mipH;
|
||
|
const UByte* pmipdata = pim->GetMipMapLevelData(level, &mipW, &mipH);
|
||
|
if (pmipdata == 0) //????
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(1, "GRendererOGL: can't find mipmap level in texture");
|
||
|
break;
|
||
|
}
|
||
|
glTexImage2D(GL_TEXTURE_2D, level, GL_ALPHA, mipW, mipH, 0, GL_ALPHA, GL_UNSIGNED_BYTE,
|
||
|
pmipdata);
|
||
|
++level;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TextureFmt = GL_ALPHA;
|
||
|
TextureData = GL_UNSIGNED_BYTE;
|
||
|
#endif
|
||
|
#ifndef GL_VERSION_ES_CM_1_0
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level-1);
|
||
|
#endif
|
||
|
|
||
|
if (pnewData != data)
|
||
|
GFREE(pnewData);
|
||
|
CallHandlers(ChangeHandler::Event_DataChange);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
void GTextureOGLImpl::Update(int level, int n, const UpdateRect *rects, const GImageBase *pim)
|
||
|
{
|
||
|
GLenum datatype = GL_UNSIGNED_BYTE;
|
||
|
GLenum internalFormat = GL_RGBA; // avoid warning.
|
||
|
bool convert = 0;
|
||
|
|
||
|
if (n == 0)
|
||
|
return;
|
||
|
|
||
|
if (pim->Format == GImage::Image_ARGB_8888)
|
||
|
{
|
||
|
internalFormat = GL_RGBA;
|
||
|
#ifdef GFC_OS_PS3
|
||
|
datatype = GL_UNSIGNED_INT_8_8_8_8;
|
||
|
// if (TextureFmt != internalFormat || TextureData != datatype)
|
||
|
#endif
|
||
|
}
|
||
|
else if (pim->Format == GImage::Image_RGB_888)
|
||
|
internalFormat = GL_RGB;
|
||
|
else if (pim->Format == GImage::Image_A_8)
|
||
|
{
|
||
|
#ifdef GFC_GL_NO_ALPHA_TEXTURES
|
||
|
convert = 1;
|
||
|
internalFormat = GL_RGBA;
|
||
|
# ifdef GFC_OS_PS3
|
||
|
datatype = GL_UNSIGNED_INT_8_8_8_8;
|
||
|
# endif
|
||
|
#else
|
||
|
internalFormat = GL_ALPHA;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
glBindTexture(GL_TEXTURE_2D, TextureId);
|
||
|
|
||
|
#ifndef GFC_GL_NO_TEX_UPDATE
|
||
|
|
||
|
#if (defined(GL_UNPACK_ROW_LENGTH) && defined(GL_UNPACK_ALIGNMENT))
|
||
|
if (!convert && pim->Pitch == pim->Width * pim->GetBytesPerPixel())
|
||
|
{
|
||
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, pim->Width);
|
||
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||
|
|
||
|
for (int i = 0; i < n; i++)
|
||
|
glTexSubImage2D(GL_TEXTURE_2D, level,
|
||
|
rects[i].dest.x, rects[i].dest.y, rects[i].src.Width(), rects[i].src.Height(),
|
||
|
internalFormat, datatype, pim->pData + pim->Pitch * rects[i].src.Top + pim->GetBytesPerPixel() * rects[i].src.Left);
|
||
|
|
||
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||
|
}
|
||
|
else if (!convert && pim->Pitch == ((3 + pim->Width * pim->GetBytesPerPixel()) & ~3))
|
||
|
{
|
||
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, pim->Width);
|
||
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
||
|
|
||
|
for (int i = 0; i < n; i++)
|
||
|
glTexSubImage2D(GL_TEXTURE_2D, level,
|
||
|
rects[i].dest.x, rects[i].dest.y, rects[i].src.Width(), rects[i].src.Height(),
|
||
|
internalFormat, datatype, pim->pData + pim->Pitch * rects[i].src.Top + pim->GetBytesPerPixel() * rects[i].src.Left);
|
||
|
|
||
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||
|
}
|
||
|
else
|
||
|
#endif
|
||
|
if (convert) // convert alpha to rgba
|
||
|
{
|
||
|
int s = rects[0].src.Width() * rects[0].src.Height();
|
||
|
for (int i = 0; i < n; i++)
|
||
|
if (rects[i].src.Width() * rects[i].src.Height() > s)
|
||
|
s = rects[i].src.Width() * rects[i].src.Height();
|
||
|
UByte *pdata = (UByte*)GALLOC(s * 4, GStat_Default_Mem);
|
||
|
|
||
|
for (int i = 0; i < n; i++)
|
||
|
{
|
||
|
for (int j = 0; j < rects[i].src.Height(); j++)
|
||
|
for (int k = 0; k < rects[i].src.Width(); k++)
|
||
|
{
|
||
|
pdata[k*4+j*rects[i].src.Width()*4+0] = 255;
|
||
|
pdata[k*4+j*rects[i].src.Width()*4+1] = 255;
|
||
|
pdata[k*4+j*rects[i].src.Width()*4+2] = 255;
|
||
|
pdata[k*4+j*rects[i].src.Width()*4+3] =
|
||
|
pim->pData[pim->Pitch * (j + rects[i].src.Top) +
|
||
|
pim->GetBytesPerPixel() * (k + rects[i].src.Left)];
|
||
|
}
|
||
|
|
||
|
glTexSubImage2D(GL_TEXTURE_2D, level,
|
||
|
rects[i].dest.x, rects[i].dest.y, rects[i].src.Width(), rects[i].src.Height(),
|
||
|
internalFormat, datatype, pdata);
|
||
|
}
|
||
|
|
||
|
GFREE(pdata);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
int s = rects[0].src.Width() * rects[0].src.Height();
|
||
|
for (int i = 0; i < n; i++)
|
||
|
if (rects[i].src.Width() * rects[i].src.Height() > s)
|
||
|
s = rects[i].src.Width() * rects[i].src.Height();
|
||
|
UByte *pdata = (UByte*)GALLOC(s * pim->GetBytesPerPixel(), GStat_Default_Mem);
|
||
|
|
||
|
#if defined(GL_UNPACK_ALIGNMENT)
|
||
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||
|
#endif
|
||
|
|
||
|
for (int i = 0; i < n; i++)
|
||
|
{
|
||
|
for (int j = 0; j < rects[i].src.Height(); j++)
|
||
|
memcpy(pdata + j * rects[i].src.Width() * pim->GetBytesPerPixel(),
|
||
|
pim->pData + pim->Pitch * (j + rects[i].src.Top) + pim->GetBytesPerPixel() * rects[i].src.Left,
|
||
|
rects[i].src.Width() * pim->GetBytesPerPixel());
|
||
|
|
||
|
glTexSubImage2D(GL_TEXTURE_2D, level,
|
||
|
rects[i].dest.x, rects[i].dest.y, rects[i].src.Width(), rects[i].src.Height(),
|
||
|
internalFormat, datatype, pdata);
|
||
|
}
|
||
|
|
||
|
GFREE(pdata);
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
UInt mipw = TexWidth, miph = TexHeight;
|
||
|
|
||
|
for (int i = 0; i < level; i++)
|
||
|
{
|
||
|
mipw >>= 1;
|
||
|
miph >>= 1;
|
||
|
if (mipw < 1)
|
||
|
mipw = 1;
|
||
|
if (miph < 1)
|
||
|
miph = 1;
|
||
|
}
|
||
|
|
||
|
for (int i = 0; i < n; i++)
|
||
|
{
|
||
|
for (int j = 0; j < rects[i].src.Height(); j++)
|
||
|
memcpy(TexData[level] + ((j + rects[i].dest.y) * mipw + rects[i].dest.x) * pim->GetBytesPerPixel(),
|
||
|
pim->pData + pim->Pitch * (j + rects[i].src.Top) + pim->GetBytesPerPixel() * rects[i].src.Left,
|
||
|
rects[i].src.Width() * pim->GetBytesPerPixel());
|
||
|
}
|
||
|
|
||
|
glTexImage2D(GL_TEXTURE_2D, level, internalFormat, mipw, miph, 0, internalFormat, datatype, TexData[level]);
|
||
|
|
||
|
#endif
|
||
|
|
||
|
CallHandlers(ChangeHandler::Event_DataChange);
|
||
|
}
|
||
|
|
||
|
int GTextureOGLImpl::Map(int level, int n, MapRect* maps, int flags)
|
||
|
{
|
||
|
GUNUSED2(n,flags);
|
||
|
GASSERT(level < Mipmaps && n > 0 && maps && TexData[level]);
|
||
|
|
||
|
UInt bpp=0;
|
||
|
switch (TextureFmt)
|
||
|
{
|
||
|
#ifdef GL_BGRA
|
||
|
case GL_BGRA:
|
||
|
#endif
|
||
|
case GL_RGBA:
|
||
|
bpp = 4;
|
||
|
break;
|
||
|
case GL_RGB:
|
||
|
bpp = 3;
|
||
|
break;
|
||
|
case GL_ALPHA:
|
||
|
bpp = 1;
|
||
|
break;
|
||
|
}
|
||
|
UInt mipw = TexWidth, miph = TexHeight;
|
||
|
for (int i = 0; i < level; i++)
|
||
|
{
|
||
|
mipw >>= 1;
|
||
|
miph >>= 1;
|
||
|
if (mipw < 1)
|
||
|
mipw = 1;
|
||
|
if (miph < 1)
|
||
|
miph = 1;
|
||
|
}
|
||
|
|
||
|
maps[0].width = mipw;
|
||
|
maps[0].height = miph;
|
||
|
maps[0].pitch = mipw * bpp;
|
||
|
maps[0].pData = TexData[level];
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
bool GTextureOGLImpl::Unmap(int level, int n, MapRect* maps, int flags)
|
||
|
{
|
||
|
GUNUSED2(flags,n);
|
||
|
|
||
|
GLuint texFormat = TextureFmt;
|
||
|
#if defined(GFC_OS_WIN32) && defined(GL_BGRA)
|
||
|
if (texFormat == GL_BGRA)
|
||
|
texFormat = GL_RGBA;
|
||
|
else if (texFormat == GL_BGR)
|
||
|
texFormat = GL_RGB;
|
||
|
#endif
|
||
|
glBindTexture(GL_TEXTURE_2D, TextureId);
|
||
|
glTexImage2D(GL_TEXTURE_2D, level, texFormat, maps[0].width, maps[0].height, 0, TextureFmt, TextureData, maps[0].pData);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void GTextureOGLImpl::Bind(int stageIndex, GRenderer::BitmapWrapMode WrapMode, GRenderer::BitmapSampleMode SampleMode, bool useMipmaps)
|
||
|
{
|
||
|
pRenderer->glActiveTexture(GL_TEXTURE0 + stageIndex);
|
||
|
glBindTexture(GL_TEXTURE_2D, TextureId);
|
||
|
glEnable(GL_TEXTURE_2D);
|
||
|
|
||
|
pRenderer->ApplySampleMode(WrapMode, SampleMode, useMipmaps);
|
||
|
}
|
||
|
|
||
|
GTextureOGLImplYUV::~GTextureOGLImplYUV()
|
||
|
{
|
||
|
ReleaseTextureId();
|
||
|
}
|
||
|
|
||
|
void GTextureOGLImplYUV::ReleaseTextureId()
|
||
|
{
|
||
|
for (int i = 0; i < 3; i++)
|
||
|
{
|
||
|
if (TextureUVA[i])
|
||
|
{
|
||
|
if (DeleteTexture)
|
||
|
{
|
||
|
if (pRenderer)
|
||
|
pRenderer->AddResourceForReleasing(TextureId);
|
||
|
else
|
||
|
glDeleteTextures(1, TextureUVA+i);
|
||
|
}
|
||
|
if (TexData)
|
||
|
for (int j = 0; j < Mipmaps; j++)
|
||
|
if (TexData[Mipmaps+i*Mipmaps+j])
|
||
|
GFREE(TexData[Mipmaps+i*Mipmaps+j]);
|
||
|
}
|
||
|
TextureUVA[i] = 0;
|
||
|
}
|
||
|
|
||
|
if (TextureId)
|
||
|
{
|
||
|
if (DeleteTexture)
|
||
|
{
|
||
|
if (pRenderer)
|
||
|
pRenderer->AddResourceForReleasing(TextureId);
|
||
|
else
|
||
|
glDeleteTextures(1, &TextureId);
|
||
|
}
|
||
|
|
||
|
if (TexData)
|
||
|
for (int j = 0; j < Mipmaps; j++)
|
||
|
if (TexData[j])
|
||
|
GFREE(TexData[j]);
|
||
|
TextureId = 0;
|
||
|
}
|
||
|
|
||
|
GFREE(TexData);
|
||
|
TexData = 0;
|
||
|
}
|
||
|
|
||
|
bool GTextureOGLImplYUV::InitDynamicTexture(int width, int height, GImage::ImageFormat format, int mipmaps, UInt usage)
|
||
|
{
|
||
|
if (!pRenderer)
|
||
|
return 0;
|
||
|
|
||
|
GUNUSED(usage);
|
||
|
ReleaseTextureId();
|
||
|
|
||
|
TexWidth = width;
|
||
|
TexHeight = height;
|
||
|
DeleteTexture = 1;
|
||
|
|
||
|
UInt ntex = (format == GImage::Image_ARGB_8888 ? 4 : 3);
|
||
|
Mipmaps = mipmaps+1;
|
||
|
TextureFmt = GL_LUMINANCE;
|
||
|
TextureData = GL_UNSIGNED_BYTE;
|
||
|
TexData = (GLubyte**)GALLOC(sizeof(GLubyte*) * Mipmaps * ntex, GStat_Default_Mem);
|
||
|
UInt mipw = TexWidth, miph = TexHeight;
|
||
|
for (int i = 0; i < Mipmaps; i++)
|
||
|
{
|
||
|
TexData[i] = (GLubyte*)GALLOC(mipw * miph, GStat_Default_Mem);
|
||
|
TexData[i+Mipmaps] = (GLubyte*)GALLOC((mipw >> 1) * (miph >> 1), GStat_Default_Mem);
|
||
|
TexData[i+Mipmaps*2] = (GLubyte*)GALLOC((mipw >> 1) * (miph >> 1), GStat_Default_Mem);
|
||
|
if (ntex == 4)
|
||
|
TexData[i+Mipmaps*3] = (GLubyte*)GALLOC( mipw * miph, GStat_Default_Mem);
|
||
|
|
||
|
mipw >>= 1;
|
||
|
miph >>= 1;
|
||
|
if (mipw < 1)
|
||
|
mipw = 1;
|
||
|
if (miph < 1)
|
||
|
miph = 1;
|
||
|
}
|
||
|
|
||
|
glGenTextures(1, (GLuint*)&TextureId);
|
||
|
glGenTextures(ntex-1, TextureUVA);
|
||
|
glBindTexture(GL_TEXTURE_2D, TextureId);
|
||
|
glTexImage2D(GL_TEXTURE_2D, 0, TextureFmt, TexWidth, TexHeight, 0, TextureFmt, TextureData, 0);
|
||
|
glBindTexture(GL_TEXTURE_2D, TextureUVA[0]);
|
||
|
glTexImage2D(GL_TEXTURE_2D, 0, TextureFmt, TexWidth>>1, TexHeight>>1, 0, TextureFmt, TextureData, 0);
|
||
|
glBindTexture(GL_TEXTURE_2D, TextureUVA[1]);
|
||
|
glTexImage2D(GL_TEXTURE_2D, 0, TextureFmt, TexWidth>>1, TexHeight>>1, 0, TextureFmt, TextureData, 0);
|
||
|
if (ntex == 4)
|
||
|
{
|
||
|
glBindTexture(GL_TEXTURE_2D, TextureUVA[2]);
|
||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, TexWidth, TexHeight, 0, GL_ALPHA, TextureData, 0);
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
int GTextureOGLImplYUV::Map(int level, int n, MapRect* maps, int flags)
|
||
|
{
|
||
|
GUNUSED(flags);
|
||
|
GASSERT(n >= (TextureUVA[2] ? 4 : 3) && maps);
|
||
|
|
||
|
int h = TexHeight;
|
||
|
int w = TexWidth;
|
||
|
|
||
|
for (int i = 0; i < level; i++)
|
||
|
{
|
||
|
h >>= 1;
|
||
|
if (h < 1)
|
||
|
h = 1;
|
||
|
w >>= 1;
|
||
|
if (w < 1)
|
||
|
w = 1;
|
||
|
}
|
||
|
|
||
|
n = TextureUVA[2] ? 4 : 3;
|
||
|
maps[0].width = w;
|
||
|
maps[0].height = h;
|
||
|
maps[0].pitch = w;
|
||
|
maps[0].pData = TexData[level];
|
||
|
maps[1].width = w>>1;
|
||
|
maps[1].height = h>>1;
|
||
|
maps[1].pitch = w>>1;
|
||
|
maps[1].pData = TexData[level+Mipmaps];
|
||
|
maps[2].width = w>>1;
|
||
|
maps[2].height = h>>1;
|
||
|
maps[2].pitch = w>>1;
|
||
|
maps[2].pData = TexData[level+Mipmaps*2];
|
||
|
if (TextureUVA[2])
|
||
|
{
|
||
|
maps[3].width = w;
|
||
|
maps[3].height = h;
|
||
|
maps[3].pitch = w;
|
||
|
maps[3].pData = TexData[level+Mipmaps*3];
|
||
|
}
|
||
|
return n;
|
||
|
}
|
||
|
|
||
|
bool GTextureOGLImplYUV::Unmap(int level, int n, MapRect* maps, int flags)
|
||
|
{
|
||
|
GUNUSED2(n,flags);
|
||
|
GASSERT(n == (TextureUVA[2] ? 4 : 3));
|
||
|
|
||
|
glBindTexture(GL_TEXTURE_2D, TextureId);
|
||
|
glTexImage2D(GL_TEXTURE_2D, level, TextureFmt, maps[0].width, maps[0].height, 0, TextureFmt, TextureData, maps[0].pData);
|
||
|
glBindTexture(GL_TEXTURE_2D, TextureUVA[0]);
|
||
|
glTexImage2D(GL_TEXTURE_2D, level, TextureFmt, maps[1].width, maps[1].height, 0, TextureFmt, TextureData, maps[1].pData);
|
||
|
glBindTexture(GL_TEXTURE_2D, TextureUVA[1]);
|
||
|
glTexImage2D(GL_TEXTURE_2D, level, TextureFmt, maps[2].width, maps[2].height, 0, TextureFmt, TextureData, maps[2].pData);
|
||
|
if (TextureUVA[2])
|
||
|
{
|
||
|
glBindTexture(GL_TEXTURE_2D, TextureUVA[2]);
|
||
|
glTexImage2D(GL_TEXTURE_2D, level, GL_ALPHA, maps[3].width, maps[3].height, 0, GL_ALPHA, TextureData, maps[3].pData);
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
void GTextureOGLImplYUV::Bind(int stageIndex, GRenderer::BitmapWrapMode WrapMode, GRenderer::BitmapSampleMode SampleMode, bool useMipmaps)
|
||
|
{
|
||
|
GASSERT(stageIndex == 0);
|
||
|
GUNUSED(stageIndex);
|
||
|
|
||
|
for (int i = 0; i < (TextureUVA[2] ? 3 : 2); i++)
|
||
|
{
|
||
|
pRenderer->glActiveTexture(GL_TEXTURE1 + i);
|
||
|
glBindTexture(GL_TEXTURE_2D, TextureUVA[i]);
|
||
|
glEnable(GL_TEXTURE_2D);
|
||
|
pRenderer->ApplySampleMode(WrapMode, SampleMode, useMipmaps);
|
||
|
}
|
||
|
|
||
|
pRenderer->glActiveTexture(GL_TEXTURE0);
|
||
|
glBindTexture(GL_TEXTURE_2D, TextureId);
|
||
|
glEnable(GL_TEXTURE_2D);
|
||
|
pRenderer->ApplySampleMode(WrapMode, SampleMode, useMipmaps);
|
||
|
}
|
||
|
|
||
|
|
||
|
// GTextureOGLImpl implementation
|
||
|
|
||
|
// Creates an OpenGL texture of the specified dst dimensions, from a
|
||
|
// resampled version of the given src image. Does a bilinear
|
||
|
// resampling to create the dst image.
|
||
|
static void SoftwareResample(
|
||
|
int bytesPerPixel,
|
||
|
int srcWidth,
|
||
|
int srcHeight,
|
||
|
int srcPitch,
|
||
|
UByte* psrcData,
|
||
|
int dstWidth,
|
||
|
int dstHeight)
|
||
|
{
|
||
|
UByte* rescaled = 0;
|
||
|
|
||
|
unsigned internalFormat = 0;
|
||
|
unsigned inputFormat = 0;
|
||
|
GLint dataType = GL_UNSIGNED_BYTE;
|
||
|
|
||
|
switch(bytesPerPixel)
|
||
|
{
|
||
|
case 3:
|
||
|
#ifdef GFC_OS_PS3
|
||
|
dataType = GL_UNSIGNED_INT_8_8_8_8;
|
||
|
inputFormat = GL_RGBA;
|
||
|
internalFormat = GL_RGBA;
|
||
|
|
||
|
rescaled = (UByte*)GALLOC(dstWidth * dstHeight * 4, GStat_Default_Mem);
|
||
|
|
||
|
GRenderer::ResizeImage(&rescaled[0], dstWidth, dstHeight, dstWidth * 4,
|
||
|
psrcData, srcWidth, srcHeight, srcPitch,
|
||
|
GRenderer::ResizeRgbToRgba);
|
||
|
#else
|
||
|
inputFormat = GL_RGB;
|
||
|
internalFormat = GL_RGB;
|
||
|
rescaled = (UByte*)GALLOC(dstWidth * dstHeight * bytesPerPixel, GStat_Default_Mem);
|
||
|
|
||
|
GRenderer::ResizeImage(&rescaled[0], dstWidth, dstHeight, dstWidth * 3,
|
||
|
psrcData, srcWidth, srcHeight, srcPitch,
|
||
|
GRenderer::ResizeRgbToRgb);
|
||
|
#endif
|
||
|
break;
|
||
|
|
||
|
case 4:
|
||
|
rescaled = (UByte*)GALLOC(dstWidth * dstHeight * bytesPerPixel, GStat_Default_Mem);
|
||
|
inputFormat = GL_RGBA;
|
||
|
internalFormat = GL_RGBA;
|
||
|
#ifdef GFC_OS_PS3
|
||
|
dataType = GL_UNSIGNED_INT_8_8_8_8;
|
||
|
#endif
|
||
|
GRenderer::ResizeImage(&rescaled[0], dstWidth, dstHeight, dstWidth * 4,
|
||
|
psrcData, srcWidth, srcHeight, srcPitch,
|
||
|
GRenderer::ResizeRgbaToRgba);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, dstWidth, dstHeight,
|
||
|
0, inputFormat, dataType, &rescaled[0]);
|
||
|
|
||
|
GFREE(rescaled);
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifdef GFC_OS_PS3
|
||
|
#include "GRendererOGLImplPS3.cpp"
|
||
|
#elif defined(GL_ARB_fragment_program)
|
||
|
#include "GRendererOGLImplAsm.cpp"
|
||
|
#endif
|
||
|
|
||
|
// Factory.
|
||
|
GRendererOGL* GRendererOGL::CreateRenderer()
|
||
|
{
|
||
|
#ifdef GFC_OS_PS3
|
||
|
return new GRendererOGLImplPS3;
|
||
|
#elif defined(GL_ARB_fragment_program)
|
||
|
return new GRendererOGLImplAsm;
|
||
|
#else
|
||
|
return new GRendererOGLImpl;
|
||
|
#endif
|
||
|
}
|
||
|
|