custom rendertarget support for gl

This commit is contained in:
aap 2020-08-10 13:31:33 +02:00
parent a29bcef4d7
commit b1507e5099
3 changed files with 213 additions and 77 deletions

View File

@ -235,6 +235,8 @@ static GlState curGlState, oldGlState;
static int32 activeTexture; static int32 activeTexture;
static uint32 boundTexture[MAXNUMSTAGES]; static uint32 boundTexture[MAXNUMSTAGES];
static uint32 currentFramebuffer;
static uint32 blendMap[] = { static uint32 blendMap[] = {
GL_ZERO, // actually invalid GL_ZERO, // actually invalid
GL_ZERO, GL_ZERO,
@ -415,6 +417,16 @@ bindTexture(uint32 texid)
return prev; return prev;
} }
void
bindFramebuffer(uint32 fbo)
{
//glBindFramebuffer(GL_FRAMEBUFFER, fbo);
if(currentFramebuffer != fbo){
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
currentFramebuffer = fbo;
}
}
// TODO: support mipmaps // TODO: support mipmaps
static GLint filterConvMap_NoMIP[] = { static GLint filterConvMap_NoMIP[] = {
0, GL_NEAREST, GL_LINEAR, 0, GL_NEAREST, GL_LINEAR,
@ -990,62 +1002,44 @@ flushCache(void)
} }
static void static void
clearCamera(Camera *cam, RGBA *col, uint32 mode) setFrameBuffer(Camera *cam)
{ {
RGBAf colf; Raster *fbuf = cam->frameBuffer;
GLbitfield mask; Raster *zbuf = cam->zBuffer;
assert(fbuf);
convColor(&colf, col); Gl3Raster *natfb = PLUGINOFFSET(Gl3Raster, fbuf, nativeRasterOffset);
glClearColor(colf.red, colf.green, colf.blue, colf.alpha); Gl3Raster *natzb = PLUGINOFFSET(Gl3Raster, zbuf, nativeRasterOffset);
mask = 0; assert(fbuf->type == Raster::CAMERA || fbuf->type == Raster::CAMERATEXTURE);
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 // Have to make sure depth buffer is attached to FB's fbo
showRaster(Raster *raster, uint32 flags) bindFramebuffer(natfb->fbo);
{ if(zbuf){
// TODO: do this properly! if(natfb->fboMate == zbuf){
#ifdef LIBRW_SDL2 // all good
SDL_GL_SwapWindow(glGlobals.window); assert(natzb->fboMate == fbuf);
#else }else{
if(flags & Raster::FLIPWAITVSYNCH) if(natzb->fboMate){
glfwSwapInterval(1); // have to detatch from fbo first!
else Gl3Raster *oldfb = PLUGINOFFSET(Gl3Raster, natzb->fboMate, nativeRasterOffset);
glfwSwapInterval(0); if(oldfb->fbo){
glfwSwapBuffers(glGlobals.window); bindFramebuffer(oldfb->fbo);
#endif glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
} bindFramebuffer(natfb->fbo);
}
static bool32 oldfb->fboMate = nil;
rasterRenderFast(Raster *raster, int32 x, int32 y) }
{ natfb->fboMate = zbuf;
Raster *src = raster; natzb->fboMate = fbuf;
Raster *dst = Raster::getCurrentContext(); if(natfb->fbo)
Gl3Raster *natdst = PLUGINOFFSET(Gl3Raster, dst, nativeRasterOffset); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, natzb->texid, 0);
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; }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 static void
@ -1105,7 +1099,7 @@ beginUpdate(Camera *cam)
proj[10] = -(cam->farPlane+cam->nearPlane)*invz; proj[10] = -(cam->farPlane+cam->nearPlane)*invz;
proj[11] = 0.0f; proj[11] = 0.0f;
proj[14] = -2.0f*invz; proj[14] = 2.0f*invz;
proj[15] = 1.0f; proj[15] = 1.0f;
} }
memcpy(&cam->devProj, &proj, sizeof(RawMatrix)); memcpy(&cam->devProj, &proj, sizeof(RawMatrix));
@ -1122,12 +1116,20 @@ beginUpdate(Camera *cam)
stateDirty = 1; stateDirty = 1;
} }
setFrameBuffer(cam);
int w, h; int w, h;
if(cam->frameBuffer->type == Raster::CAMERA){
#ifdef LIBRW_SDL2 #ifdef LIBRW_SDL2
SDL_GetWindowSize(glGlobals.window, &w, &h); SDL_GetWindowSize(glGlobals.window, &w, &h);
#else #else
glfwGetWindowSize(glGlobals.window, &w, &h); glfwGetWindowSize(glGlobals.window, &w, &h);
#endif #endif
}else{
w = cam->frameBuffer->width;
h = cam->frameBuffer->height;
}
if(w != glGlobals.presentWidth || h != glGlobals.presentHeight){ if(w != glGlobals.presentWidth || h != glGlobals.presentHeight){
glViewport(0, 0, w, h); glViewport(0, 0, w, h);
glGlobals.presentWidth = w; 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 #ifdef LIBRW_SDL2
static int static int
openSDL2(EngineOpenParams *openparams) openSDL2(EngineOpenParams *openparams)

View File

@ -80,9 +80,6 @@ rasterCreateTexture(Raster *raster)
return 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* static Raster*
rasterCreateCameraTexture(Raster *raster) rasterCreateCameraTexture(Raster *raster)
{ {
@ -138,26 +135,64 @@ rasterCreateCameraTexture(Raster *raster)
natras->addressV = 0; natras->addressV = 0;
glBindTexture(GL_TEXTURE_2D, 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; return raster;
} }
static Raster* static Raster*
rasterCreateCamera(Raster *raster) rasterCreateCamera(Raster *raster)
{ {
Gl3Raster *natras = PLUGINOFFSET(Gl3Raster, raster, nativeRasterOffset);
// TODO: set/check width, height, depth, format? // TODO: set/check width, height, depth, format?
raster->flags |= Raster::DONTALLOCATE;
raster->originalWidth = raster->width; raster->originalWidth = raster->width;
raster->originalHeight = raster->height; raster->originalHeight = raster->height;
raster->stride = 0; raster->stride = 0;
raster->pixels = nil; raster->pixels = nil;
natras->texid = 0;
natras->fbo = 0;
natras->fboMate = nil;
return raster; return raster;
} }
static Raster* static Raster*
rasterCreateZbuffer(Raster *raster) rasterCreateZbuffer(Raster *raster)
{ {
Gl3Raster *natras = PLUGINOFFSET(Gl3Raster, raster, nativeRasterOffset);
// TODO: set/check width, height, depth, format? // 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; return raster;
} }
@ -192,27 +227,21 @@ GL_RGB5
Raster* Raster*
rasterCreate(Raster *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){ switch(raster->type){
#ifdef RW_OPENGL #ifdef RW_OPENGL
case Raster::NORMAL: case Raster::NORMAL:
case Raster::TEXTURE: 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); return rasterCreateTexture(raster);
case Raster::CAMERATEXTURE: case Raster::CAMERATEXTURE:
if(raster->flags & Raster::DONTALLOCATE)
return raster;
return rasterCreateCameraTexture(raster); return rasterCreateCameraTexture(raster);
case Raster::ZBUFFER: case Raster::ZBUFFER:
return rasterCreateZbuffer(raster); return rasterCreateZbuffer(raster);
case Raster::CAMERA: case Raster::CAMERA:
@ -248,13 +277,13 @@ memset(px, 0, raster->stride*raster->height);
GLuint fbo; GLuint fbo;
GLenum e; GLenum e;
glGenFramebuffers(1, &fbo); glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo); bindFramebuffer(fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, natras->texid, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, natras->texid, 0);
e = glCheckFramebufferStatus(GL_FRAMEBUFFER); e = glCheckFramebufferStatus(GL_FRAMEBUFFER);
assert(natras->format == GL_RGBA); assert(natras->format == GL_RGBA);
glReadPixels(0, 0, raster->width, raster->height, natras->format, natras->type, px); glReadPixels(0, 0, raster->width, raster->height, natras->format, natras->type, px);
//e = glGetError(); printf("GL err4 %x (%x)\n", e, natras->format); //e = glGetError(); printf("GL err4 %x (%x)\n", e, natras->format);
glBindFramebuffer(GL_FRAMEBUFFER, 0); bindFramebuffer(0);
glDeleteFramebuffers(1, &fbo); glDeleteFramebuffers(1, &fbo);
#else #else
uint32 prev = bindTexture(natras->texid); uint32 prev = bindTexture(natras->texid);
@ -456,15 +485,53 @@ createNativeRaster(void *object, int32 offset, int32)
{ {
Gl3Raster *ras = PLUGINOFFSET(Gl3Raster, object, offset); Gl3Raster *ras = PLUGINOFFSET(Gl3Raster, object, offset);
ras->texid = 0; ras->texid = 0;
ras->fbo = 0;
ras->fboMate = nil;
return object; return object;
} }
static void* static void*
destroyNativeRaster(void *object, int32 offset, int32) 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 #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 #endif
return object; return object;
} }
@ -474,6 +541,8 @@ copyNativeRaster(void *dst, void *, int32 offset, int32)
{ {
Gl3Raster *d = PLUGINOFFSET(Gl3Raster, dst, offset); Gl3Raster *d = PLUGINOFFSET(Gl3Raster, dst, offset);
d->texid = 0; d->texid = 0;
d->fbo = 0;
d->fboMate = nil;
return dst; return dst;
} }

View File

@ -184,6 +184,7 @@ void setTexture(int32 n, Texture *tex);
void setAlphaBlend(bool32 enable); void setAlphaBlend(bool32 enable);
bool32 getAlphaBlend(void); bool32 getAlphaBlend(void);
void bindFramebuffer(uint32 fbo);
uint32 bindTexture(uint32 texid); uint32 bindTexture(uint32 texid);
void flushCache(void); void flushCache(void);
@ -235,6 +236,9 @@ struct Gl3Raster
uint8 filterMode; uint8 filterMode;
uint8 addressU; uint8 addressU;
uint8 addressV; uint8 addressV;
uint32 fbo; // used for camera texture only!
Raster *fboMate; // color or zbuffer raster mate of this one
}; };
Texture *readNativeTexture(Stream *stream); Texture *readNativeTexture(Stream *stream);