From 1d641c45db33e4f25fa5814e41011aeece956c34 Mon Sep 17 00:00:00 2001 From: Ivan Mahonin Date: Aug 24 2020 11:35:54 +0000 Subject: framebuffer --- diff --git a/demo/.gitignore b/demo/.gitignore index b0bedda..2b73574 100644 --- a/demo/.gitignore +++ b/demo/.gitignore @@ -1,2 +1,3 @@ /copy/ /build/ +screenshot.png diff --git a/demo/src/SConstruct b/demo/src/SConstruct index 69ea914..3e03308 100644 --- a/demo/src/SConstruct +++ b/demo/src/SConstruct @@ -17,6 +17,7 @@ sources = [ 'common.c', 'drawing.c', 'font.c', + 'framebuffer.c', 'main.c', 'phisics.c', 'sprites.c' ] diff --git a/demo/src/framebuffer.c b/demo/src/framebuffer.c new file mode 100644 index 0000000..e118d5c --- /dev/null +++ b/demo/src/framebuffer.c @@ -0,0 +1,44 @@ + +#include + +#include + +#include "drawing.h" + + +static double t = 0; +static int w = 0, h = 0; +static Framebuffer buffer; +static Animation texture; + + + +void framebufferInit() { + buffer = createFramebufferFromFile("data/sprite/snake.png"); + w = framebufferGetWidth(buffer); + h = framebufferGetHeight(buffer); + texture = createAnimationFromFramebuffer(buffer); +} + + +void framebufferDraw() { + double step = 0.1; + t += worldGetFrameTime(); + + while(t > step) { + saveState(); + target(buffer); + strokeWidth(randomFloat()*64); + stroke(colorByHSV(randomFloat()*360, 1, 1)); + point( randomFloat()*w, randomFloat()*h ); + restoreState(); + t -= step; + } + + saveState(); + translate(1024 - 256, 256); + rotate(30); + rectTextured(texture, -0.5*w, -0.5*h, w, h); + restoreState(); +} + diff --git a/demo/src/framebuffer.h b/demo/src/framebuffer.h new file mode 100644 index 0000000..b405bc1 --- /dev/null +++ b/demo/src/framebuffer.h @@ -0,0 +1,10 @@ +#ifndef FRAMEBUFFER_H +#define FRAMEBUFFER_H + + +void framebufferInit(); +void framebufferDraw(); + + +#endif + diff --git a/demo/src/main.c b/demo/src/main.c index c23f938..ae75efb 100644 --- a/demo/src/main.c +++ b/demo/src/main.c @@ -6,6 +6,7 @@ #include "sprites.h" #include "font.h" #include "drawing.h" +#include "framebuffer.h" void init() { @@ -14,10 +15,12 @@ void init() { spritesInit(); fontInit(); drawingInit(); + framebufferInit(); } void draw() { commonDraw(); + framebufferDraw(); drawingDraw(); phisicsDraw(); spritesDraw(); @@ -29,6 +32,11 @@ void draw() { strokeWidth(20); point(mouseX(), mouseY()); restoreState(); + + if (keyDown("p")) { + viewportSave("screenshot.png"); + messageBox("screenshot saved to file: screenshot.png"); + } } int main() { diff --git a/src/SConstruct b/src/SConstruct index eeb54da..5ad4807 100644 --- a/src/SConstruct +++ b/src/SConstruct @@ -40,6 +40,7 @@ headers = [ 'common.h', 'drawing.h', 'font.h', + 'framebuffer.h', 'group.h', 'sprite.h', 'world.h' ] @@ -54,6 +55,7 @@ sources = [ 'common.c', 'drawing.c', 'font.c', + 'framebuffer.c', 'geometry.c', 'gl.c', 'group.c', diff --git a/src/animation.c b/src/animation.c index fd9838b..c9fcf9c 100644 --- a/src/animation.c +++ b/src/animation.c @@ -139,7 +139,9 @@ unsigned int imageToGLTexture(int width, int height, const void *pixels, int wra { return imageToGLTextureEx(width, height, pixels, wrap, wrap, TRUE, TRUE); } -unsigned int imageToGLTextureEx(int width, int height, const void *pixels, int horWrap, int vertWrap, int smooth, int mipMap) { +int imageToExistingGLTexture(unsigned int texid, int width, int height, const void *pixels) { + if (!texid || width <= 0 || height <= 0 || !pixels) return FALSE; + // convert to float and premult alpha size_t count = (size_t)width*height*4; float *buffer = (float*)malloc(count*sizeof(float)); @@ -207,16 +209,18 @@ unsigned int imageToGLTextureEx(int width, int height, const void *pixels, int h while(w > maxSize) mipx(buffer, &w, &h); while(h > maxSize) mipy(buffer, &w, &h); - // create OpenGL texture - unsigned int texid = 0, prevtex = 0; + + // upload to OpenGL texture + unsigned int prevtex = 0; + int minFilter = 0; glGetIntegerv(GL_TEXTURE_BINDING_2D, (int*)&prevtex); - glGenTextures(1, &texid); glBindTexture(GL_TEXTURE_2D, texid); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, smooth ? GL_LINEAR : GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, smooth ? (mipMap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR): (mipMap ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST)); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, horWrap ? GL_REPEAT : GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, vertWrap ? GL_REPEAT : GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -0.7f); + glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, &minFilter); + + int mipMap = minFilter == GL_NEAREST_MIPMAP_NEAREST + || minFilter == GL_NEAREST_MIPMAP_LINEAR + || minFilter == GL_LINEAR_MIPMAP_NEAREST + || minFilter == GL_LINEAR_MIPMAP_LINEAR; // build mip levels unsigned char *ibuffer = malloc((size_t)w*h*4); @@ -251,6 +255,22 @@ unsigned int imageToGLTextureEx(int width, int height, const void *pixels, int h free(buffer); glBindTexture(GL_TEXTURE_2D, prevtex); + return TRUE; +} + +unsigned int imageToGLTextureEx(int width, int height, const void *pixels, int horWrap, int vertWrap, int smooth, int mipMap) { + // create OpenGL texture + unsigned int texid = 0, prevtex = 0; + glGetIntegerv(GL_TEXTURE_BINDING_2D, (int*)&prevtex); + glGenTextures(1, &texid); + glBindTexture(GL_TEXTURE_2D, texid); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, smooth ? GL_LINEAR : GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, smooth ? (mipMap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR): (mipMap ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST)); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, horWrap ? GL_REPEAT : GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, vertWrap ? GL_REPEAT : GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -0.7f); + imageToExistingGLTexture(texid, width, height, pixels); + glBindTexture(GL_TEXTURE_2D, prevtex); return texid; } @@ -274,24 +294,40 @@ int imageFromGLTexture(unsigned int texid, int *outWidth, int *outHeight, unsign return outPixels != NULL; } -unsigned int imageGetPixel(int width, int height, const void *pixels, int x, int y) { - if (x < 0 || x >= width || y < 0 || y >= height || !pixels) return 0; - const unsigned char *p = (const unsigned char *)pixels + 4*((size_t)width*y + x); +int viewportSave(const char *path) { + int width = 0; + int height = 0; + unsigned char *pixels = NULL; + if (!imageFromViewport(&width, &height, &pixels)) return FALSE; + return imageSave(path, width, height, pixels); +} + +unsigned int pixelGet(const void *pixel) { + const unsigned char *p = (const unsigned char *)pixel; return (((unsigned int)p[0]) << 24) | (((unsigned int)p[1]) << 16) | (((unsigned int)p[2]) << 8) | (((unsigned int)p[3]) << 0); } -void imageSetPixel(int width, int height, void *pixels, int x, int y, unsigned int color) { - if (x < 0 || x >= width || y < 0 || y >= height || !pixels) return; - unsigned char *p = (unsigned char *)pixels + 4*((size_t)width*y + x); +void pixelSet(void *pixel, unsigned int color) { + unsigned char *p = (unsigned char *)pixel; p[0] = (color >> 24); p[1] = (color >> 16) & 0xFF; - p[2] = (color >> 24) & 0xFF; + p[2] = (color >> 8) & 0xFF; p[3] = (color ) & 0xFF; } +unsigned int imageGetPixel(int width, int height, const void *pixels, int x, int y) { + if (x < 0 || x >= width || y < 0 || y >= height || !pixels) return 0; + return pixelGet((const unsigned char *)pixels + 4*((size_t)width*y + x)); +} + +void imageSetPixel(int width, int height, void *pixels, int x, int y, unsigned int color) { + if (x < 0 || x >= width || y < 0 || y >= height || !pixels) return; + pixelSet((unsigned char *)pixels + 4*((size_t)width*y + x), color); +} + void imageSetPixel(int width, int height, void *pixels, int x, int y, unsigned int color); @@ -413,6 +449,25 @@ Animation createAnimationFromImageEx(int width, int height, const void *pixels, Animation createAnimationFromImage(int width, int height, const void *pixels, int wrap) { return createAnimationFromGLTexId(imageToGLTexture(width, height, pixels, wrap)); } +Animation createAnimationFromFramebuffer(Framebuffer framebuffer) { + unsigned int texid = framebufferGetGLTexId(framebuffer); + Animation animation = createAnimationFromGLTexId(texid); + //animationGLTexIdSetOwnership(texid, FALSE); + return animation; +} + +Animation createAnimationFromViewportEx(int horWrap, int vertWrap, int smooth, int mipMap) { + int width = 0; + int height = 0; + unsigned char *pixels = NULL; + if (!imageFromViewport(&width, &height, &pixels)) return createAnimationEmpty(); + return createAnimationFromImageEx(width, height, pixels, horWrap, vertWrap, smooth, mipMap); +} + +Animation createAnimationFromViewport() + { return createAnimationFromViewportEx(FALSE, FALSE, TRUE, TRUE); } + + Animation createAnimation(const char *path) { return createAnimationEx(path, TRUE, FALSE, FALSE); } diff --git a/src/animation.h b/src/animation.h index 5fb9740..3876f18 100644 --- a/src/animation.h +++ b/src/animation.h @@ -3,6 +3,8 @@ #include "common.h" +#include "framebuffer.h" + typedef struct _Animation *Animation; @@ -11,8 +13,13 @@ int imageLoad(const char *path, int *outWidth, int *outHeight, unsigned char **o int imageSave(const char *path, int width, int height, const void *pixels); unsigned int imageToGLTexture(int width, int height, const void *pixels, int wrap); unsigned int imageToGLTextureEx(int width, int height, const void *pixels, int horWrap, int vertWrap, int smooth, int mipMap); +int imageToExistingGLTexture(unsigned int texid, int width, int height, const void *pixels); int imageFromGLTexture(unsigned int texid, int *outWidth, int *outHeight, unsigned char **outPixels); +int imageFromViewport(int *outWidth, int *outHeight, unsigned char **outPixels); +int viewportSave(const char *path); +unsigned int pixelGet(const void *pixel); +void pixelSet(void *pixel, unsigned int color); unsigned int imageGetPixel(int width, int height, const void *pixels, int x, int y); void imageSetPixel(int width, int height, void *pixels, int x, int y, unsigned int color); @@ -22,6 +29,9 @@ Animation createAnimationEx(const char *path, int smooth, int horWrap, int vertW Animation createAnimationFromGLTexId(unsigned int texid); Animation createAnimationFromImage(int width, int height, const void *pixels, int wrap); Animation createAnimationFromImageEx(int width, int height, const void *pixels, int horWrap, int vertWrap, int smooth, int mipMap); +Animation createAnimationFromFramebuffer(Framebuffer framebuffer); +Animation createAnimationFromViewport(); +Animation createAnimationFromViewportEx(int horWrap, int vertWrap, int smooth, int mipMap); Animation createAnimationEmpty(); void animationDestroy(Animation animation); diff --git a/src/common.c b/src/common.c index 78f59ac..2feabc7 100644 --- a/src/common.c +++ b/src/common.c @@ -14,6 +14,16 @@ struct _Directory { }; +static const float yuvToRgb[3][3] = { + { 1.0, 0.0 , 1.402 }, + { 1.0, -0.344136, -0.714136 }, + { 1.0, 1.772 , 0.0 } }; + +static const float rgbToYuv[3][3] = { + { 0.299 , 0.587 , 0.114 }, + { -0.168736, -0.331264, 0.5 }, + { 0.5 , -0.418688, -0.081312 } }; + static char *colors[][2] = { { "transparent", "0 0 0 0" }, @@ -129,19 +139,10 @@ void heliLowercase(char *x) { while(*x) { *x = tolower(*x); ++x; } } -static unsigned int colorToInt(double c) { - if (!(c > 0)) c = 0; - if (!(c < 1)) c = 1; - return (unsigned int)floor(c*255.99); -} - - -void heliColorToDouble(unsigned int code, double *rgba) { - rgba[0] = ( code >> 24 )/255.0; - rgba[1] = ((code >> 16) & 0xFFu)/255.0; - rgba[2] = ((code >> 8) & 0xFFu)/255.0; - rgba[3] = ( code & 0xFFu)/255.0; -} +static double colorClamp(double c) + { return c > 0 ? (c < 1 ? c : 1) : 0; } +static unsigned int colorToInt(double c) + { return (unsigned int)floor(colorClamp(c)*255.99); } unsigned int colorByRGBA(double r, double g, double b, double a) { return (colorToInt(r) << 24) @@ -149,9 +150,105 @@ unsigned int colorByRGBA(double r, double g, double b, double a) { | (colorToInt(b) << 8) | colorToInt(a); } +unsigned int colorByYUVA(double y, double u, double v, double a) { + return colorByRGBA( + yuvToRgb[0][0]*y + yuvToRgb[0][1]*u + yuvToRgb[0][2]*v, + yuvToRgb[1][0]*y + yuvToRgb[1][1]*u + yuvToRgb[1][2]*v, + yuvToRgb[2][0]*y + yuvToRgb[2][1]*u + yuvToRgb[2][2]*v, + a ); +} +unsigned int colorByHSVA(double h, double s, double v, double a) { + h -= floor(h/360)*360; + h /= 60.0; + int i = (int)h; + double f = h - i; + double p = v*(1 - s); + double q = v*(1 - s*f); + double t = v*(1 - s*(1 - f)); + switch(i) { + case 0: return colorByRGBA(v, t, p, a); + case 1: return colorByRGBA(q, v, p, a); + case 2: return colorByRGBA(p, v, t, a); + case 3: return colorByRGBA(p, q, v, a); + case 4: return colorByRGBA(t, p, v, a); + case 5: return colorByRGBA(v, p, q, a); + } + return colorByRGBA(v, t, p, a); +} unsigned int colorByRGB(double r, double g, double b) { return colorByRGBA(r, g, b, 1); } +unsigned int colorByHSV(double h, double s, double v) + { return colorByHSVA(h, s, v, 1); } +unsigned int colorByYUV(double y, double u, double v) + { return colorByYUVA(y, u, v, 1); } + +double colorGetRed (unsigned int color) { return ( color >> 24 )/255.0; } +double colorGetGreen(unsigned int color) { return ((color >> 16) & 0xFFu)/255.0; } +double colorGetBlue (unsigned int color) { return ((color >> 8) & 0xFFu)/255.0; } +double colorGetAlpha(unsigned int color) { return ( color & 0xFFu)/255.0; } +void heliColorToDouble(unsigned int code, double *rgba) { + rgba[0] = colorGetRed (code); + rgba[1] = colorGetGreen(code); + rgba[2] = colorGetBlue (code); + rgba[3] = colorGetAlpha(code); +} + +double colorGetYLuminance(unsigned int color) { + return rgbToYuv[0][0]*colorGetRed (color) + + rgbToYuv[0][1]*colorGetGreen(color) + + rgbToYuv[0][2]*colorGetBlue (color); +} +double colorGetUChrominance(unsigned int color) { + return rgbToYuv[1][0]*colorGetRed (color) + + rgbToYuv[1][1]*colorGetGreen(color) + + rgbToYuv[1][2]*colorGetBlue (color); +} +double colorGetVChrominance(unsigned int color) { + return rgbToYuv[1][0]*colorGetRed (color) + + rgbToYuv[1][1]*colorGetGreen(color) + + rgbToYuv[1][2]*colorGetBlue (color); +} + + +static int colorMin(double *c) + { return c[0] < c[1] ? (c[0] < c[2] ? 0 : 2) : (c[1] < c[2] ? 1 : 2); } +static int colorMax(double *c) + { return c[0] > c[1] ? (c[0] > c[2] ? 0 : 2) : (c[1] > c[2] ? 1 : 2); } +double colorGetHue(unsigned int color) { + double rgb[] = { colorGetRed (color), + colorGetGreen(color), + colorGetBlue (color) }; + int cmin = colorMin(rgb); + int cmax = colorMax(rgb); + double d = rgb[cmax] - rgb[cmin]; + double h = 0; + if (d > HELI_PRECISION) { + d = 1.0/d; + switch(cmax){ + case 0: h = (rgb[1] - rgb[2])*d + 0; break; + case 1: h = (rgb[2] - rgb[0])*d + 2; break; + case 2: h = (rgb[0] - rgb[1])*d + 4; break; + } + h /= 6; h -= floor(h); h *= 360; + } + return h; +} +double colorGetSaturation(unsigned int color) { + double rgb[] = { colorGetRed (color), + colorGetGreen(color), + colorGetBlue (color) }; + int cmin = colorMin(rgb); + int cmax = colorMax(rgb); + return rgb[cmax] > HELI_PRECISION ? (rgb[cmax] - rgb[cmin])/rgb[cmax] : 0; +} +double colorGetValue(unsigned int color) { + double rgb[] = { colorGetRed (color), + colorGetGreen(color), + colorGetBlue (color) }; + return rgb[colorMax(rgb)]; +} + unsigned int colorByName(const char *colorName) { unsigned int code = 0; diff --git a/src/drawing.c b/src/drawing.c index 4cbd4dd..4a22d8e 100644 --- a/src/drawing.c +++ b/src/drawing.c @@ -142,6 +142,59 @@ void cliprect(double x, double y, double width, double height) { void noClip() { for(int i = 0; i < 4; ++i) glDisable(GL_CLIP_PLANE0 + i); } + +void projectionByViewport() { + int vp[4] = {}; + glGetIntegerv(GL_VIEWPORT, vp); + unsigned int mode; + glGetIntegerv(GL_MATRIX_MODE, (int*)&mode); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, vp[2], vp[3], 0, -1.0, 1.0); + glMatrixMode(mode); +} + + +void viewportByFramebuffer(Framebuffer framebuffer) { + if (framebuffer) + glViewport(0, 0, framebufferGetWidth(framebuffer), framebufferGetHeight(framebuffer)); + else + glViewport(0, 0, worldGetWidth(), worldGetHeight()); +} + + +void viewportByWindow() + { viewportByFramebuffer(NULL); } + + +void targetEx(Framebuffer framebuffer, int updateViewport, int updateProjection) { + if (framebuffer) { + if (heliGLBindFramebufferPtr) { + unsigned int id = framebufferGetGLId(framebuffer); + heliGLBindFramebufferPtr(GL_READ_FRAMEBUFFER, id); + heliGLBindFramebufferPtr(GL_DRAW_FRAMEBUFFER, id); + } + if (updateViewport) { + viewportByFramebuffer(framebuffer); + if (updateProjection) projectionByViewport(); + } + } else { + if (heliGLBindFramebufferPtr) { + heliGLBindFramebufferPtr(GL_READ_FRAMEBUFFER, heliGLWindowFramebufferReadId); + heliGLBindFramebufferPtr(GL_DRAW_FRAMEBUFFER, heliGLWindowFramebufferDrawId); + } + if (updateViewport) { + viewportByWindow(); + if (updateProjection) projectionByViewport(); + } + } +} +void target(Framebuffer framebuffer) + { targetEx(framebuffer, TRUE, TRUE); } +void noTarget() + { target(NULL); } + + void rect(double x, double y, double width, double height) { resetPath(); heliFillRectSimple(x, y, x+width, y+height, heliGLGetAAResolution()); @@ -400,9 +453,9 @@ static void drawFill() { glVertex2d(l, b); glEnd(); - if (heliGlStencilOpSeparatePtr) { - heliGlStencilOpSeparatePtr(GL_FRONT, GL_INCR_WRAP, GL_INCR_WRAP, GL_INCR_WRAP); - heliGlStencilOpSeparatePtr(GL_BACK, GL_DECR_WRAP, GL_DECR_WRAP, GL_DECR_WRAP); + if (heliGLStencilOpSeparatePtr) { + heliGLStencilOpSeparatePtr(GL_FRONT, GL_INCR_WRAP, GL_INCR_WRAP, GL_INCR_WRAP); + heliGLStencilOpSeparatePtr(GL_BACK, GL_DECR_WRAP, GL_DECR_WRAP, GL_DECR_WRAP); glBegin(GL_TRIANGLE_FAN); for(int i = 0; i < pathSize; i += 2) glVertex2dv(&path[i]); @@ -718,15 +771,18 @@ void resetState() { resetStateEx(STATE_ALL); } void resetStateEx(unsigned int flags) { - if (flags & STATE_FILL_COLOR ) fill(colorByRGBA(0.5, 0.5, 0.5, 1)); - if (flags & STATE_FILL_TEXTURE ) noFillTexture(); - if (flags & STATE_STROKE_COLOR ) stroke(colorByRGBA(0, 0, 0, 1)); - if (flags & STATE_STROKE_TEXTURE) noStrokeTexture(); - if (flags & STATE_STROKE_WIDTH ) strokeWidth(1); - if (flags & STATE_TEXT_ALIGN ) textAlign(HALIGN_LEFT, VALIGN_TOP); - if (flags & STATE_TEXT_SIZE ) textSize(24); - if (flags & STATE_TRANSFORM ) noTransform(); - if (flags & STATE_CLIP ) noClip(); + if (flags & STATE_FILL_COLOR ) fill(colorByRGBA(0.5, 0.5, 0.5, 1)); + if (flags & STATE_FILL_TEXTURE ) noFillTexture(); + if (flags & STATE_STROKE_COLOR ) stroke(colorByRGBA(0, 0, 0, 1)); + if (flags & STATE_STROKE_TEXTURE ) noStrokeTexture(); + if (flags & STATE_STROKE_WIDTH ) strokeWidth(1); + if (flags & STATE_TEXT_ALIGN ) textAlign(HALIGN_LEFT, VALIGN_TOP); + if (flags & STATE_TEXT_SIZE ) textSize(24); + if (flags & STATE_TRANSFORM ) noTransform(); + if (flags & STATE_CLIP ) noClip(); + if (flags & STATE_TARGET_FRAMEBUFFER) targetEx(NULL, FALSE, FALSE); + if (flags & STATE_TARGET_VIEWPORT ) viewportByWindow(); + if (flags & STATE_TARGET_PROJECTION ) projectionByViewport(); } void saveState() @@ -775,8 +831,11 @@ void restoreState() { } void heliDrawingClearFrame() { + unsigned int prev; + glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, (int*)&prev); glClearColor(colorBack[0], colorBack[1], colorBack[2], colorBack[3]); - glClear(GL_COLOR_BUFFER_BIT); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + if (heliGLBindFramebufferPtr) heliGLBindFramebufferPtr(GL_DRAW_FRAMEBUFFER, prev); } void heliDrawingPrepareFrame() { @@ -789,7 +848,10 @@ void heliDrawingPrepareFrame() { glDisable(GL_MULTISAMPLE); glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + if (heliGLBlendFuncSeparatePtr) + heliGLBlendFuncSeparatePtr(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); + else + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_LINE_SMOOTH); glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); } diff --git a/src/drawing.h b/src/drawing.h index e06cbb1..197b2b9 100644 --- a/src/drawing.h +++ b/src/drawing.h @@ -7,20 +7,23 @@ typedef enum _StateFlags { - STATE_FILL_COLOR = 1 << 0, - STATE_FILL_TEXTURE = 1 << 1, + STATE_FILL_COLOR = 1 << 0, + STATE_FILL_TEXTURE = 1 << 1, - STATE_STROKE_COLOR = 1 << 2, - STATE_STROKE_TEXTURE = 1 << 3, - STATE_STROKE_WIDTH = 1 << 4, + STATE_STROKE_COLOR = 1 << 2, + STATE_STROKE_TEXTURE = 1 << 3, + STATE_STROKE_WIDTH = 1 << 4, - STATE_TEXT_ALIGN = 1 << 5, - STATE_TEXT_SIZE = 1 << 6, - STATE_TEXT_FONT = 1 << 7, + STATE_TEXT_ALIGN = 1 << 5, + STATE_TEXT_SIZE = 1 << 6, + STATE_TEXT_FONT = 1 << 7, - STATE_TRANSFORM = 1 << 8, - STATE_CLIP = 1 << 9, + STATE_TRANSFORM = 1 << 8, + STATE_CLIP = 1 << 9, + STATE_TARGET_FRAMEBUFFER = 1 << 10, + STATE_TARGET_VIEWPORT = 1 << 11, + STATE_TARGET_PROJECTION = 1 << 12, STATE_FILL = STATE_FILL_COLOR | STATE_FILL_TEXTURE, @@ -30,12 +33,16 @@ typedef enum _StateFlags { STATE_TEXT = STATE_TEXT_ALIGN | STATE_TEXT_SIZE | STATE_TEXT_FONT, + STATE_TARGET = STATE_TARGET_FRAMEBUFFER + | STATE_TARGET_VIEWPORT + | STATE_TARGET_PROJECTION, STATE_ALL = STATE_FILL | STATE_STROKE | STATE_TEXT | STATE_TRANSFORM - | STATE_CLIP, + | STATE_CLIP + | STATE_TARGET, } StateFlags; @@ -58,15 +65,41 @@ void noTransform(); void cliprect(double x, double y, double width, double height); void noClip(); +void projectionByViewport(); +void viewportByFramebuffer(Framebuffer framebuffer); +void viewportByWindow(); +void targetEx(Framebuffer framebuffer, int updateViewport, int updateProjection); +void target(Framebuffer framebuffer); +void noTarget(); + void resetState(); void resetStateEx(unsigned int flags); void saveState(); void saveStateEx(unsigned int flags); void restoreState(); + unsigned int colorByName(const char *colorName); unsigned int colorByRGB(double r, double g, double b); unsigned int colorByRGBA(double r, double g, double b, double a); +unsigned int colorByHSV(double h, double s, double v); +unsigned int colorByHSVA(double h, double s, double v, double a); +unsigned int colorByYUV(double y, double u, double v); +unsigned int colorByYUVA(double y, double u, double v, double a); + +double colorGetRed(unsigned int color); +double colorGetGreen(unsigned int color); +double colorGetBlue(unsigned int color); +double colorGetAlpha(unsigned int color); + +double colorGetHue(unsigned int color); +double colorGetSaturation(unsigned int color); +double colorGetValue(unsigned int color); + +double colorGetYLuminance(unsigned int color); +double colorGetUChrominance(unsigned int color); +double colorGetVChrominance(unsigned int color); + void rect(double x, double y, double width, double height); void rectTextured(Animation animation, double x, double y, double width, double height); diff --git a/src/framebuffer.c b/src/framebuffer.c new file mode 100644 index 0000000..0cf3e21 --- /dev/null +++ b/src/framebuffer.c @@ -0,0 +1,237 @@ + + +#include "private.h" +#include "world.h" +#include "framebuffer.h" + + +struct _Framebuffer { + int width; + int height; + unsigned int texture_id; + unsigned int renderbuffer_id; + unsigned int framebuffer_id; +}; + + +static void heliInitFramebuffer( + Framebuffer fb, + int width, + int height, + const void *pixels, + int horWrap, + int vertWrap, + int smooth, + int multisample, + int simple +) { + fb->width = width; + fb->height = height; + fb->texture_id = 0; + fb->renderbuffer_id = 0; + fb->framebuffer_id = 0; + + unsigned int prev = 0; + glGetIntegerv(GL_TEXTURE_BINDING_2D, (int*)&prev); + glGenTextures(1, &fb->texture_id); + glBindTexture(GL_TEXTURE_2D, fb->texture_id); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, smooth ? GL_LINEAR : GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, smooth ? GL_LINEAR : GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, horWrap ? GL_REPEAT : GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, vertWrap ? GL_REPEAT : GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -0.7f); + if (multisample) + heliGLTexImage2DMultisamplePtr(GL_TEXTURE_2D_MULTISAMPLE, multisample, GL_RGBA, fb->width, fb->height, GL_TRUE); + else + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fb->width, fb->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + glBindTexture(GL_TEXTURE_2D, prev); + + if (!simple) { + glGetIntegerv(GL_RENDERBUFFER_BINDING, (int*)&prev); + heliGLGenRenderbuffersPtr(1, &fb->renderbuffer_id); + heliGLBindRenderbufferPtr(GL_RENDERBUFFER, fb->renderbuffer_id); + if (multisample) + heliGLRenderbufferStorageMultisamplePtr(GL_RENDERBUFFER, multisample, GL_STENCIL_INDEX8, fb->width, fb->height); + else + heliGLRenderbufferStoragePtr(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, fb->width, fb->height); + heliGLBindRenderbufferPtr(GL_RENDERBUFFER, prev); + } + + glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, (int*)&prev); + heliGLGenFramebuffersPtr(1, &fb->framebuffer_id); + heliGLBindFramebufferPtr(GL_DRAW_FRAMEBUFFER, fb->framebuffer_id); + if (fb->renderbuffer_id) + heliGLFramebufferRenderbufferPtr(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fb->renderbuffer_id); + if (multisample) + heliGLFramebufferTexture2DPtr(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, fb->texture_id, 0); + else + heliGLFramebufferTexture2DPtr(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb->texture_id, 0); + heliGLBindFramebufferPtr(GL_DRAW_FRAMEBUFFER, prev); +} + + +static void heliDeinitFramebuffer(Framebuffer fb) { + if (fb->framebuffer_id) { + unsigned int id = 0; + glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, (int*)&id); + if (id == fb->framebuffer_id) heliGLBindFramebufferPtr(GL_DRAW_FRAMEBUFFER, 0); + glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, (int*)&id); + if (id == fb->framebuffer_id) heliGLBindFramebufferPtr(GL_READ_FRAMEBUFFER, 0); + heliGLDeleteFramebuffersPtr(1, &fb->framebuffer_id); + fb->framebuffer_id = 0; + } + if (fb->renderbuffer_id) { + heliGLDeleteRenderbuffersPtr(1, &fb->renderbuffer_id); + fb->renderbuffer_id = 0; + } + if (fb->texture_id) { + glDeleteTextures(1, &fb->texture_id); + fb->texture_id = 0; + } + fb->width = 0; + fb->height = 0; +} + + +Framebuffer createFramebufferEx(int width, int height, const void *pixels, int horWrap, int vertWrap, int smooth) { + Framebuffer fb = calloc(1, sizeof(*fb)); + + if (width <= 0 || height <= 0) { + fprintf(stderr, "helianthus: cannot create framebuffer, bad size: %dx%d\n", width, height); + return fb; + } + + if (!heliGLGenFramebuffersPtr || !heliGLGenRenderbuffersPtr) { + fprintf(stderr, "helianthus: cannot create framebuffer, seems OpenGL version is too low\n"); + return fb; + } + + if (heliGLTexImage2DMultisamplePtr && heliGLRenderbufferStoragePtr) { + for(int multisample = 8; multisample >= 4; multisample /= 2) { + glGetError(); + heliInitFramebuffer(fb, width, height, NULL, horWrap, vertWrap, smooth, multisample, FALSE); + if (glGetError() == GL_NO_ERROR) { + if (pixels) { + struct _Framebuffer ffb = {}; + heliInitFramebuffer(&ffb, width, height, pixels, FALSE, FALSE, FALSE, 0, TRUE); + + unsigned int prevR = 0, prevD = 0; + glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, (int*)&prevR); + glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, (int*)&prevD); + heliGLBindFramebufferPtr(GL_READ_FRAMEBUFFER, ffb.framebuffer_id); + heliGLBindFramebufferPtr(GL_DRAW_FRAMEBUFFER, fb->framebuffer_id); + heliGLBlitFramebufferPtr(0, 0, fb->width, fb->height, 0, 0, fb->width, fb->height, GL_COLOR_BUFFER_BIT, GL_NEAREST); + heliGLBindFramebufferPtr(GL_READ_FRAMEBUFFER, prevR); + heliGLBindFramebufferPtr(GL_DRAW_FRAMEBUFFER, prevD); + + heliDeinitFramebuffer(&ffb); + } + break; + } + heliDeinitFramebuffer(fb); + } + } + + if (!fb->framebuffer_id) { + fprintf(stderr, "helianthus: cannot initialize multisampling for framebuffer\n"); + heliDeinitFramebuffer(fb); + heliInitFramebuffer(fb, width, height, pixels, horWrap, vertWrap, smooth, 0, FALSE); + } + + return fb; +} + + +Framebuffer createFramebuffer(int width, int height) + { return createFramebufferEx(width, height, NULL, FALSE, FALSE, TRUE); } + + +Framebuffer createFramebufferFromFile(const char *path) { + int width = 0; + int height = 0; + unsigned char *pixels = NULL; + imageLoad(path, &width, &height, &pixels); + return createFramebufferEx(width, height, pixels, FALSE, FALSE, TRUE); +} + + +void framebufferDestroy(Framebuffer framebuffer) { + HeliDrawingState *ss = heliDrawingGetState(); + if (framebuffer->framebuffer_id) { + for(HeliDrawingState *s = heliDrawingGetStateStack(); s <= ss; ++s) { + if (ss->glState.framebuffer_read_id == framebuffer->framebuffer_id) + ss->glState.framebuffer_read_id = 0; + if (ss->glState.framebuffer_draw_id == framebuffer->framebuffer_id) + ss->glState.framebuffer_draw_id = 0; + } + } + heliDeinitFramebuffer(framebuffer); + free(framebuffer); +} + + +int framebufferGetWidth(Framebuffer framebuffer) + { return framebuffer->width; } +int framebufferGetHeight(Framebuffer framebuffer) + { return framebuffer->height; } +unsigned int framebufferGetGLTexId(Framebuffer framebuffer) + { return framebuffer->texture_id; } +unsigned int framebufferGetGLId(Framebuffer framebuffer) + { return framebuffer->framebuffer_id; } + + +int imageFromViewport(int *outWidth, int *outHeight, unsigned char **outPixels) { + *outWidth = 0; + *outHeight = 0; + *outPixels = NULL; + + int vp[4] = {}; + glGetIntegerv(GL_VIEWPORT, vp); + + if (vp[2] <= 0 || vp[3] <= 0) return FALSE; + + unsigned char *buffer = malloc(vp[2]*vp[3]*4); + glGetError(); + glReadPixels(vp[0], vp[1], vp[2], vp[3], GL_RGBA, GL_UNSIGNED_BYTE, buffer); + if (glGetError() != GL_NO_ERROR) { + if (!heliGLBindFramebufferPtr || !heliGLBlitFramebufferPtr) { + fprintf(stderr, "helianthus: cannot read viewport pixels\n"); + free(buffer); + return FALSE; + } + + // blit multisample buffer + struct _Framebuffer ffb = {}; + heliInitFramebuffer(&ffb, vp[2], vp[3], NULL, FALSE, FALSE, FALSE, 0, TRUE); + + unsigned int prevR = 0, prevD = 0; + glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, (int*)&prevR); + glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, (int*)&prevD); + heliGLBindFramebufferPtr(GL_DRAW_FRAMEBUFFER, ffb.framebuffer_id); + heliGLBlitFramebufferPtr(vp[0], vp[1], vp[2], vp[3], 0, 0, vp[2], vp[3], GL_COLOR_BUFFER_BIT, GL_NEAREST); + heliGLBindFramebufferPtr(GL_READ_FRAMEBUFFER, ffb.framebuffer_id); + glReadPixels(0, 0, vp[2], vp[3], GL_RGBA, GL_UNSIGNED_BYTE, buffer); + heliGLBindFramebufferPtr(GL_READ_FRAMEBUFFER, prevR); + heliGLBindFramebufferPtr(GL_DRAW_FRAMEBUFFER, prevD); + + heliDeinitFramebuffer(&ffb); + } + + // flip image + size_t rowSize = vp[2]*4; + unsigned char *row = malloc(rowSize); + for(int i = vp[3]/2 - 1; i >= 0; --i) { + unsigned char *r0 = buffer + rowSize*i; + unsigned char *r1 = buffer + rowSize*(vp[3]-i-1); + memcpy(row, r0, rowSize); + memcpy(r0, r1, rowSize); + memcpy(r1, row, rowSize); + } + + *outWidth = vp[2]; + *outHeight = vp[3]; + *outPixels = buffer; + return TRUE; +} + + diff --git a/src/framebuffer.h b/src/framebuffer.h new file mode 100644 index 0000000..8024712 --- /dev/null +++ b/src/framebuffer.h @@ -0,0 +1,21 @@ +#ifndef HELI_FRAMEBUFFER_H +#define HELI_FRAMEBUFFER_H + + +#include "common.h" + +typedef struct _Framebuffer *Framebuffer; + + +Framebuffer createFramebuffer(int width, int height); +Framebuffer createFramebufferEx(int width, int height, const void *pixels, int horWrap, int vertWrap, int smooth); +Framebuffer createFramebufferFromFile(const char *path); +void framebufferDestroy(Framebuffer framebuffer); + +int framebufferGetWidth(Framebuffer framebuffer); +int framebufferGetHeight(Framebuffer framebuffer); +unsigned int framebufferGetGLTexId(Framebuffer framebuffer); +unsigned int framebufferGetGLId(Framebuffer framebuffer); + + +#endif diff --git a/src/gl.c b/src/gl.c index 20af865..ab0b92b 100644 --- a/src/gl.c +++ b/src/gl.c @@ -3,6 +3,25 @@ #include "drawing.h" +HeliGLBlendFuncSeparatePtr heliGLBlendFuncSeparatePtr; +HeliGLStencilOpSeparatePtr heliGLStencilOpSeparatePtr; +HeliGLTexImage2DMultisamplePtr heliGLTexImage2DMultisamplePtr; +HeliGLGenFramebuffersPtr heliGLGenFramebuffersPtr; +HeliGLDeleteFramebuffersPtr heliGLDeleteFramebuffersPtr; +HeliGLBindFramebufferPtr heliGLBindFramebufferPtr; +HeliGLBlitFramebufferPtr heliGLBlitFramebufferPtr; +HeliGLFramebufferRenderbufferPtr heliGLFramebufferRenderbufferPtr; +HeliGLFramebufferTexture2DPtr heliGLFramebufferTexture2DPtr; +HeliGLGenRenderbuffersPtr heliGLGenRenderbuffersPtr; +HeliGLDeleteRenderbuffersPtr heliGLDeleteRenderbuffersPtr; +HeliGLBindRenderbufferPtr heliGLBindRenderbufferPtr; +HeliGLRenderbufferStoragePtr heliGLRenderbufferStoragePtr; +HeliGLRenderbufferStorageMultisamplePtr heliGLRenderbufferStorageMultisamplePtr; + +unsigned int heliGLWindowFramebufferReadId = 0; +unsigned int heliGLWindowFramebufferDrawId = 0; + + double heliGLGetAAResolution() { if (!heliGLIsIntegerClipping()) return 0; @@ -150,6 +169,15 @@ void heliGLGetCommonState(HeliGLCommonState *state, unsigned int flags) { glGetClipPlane(GL_CLIP_PLANE0 + i, state->clipPlanes[i].equation); } } + + if (state->flags & STATE_TARGET_FRAMEBUFFER) { + glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, (int*)&state->framebuffer_read_id); + glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, (int*)&state->framebuffer_draw_id); + } + if (state->flags & STATE_TARGET_VIEWPORT) + glGetIntegerv(GL_VIEWPORT, state->viewport); + if (state->flags & STATE_TARGET_PROJECTION) + glGetDoublev(GL_PROJECTION_MATRIX, state->projectionMatrix); } @@ -177,5 +205,21 @@ void heliGLSetCommonState(const HeliGLCommonState *state) { glLoadMatrixd(state->modelviewMatrix); glMatrixMode(mode); } + + if (state->flags & STATE_TARGET_FRAMEBUFFER) { + if (heliGLBindFramebufferPtr) { + heliGLBindFramebufferPtr(GL_DRAW_FRAMEBUFFER, state->framebuffer_draw_id); + heliGLBindFramebufferPtr(GL_READ_FRAMEBUFFER, state->framebuffer_read_id); + } + } + if (state->flags & STATE_TARGET_VIEWPORT) + glViewport(state->viewport[0], state->viewport[1], state->viewport[2], state->viewport[3]); + if (state->flags & STATE_TARGET_PROJECTION) { + unsigned int mode; + glGetIntegerv(GL_MATRIX_MODE, (int*)&mode); + glMatrixMode(GL_PROJECTION); + glLoadMatrixd(state->projectionMatrix); + glMatrixMode(mode); + } } diff --git a/src/helianthus.h b/src/helianthus.h index 0640a6f..8605f3e 100644 --- a/src/helianthus.h +++ b/src/helianthus.h @@ -2,6 +2,11 @@ #define HELI_HELIANTUS_H +#ifdef __cplusplus +extern "C" { +#endif + + #include "helianthus/common.h" #include "helianthus/world.h" #include "helianthus/sprite.h" @@ -9,5 +14,10 @@ #include "helianthus/drawing.h" #include "helianthus/font.h" + +#ifdef __cplusplus +} +#endif + #endif diff --git a/src/private.h b/src/private.h index b826966..dc1d0e9 100644 --- a/src/private.h +++ b/src/private.h @@ -13,6 +13,8 @@ #include #include "common.h" +#include "animation.h" +#include "framebuffer.h" #include "sprite.h" #include "font.h" @@ -113,9 +115,46 @@ typedef struct _HeliGLClipPlaneState { typedef struct _HeliGLCommonState { unsigned int flags; double modelviewMatrix[16]; + double projectionMatrix[16]; + int viewport[4]; + unsigned int framebuffer_read_id; + unsigned int framebuffer_draw_id; HeliGLClipPlaneState clipPlanes[4]; } HeliGLCommonState; +typedef void (APIENTRY *HeliGLBlendFuncSeparatePtr)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +typedef void (APIENTRY *HeliGLStencilOpSeparatePtr)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +typedef void (APIENTRY *HeliGLTexImage2DMultisamplePtr)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +typedef void (APIENTRY *HeliGLGenFramebuffersPtr)(GLsizei n, GLuint *framebuffers); +typedef void (APIENTRY *HeliGLDeleteFramebuffersPtr)(GLsizei n, const GLuint *framebuffers); +typedef void (APIENTRY *HeliGLBindFramebufferPtr)(GLenum target, GLuint framebuffer); +typedef void (APIENTRY *HeliGLBlitFramebufferPtr)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +typedef void (APIENTRY *HeliGLFramebufferRenderbufferPtr)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +typedef void (APIENTRY *HeliGLFramebufferTexture2DPtr)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (APIENTRY *HeliGLGenRenderbuffersPtr)(GLsizei n, GLuint *renderbuffers); +typedef void (APIENTRY *HeliGLDeleteRenderbuffersPtr)(GLsizei n, const GLuint *renderbuffers); +typedef void (APIENTRY *HeliGLBindRenderbufferPtr)(GLenum target, GLuint renderbuffer); +typedef void (APIENTRY *HeliGLRenderbufferStoragePtr)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRY *HeliGLRenderbufferStorageMultisamplePtr)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); + +extern HeliGLBlendFuncSeparatePtr heliGLBlendFuncSeparatePtr; +extern HeliGLStencilOpSeparatePtr heliGLStencilOpSeparatePtr; +extern HeliGLTexImage2DMultisamplePtr heliGLTexImage2DMultisamplePtr; +extern HeliGLGenFramebuffersPtr heliGLGenFramebuffersPtr; +extern HeliGLDeleteFramebuffersPtr heliGLDeleteFramebuffersPtr; +extern HeliGLBindFramebufferPtr heliGLBindFramebufferPtr; +extern HeliGLBlitFramebufferPtr heliGLBlitFramebufferPtr; +extern HeliGLFramebufferRenderbufferPtr heliGLFramebufferRenderbufferPtr; +extern HeliGLFramebufferTexture2DPtr heliGLFramebufferTexture2DPtr; +extern HeliGLGenRenderbuffersPtr heliGLGenRenderbuffersPtr; +extern HeliGLDeleteRenderbuffersPtr heliGLDeleteRenderbuffersPtr; +extern HeliGLBindRenderbufferPtr heliGLBindRenderbufferPtr; +extern HeliGLRenderbufferStoragePtr heliGLRenderbufferStoragePtr; +extern HeliGLRenderbufferStorageMultisamplePtr heliGLRenderbufferStorageMultisamplePtr; + +extern unsigned int heliGLWindowFramebufferReadId; +extern unsigned int heliGLWindowFramebufferDrawId; + double heliGLGetAAResolution(); int heliGLIsIntegerClipping(); int heliGLBackTransform(double *x, double *y); @@ -154,9 +193,6 @@ typedef struct _HeliDrawingState { HeliGLCommonState glState; } HeliDrawingState; -typedef void (APIENTRY *HeliGlStencilOpSeparatePtr)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); -extern HeliGlStencilOpSeparatePtr heliGlStencilOpSeparatePtr; - HeliDrawingState *heliDrawingGetState(); HeliDrawingState *heliDrawingGetStateStack(); void heliDrawingApplyTexture(double *color, HeliTextureState *state); diff --git a/src/world.c b/src/world.c index a58fe0a..1ed4331 100644 --- a/src/world.c +++ b/src/world.c @@ -21,7 +21,6 @@ static unsigned long long elapsedTimeSinceLastFrameUs; static unsigned int prevFrameTimeMs; HeliDialog dialog; -HeliGlStencilOpSeparatePtr heliGlStencilOpSeparatePtr = NULL; static Callback initCallback; static Callback drawCallback; @@ -302,11 +301,8 @@ static void draw() { firstFrame = FALSE; - glViewport(0, 0, width, height); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, width, height, 0, -1.0, 1.0); - glMatrixMode(GL_MODELVIEW); + viewportByWindow(); + projectionByViewport(); heliDrawingPrepareFrame(); if (dialog.shown) { @@ -330,7 +326,7 @@ static void draw() { static void deinit() { - heliGlStencilOpSeparatePtr = NULL; + heliGLStencilOpSeparatePtr = NULL; if (context) SDL_GL_DeleteContext(context); context = NULL; @@ -387,7 +383,22 @@ static int init() { return FALSE; } - heliGlStencilOpSeparatePtr = SDL_GL_GetProcAddress("glStencilOpSeparate"); + heliGLBlendFuncSeparatePtr = SDL_GL_GetProcAddress("glBlendFuncSeparate"); + heliGLStencilOpSeparatePtr = SDL_GL_GetProcAddress("glStencilOpSeparate"); + heliGLTexImage2DMultisamplePtr = SDL_GL_GetProcAddress("glTexImage2DMultisample"); + heliGLGenFramebuffersPtr = SDL_GL_GetProcAddress("glGenFramebuffers"); + heliGLDeleteFramebuffersPtr = SDL_GL_GetProcAddress("glDeleteFramebuffers"); + heliGLBindFramebufferPtr = SDL_GL_GetProcAddress("glBindFramebuffer"); + heliGLBlitFramebufferPtr = SDL_GL_GetProcAddress("glBlitFramebuffer"); + heliGLFramebufferRenderbufferPtr = SDL_GL_GetProcAddress("glFramebufferRenderbuffer"); + heliGLFramebufferTexture2DPtr = SDL_GL_GetProcAddress("glFramebufferTexture2D"); + heliGLGenRenderbuffersPtr = SDL_GL_GetProcAddress("glGenRenderbuffers"); + heliGLDeleteRenderbuffersPtr = SDL_GL_GetProcAddress("glDeleteRenderbuffers"); + heliGLBindRenderbufferPtr = SDL_GL_GetProcAddress("glBindRenderbuffer"); + heliGLRenderbufferStoragePtr = SDL_GL_GetProcAddress("glRenderbufferStorage"); + heliGLRenderbufferStorageMultisamplePtr = SDL_GL_GetProcAddress("glRenderbufferStorageMultisample"); + glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, (int*)&heliGLWindowFramebufferReadId); + glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, (int*)&heliGLWindowFramebufferDrawId); return TRUE; }