aboutsummaryrefslogtreecommitdiff
path: root/archive/hge/graphics.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'archive/hge/graphics.cpp')
-rw-r--r--archive/hge/graphics.cpp1524
1 files changed, 0 insertions, 1524 deletions
diff --git a/archive/hge/graphics.cpp b/archive/hge/graphics.cpp
deleted file mode 100644
index 6ee9578..0000000
--- a/archive/hge/graphics.cpp
+++ /dev/null
@@ -1,1524 +0,0 @@
-/*
-** Haaf's Game Engine 1.8
-** Copyright (C) 2003-2007, Relish Games
-** hge.relishgames.com
-**
-** Core functions implementation: graphics
-*/
-
-// !!! FIXME: the texture data when locking/unlocking textures is in GL_BGRA format, not GL_RGBA.
-// !!! FIXME: ...but this mistake wasn't noticed for several games, since most didn't lock outside
-// !!! FIXME: of a piece of code that was #ifdef'd for Unix anyhow.
-// !!! FIXME: But if you lock textures and the colors are wrong, that's what happened. We need to
-// !!! FIXME: sort out all the places where we're passing things around in RGBA to fix this.
-// !!! FIXME: In the mean time, it's usually easier to just change your application to expect
-// !!! FIXME: locked textures to be RGBA instead of BGRA.
-
-// !!! FIXME: ...apparently we're locking textures upside down, too?
-
-#include "hge_impl.h"
-
-#define SUPPORT_CXIMAGE 1
-#if SUPPORT_CXIMAGE
-// conflict with Mac OS X 10.3.9 SDK...
-#ifdef _T
-#undef _T
-#endif
-#include "CxImage/ximage.h"
-#else
-/* Use DevIL instead of CXImage */
-#include <IL/il.h>
-#include <IL/ilu.h>
-#endif
-
-// avoiding glext.h here ...
-#ifndef GL_TEXTURE_RECTANGLE_ARB
-#define GL_TEXTURE_RECTANGLE_ARB 0x84F5
-#endif
-#ifndef GL_FRAMEBUFFER_EXT
-#define GL_FRAMEBUFFER_EXT 0x8D40
-#endif
-#ifndef GL_RENDERBUFFER_EXT
-#define GL_RENDERBUFFER_EXT 0x8D41
-#endif
-#ifndef GL_COLOR_ATTACHMENT0_EXT
-#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0
-#endif
-#ifndef GL_DEPTH_ATTACHMENT_EXT
-#define GL_DEPTH_ATTACHMENT_EXT 0x8D00
-#endif
-#ifndef GL_FRAMEBUFFER_COMPLETE_EXT
-#define GL_FRAMEBUFFER_COMPLETE_EXT 0x8CD5
-#endif
-#ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
-#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
-#endif
-#ifndef GL_YCBCR_422_APPLE
-#define GL_YCBCR_422_APPLE 0x85B9
-#endif
-#ifndef GL_UNSIGNED_SHORT_8_8_APPLE
-#define GL_UNSIGNED_SHORT_8_8_APPLE 0x85BA
-#endif
-#ifndef GL_UNSIGNED_SHORT_8_8_REV_APPLE
-#define GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB
-#endif
-static const char* GRAPHICS_SRC_FN="hge/graphics.cpp";
-struct gltexture
-{
- GLuint name;
- GLuint width;
- GLuint height;
- GLuint potw; // Power-of-two width.
- GLuint poth; // Power-of-two height.
- const char *filename; // if backed by a file, not a managed buffer.
- DWORD *pixels; // original rgba data.
- DWORD *lock_pixels; // for locked texture
- bool is_render_target;
- bool lost;
- bool lock_readonly;
- GLint lock_x;
- GLint lock_y;
- GLint lock_width;
- GLint lock_height;
-};
-
-static DWORD *_DecodeImage(BYTE *data, const char *fname, DWORD size, int &width, int &height)
-{
- width = height = 0;
-
- DWORD *pixels = NULL;
- const size_t fnamelen = fname ? strlen(fname) : 0;
- if ( (fnamelen > 5) && (strcasecmp((fname + fnamelen) - 5, ".rgba") == 0) )
- {
- DWORD *ptr = (DWORD *) data;
- DWORD w = ptr[0];
- DWORD h = ptr[1];
- BYTESWAP(w);
- BYTESWAP(h);
- if ( ((w * h * 4) + 8) == size ) // not truncated?
- {
- width = (int) w;
- height = (int) h;
- pixels = new DWORD[width * height];
- memcpy(pixels, ptr + 2, w * h * 4); // !!! FIXME: ignores pitch.
- }
- return pixels;
- }
-
-#if SUPPORT_CXIMAGE
- CxImage img;
- img.Decode(data, size, CXIMAGE_FORMAT_UNKNOWN);
- if (img.IsValid())
- {
- width = img.GetWidth();
- height = img.GetHeight();
- pixels = new DWORD[width * height];
- BYTE *wptr = (BYTE *) pixels;
- const bool hasalpha = img.AlphaIsValid();
- for (int y = 0; y < height; y++)
- {
- for (int x = 0; x < width; x++)
- {
- const RGBQUAD rgb = img.GetPixelColor(x, y, true);
- *(wptr++) = rgb.rgbRed;
- *(wptr++) = rgb.rgbGreen;
- *(wptr++) = rgb.rgbBlue;
- *(wptr++) = hasalpha ? rgb.rgbReserved : 0xFF; // alpha.
- }
- }
- }
-#else
- ilInit();
- iluInit();
-
- ILuint id;
- ilGenImages(1, &id);
-
- if(ilLoadImage(fname)) {
- printf("success: %s\n", fname);
- ILinfo info;
- iluGetImageInfo(&info);
- width = info.Width;
- height = info.Height;
- size = info.SizeOfData;
- pixels = new DWORD[width * height];
- ilCopyPixels(0, 0, 0, width, height, 0, IL_RGBA, IL_UNSIGNED_INT, pixels);
- ilShutDown();
- }
-#endif
-
- return pixels;
-}
-
-
-void HGE_Impl::_BindTexture(gltexture *t)
-{
- // The Direct3D renderer is using managed textures, so they aren't every
- // actually "lost" ... we may have to rebuild them here, though.
- if ((t != NULL) && (t->lost))
- _ConfigureTexture(t, t->width, t->height, t->pixels);
-
- if ( ((HTEXTURE)t) != CurTexture )
- {
- pOpenGLDevice->glBindTexture(pOpenGLDevice->TextureTarget, t ? t->name : 0);
- CurTexture = (HTEXTURE) t;
- }
-}
-
-void CALL HGE_Impl::Gfx_Clear(DWORD color)
-{
- GLbitfield flags = GL_COLOR_BUFFER_BIT;
- if ( ((pCurTarget) && (pCurTarget->depth)) || bZBuffer )
- flags |= GL_DEPTH_BUFFER_BIT;
-
- const GLfloat a = ((GLfloat) ((color >> 24) & 0xFF)) / 255.0f;
- const GLfloat r = ((GLfloat) ((color >> 16) & 0xFF)) / 255.0f;
- const GLfloat g = ((GLfloat) ((color >> 8) & 0xFF)) / 255.0f;
- const GLfloat b = ((GLfloat) ((color >> 0) & 0xFF)) / 255.0f;
- pOpenGLDevice->glClearColor(r, g, b, a);
- pOpenGLDevice->glClear(flags);
-}
-
-void CALL HGE_Impl::Gfx_SetClipping(int x, int y, int w, int h)
-{
- int scr_width, scr_height;
- struct { int X; int Y; int Width; int Height; float MinZ; float MaxZ; } vp;
-
- if(!pCurTarget) {
- scr_width=pHGE->System_GetStateInt(HGE_SCREENWIDTH);
- scr_height=pHGE->System_GetStateInt(HGE_SCREENHEIGHT);
- }
- else {
- scr_width=Texture_GetWidth(pCurTarget->tex);
- scr_height=Texture_GetHeight(pCurTarget->tex);
- }
-
- if(!w) {
- vp.X=0;
- vp.Y=0;
- vp.Width=scr_width;
- vp.Height=scr_height;
- }
- else
- {
- if(x<0) { w+=x; x=0; }
- if(y<0) { h+=y; y=0; }
-
- if(x+w > scr_width) w=scr_width-x;
- if(y+h > scr_height) h=scr_height-y;
-
- vp.X=x;
- vp.Y=y;
- vp.Width=w;
- vp.Height=h;
- }
-
- if ((clipX == vp.X) && (clipY == vp.Y) && (clipW == vp.Width) && (clipH == vp.Height))
- return; // nothing to do here, don't call into the GL.
-
- vp.MinZ=0.0f;
- vp.MaxZ=1.0f;
-
- _render_batch();
-
- clipX = vp.X;
- clipY = vp.Y;
- clipW = vp.Width;
- clipH = vp.Height;
- pOpenGLDevice->glScissor(vp.X, (scr_height-vp.Y)-vp.Height, vp.Width, vp.Height);
-}
-
-void CALL HGE_Impl::Gfx_SetTransform(float x, float y, float dx, float dy, float rot, float hscale, float vscale)
-{
- if ((x == 0.0f) && (y == 0.0f) && (dx == 0.0f) && (dy == 0.0f) && (rot == 0.0f) && (hscale == 0.0f) && (vscale == 0.0f))
- {
- //reset everything
- pOpenGLDevice->glMatrixMode(GL_MODELVIEW);
- pOpenGLDevice->glLoadIdentity();
- bTransforming=false;
- return;
- }
-
- _render_batch();
- bTransforming = true;
-
- pOpenGLDevice->glMatrixMode(GL_MODELVIEW);
- //we have to reset the matrix in all cases.
- //or this would cause insane transforming...
- pOpenGLDevice->glLoadIdentity();
- pOpenGLDevice->glTranslatef(-x, -y, 0.0f);
- pOpenGLDevice->glScalef(hscale, vscale, 1.0f);
- pOpenGLDevice->glRotatef(rot, 0.0f, 0.0f, 1.0f);
- pOpenGLDevice->glTranslatef(x+dx, y+dy, 0.0f);
-}
-
-bool CALL HGE_Impl::Gfx_BeginScene(HTARGET targ)
-{
- CRenderTargetList *target=(CRenderTargetList *)targ;
-
- if(VertArray)
- {
- _PostError("Gfx_BeginScene: Scene is already being rendered");
- return false;
- }
-
- if(target != pCurTarget)
- {
- if (pOpenGLDevice->have_GL_EXT_framebuffer_object)
- pOpenGLDevice->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, (target) ? target->frame : 0);
-
- if ( ((target) && (target->depth)) || (bZBuffer) )
- pOpenGLDevice->glEnable(GL_DEPTH_TEST);
- else
- pOpenGLDevice->glDisable(GL_DEPTH_TEST);
-
- // d3d's SetRenderTarget() forces the viewport to surface size...
- if (target)
- {
- pOpenGLDevice->glScissor(0, 0, target->width, target->height);
- pOpenGLDevice->glViewport(0, 0, target->width, target->height);
- _SetProjectionMatrix(target->width, target->height);
- }
- else
- {
- pOpenGLDevice->glScissor(0, 0, nScreenWidth, nScreenHeight);
- pOpenGLDevice->glViewport(0, 0, nScreenWidth, nScreenHeight);
- _SetProjectionMatrix(nScreenWidth, nScreenHeight);
- }
-
- pOpenGLDevice->glMatrixMode(GL_MODELVIEW);
- pOpenGLDevice->glLoadIdentity();
-
- pCurTarget=target;
- }
-
- VertArray = pVB;
- return true;
-}
-
-void CALL HGE_Impl::Gfx_EndScene()
-{
- _render_batch(true);
-
- // no "real" render targets? Push the framebuffer to a texture.
- // This is not going to work in lots of legitimate scenarios, but it will
- // most of the time, so it's better than nothing when you lack FBOs.
- if ((pCurTarget) && (!pOpenGLDevice->have_GL_EXT_framebuffer_object))
- {
- gltexture *pTex = (gltexture *) pCurTarget->tex;
- if ((pTex != NULL) && (pTex->lost))
- _ConfigureTexture(pTex, pTex->width, pTex->height, pTex->pixels);
-
- const int width = pCurTarget->width;
- const int height = pCurTarget->height;
- pOpenGLDevice->glFinish();
- DWORD *pixels = new DWORD[width * height];
- pOpenGLDevice->glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
- pOpenGLDevice->glBindTexture(pOpenGLDevice->TextureTarget, pTex->name);
- pOpenGLDevice->glTexSubImage2D(pOpenGLDevice->TextureTarget, 0, 0, 0, width, height,
- GL_RGBA, GL_UNSIGNED_BYTE, pixels);
- pOpenGLDevice->glBindTexture(pOpenGLDevice->TextureTarget, CurTexture ? (((gltexture *) CurTexture)->name) : 0);
- delete[] pixels;
- }
-
- if(!pCurTarget) SDL_GL_SwapBuffers();
- //const GLenum err = pOpenGLDevice->glGetError();
- //if (err != GL_NO_ERROR) printf("GL error! 0x%X\n", (int) err);
- //Gfx_Clear(0xFF | (0xFF<<24) | (random() & 0xFF << 16) | (random() & 0xFF << 8));
- //Gfx_Clear(0xFF000000);
-}
-
-void HGE_Impl::_SetTextureFilter()
-{
- const GLenum filter = (bTextureFilter) ? GL_LINEAR : GL_NEAREST;
- pOpenGLDevice->glTexParameteri(pOpenGLDevice->TextureTarget, GL_TEXTURE_MIN_FILTER, filter);
- pOpenGLDevice->glTexParameteri(pOpenGLDevice->TextureTarget, GL_TEXTURE_MAG_FILTER, filter);
-}
-
-
-bool HGE_Impl::_PrimsOutsideClipping(const hgeVertex *v, const int verts)
-{
- if (bTransforming)
- return false; // screw it, let the GL do the clipping.
-
- const int maxX = clipX + clipW;
- const int maxY = clipY + clipH;
- for (int i = 0; i < verts; i++, v++)
- {
- const int x = v->x;
- const int y = v->y;
- if ((x > clipX) && (x < maxX) && (y > clipY) && (y < maxY))
- return false;
- }
- return true;
-}
-
-
-void CALL HGE_Impl::Gfx_RenderLine(float x1, float y1, float x2, float y2, DWORD color, float z)
-{
- if (VertArray)
- {
- if(CurPrimType!=HGEPRIM_LINES || nPrim>=VERTEX_BUFFER_SIZE/HGEPRIM_LINES || CurTexture || CurBlendMode!=BLEND_DEFAULT)
- {
- _render_batch();
-
- CurPrimType=HGEPRIM_LINES;
- if(CurBlendMode != BLEND_DEFAULT) _SetBlendMode(BLEND_DEFAULT);
- _BindTexture(NULL);
- }
-
- int i=nPrim*HGEPRIM_LINES;
- VertArray[i].x = x1; VertArray[i+1].x = x2;
- VertArray[i].y = y1; VertArray[i+1].y = y2;
- VertArray[i].z = VertArray[i+1].z = z;
- VertArray[i].col = VertArray[i+1].col = color;
- VertArray[i].tx = VertArray[i+1].tx =
- VertArray[i].ty = VertArray[i+1].ty = 0.0f;
-
- if (!_PrimsOutsideClipping(&VertArray[i], HGEPRIM_LINES))
- nPrim++;
- }
-}
-
-template <class T> static inline const T Min(const T a, const T b) { return a < b ? a : b; }
-template <class T> static inline const T Max(const T a, const T b) { return a > b ? a : b; }
-
-void CALL HGE_Impl::Gfx_RenderTriple(const hgeTriple *triple)
-{
- if (VertArray)
- {
- const hgeVertex *v = triple->v;
- if (_PrimsOutsideClipping(v, HGEPRIM_TRIPLES))
- {
- // check for overlap, despite triangle points being outside clipping...
- const int maxX = clipX + clipW;
- const int maxY = clipY + clipH;
- const int leftmost = Min(Min(v[0].x, v[1].x), v[2].x);
- const int rightmost = Max(Max(v[0].x, v[1].x), v[2].x);
- const int topmost = Min(Min(v[0].y, v[1].y), v[2].y);
- const int bottommost = Max(Max(v[0].y, v[1].y), v[2].y);
- if ( ((clipX < leftmost) || (clipX > rightmost)) &&
- ((maxX < leftmost) || (maxX > rightmost)) &&
- ((clipY < topmost) || (clipY > bottommost)) &&
- ((maxY < topmost) || (maxY > bottommost)) )
- return; // no, this is really totally clipped.
- }
-
- if(CurPrimType!=HGEPRIM_TRIPLES || nPrim>=VERTEX_BUFFER_SIZE/HGEPRIM_TRIPLES || CurTexture!=triple->tex || CurBlendMode!=triple->blend)
- {
- _render_batch();
-
- CurPrimType=HGEPRIM_TRIPLES;
- if(CurBlendMode != triple->blend) _SetBlendMode(triple->blend);
- _BindTexture((gltexture *) triple->tex);
- }
-
- memcpy(&VertArray[nPrim*HGEPRIM_TRIPLES], triple->v, sizeof(hgeVertex)*HGEPRIM_TRIPLES);
- nPrim++;
- }
-}
-
-void CALL HGE_Impl::Gfx_RenderQuad(const hgeQuad *quad)
-{
- if (VertArray)
- {
- const hgeVertex *v = quad->v;
- if (_PrimsOutsideClipping(v, HGEPRIM_QUADS))
- {
- // check for overlap, despite quad points being outside clipping...
- const int maxX = clipX + clipW;
- const int maxY = clipY + clipH;
- const int leftmost = Min(Min(Min(v[0].x, v[1].x), v[2].x), v[3].x);
- const int rightmost = Max(Max(Max(v[0].x, v[1].x), v[2].x), v[3].x);
- const int topmost = Min(Min(Min(v[0].y, v[1].y), v[2].y), v[3].y);
- const int bottommost = Max(Max(Max(v[0].y, v[1].y), v[2].y), v[3].y);
- if ( ((clipX < leftmost) || (clipX > rightmost)) &&
- ((maxX < leftmost) || (maxX > rightmost)) &&
- ((clipY < topmost) || (clipY > bottommost)) &&
- ((maxY < topmost) || (maxY > bottommost)) )
- return; // no, this is really totally clipped.
- }
-
- if(CurPrimType!=HGEPRIM_QUADS || nPrim>=VERTEX_BUFFER_SIZE/HGEPRIM_QUADS || CurTexture!=quad->tex || CurBlendMode!=quad->blend)
- {
- _render_batch();
-
- CurPrimType=HGEPRIM_QUADS;
- if(CurBlendMode != quad->blend) _SetBlendMode(quad->blend);
- _BindTexture((gltexture *) quad->tex);
- }
-
- memcpy(&VertArray[nPrim*HGEPRIM_QUADS], quad->v, sizeof(hgeVertex)*HGEPRIM_QUADS);
- nPrim++;
- }
-}
-
-hgeVertex* CALL HGE_Impl::Gfx_StartBatch(int prim_type, HTEXTURE tex, int blend, int *max_prim)
-{
- if(VertArray)
- {
- _render_batch();
-
- CurPrimType=prim_type;
- if(CurBlendMode != blend) _SetBlendMode(blend);
- _BindTexture((gltexture *) tex);
- *max_prim=VERTEX_BUFFER_SIZE / prim_type;
- return VertArray;
- }
- else return 0;
-}
-
-void CALL HGE_Impl::Gfx_FinishBatch(int nprim)
-{
- nPrim = nprim;
-}
-
-bool HGE_Impl::_BuildTarget(CRenderTargetList *pTarget, GLuint texname, int width, int height, bool zbuffer)
-{
- bool okay = true; // no FBOs? Fake success by default.
- if (pOpenGLDevice->have_GL_EXT_framebuffer_object)
- {
- pOpenGLDevice->glGenFramebuffersEXT(1, &pTarget->frame);
- if (zbuffer)
- pOpenGLDevice->glGenRenderbuffersEXT(1, &pTarget->depth);
- pOpenGLDevice->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, pTarget->frame);
- pOpenGLDevice->glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, pOpenGLDevice->TextureTarget, texname, 0);
- if (zbuffer)
- {
- pOpenGLDevice->glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, pTarget->depth);
- pOpenGLDevice->glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, width, height);
- pOpenGLDevice->glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, pTarget->depth);
- }
-
- GLenum rc = pOpenGLDevice->glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
- if ((rc == GL_FRAMEBUFFER_COMPLETE_EXT) && (pOpenGLDevice->glGetError() == GL_NO_ERROR))
- {
- pOpenGLDevice->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- okay = true;
- }
- else
- {
- pOpenGLDevice->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
- pOpenGLDevice->glDeleteRenderbuffersEXT(1, &pTarget->depth);
- pOpenGLDevice->glDeleteFramebuffersEXT(1, &pTarget->frame);
- }
- pOpenGLDevice->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, pCurTarget ? pCurTarget->frame : 0);
- }
-
- return okay;
-}
-
-HTARGET CALL HGE_Impl::Target_Create(int width, int height, bool zbuffer)
-{
- bool okay = false;
- CRenderTargetList *pTarget = new CRenderTargetList;
- memset(pTarget, '\0', sizeof (CRenderTargetList));
-
- pTarget->tex = _BuildTexture(width, height, NULL);
- gltexture *gltex = (gltexture *) pTarget->tex;
- gltex->is_render_target = true;
- gltex->lost = false;
- _ConfigureTexture(gltex, width, height, NULL);
-
- pTarget->width = width;
- pTarget->height = height;
-
- okay = _BuildTarget(pTarget, gltex->name, width, height, zbuffer);
- if (!okay)
- {
- System_Log("%s: OpenGL: Failed to create render target!",GRAPHICS_SRC_FN);
- Texture_Free(pTarget->tex);
- delete pTarget;
- return 0;
- }
-
- pTarget->next=pTargets;
- pTargets=pTarget;
-
- return (HTARGET)pTarget;
-}
-
-void CALL HGE_Impl::Target_Free(HTARGET target)
-{
- CRenderTargetList *pTarget=pTargets, *pPrevTarget=NULL;
-
- while(pTarget)
- {
- if((CRenderTargetList *)target == pTarget)
- {
- if(pPrevTarget)
- pPrevTarget->next = pTarget->next;
- else
- pTargets = pTarget->next;
-
- if (pOpenGLDevice->have_GL_EXT_framebuffer_object)
- {
- if (pCurTarget == (CRenderTargetList *)target)
- pOpenGLDevice->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
- if (pTarget->depth)
- pOpenGLDevice->glDeleteRenderbuffersEXT(1, &pTarget->depth);
- pOpenGLDevice->glDeleteFramebuffersEXT(1, &pTarget->frame);
- }
-
- if (pCurTarget == (CRenderTargetList *)target)
- pCurTarget = 0;
-
- Texture_Free(pTarget->tex);
- delete pTarget;
- return;
- }
-
- pPrevTarget = pTarget;
- pTarget = pTarget->next;
- }
-}
-
-HTEXTURE CALL HGE_Impl::Target_GetTexture(HTARGET target)
-{
- CRenderTargetList *targ=(CRenderTargetList *)target;
- if(target) return targ->tex;
- else return 0;
-}
-
-static inline bool _IsPowerOfTwo(const GLuint x)
-{
- return ((x & (x - 1)) == 0);
-}
-
-static inline GLuint _NextPowerOfTwo(GLuint x)
-{
- x--;
- for (unsigned i = 1; i < (sizeof(GLuint) * 8); i <<= 1)
- x |= x >> i;
- return x + 1;
-}
-
-void HGE_Impl::_ConfigureTexture(gltexture *t, int width, int height, DWORD *pixels)
-{
- GLuint tex = 0;
- pOpenGLDevice->glGenTextures(1, &tex);
-
- t->lost = false;
- t->name = tex;
- t->width = width;
- t->height = height;
- t->pixels = pixels;
- t->potw = 0;
- t->poth = 0;
-
- // see if we're backed by a file and not RAM.
- const bool loadFromFile = ((pixels == NULL) && (t->filename != NULL));
- if (loadFromFile)
- {
- DWORD size = 0;
- BYTE *data = (BYTE *) pHGE->Resource_Load(t->filename, &size);
- if (data != NULL)
- {
- int w, h;
- pixels = _DecodeImage(data, t->filename, size, w, h);
- if ((w != width) || (h != height)) // yikes, file changed?
- {
- delete[] pixels;
- pixels = NULL;
- }
- Resource_Free(data);
- }
- }
-
- pOpenGLDevice->glBindTexture(pOpenGLDevice->TextureTarget, tex);
- if (pOpenGLDevice->TextureTarget != GL_TEXTURE_RECTANGLE_ARB)
- {
- pOpenGLDevice->glTexParameterf(pOpenGLDevice->TextureTarget, GL_TEXTURE_MIN_LOD, 0.0f);
- pOpenGLDevice->glTexParameterf(pOpenGLDevice->TextureTarget, GL_TEXTURE_MAX_LOD, 0.0f);
- pOpenGLDevice->glTexParameteri(pOpenGLDevice->TextureTarget, GL_TEXTURE_BASE_LEVEL, 0);
- pOpenGLDevice->glTexParameteri(pOpenGLDevice->TextureTarget, GL_TEXTURE_MAX_LEVEL, 0);
- }
- const GLenum intfmt = pOpenGLDevice->have_GL_EXT_texture_compression_s3tc ? GL_COMPRESSED_RGBA_S3TC_DXT5_EXT : GL_RGBA;
- if ((pOpenGLDevice->have_GL_ARB_texture_rectangle) || (pOpenGLDevice->have_GL_ARB_texture_non_power_of_two) || (_IsPowerOfTwo(width) && _IsPowerOfTwo(height))) {
- pOpenGLDevice->glTexImage2D(pOpenGLDevice->TextureTarget, 0, intfmt, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
- }
- else
- {
- t->potw = _NextPowerOfTwo(width);
- t->poth = _NextPowerOfTwo(height);
- pOpenGLDevice->glTexImage2D(pOpenGLDevice->TextureTarget, 0, intfmt, t->potw, t->poth, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
- pOpenGLDevice->glTexSubImage2D(pOpenGLDevice->TextureTarget, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
- }
-
- pOpenGLDevice->glBindTexture(pOpenGLDevice->TextureTarget, CurTexture ? (((gltexture *) CurTexture)->name) : 0);
-
- if (loadFromFile)
- delete[] pixels;
-}
-
-HTEXTURE HGE_Impl::_BuildTexture(int width, int height, DWORD *pixels)
-{
- gltexture *retval = new gltexture;
- memset(retval, '\0', sizeof (gltexture));
- retval->lost = true; // we'll actually generate a texture and upload when forced.
- retval->width = width;
- retval->height = height;
- retval->pixels = pixels;
- return (HTEXTURE)retval;
-}
-
-HTEXTURE CALL HGE_Impl::Texture_Create(int width, int height)
-{
- DWORD *pixels = new DWORD[width * height];
- memset(pixels, '\0', sizeof (DWORD) * width * height);
- HTEXTURE retval = _BuildTexture(width, height, pixels);
-
- // the Direct3D renderer doesn't add these to the (textures) list, but we need them for when we "lose" the GL context.
- if (retval != 0)
- {
- CTextureList *texItem=new CTextureList;
- texItem->tex=retval;
- texItem->width=width;
- texItem->height=height;
- texItem->next=textures;
- textures=texItem;
- }
-
- return retval;
-}
-
-HTEXTURE CALL HGE_Impl::Texture_Load(const char *filename, DWORD size, bool bMipmap)
-{
- HTEXTURE retval = 0;
- int width = 0;
- int height = 0;
-
- void *data;
- DWORD _size;
- CTextureList *texItem;
- const char *fname = NULL;
- if(size) { data=(void *)filename; _size=size; }
- else
- {
- fname = filename;
- data=pHGE->Resource_Load(filename, &_size);
- if(!data) return 0;
- }
-
- DWORD *pixels = _DecodeImage((BYTE *) data, fname, _size, width, height);
- if (pixels != NULL)
- retval = _BuildTexture(width, height, pixels);
-
- if(!size) Resource_Free(data);
-
- if (retval == 0)
- {
- STUBBED("texture load fail!");
- _PostError("Can't create texture");
- }
- else
- {
- texItem=new CTextureList;
- texItem->tex=retval;
- texItem->width=width;
- texItem->height=height;
- texItem->next=textures;
- textures=texItem;
-
- // force an upload to the GL and lose our copy if it's backed by
- // a file. We won't keep it here to conserve system RAM.
- if (!size)
- {
- gltexture *t = (gltexture *) retval;
- _ConfigureTexture(t, t->width, t->height, t->pixels);
- delete[] t->pixels;
- t->pixels = NULL;
- t->filename = strcpy(new char[strlen(filename) + 1], filename);
- }
- }
-
- return retval;
-}
-
-void CALL HGE_Impl::Texture_Free(HTEXTURE tex)
-{
- if (pOpenGLDevice == NULL)
- return; // in case we already shut down.
-
- CTextureList *texItem=textures, *texPrev=0;
-
- while(texItem)
- {
- if(texItem->tex==tex)
- {
- if(texPrev) texPrev->next=texItem->next;
- else textures=texItem->next;
- delete texItem;
- break;
- }
- texPrev=texItem;
- texItem=texItem->next;
- }
- if(tex)
- {
- gltexture *pTex = (gltexture *) tex;
- delete[] pTex->filename;
- delete[] pTex->lock_pixels;
- delete[] pTex->pixels;
- pOpenGLDevice->glDeleteTextures(1, &pTex->name);
- delete pTex;
- }
-}
-
-int CALL HGE_Impl::Texture_GetWidth(HTEXTURE tex, bool bOriginal)
-{
- CTextureList *texItem=textures;
-
- if(bOriginal)
- {
- while(texItem)
- {
- if(texItem->tex==tex) return texItem->width;
- texItem=texItem->next;
- }
- }
- else
- {
- return ((gltexture*)tex)->width;
- }
- return 0;
-}
-
-
-int CALL HGE_Impl::Texture_GetHeight(HTEXTURE tex, bool bOriginal)
-{
- CTextureList *texItem=textures;
-
- if(bOriginal)
- {
- while(texItem)
- {
- if(texItem->tex==tex) return texItem->height;
- texItem=texItem->next;
- }
- }
- else
- {
- return ((gltexture*)tex)->height;
- }
- return 0;
-}
-
-// HGE extension!
-// fast path for pushing YUV video to a texture instead of having to
-// lock/convert-to-rgba/unlock...current HGE semantics involve a
-// lot of unnecessary overhead on this, not to mention the conversion
-// on the CPU is painful on PowerPC chips.
-// This lets us use OpenGL extensions to move data to the hardware
-// without conversion.
-// Don't taunt this function. Side effects are probably rampant.
-bool CALL HGE_Impl::HGEEXT_Texture_PushYUV422(HTEXTURE tex, const BYTE *yuv)
-{
- if (!pOpenGLDevice->have_GL_APPLE_ycbcr_422)
- return false;
-
- gltexture *pTex=(gltexture*)tex;
- assert(!pTex->lock_pixels);
-
- if (pTex->lost) // just reupload the whole thing.
- _ConfigureTexture(pTex, pTex->width, pTex->height, pTex->pixels);
-
- // Any existing pixels aren't valid anymore.
- if (pTex->pixels)
- {
- delete[] pTex->pixels;
- pTex->pixels = NULL;
- }
-
- pOpenGLDevice->glBindTexture(pOpenGLDevice->TextureTarget, pTex->name);
- pOpenGLDevice->glTexSubImage2D(pOpenGLDevice->TextureTarget, 0, 0, 0,
- pTex->width, pTex->height, GL_YCBCR_422_APPLE,
- GL_UNSIGNED_SHORT_8_8_APPLE, yuv);
- pOpenGLDevice->glBindTexture(pOpenGLDevice->TextureTarget, CurTexture ? (((gltexture *) CurTexture)->name) : 0);
- return true;
-}
-
-DWORD * CALL HGE_Impl::Texture_Lock(HTEXTURE tex, bool bReadOnly, int left, int top, int width, int height)
-{
- gltexture *pTex=(gltexture*)tex;
-
- if (pTex->lock_pixels)
- {
- assert(false && "multiple lock of texture...");
- return 0;
- }
-
- // see if we're backed by a file and not RAM.
- const bool loadFromFile = ((pTex->pixels == NULL) && (pTex->filename != NULL));
- if (loadFromFile)
- {
- DWORD size = 0;
- BYTE *data = (BYTE *) pHGE->Resource_Load(pTex->filename, &size);
- if (data != NULL)
- {
- int w, h;
- pTex->pixels = _DecodeImage(data, pTex->filename, size, w, h);
- if ((w != (int)pTex->width) || (h != (int)pTex->height)) // yikes, file changed?
- {
- delete[] pTex->pixels;
- pTex->pixels = NULL;
- }
- Resource_Free(data);
- }
- if (pTex->pixels != NULL)
- {
- // can't go back to file after we lock, since app might change data.
- if (!bReadOnly)
- {
- delete[] pTex->filename;
- pTex->filename = NULL;
- }
- }
- }
-
- if ((pTex->pixels == NULL) && (!pTex->is_render_target)) // can't lock this texture...?!
- return 0;
-
- // !!! FIXME: is this right?
- if((width == 0) && (height == 0))
- {
- width = pTex->width;
- height = pTex->height;
- }
-
- // !!! FIXME: do something with this?
- assert(width > 0);
- assert(width <= (int)pTex->width);
- assert(height > 0);
- assert(height <= (int)pTex->height);
- assert(left >= 0);
- assert(left <= width);
- assert(top >= 0);
- assert(top <= height);
-
- pTex->lock_readonly = bReadOnly;
- pTex->lock_x = left;
- pTex->lock_y = top;
- pTex->lock_width = width;
- pTex->lock_height = height;
- pTex->lock_pixels = new DWORD[width * height];
-
- DWORD *dst = pTex->lock_pixels;
-
- if (pTex->is_render_target)
- {
- assert(false && "need to bind fbo before glReadPixels...");
- DWORD *upsideDown = new DWORD[width * height];
- DWORD *src = upsideDown + ((height-1) * width);
- pOpenGLDevice->glReadPixels(left, (pTex->height-top)-height, width, height, GL_RGBA, GL_UNSIGNED_BYTE, upsideDown);
- for (int i = 0; i < height; i++)
- {
- memcpy(dst, src, width * sizeof (DWORD));
- dst += width;
- src -= width;
- }
- delete[] upsideDown;
- }
- else
- {
- DWORD *src = pTex->pixels + ((top*pTex->width) + left);
- for (int i = 0; i < height; i++)
- {
- memcpy(dst, src, width * sizeof (DWORD));
- dst += width;
- src += pTex->width;
- }
- }
-
- return pTex->lock_pixels;
-}
-
-
-void CALL HGE_Impl::Texture_Unlock(HTEXTURE tex)
-{
- gltexture *pTex=(gltexture*)tex;
-
- if (pTex->lock_pixels == NULL) return; // not locked.
-
- if (!pTex->lock_readonly) // have to reupload to the hardware.
- {
- // need to update pTex->pixels ...
- const DWORD *src = pTex->lock_pixels;
- DWORD *dst = pTex->pixels + ((pTex->lock_y*pTex->width) + pTex->lock_x);
- for (int i = 0; i < pTex->lock_height; i++)
- {
- memcpy(dst, src, pTex->lock_width * sizeof (DWORD));
- dst += pTex->width;
- src += pTex->lock_width;
- }
-
- if (pTex->lost) // just reupload the whole thing.
- _ConfigureTexture(pTex, pTex->width, pTex->height, pTex->pixels);
- else
- {
- pOpenGLDevice->glBindTexture(pOpenGLDevice->TextureTarget, pTex->name);
- pOpenGLDevice->glTexSubImage2D(pOpenGLDevice->TextureTarget, 0, pTex->lock_x,
- (pTex->height-pTex->lock_y)-pTex->lock_height,
- pTex->lock_width, pTex->lock_height, GL_RGBA,
- GL_UNSIGNED_BYTE, pTex->lock_pixels);
- pOpenGLDevice->glBindTexture(pOpenGLDevice->TextureTarget, CurTexture ? (((gltexture *) CurTexture)->name) : 0);
- }
- }
-
- // if we were read-only and we're backed by a file, ditch the uncompressed copy in system RAM.
- if ((pTex->filename != NULL) && (pTex->lock_readonly))
- {
- delete[] pTex->pixels;
- pTex->pixels = NULL;
- }
-
- delete[] pTex->lock_pixels;
- pTex->lock_pixels = NULL;
- pTex->lock_readonly = false;
- pTex->lock_x = -1;
- pTex->lock_y = -1;
- pTex->lock_width = -1;
- pTex->lock_height = -1;
-}
-
-//////// Implementation ////////
-
-#define DEBUG_VERTICES 0
-#if DEBUG_VERTICES
-static inline void print_vertex(const hgeVertex *v)
-{
- printf(" (%f, %f, %f), 0x%X, (%f, %f)\n", v->x, v->y, v->z, v->col, v->tx, v->ty);
-}
-#endif
-
-void HGE_Impl::_render_batch(bool bEndScene)
-{
- if(VertArray)
- {
- if(nPrim)
- {
- const float h = (float) ((pCurTarget) ? pCurTarget->height : nScreenHeight);
-
- // texture rectangles range from 0 to size, not 0 to 1. :/
- float texwmult = 1.0f;
- float texhmult = 1.0f;
-
- if (CurTexture)
- {
- _SetTextureFilter();
- const gltexture *pTex = ((gltexture *)CurTexture);
- if (pOpenGLDevice->TextureTarget == GL_TEXTURE_RECTANGLE_ARB)
- {
- texwmult = pTex->width;
- texhmult = pTex->height;
- }
- else if ((pTex->potw != 0) && (pTex->poth != 0))
- {
- texwmult = ( ((float)pTex->width) / ((float)pTex->potw) );
- texhmult = ( ((float)pTex->height) / ((float)pTex->poth) );
- }
- }
-
- for (int i = 0; i < nPrim*CurPrimType; i++)
- {
- // (0, 0) is the lower left in OpenGL, upper left in D3D.
- VertArray[i].y = h - VertArray[i].y;
-
- // Z axis is inverted in OpenGL from D3D.
- VertArray[i].z = -VertArray[i].z;
-
- // (0, 0) is lower left texcoord in OpenGL, upper left in D3D.
- // Also, scale for texture rectangles vs. 2D textures.
- VertArray[i].tx *= texwmult;
- VertArray[i].ty = (1.0f - VertArray[i].ty) * texhmult;
-
- // Colors are RGBA in OpenGL, ARGB in Direct3D.
- const DWORD color = VertArray[i].col;
- BYTE *col = (BYTE *) &VertArray[i].col;
- const BYTE a = ((color >> 24) & 0xFF);
- const BYTE r = ((color >> 16) & 0xFF);
- const BYTE g = ((color >> 8) & 0xFF);
- const BYTE b = ((color >> 0) & 0xFF);
- col[0] = r;
- col[1] = g;
- col[2] = b;
- col[3] = a;
- }
-
- switch(CurPrimType)
- {
- case HGEPRIM_QUADS:
- pOpenGLDevice->glDrawElements(GL_TRIANGLES, nPrim * 6, GL_UNSIGNED_SHORT, pIB);
- #if DEBUG_VERTICES
- for (int i = 0; i < nPrim*6; i+=3)
- {
- printf("QUAD'S TRIANGLE:\n");
- print_vertex(&pVB[pIB[i+0]]);
- print_vertex(&pVB[pIB[i+1]]);
- print_vertex(&pVB[pIB[i+2]]);
- }
- printf("DONE.\n");
- #endif
- break;
-
- case HGEPRIM_TRIPLES:
- pOpenGLDevice->glDrawArrays(GL_TRIANGLES, 0, nPrim * 3);
- break;
-
- case HGEPRIM_LINES:
- pOpenGLDevice->glDrawArrays(GL_LINES, 0, nPrim * 2);
- break;
- }
-
- nPrim=0;
- }
- if(bEndScene) VertArray = 0;
- else VertArray = pVB;
- }
-}
-
-void HGE_Impl::_SetBlendMode(int blend)
-{
- if((blend & BLEND_ALPHABLEND) != (CurBlendMode & BLEND_ALPHABLEND))
- {
- if(blend & BLEND_ALPHABLEND) pOpenGLDevice->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- else pOpenGLDevice->glBlendFunc(GL_SRC_ALPHA, GL_ONE);
- }
-
- if((blend & BLEND_ZWRITE) != (CurBlendMode & BLEND_ZWRITE))
- {
- if(blend & BLEND_ZWRITE) pOpenGLDevice->glDepthMask(GL_TRUE);
- else pOpenGLDevice->glDepthMask(GL_FALSE);
- }
-
- if((blend & BLEND_COLORADD) != (CurBlendMode & BLEND_COLORADD))
- {
- if(blend & BLEND_COLORADD) pOpenGLDevice->glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD);
- else pOpenGLDevice->glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
- }
-
- CurBlendMode = blend;
-}
-
-void HGE_Impl::_SetProjectionMatrix(int width, int height)
-{
- pOpenGLDevice->glMatrixMode(GL_PROJECTION);
- pOpenGLDevice->glLoadIdentity();
- pOpenGLDevice->glOrtho(0, (float)width, 0, (float)height, 0.0f, 1.0f);
- bTransforming = false;
- clipX = 0;
- clipY = 0;
- clipW = width;
- clipH = height;
-}
-
-void HGE_Impl::_UnloadOpenGLEntryPoints()
-{
- #define GL_PROC(ext,fn,call,ret,params) pOpenGLDevice->fn = NULL;
- #include "hge_glfuncs.h"
- #undef GL_PROC
-}
-
-bool HGE_Impl::_HaveOpenGLExtension(const char *extlist, const char *ext)
-{
- const char *ptr = strstr(extlist, ext);
- if (ptr == NULL)
- return false;
-
- const char endchar = ptr[strlen(ext)];
- if ((endchar == '\0') || (endchar == ' '))
- return true; // extension is in the list.
-
- return false; // just not supported, fail.
-}
-
-bool HGE_Impl::_LoadOpenGLEntryPoints()
-{
- System_Log("%s: OpenGL: loading entry points and examining extensions...",GRAPHICS_SRC_FN);
-
- // these can be reset to false below...
- pOpenGLDevice->have_base_opengl = true;
- pOpenGLDevice->have_GL_ARB_texture_rectangle = true;
- pOpenGLDevice->have_GL_ARB_texture_non_power_of_two = true;
- pOpenGLDevice->have_GL_EXT_framebuffer_object = true;
- pOpenGLDevice->have_GL_EXT_texture_compression_s3tc = true;
- pOpenGLDevice->have_GL_ARB_vertex_buffer_object = true;
- pOpenGLDevice->have_GL_APPLE_ycbcr_422 = true;
-
- #define GL_PROC(ext,fn,call,ret,params) \
- if (pOpenGLDevice->have_##ext) { \
- if ((pOpenGLDevice->fn = (_HGE_PFN_##fn) SDL_GL_GetProcAddress(#fn)) == NULL) { \
- System_Log("Failed to load OpenGL entry point '" #fn "'"); \
- pOpenGLDevice->have_##ext = false; \
- } \
- } else {}
- #include "hge_glfuncs.h"
- #undef GL_PROC
-
- if (!pOpenGLDevice->have_base_opengl)
- {
- _UnloadOpenGLEntryPoints();
- return false;
- }
-
- System_Log("%s: GL_RENDERER: %s",GRAPHICS_SRC_FN, (const char *) pOpenGLDevice->glGetString(GL_RENDERER));
- System_Log("%s: GL_VENDOR: %s",GRAPHICS_SRC_FN, (const char *) pOpenGLDevice->glGetString(GL_VENDOR));
- System_Log("%s: GL_VERSION: %s",GRAPHICS_SRC_FN, (const char *) pOpenGLDevice->glGetString(GL_VERSION));
-
- const char *verstr = (const char *) pOpenGLDevice->glGetString(GL_VERSION);
- int maj = 0;
- int min = 0;
- sscanf(verstr, "%d.%d", &maj, &min);
-
- if ( (maj < 1) || ((maj == 1) && (min < 2)) )
- {
- _PostError("OpenGL implementation must be at least version 1.2");
- _UnloadOpenGLEntryPoints();
- return false;
- }
-
- const char *exts = (const char *) pOpenGLDevice->glGetString(GL_EXTENSIONS);
-
- // NPOT texture support ...
-
- if (_HaveOpenGLExtension(exts, "GL_ARB_texture_rectangle"))
- pOpenGLDevice->have_GL_ARB_texture_rectangle = true;
- else if (_HaveOpenGLExtension(exts, "GL_EXT_texture_rectangle"))
- pOpenGLDevice->have_GL_ARB_texture_rectangle = true;
- else if (_HaveOpenGLExtension(exts, "GL_NV_texture_rectangle"))
- pOpenGLDevice->have_GL_ARB_texture_rectangle = true;
- else
- pOpenGLDevice->have_GL_ARB_texture_rectangle = false;
-
- if (maj >= 2)
- pOpenGLDevice->have_GL_ARB_texture_non_power_of_two = true;
- else if (_HaveOpenGLExtension(exts, "GL_ARB_texture_non_power_of_two"))
- pOpenGLDevice->have_GL_ARB_texture_non_power_of_two = true;
- else
- pOpenGLDevice->have_GL_ARB_texture_non_power_of_two = false;
-
- if (pOpenGLDevice->have_GL_ARB_texture_rectangle)
- {
- System_Log("%s: OpenGL: Using GL_ARB_texture_rectangle",GRAPHICS_SRC_FN);
- pOpenGLDevice->TextureTarget = GL_TEXTURE_RECTANGLE_ARB;
- }
- else if (pOpenGLDevice->have_GL_ARB_texture_non_power_of_two)
- {
- System_Log("%s: OpenGL: Using GL_ARB_texture_non_power_of_two",GRAPHICS_SRC_FN);
- pOpenGLDevice->TextureTarget = GL_TEXTURE_2D;
- }
- else
- {
- // We can fake this with POT textures. Get a real OpenGL!
- System_Log("%s: OpenGL: Using power-of-two textures. This costs more memory!",GRAPHICS_SRC_FN);
- pOpenGLDevice->TextureTarget = GL_TEXTURE_2D;
- }
-
- // render-to-texture support ...
-
- // is false if an entry point is missing, but we still need to check for the extension string...
- if (pOpenGLDevice->have_GL_EXT_framebuffer_object)
- {
- // Disable this on Mac OS X Tiger, since some drivers appear to be buggy.
- if ((pHGE->MacOSXVersion) && (pHGE->MacOSXVersion < 0x1050))
- pOpenGLDevice->have_GL_EXT_framebuffer_object = false;
- else if (_HaveOpenGLExtension(exts, "GL_EXT_framebuffer_object"))
- pOpenGLDevice->have_GL_EXT_framebuffer_object = true;
- else
- pOpenGLDevice->have_GL_EXT_framebuffer_object = false;
- }
-
- if (pOpenGLDevice->have_GL_EXT_framebuffer_object)
- System_Log("%s: OpenGL: Using GL_EXT_framebuffer_object",GRAPHICS_SRC_FN);
- else
- System_Log("%s: OpenGL: WARNING! No render-to-texture support. Things may render badly.",GRAPHICS_SRC_FN);
-
-
- // Texture compression ...
-
- if (bForceTextureCompression &&
- _HaveOpenGLExtension(exts, "GL_ARB_texture_compression") &&
- _HaveOpenGLExtension(exts, "GL_EXT_texture_compression_s3tc"))
- pOpenGLDevice->have_GL_EXT_texture_compression_s3tc = true;
- else
- pOpenGLDevice->have_GL_EXT_texture_compression_s3tc = false;
-
- if (pOpenGLDevice->have_GL_EXT_texture_compression_s3tc)
- System_Log("%s: OpenGL: Using GL_EXT_texture_compression_s3tc",GRAPHICS_SRC_FN);
- else if (bForceTextureCompression)
- {
- bForceTextureCompression = false; // oh well.
- System_Log("%s: OpenGL: WARNING: no texture compression support, in a low-memory system.",GRAPHICS_SRC_FN);
- System_Log("%s: OpenGL: Performance may be very bad!",GRAPHICS_SRC_FN);
- }
-
- // YUV textures...
-
- if (_HaveOpenGLExtension(exts, "GL_APPLE_ycbcr_422"))
- pOpenGLDevice->have_GL_APPLE_ycbcr_422 = true;
- else
- pOpenGLDevice->have_GL_APPLE_ycbcr_422 = false;
-
- if (pOpenGLDevice->have_GL_APPLE_ycbcr_422)
- System_Log("%s: OpenGL: Using GL_APPLE_ycbcr_422 to render YUV frames.",GRAPHICS_SRC_FN);
- else
- System_Log("%s: OpenGL: WARNING: no YUV texture support; videos may render slowly.",GRAPHICS_SRC_FN);
-
- // VBOs...
-
- // is false if an entry point is missing, but we still need to check for the extension string...
- if (pOpenGLDevice->have_GL_ARB_vertex_buffer_object)
- {
- if (_HaveOpenGLExtension(exts, "GL_ARB_vertex_buffer_object"))
- pOpenGLDevice->have_GL_ARB_vertex_buffer_object = true;
- else
- pOpenGLDevice->have_GL_ARB_vertex_buffer_object = false;
- }
-
- if (pOpenGLDevice->have_GL_ARB_vertex_buffer_object)
- System_Log("%s: OpenGL: Using GL_ARB_vertex_buffer_object",GRAPHICS_SRC_FN);
- else
- System_Log("%s: OpenGL: WARNING! No VBO support; performance may suffer.",GRAPHICS_SRC_FN);
-
- return true;
-}
-
-bool HGE_Impl::_GfxInit()
-{
- CurTexture = 0;
-
-// Init OpenGL ... SDL should have created a context at this point.
- assert(pOpenGLDevice == NULL);
- pOpenGLDevice = new COpenGLDevice;
- if (!_LoadOpenGLEntryPoints())
- return false; // already called _PostError().
-
- nScreenBPP=SDL_GetVideoSurface()->format->BitsPerPixel;
-
- _AdjustWindow();
-
- System_Log("%s: Mode: %d x %d\n",GRAPHICS_SRC_FN,nScreenWidth,nScreenHeight);
-// Create vertex batch buffer
-
- VertArray=0;
- textures=0;
- IndexBufferObject=0;
-
-// Init all stuff that can be lost
-
- if(!_init_lost()) return false;
-
- // make sure the framebuffers are cleared and force to screen
- pOpenGLDevice->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- SDL_GL_SwapBuffers();
- pOpenGLDevice->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- SDL_GL_SwapBuffers();
-
- return true;
-}
-
-void HGE_Impl::_AdjustWindow()
-{
- // no-op.
-}
-
-void HGE_Impl::_Resize(int width, int height)
-{
- if(hwndParent)
- {
- //if(procFocusLostFunc) procFocusLostFunc();
- STUBBED("resize");
- #if 0
- d3dppW.BackBufferWidth=width;
- d3dppW.BackBufferHeight=height;
- nScreenWidth=width;
- nScreenHeight=height;
-
- _SetProjectionMatrix(nScreenWidth, nScreenHeight);
- _GfxRestore();
- #endif
-
- //if(procFocusGainFunc) procFocusGainFunc();
- }
-}
-
-void HGE_Impl::_GfxDone()
-{
- //CRenderTargetList *target=pTargets;
-
- while(textures) Texture_Free(textures->tex);
- while(pTargets) Target_Free((HTARGET) pTargets);
- textures=0;
- pTargets=0;
-
- VertArray = 0;
- delete[] pVB;
- pVB=0;
- delete[] pIB;
- pIB=0;
-
- if(pOpenGLDevice)
- {
- if (pOpenGLDevice->have_GL_ARB_vertex_buffer_object)
- {
- if (IndexBufferObject != 0)
- {
- pOpenGLDevice->glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, 0);
- pOpenGLDevice->glDeleteBuffersARB(1, &IndexBufferObject);
- IndexBufferObject = 0;
- }
- }
-
- delete pOpenGLDevice;
- pOpenGLDevice=0;
- }
-}
-
-
-bool HGE_Impl::_GfxRestore()
-{
- if(!pOpenGLDevice) return false;
-
- delete[] pVB;
- pVB=0;
-
- delete[] pIB;
- pIB=0;
-
- _UnloadOpenGLEntryPoints();
- if (!_LoadOpenGLEntryPoints())
- return false;
-
- if(!_init_lost()) return false;
-
- if(procGfxRestoreFunc) return procGfxRestoreFunc();
-
- return true;
-}
-
-
-bool HGE_Impl::_init_lost()
-{
- _BindTexture(NULL); // make sure nothing is bound, so everything that we do bind regenerates.
-
- for (CTextureList *item = textures; item != NULL; item = item->next)
- {
- gltexture *t = (gltexture *) item->tex;
- if (t == NULL) continue;
- t->lost = true;
- t->name = 0;
- }
-
- CRenderTargetList *target=pTargets;
- while(target)
- {
- gltexture *tex = (gltexture *) target->tex;
- _BindTexture(tex); // force texture recreation.
- _BindTexture(NULL);
- _BuildTarget(target, tex ? tex->name : 0, target->width, target->height, target->depth != 0);
- target=target->next;
- }
-
-// Create Vertex buffer
- // We just use a client-side array, since you can reasonably count on support
- // existing in any GL, and it basically offers the same functionality that
- // HGE uses in Direct3D: it locks the vertex buffer, unlocks in time to
- // draw something, then relocks again immediately...more or less, that method
- // offers the same performance metrics as a client-side array.
- // We _will_ stuff the indices in a buffer object, though, if possible,
- // since they never change...this matches the D3D behaviour better, since
- // they lock, store, and forget about it, but without a buffer object,
- // we'd have to pass the array over the bus every glDrawElements() call.
- // It's not worth the tapdance for vertex buffer objects though, due to
- // HGE's usage patterns.
- pVB = new hgeVertex[VERTEX_BUFFER_SIZE];
-
-// Create and setup Index buffer
- pIB = new GLushort[VERTEX_BUFFER_SIZE*6/4];
- GLushort *pIndices = pIB;
- int n = 0;
- for(int i=0; i<VERTEX_BUFFER_SIZE/4; i++) {
- *pIndices++=n;
- *pIndices++=n+1;
- *pIndices++=n+2;
- *pIndices++=n+2;
- *pIndices++=n+3;
- *pIndices++=n;
- n+=4;
- }
-
- #if !DEBUG_VERTICES // need pIB for DEBUG_VERTICES.
- if (pOpenGLDevice->have_GL_ARB_vertex_buffer_object)
- {
- // stay bound forever. The Index Buffer Object never changes.
- pOpenGLDevice->glGenBuffersARB(1, &IndexBufferObject);
- pOpenGLDevice->glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, IndexBufferObject);
- pOpenGLDevice->glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER, sizeof (GLushort) * ((VERTEX_BUFFER_SIZE*6)/4), pIB, GL_STATIC_DRAW);
- delete[] pIB;
- pIB=0;
- }
- #endif
-
- // always use client-side arrays; set it up once at startup.
- pOpenGLDevice->glVertexPointer(3, GL_FLOAT, sizeof (hgeVertex), &pVB[0].x);
- pOpenGLDevice->glColorPointer(4, GL_UNSIGNED_BYTE, sizeof (hgeVertex), &pVB[0].col);
- pOpenGLDevice->glTexCoordPointer(2, GL_FLOAT, sizeof (hgeVertex), &pVB[0].tx);
- pOpenGLDevice->glEnableClientState(GL_VERTEX_ARRAY);
- pOpenGLDevice->glEnableClientState(GL_COLOR_ARRAY);
- pOpenGLDevice->glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-
-// Set common render states
-
- pOpenGLDevice->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- pOpenGLDevice->glPixelStorei(GL_PACK_ALIGNMENT, 1);
-
- //pD3DDevice->SetRenderState( D3DRS_LASTPIXEL, FALSE );
- pOpenGLDevice->glDisable(GL_TEXTURE_2D);
- if (pOpenGLDevice->have_GL_ARB_texture_rectangle)
- pOpenGLDevice->glDisable(GL_TEXTURE_RECTANGLE_ARB);
- pOpenGLDevice->glEnable(pOpenGLDevice->TextureTarget);
- pOpenGLDevice->glEnable(GL_SCISSOR_TEST);
- pOpenGLDevice->glDisable(GL_CULL_FACE);
- pOpenGLDevice->glDisable(GL_LIGHTING);
- pOpenGLDevice->glDepthFunc(GL_GEQUAL);
-
- if (bZBuffer)
- pOpenGLDevice->glEnable(GL_DEPTH_TEST);
- else
- pOpenGLDevice->glDisable(GL_DEPTH_TEST);
-
- pOpenGLDevice->glEnable(GL_BLEND);
- pOpenGLDevice->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- pOpenGLDevice->glEnable(GL_ALPHA_TEST);
- pOpenGLDevice->glAlphaFunc(GL_GEQUAL, 1.0f / 255.0f);
-
- pOpenGLDevice->glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-
- _SetTextureFilter();
-
- // !!! FIXME: this isn't what HGE's Direct3D code does, but the game I'm working with
- // !!! FIXME: forces clamping outside of HGE, so I just wedged it in here.
- // Apple says texture rectangle on ATI X1000 chips only supports CLAMP_TO_EDGE.
- // Texture rectangle only supports CLAMP* wrap modes anyhow.
- pOpenGLDevice->glTexParameteri(pOpenGLDevice->TextureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- pOpenGLDevice->glTexParameteri(pOpenGLDevice->TextureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- pOpenGLDevice->glTexParameteri(pOpenGLDevice->TextureTarget, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
-
- nPrim=0;
- CurPrimType=HGEPRIM_QUADS;
- CurBlendMode = BLEND_DEFAULT;
- CurTexture = 0;
-
- pOpenGLDevice->glScissor(0, 0, nScreenWidth, nScreenHeight);
- pOpenGLDevice->glViewport(0, 0, nScreenWidth, nScreenHeight);
-
- // make sure the framebuffer is cleared and force to screen
- pOpenGLDevice->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
- _SetProjectionMatrix(nScreenWidth, nScreenHeight);
- pOpenGLDevice->glMatrixMode(GL_MODELVIEW);
- pOpenGLDevice->glLoadIdentity();
-
- return true;
-}