diff options
Diffstat (limited to 'hge/graphics.cpp')
-rw-r--r-- | hge/graphics.cpp | 1524 |
1 files changed, 0 insertions, 1524 deletions
diff --git a/hge/graphics.cpp b/hge/graphics.cpp deleted file mode 100644 index 6ee9578..0000000 --- a/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; -} |