diff --git a/src/gl/gl3device.cpp b/src/gl/gl3device.cpp index 3f01321..2638d4b 100644 --- a/src/gl/gl3device.cpp +++ b/src/gl/gl3device.cpp @@ -235,6 +235,8 @@ static GlState curGlState, oldGlState; static int32 activeTexture; static uint32 boundTexture[MAXNUMSTAGES]; +static uint32 currentFramebuffer; + static uint32 blendMap[] = { GL_ZERO, // actually invalid GL_ZERO, @@ -415,6 +417,16 @@ bindTexture(uint32 texid) return prev; } +void +bindFramebuffer(uint32 fbo) +{ + //glBindFramebuffer(GL_FRAMEBUFFER, fbo); + if(currentFramebuffer != fbo){ + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + currentFramebuffer = fbo; + } +} + // TODO: support mipmaps static GLint filterConvMap_NoMIP[] = { 0, GL_NEAREST, GL_LINEAR, @@ -990,62 +1002,44 @@ flushCache(void) } static void -clearCamera(Camera *cam, RGBA *col, uint32 mode) +setFrameBuffer(Camera *cam) { - RGBAf colf; - GLbitfield mask; + Raster *fbuf = cam->frameBuffer; + Raster *zbuf = cam->zBuffer; + assert(fbuf); - convColor(&colf, col); - glClearColor(colf.red, colf.green, colf.blue, colf.alpha); - mask = 0; - if(mode & Camera::CLEARIMAGE) - mask |= GL_COLOR_BUFFER_BIT; - if(mode & Camera::CLEARZ) - mask |= GL_DEPTH_BUFFER_BIT; - glDepthMask(GL_TRUE); - glClear(mask); - glDepthMask(rwStateCache.zwrite); -} + Gl3Raster *natfb = PLUGINOFFSET(Gl3Raster, fbuf, nativeRasterOffset); + Gl3Raster *natzb = PLUGINOFFSET(Gl3Raster, zbuf, nativeRasterOffset); + assert(fbuf->type == Raster::CAMERA || fbuf->type == Raster::CAMERATEXTURE); -static void -showRaster(Raster *raster, uint32 flags) -{ - // TODO: do this properly! -#ifdef LIBRW_SDL2 - SDL_GL_SwapWindow(glGlobals.window); -#else - if(flags & Raster::FLIPWAITVSYNCH) - glfwSwapInterval(1); - else - glfwSwapInterval(0); - glfwSwapBuffers(glGlobals.window); -#endif -} - -static bool32 -rasterRenderFast(Raster *raster, int32 x, int32 y) -{ - Raster *src = raster; - Raster *dst = Raster::getCurrentContext(); - Gl3Raster *natdst = PLUGINOFFSET(Gl3Raster, dst, nativeRasterOffset); - Gl3Raster *natsrc = PLUGINOFFSET(Gl3Raster, src, nativeRasterOffset); - - switch(dst->type){ - case Raster::NORMAL: - case Raster::TEXTURE: - case Raster::CAMERATEXTURE: - switch(src->type){ - case Raster::CAMERA: - setActiveTexture(0); - glBindTexture(GL_TEXTURE_2D, natdst->texid); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, x, (dst->height-src->height)-y, - 0, 0, src->width, src->height); - glBindTexture(GL_TEXTURE_2D, boundTexture[0]); - return 1; + // Have to make sure depth buffer is attached to FB's fbo + bindFramebuffer(natfb->fbo); + if(zbuf){ + if(natfb->fboMate == zbuf){ + // all good + assert(natzb->fboMate == fbuf); + }else{ + if(natzb->fboMate){ + // have to detatch from fbo first! + Gl3Raster *oldfb = PLUGINOFFSET(Gl3Raster, natzb->fboMate, nativeRasterOffset); + if(oldfb->fbo){ + bindFramebuffer(oldfb->fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0); + bindFramebuffer(natfb->fbo); + } + oldfb->fboMate = nil; + } + natfb->fboMate = zbuf; + natzb->fboMate = fbuf; + if(natfb->fbo) + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, natzb->texid, 0); } - break; + }else{ + // remove z-buffer + if(natfb->fboMate && natfb->fbo) + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0); + natfb->fboMate = nil; } - return 0; } static void @@ -1105,7 +1099,7 @@ beginUpdate(Camera *cam) proj[10] = -(cam->farPlane+cam->nearPlane)*invz; proj[11] = 0.0f; - proj[14] = -2.0f*invz; + proj[14] = 2.0f*invz; proj[15] = 1.0f; } memcpy(&cam->devProj, &proj, sizeof(RawMatrix)); @@ -1122,12 +1116,20 @@ beginUpdate(Camera *cam) stateDirty = 1; } + setFrameBuffer(cam); + int w, h; + if(cam->frameBuffer->type == Raster::CAMERA){ #ifdef LIBRW_SDL2 - SDL_GetWindowSize(glGlobals.window, &w, &h); + SDL_GetWindowSize(glGlobals.window, &w, &h); #else - glfwGetWindowSize(glGlobals.window, &w, &h); + glfwGetWindowSize(glGlobals.window, &w, &h); #endif + }else{ + w = cam->frameBuffer->width; + h = cam->frameBuffer->height; + } + if(w != glGlobals.presentWidth || h != glGlobals.presentHeight){ glViewport(0, 0, w, h); glGlobals.presentWidth = w; @@ -1135,6 +1137,67 @@ beginUpdate(Camera *cam) } } +static void +clearCamera(Camera *cam, RGBA *col, uint32 mode) +{ + RGBAf colf; + GLbitfield mask; + + setFrameBuffer(cam); + + convColor(&colf, col); + glClearColor(colf.red, colf.green, colf.blue, colf.alpha); + mask = 0; + if(mode & Camera::CLEARIMAGE) + mask |= GL_COLOR_BUFFER_BIT; + if(mode & Camera::CLEARZ) + mask |= GL_DEPTH_BUFFER_BIT; + glDepthMask(GL_TRUE); + glClear(mask); + glDepthMask(rwStateCache.zwrite); +} + +static void +showRaster(Raster *raster, uint32 flags) +{ + // TODO: do this properly! +#ifdef LIBRW_SDL2 + SDL_GL_SwapWindow(glGlobals.window); +#else + if(flags & Raster::FLIPWAITVSYNCH) + glfwSwapInterval(1); + else + glfwSwapInterval(0); + glfwSwapBuffers(glGlobals.window); +#endif +} + +static bool32 +rasterRenderFast(Raster *raster, int32 x, int32 y) +{ + Raster *src = raster; + Raster *dst = Raster::getCurrentContext(); + Gl3Raster *natdst = PLUGINOFFSET(Gl3Raster, dst, nativeRasterOffset); + Gl3Raster *natsrc = PLUGINOFFSET(Gl3Raster, src, nativeRasterOffset); + + switch(dst->type){ + case Raster::NORMAL: + case Raster::TEXTURE: + case Raster::CAMERATEXTURE: + switch(src->type){ + case Raster::CAMERA: + setActiveTexture(0); + glBindTexture(GL_TEXTURE_2D, natdst->texid); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, x, (dst->height-src->height)-y, + 0, 0, src->width, src->height); + glBindTexture(GL_TEXTURE_2D, boundTexture[0]); + return 1; + } + break; + } + return 0; +} + #ifdef LIBRW_SDL2 static int openSDL2(EngineOpenParams *openparams) diff --git a/src/gl/gl3raster.cpp b/src/gl/gl3raster.cpp index 4306d06..f8d2d85 100644 --- a/src/gl/gl3raster.cpp +++ b/src/gl/gl3raster.cpp @@ -80,9 +80,6 @@ rasterCreateTexture(Raster *raster) return raster; } -// This is totally fake right now, can't render to it. Only used to copy into from FB -// For rendering the idea would probably be to render to the backbuffer and copy it here afterwards. -// alternatively just use FBOs but that probably needs some more infrastructure. static Raster* rasterCreateCameraTexture(Raster *raster) { @@ -138,26 +135,64 @@ rasterCreateCameraTexture(Raster *raster) natras->addressV = 0; glBindTexture(GL_TEXTURE_2D, 0); + + + glGenFramebuffers(1, &natras->fbo); + bindFramebuffer(natras->fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, natras->texid, 0); + bindFramebuffer(0); + natras->fboMate = nil; + return raster; } static Raster* rasterCreateCamera(Raster *raster) { + Gl3Raster *natras = PLUGINOFFSET(Gl3Raster, raster, nativeRasterOffset); + // TODO: set/check width, height, depth, format? - raster->flags |= Raster::DONTALLOCATE; raster->originalWidth = raster->width; raster->originalHeight = raster->height; raster->stride = 0; raster->pixels = nil; + + natras->texid = 0; + natras->fbo = 0; + natras->fboMate = nil; + return raster; } static Raster* rasterCreateZbuffer(Raster *raster) { + Gl3Raster *natras = PLUGINOFFSET(Gl3Raster, raster, nativeRasterOffset); + // TODO: set/check width, height, depth, format? - raster->flags |= Raster::DONTALLOCATE; + raster->originalWidth = raster->width; + raster->originalHeight = raster->height; + raster->stride = 0; + raster->pixels = nil; + + natras->internalFormat = GL_DEPTH_COMPONENT; + natras->format = GL_DEPTH_COMPONENT; + natras->type = GL_UNSIGNED_BYTE; + + glGenTextures(1, &natras->texid); + glBindTexture(GL_TEXTURE_2D, natras->texid); + glTexImage2D(GL_TEXTURE_2D, 0, natras->internalFormat, + raster->width, raster->height, + 0, natras->format, natras->type, nil); + natras->filterMode = 0; + natras->addressU = 0; + natras->addressV = 0; + + glBindTexture(GL_TEXTURE_2D, 0); + + natras->fbo = 0; + natras->fboMate = nil; + return raster; } @@ -192,27 +227,21 @@ GL_RGB5 Raster* rasterCreate(Raster *raster) { + if(raster->width == 0 || raster->height == 0){ + raster->flags |= Raster::DONTALLOCATE; + raster->stride = 0; + return raster; + } + if(raster->flags & Raster::DONTALLOCATE) + return raster; + switch(raster->type){ #ifdef RW_OPENGL case Raster::NORMAL: case Raster::TEXTURE: - // Dummy to use as subraster - // ^ what did i do there? - if(raster->width == 0 || raster->height == 0){ - raster->flags |= Raster::DONTALLOCATE; - raster->stride = 0; - return raster; - } - - if(raster->flags & Raster::DONTALLOCATE) - return raster; return rasterCreateTexture(raster); - case Raster::CAMERATEXTURE: - if(raster->flags & Raster::DONTALLOCATE) - return raster; return rasterCreateCameraTexture(raster); - case Raster::ZBUFFER: return rasterCreateZbuffer(raster); case Raster::CAMERA: @@ -248,13 +277,13 @@ memset(px, 0, raster->stride*raster->height); GLuint fbo; GLenum e; glGenFramebuffers(1, &fbo); - glBindFramebuffer(GL_FRAMEBUFFER, fbo); + bindFramebuffer(fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, natras->texid, 0); e = glCheckFramebufferStatus(GL_FRAMEBUFFER); assert(natras->format == GL_RGBA); glReadPixels(0, 0, raster->width, raster->height, natras->format, natras->type, px); //e = glGetError(); printf("GL err4 %x (%x)\n", e, natras->format); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + bindFramebuffer(0); glDeleteFramebuffers(1, &fbo); #else uint32 prev = bindTexture(natras->texid); @@ -456,15 +485,53 @@ createNativeRaster(void *object, int32 offset, int32) { Gl3Raster *ras = PLUGINOFFSET(Gl3Raster, object, offset); ras->texid = 0; + ras->fbo = 0; + ras->fboMate = nil; return object; } static void* destroyNativeRaster(void *object, int32 offset, int32) { - Gl3Raster *ras = PLUGINOFFSET(Gl3Raster, object, offset); + Raster *raster = (Raster*)object; + Gl3Raster *natras = PLUGINOFFSET(Gl3Raster, object, offset); #ifdef RW_OPENGL - glDeleteTextures(1, &ras->texid); + switch(raster->type){ + case Raster::NORMAL: + case Raster::TEXTURE: + glDeleteTextures(1, &natras->texid); + break; + + case Raster::CAMERATEXTURE: + if(natras->fboMate){ + // Break apart from currently associated zbuffer + Gl3Raster *zras = PLUGINOFFSET(Gl3Raster, natras->fboMate, offset); + zras->fboMate = nil; + natras->fboMate = nil; + } + glDeleteFramebuffers(1, &natras->fbo); + glDeleteTextures(1, &natras->texid); + break; + + case Raster::ZBUFFER: + if(natras->fboMate){ + // Detatch from FBO we may be attached to + Gl3Raster *oldfb = PLUGINOFFSET(Gl3Raster, natras->fboMate, nativeRasterOffset); + if(oldfb->fbo){ + bindFramebuffer(oldfb->fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0); + } + oldfb->fboMate = nil; + } + glDeleteTextures(1, &natras->texid); + break; + + case Raster::CAMERA: + break; + } + natras->texid = 0; + natras->fbo = 0; + #endif return object; } @@ -474,6 +541,8 @@ copyNativeRaster(void *dst, void *, int32 offset, int32) { Gl3Raster *d = PLUGINOFFSET(Gl3Raster, dst, offset); d->texid = 0; + d->fbo = 0; + d->fboMate = nil; return dst; } diff --git a/src/gl/rwgl3.h b/src/gl/rwgl3.h index 53fd763..0db16f7 100644 --- a/src/gl/rwgl3.h +++ b/src/gl/rwgl3.h @@ -184,6 +184,7 @@ void setTexture(int32 n, Texture *tex); void setAlphaBlend(bool32 enable); bool32 getAlphaBlend(void); +void bindFramebuffer(uint32 fbo); uint32 bindTexture(uint32 texid); void flushCache(void); @@ -235,6 +236,9 @@ struct Gl3Raster uint8 filterMode; uint8 addressU; uint8 addressV; + + uint32 fbo; // used for camera texture only! + Raster *fboMate; // color or zbuffer raster mate of this one }; Texture *readNativeTexture(Stream *stream);