diff options
Diffstat (limited to 'source/blender/gpu/intern/gpu_draw.c')
-rw-r--r-- | source/blender/gpu/intern/gpu_draw.c | 677 |
1 files changed, 324 insertions, 353 deletions
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index 514f2f71bd7..fdb5894e9ed 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -38,8 +38,6 @@ #include <string.h> -#include "GPU_glew.h" - #include "BLI_blenlib.h" #include "BLI_hash.h" #include "BLI_linklist.h" @@ -81,6 +79,7 @@ #include "GPU_draw.h" #include "GPU_extensions.h" #include "GPU_material.h" +#include "GPU_matrix.h" #include "GPU_shader.h" #include "GPU_texture.h" @@ -109,23 +108,27 @@ static void gpu_mcol(unsigned int ucol) } void GPU_render_text( - MTexPoly *mtexpoly, int mode, - const char *textstr, int textlen, unsigned int *col, + int mode, const char *textstr, int textlen, unsigned int *col, const float *v_quad[4], const float *uv_quad[4], int glattrib) { - if ((mode & GEMAT_TEXT) && (textlen > 0) && mtexpoly->tpage) { + /* XXX, 2.8 removes texface */ +#if 0 + Image *ima = mtexpoly->tpage; +#else + Image *ima = NULL; +#endif + if ((mode & GEMAT_TEXT) && (textlen > 0) && ima) { const float *v1 = v_quad[0]; const float *v2 = v_quad[1]; const float *v3 = v_quad[2]; const float *v4 = v_quad[3]; - Image *ima = (Image *)mtexpoly->tpage; const size_t textlen_st = textlen; float centerx, centery, sizex, sizey, transx, transy, movex, movey, advance; - + /* multiline */ float line_start = 0.0f, line_height; - + if (v4) line_height = max_ffff(v1[1], v2[1], v3[1], v4[2]) - min_ffff(v1[1], v2[1], v3[1], v4[2]); else @@ -133,50 +136,48 @@ void GPU_render_text( line_height *= 1.2f; /* could be an option? */ /* end multiline */ - + /* color has been set */ - if (mtexpoly->mode & TF_OBCOL) - col = NULL; - else if (!col) + if (!col) glColor3f(1.0f, 1.0f, 1.0f); - glPushMatrix(); - + gpuPushMatrix(); + /* get the tab width */ ImBuf *first_ibuf = BKE_image_get_first_ibuf(ima); matrixGlyph(first_ibuf, ' ', ¢erx, ¢ery, - &sizex, &sizey, &transx, &transy, &movex, &movey, &advance); - + &sizex, &sizey, &transx, &transy, &movex, &movey, &advance); + float advance_tab = advance * 4; /* tab width could also be an option */ - - + + for (size_t index = 0; index < textlen_st; ) { unsigned int character; float uv[4][2]; /* lets calculate offset stuff */ character = BLI_str_utf8_as_unicode_and_size_safe(textstr + index, &index); - + if (character == '\n') { - glTranslatef(line_start, -line_height, 0.0f); + gpuTranslate2f(line_start, -line_height); line_start = 0.0f; continue; } else if (character == '\t') { - glTranslatef(advance_tab, 0.0f, 0.0f); + gpuTranslate2f(advance_tab, 0.0f); line_start -= advance_tab; /* so we can go back to the start of the line */ continue; - + } else if (character > USHRT_MAX) { /* not much we can do here bmfonts take ushort */ character = '?'; } - + /* space starts at offset 1 */ /* character = character - ' ' + 1; */ matrixGlyph(first_ibuf, character, & centerx, ¢ery, - &sizex, &sizey, &transx, &transy, &movex, &movey, &advance); + &sizex, &sizey, &transx, &transy, &movex, &movey, &advance); uv[0][0] = (uv_quad[0][0] - centerx) * sizex + transx; uv[0][1] = (uv_quad[0][1] - centery) * sizey + transy; @@ -184,13 +185,13 @@ void GPU_render_text( uv[1][1] = (uv_quad[1][1] - centery) * sizey + transy; uv[2][0] = (uv_quad[2][0] - centerx) * sizex + transx; uv[2][1] = (uv_quad[2][1] - centery) * sizey + transy; - + glBegin(GL_POLYGON); if (glattrib >= 0) glVertexAttrib2fv(glattrib, uv[0]); else glTexCoord2fv(uv[0]); if (col) gpu_mcol(col[0]); glVertex3f(sizex * v1[0] + movex, sizey * v1[1] + movey, v1[2]); - + if (glattrib >= 0) glVertexAttrib2fv(glattrib, uv[1]); else glTexCoord2fv(uv[1]); if (col) gpu_mcol(col[1]); @@ -212,28 +213,29 @@ void GPU_render_text( } glEnd(); - glTranslatef(advance, 0.0f, 0.0f); + gpuTranslate2f(advance, 0.0f); line_start -= advance; /* so we can go back to the start of the line */ } - glPopMatrix(); + gpuPopMatrix(); BKE_image_release_ibuf(ima, first_ibuf, NULL); } } /* Checking powers of two for images since OpenGL ES requires it */ - +#ifdef WITH_DDS static bool is_power_of_2_resolution(int w, int h) { return is_power_of_2_i(w) && is_power_of_2_i(h); } +#endif static bool is_over_resolution_limit(GLenum textarget, int w, int h) { int size = (textarget == GL_TEXTURE_2D) ? GPU_max_texture_size() : GPU_max_cube_map_size(); int reslimit = (U.glreslimit != 0) ? - min_ii(U.glreslimit, size) : size; + min_ii(U.glreslimit, size) : size; return (w > reslimit || h > reslimit); } @@ -269,8 +271,7 @@ static struct GPUTextureState { int alphablend; float anisotropic; int gpu_mipmap; - MTexPoly *lasttface; -} GTS = {0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 1, 0, 0, -1, 1.0f, 0, NULL}; +} GTS = {0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 1, 0, 0, -1, 1.0f, 0}; /* Mipmap settings */ @@ -279,36 +280,13 @@ void GPU_set_gpu_mipmapping(int gpu_mipmap) int old_value = GTS.gpu_mipmap; /* only actually enable if it's supported */ - GTS.gpu_mipmap = gpu_mipmap && GLEW_EXT_framebuffer_object; + GTS.gpu_mipmap = gpu_mipmap; if (old_value != GTS.gpu_mipmap) { GPU_free_images(); } } -static void gpu_generate_mipmap(GLenum target) -{ - const bool is_ati = GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY); - int target_enabled = 0; - - /* work around bug in ATI driver, need to have GL_TEXTURE_2D enabled - * http://www.opengl.org/wiki/Common_Mistakes#Automatic_mipmap_generation */ - if (is_ati) { - target_enabled = glIsEnabled(target); - if (!target_enabled) - glEnable(target); - } - - /* TODO: simplify when we transition to GL >= 3 */ - if (GLEW_VERSION_3_0 || GLEW_ARB_framebuffer_object) - glGenerateMipmap(target); - else if (GLEW_EXT_framebuffer_object) - glGenerateMipmapEXT(target); - - if (is_ati && !target_enabled) - glDisable(target); -} - void GPU_set_mipmap(bool mipmap) { if (GTS.domipmap != mipmap) { @@ -415,43 +393,16 @@ static unsigned int *gpu_get_image_bindcode(Image *ima, GLenum textarget) return bind; } -void GPU_clear_tpage(bool force) -{ - if (GTS.lasttface == NULL && !force) - return; - - GTS.lasttface = NULL; - GTS.curtile = 0; - GTS.curima = NULL; - if (GTS.curtilemode != 0) { - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - } - GTS.curtilemode = 0; - GTS.curtileXRep = 0; - GTS.curtileYRep = 0; - GTS.alphablend = -1; - - glDisable(GL_BLEND); - glDisable(GL_TEXTURE_2D); - glDisable(GL_TEXTURE_GEN_S); - glDisable(GL_TEXTURE_GEN_T); - glDisable(GL_ALPHA_TEST); -} - static void gpu_set_alpha_blend(GPUBlendMode alphablend) { if (alphablend == GPU_BLEND_SOLID) { glDisable(GL_BLEND); - glDisable(GL_ALPHA_TEST); glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } else if (alphablend == GPU_BLEND_ADD) { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); - glDisable(GL_ALPHA_TEST); glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); } else if (ELEM(alphablend, GPU_BLEND_ALPHA, GPU_BLEND_ALPHA_SORT)) { @@ -460,59 +411,20 @@ static void gpu_set_alpha_blend(GPUBlendMode alphablend) /* for OpenGL render we use the alpha channel, this makes alpha blend correct */ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - + /* if U.glalphaclip == 1.0, some cards go bonkers... * turn off alpha test in this case */ - /* added after 2.45 to clip alpha */ - if (U.glalphaclip == 1.0f) { - glDisable(GL_ALPHA_TEST); - } - else { - glEnable(GL_ALPHA_TEST); - glAlphaFunc(GL_GREATER, U.glalphaclip); - } } else if (alphablend == GPU_BLEND_CLIP) { glDisable(GL_BLEND); glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); - glEnable(GL_ALPHA_TEST); - glAlphaFunc(GL_GREATER, 0.5f); } else if (alphablend == GPU_BLEND_ALPHA_TO_COVERAGE) { - glEnable(GL_ALPHA_TEST); - glAlphaFunc(GL_GREATER, U.glalphaclip); glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE); } } -static void gpu_verify_alpha_blend(int alphablend) -{ - /* verify alpha blending modes */ - if (GTS.alphablend == alphablend) - return; - - gpu_set_alpha_blend(alphablend); - GTS.alphablend = alphablend; -} - -static void gpu_verify_reflection(Image *ima) -{ - if (ima && (ima->flag & IMA_REFLECT)) { - /* enable reflection mapping */ - glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); - glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); - - glEnable(GL_TEXTURE_GEN_S); - glEnable(GL_TEXTURE_GEN_T); - } - else { - /* disable reflection mapping */ - glDisable(GL_TEXTURE_GEN_S); - glDisable(GL_TEXTURE_GEN_T); - } -} - typedef struct VerifyThreadData { ImBuf *ibuf; float *srgb_frect; @@ -534,8 +446,6 @@ static void gpu_verify_high_bit_srgb_buffer_slice(float *srgb_frect, ibuf->x, height, ibuf->x, ibuf->x); IMB_buffer_float_unpremultiply(current_srgb_frect, ibuf->x, height); - /* Clamp buffer colors to 1.0 to avoid artifacts due to glu for hdr images. */ - IMB_buffer_float_clamp(current_srgb_frect, ibuf->x, height); } static void verify_thread_do(void *data_v, @@ -604,19 +514,6 @@ int GPU_verify_image( return (ima != NULL); } - /* if tiling mode or repeat changed, change texture matrix to fit */ - if (GTS.tilemode != GTS.curtilemode || GTS.curtileXRep != GTS.tileXRep || - GTS.curtileYRep != GTS.tileYRep) - { - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - - if (ima && (ima->tpageflag & IMA_TILES)) - glScalef(ima->xrep, ima->yrep, 1.0f); - - glMatrixMode(GL_MODELVIEW); - } - /* check if we have a valid image */ if (ima == NULL || ima->ok == 0) return 0; @@ -652,29 +549,29 @@ int GPU_verify_image( GPU_free_image(ima); ima->tpageflag &= ~IMA_TPAGE_REFRESH; } - + if (GTS.tilemode) { /* tiled mode */ if (ima->repbind == NULL) gpu_make_repbind(ima); if (GTS.tile >= ima->totbind) GTS.tile = 0; - + /* this happens when you change repeat buttons */ if (ima->repbind && textarget == GL_TEXTURE_2D) bind = &ima->repbind[GTS.tile]; else bind = gpu_get_image_bindcode(ima, textarget); - + if (*bind == 0) { short texwindx = ibuf->x / ima->xrep; short texwindy = ibuf->y / ima->yrep; - + if (GTS.tile >= ima->xrep * ima->yrep) GTS.tile = ima->xrep * ima->yrep - 1; - + short texwinsy = GTS.tile / ima->xrep; short texwinsx = GTS.tile - texwinsy * ima->xrep; - + texwinsx *= texwindx; texwinsy *= texwindy; - + tpx = texwindx; tpy = texwindy; @@ -748,7 +645,7 @@ int GPU_verify_image( memcpy(tilerectrow, rectrow, tpx * sizeof(*rectrow)); } - + rect = tilerect; } } @@ -759,13 +656,13 @@ int GPU_verify_image( else #endif GPU_create_gl_tex(bind, rect, frect, rectw, recth, textarget, mipmap, use_high_bit_depth, ima); - + /* mark as non-color data texture */ if (*bind) { if (is_data) - ima->tpageflag |= IMA_GLBIND_IS_DATA; + ima->tpageflag |= IMA_GLBIND_IS_DATA; else - ima->tpageflag &= ~IMA_GLBIND_IS_DATA; + ima->tpageflag &= ~IMA_GLBIND_IS_DATA; } /* clean up */ @@ -858,30 +755,6 @@ void GPU_create_gl_tex( int tpx = rectw; int tpy = recth; - /* scale if not a power of two. this is not strictly necessary for newer - * GPUs (OpenGL version >= 2.0) since they support non-power-of-two-textures - * Then don't bother scaling for hardware that supports NPOT textures! */ - if (textarget == GL_TEXTURE_2D && - ((!GPU_full_non_power_of_two_support() && !is_power_of_2_resolution(rectw, recth)) || - is_over_resolution_limit(textarget, rectw, recth))) - { - rectw = smaller_power_of_2_limit(rectw); - recth = smaller_power_of_2_limit(recth); - - if (use_high_bit_depth) { - ibuf = IMB_allocFromBuffer(NULL, frect, tpx, tpy); - IMB_scaleImBuf(ibuf, rectw, recth); - - frect = ibuf->rect_float; - } - else { - ibuf = IMB_allocFromBuffer(rect, NULL, tpx, tpy); - IMB_scaleImBuf(ibuf, rectw, recth); - - rect = ibuf->rect; - } - } - /* create image */ glGenTextures(1, (GLuint *)bind); glBindTexture(textarget, *bind); @@ -900,7 +773,7 @@ void GPU_create_gl_tex( if (GPU_get_mipmap() && mipmap) { if (GTS.gpu_mipmap) { - gpu_generate_mipmap(GL_TEXTURE_2D); + glGenerateMipmap(GL_TEXTURE_2D); } else { int i; @@ -951,7 +824,7 @@ void GPU_create_gl_tex( if (GPU_get_mipmap() && mipmap) { if (GTS.gpu_mipmap) { - gpu_generate_mipmap(GL_TEXTURE_CUBE_MAP); + glGenerateMipmap(GL_TEXTURE_CUBE_MAP); } else { if (!ibuf) { @@ -975,7 +848,7 @@ void GPU_create_gl_tex( if (mip_cube_map) { for (int j = 0; j < 6; j++) { glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + j, i, - informat, mipw, miph, 0, GL_RGBA, type, mip_cube_map[j]); + informat, mipw, miph, 0, GL_RGBA, type, mip_cube_map[j]); } } gpu_del_cube_map(mip_cube_map); @@ -1056,7 +929,7 @@ bool GPU_upload_dxt_texture(ImBuf *ibuf) size = ((width + 3) / 4) * ((height + 3) / 4) * blocksize; glCompressedTexImage2D(GL_TEXTURE_2D, i, format, width, height, - 0, size, ibuf->dds_data.data + offset); + 0, size, ibuf->dds_data.data + offset); offset += size; width >>= 1; @@ -1091,62 +964,6 @@ void GPU_create_gl_tex_compressed( } #endif } -static void gpu_verify_repeat(Image *ima) -{ - /* set either clamp or repeat in X/Y */ - if (ima->tpageflag & IMA_CLAMP_U) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - else - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - - if (ima->tpageflag & IMA_CLAMP_V) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - else - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); -} - -int GPU_set_tpage(MTexPoly *mtexpoly, int mipmap, int alphablend) -{ - /* check if we need to clear the state */ - if (mtexpoly == NULL) { - GPU_clear_tpage(false); - return 0; - } - - Image *ima = mtexpoly->tpage; - GTS.lasttface = mtexpoly; - - gpu_verify_alpha_blend(alphablend); - gpu_verify_reflection(ima); - - if (GPU_verify_image(ima, NULL, GL_TEXTURE_2D, mtexpoly->tile, 1, mipmap, false)) { - GTS.curtile = GTS.tile; - GTS.curima = GTS.ima; - GTS.curtilemode = GTS.tilemode; - GTS.curtileXRep = GTS.tileXRep; - GTS.curtileYRep = GTS.tileYRep; - - glEnable(GL_TEXTURE_2D); - } - else { - glDisable(GL_TEXTURE_2D); - - GTS.curtile = 0; - GTS.curima = NULL; - GTS.curtilemode = 0; - GTS.curtileXRep = 0; - GTS.curtileYRep = 0; - - return 0; - } - - gpu_verify_repeat(ima); - - /* Did this get lost in the image recode? */ - /* BKE_image_tag_time(ima);*/ - - return 1; -} /* these two functions are called on entering and exiting texture paint mode, * temporary disabling/enabling mipmapping on all images for quick texture @@ -1206,9 +1023,7 @@ void GPU_paint_set_mipmap(bool mipmap) /* check if image has been downscaled and do scaled partial update */ static bool gpu_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x, int y, int w, int h) { - if ((!GPU_full_non_power_of_two_support() && !is_power_of_2_resolution(ibuf->x, ibuf->y)) || - is_over_resolution_limit(GL_TEXTURE_2D, ibuf->x, ibuf->y)) - { + if (is_over_resolution_limit(GL_TEXTURE_2D, ibuf->x, ibuf->y)) { int x_limit = smaller_power_of_2_limit(ibuf->x); int y_limit = smaller_power_of_2_limit(ibuf->y); @@ -1261,7 +1076,7 @@ static bool gpu_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x, } if (GPU_get_mipmap()) { - gpu_generate_mipmap(GL_TEXTURE_2D); + glGenerateMipmap(GL_TEXTURE_2D); } else { ima->tpageflag &= ~IMA_MIPMAP_COMPLETE; @@ -1296,7 +1111,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i float *buffer = MEM_mallocN(w * h * sizeof(float) * 4, "temp_texpaint_float_buf"); bool is_data = (ima->tpageflag & IMA_GLBIND_IS_DATA) != 0; IMB_partial_rect_from_float(ibuf, buffer, x, y, w, h, is_data); - + if (gpu_check_scaled_image(ibuf, ima, buffer, x, y, w, h)) { MEM_freeN(buffer); BKE_image_release_ibuf(ima, ibuf, NULL); @@ -1311,7 +1126,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i /* we have already accounted for the case where GTS.gpu_mipmap is false * so we will be using GPU mipmap generation here */ if (GPU_get_mipmap()) { - gpu_generate_mipmap(GL_TEXTURE_2D); + glGenerateMipmap(GL_TEXTURE_2D); } else { ima->tpageflag &= ~IMA_MIPMAP_COMPLETE; @@ -1337,7 +1152,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i glPixelStorei(GL_UNPACK_SKIP_ROWS, y); glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, - GL_UNSIGNED_BYTE, ibuf->rect); + GL_UNSIGNED_BYTE, ibuf->rect); glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length); glPixelStorei(GL_UNPACK_SKIP_PIXELS, skip_pixels); @@ -1345,7 +1160,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i /* see comment above as to why we are using gpu mipmap generation here */ if (GPU_get_mipmap()) { - gpu_generate_mipmap(GL_TEXTURE_2D); + glGenerateMipmap(GL_TEXTURE_2D); } else { ima->tpageflag &= ~IMA_MIPMAP_COMPLETE; @@ -1361,9 +1176,9 @@ void GPU_update_images_framechange(void) if (ima->tpageflag & IMA_TWINANIM) { if (ima->twend >= ima->xrep * ima->yrep) ima->twend = ima->xrep * ima->yrep - 1; - + /* check: is bindcode not in the array? free. (to do) */ - + ima->lastframe++; if (ima->lastframe > ima->twend) ima->lastframe = ima->twsta; @@ -1386,9 +1201,9 @@ int GPU_update_image_time(Image *ima, double time) if (ima->tpageflag & IMA_TWINANIM) { if (ima->twend >= ima->xrep * ima->yrep) ima->twend = ima->xrep * ima->yrep - 1; - + /* check: is the bindcode not in the array? Then free. (still to do) */ - + float diff = (float)((float)time - ima->lastupdate); inc = (int)(diff * (float)ima->animspeed); @@ -1437,31 +1252,60 @@ void GPU_create_smoke(SmokeModifierData *smd, int highres) if (smoke_has_colors(sds->fluid)) { float *data = MEM_callocN(sizeof(float) * sds->total_cells * 4, "smokeColorTexture"); smoke_get_rgba(sds->fluid, data, 0); - sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 4, data); + sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], data, NULL); MEM_freeN(data); } /* density only */ else { - sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, smoke_get_density(sds->fluid)); + sds->tex = GPU_texture_create_3D_custom(sds->res[0], sds->res[1], sds->res[2], 1, + GPU_R8, smoke_get_density(sds->fluid), NULL); + + /* Swizzle the RGBA components to read the Red channel so + * that the shader stay the same for colored and non color + * density textures. */ + GPU_texture_bind(sds->tex, 0); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_R, GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_G, GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_B, GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, GL_RED); + GPU_texture_unbind(sds->tex); } - sds->tex_flame = (smoke_has_fuel(sds->fluid)) ? GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, smoke_get_flame(sds->fluid)) : NULL; + sds->tex_flame = (smoke_has_fuel(sds->fluid)) ? + GPU_texture_create_3D_custom(sds->res[0], sds->res[1], sds->res[2], 1, + GPU_R8, smoke_get_flame(sds->fluid), NULL) : + NULL; } else if (!sds->tex && highres) { /* rgba texture for color + density */ if (smoke_turbulence_has_colors(sds->wt)) { float *data = MEM_callocN(sizeof(float) * smoke_turbulence_get_cells(sds->wt) * 4, "smokeColorTexture"); smoke_turbulence_get_rgba(sds->wt, data, 0); - sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 4, data); + sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], data, NULL); MEM_freeN(data); } /* density only */ else { - sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1, smoke_turbulence_get_density(sds->wt)); + sds->tex = GPU_texture_create_3D_custom(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1, + GPU_R8, smoke_turbulence_get_density(sds->wt), NULL); + + /* Swizzle the RGBA components to read the Red channel so + * that the shader stay the same for colored and non color + * density textures. */ + GPU_texture_bind(sds->tex, 0); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_R, GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_G, GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_B, GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, GL_RED); + GPU_texture_unbind(sds->tex); } - sds->tex_flame = (smoke_turbulence_has_fuel(sds->wt)) ? GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1, smoke_turbulence_get_flame(sds->wt)) : NULL; + sds->tex_flame = (smoke_turbulence_has_fuel(sds->wt)) ? + GPU_texture_create_3D_custom(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1, + GPU_R8, smoke_turbulence_get_flame(sds->wt), NULL) : + NULL; } - sds->tex_shadow = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, sds->shadow); + sds->tex_shadow = GPU_texture_create_3D_custom(sds->res[0], sds->res[1], sds->res[2], 1, + GPU_R8, sds->shadow, NULL); } #else // WITH_SMOKE (void)highres; @@ -1528,7 +1372,7 @@ void GPU_free_image(Image *ima) /* free repeated image binding */ if (ima->repbind) { glDeleteTextures(ima->totbind, (GLuint *)ima->repbind); - + MEM_freeN(ima->repbind); ima->repbind = NULL; } @@ -1601,7 +1445,7 @@ typedef struct GPUMaterialFixed { float spec[3]; int hard; float alpha; -} GPUMaterialFixed; +} GPUMaterialFixed; static struct GPUMaterialState { GPUMaterialFixed (*matbuf); @@ -1616,10 +1460,10 @@ static struct GPUMaterialState { Material *gmatbuf_fixed[FIXEDMAT]; Material *gboundmat; Object *gob; + eObjectMode gob_object_mode; DupliObject *dob; Scene *gscene; int glay; - bool gscenelock; float (*gviewmat)[4]; float (*gviewinv)[4]; float (*gviewcamtexcofac); @@ -1657,12 +1501,12 @@ static void gpu_material_to_fixed( copy_v3_v3(smat->spec, &bmat->specr); smat->alpha = 1.0f; smat->hard = CLAMPIS(bmat->har, 0, 128); - + if (dimdown) { mul_v3_fl(smat->diff, 0.8f); mul_v3_fl(smat->spec, 0.5f); } - + if (gamma) { linearrgb_to_srgb_v3_v3(smat->diff, smat->diff); linearrgb_to_srgb_v3_v3(smat->spec, smat->spec); @@ -1673,7 +1517,7 @@ static void gpu_material_to_fixed( if (bmat->shade_flag & MA_OBCOLOR) mul_v3_v3(smat->diff, ob->col); - + mul_v3_v3fl(smat->spec, &bmat->specr, bmat->spec); smat->hard = CLAMPIS(bmat->har, 1, 128); smat->alpha = 1.0f; @@ -1710,8 +1554,8 @@ void GPU_end_dupli_object(void) } void GPU_begin_object_materials( - View3D *v3d, RegionView3D *rv3d, Scene *scene, Object *ob, - bool glsl, bool *do_alpha_after) + View3D *v3d, RegionView3D *rv3d, Scene *scene, ViewLayer *view_layer, Object *ob, + bool glsl, const eObjectMode object_mode, bool *do_alpha_after) { Material *ma; GPUMaterial *gpumat; @@ -1749,8 +1593,10 @@ void GPU_begin_object_materials( #ifdef WITH_GAMEENGINE if (rv3d->rflag & RV3D_IS_GAME_ENGINE) { - ob = BKE_object_lod_matob_get(ob, scene); + ob = BKE_object_lod_matob_get(ob, view_layer, object_mode); } +#else + UNUSED_VARS(view_layer); #endif /* initialize state */ @@ -1771,11 +1617,11 @@ void GPU_begin_object_materials( GMS.two_sided_lighting = (((Mesh *)ob->data)->flag & ME_TWOSIDED) != 0; GMS.gob = ob; + GMS.gob_object_mode = object_mode; GMS.gscene = scene; GMS.is_opensubdiv = use_opensubdiv; GMS.totmat = use_matcap ? 1 : ob->totcol + 1; /* materials start from 1, default material is 0 */ GMS.glay = (v3d->localvd) ? v3d->localvd->lay : v3d->lay; /* keep lamps visible in local view */ - GMS.gscenelock = (v3d->scenelock != 0); GMS.gviewmat = rv3d->viewmat; GMS.gviewinv = rv3d->viewinv; GMS.gviewcamtexcofac = rv3d->viewcamtexcofac; @@ -1789,7 +1635,7 @@ void GPU_begin_object_materials( GMS.is_alpha_pass = (v3d->transp != false); if (GMS.use_alpha_pass) *do_alpha_after = false; - + if (GMS.totmat > FIXEDMAT) { GMS.matbuf = MEM_callocN(sizeof(GPUMaterialFixed) * GMS.totmat, "GMS.matbuf"); GMS.gmatbuf = MEM_callocN(sizeof(*GMS.gmatbuf) * GMS.totmat, "GMS.matbuf"); @@ -1808,11 +1654,11 @@ void GPU_begin_object_materials( /* do material 1 too, for displists! */ memcpy(&GMS.matbuf[1], &GMS.matbuf[0], sizeof(GPUMaterialFixed)); - + GMS.alphablend[0] = GPU_BLEND_SOLID; } else { - + /* no materials assigned? */ if (ob->totcol == 0) { gpu_material_to_fixed(&GMS.matbuf[0], &defmaterial, 0, ob, new_shading_nodes, true); @@ -1827,7 +1673,7 @@ void GPU_begin_object_materials( GMS.alphablend[0] = GPU_BLEND_SOLID; } - + /* setup materials */ for (a = 1; a <= ob->totcol; a++) { /* find a suitable material */ @@ -1987,13 +1833,13 @@ int GPU_object_material_bind(int nr, void *attribs) gpu_get_particle_info(&partile_info); } - if (GPU_get_material_builtins(gpumat) & GPU_OBJECT_INFO) { + if ((GPU_get_material_builtins(gpumat) & GPU_OBJECT_INFO) != 0) { GPU_get_object_info(object_info, mat); } GPU_material_bind( - gpumat, GMS.gob->lay, GMS.glay, 1.0, !(GMS.gob->mode & OB_MODE_TEXTURE_PAINT), - GMS.gviewmat, GMS.gviewinv, GMS.gviewcamtexcofac, GMS.gscenelock); + gpumat, GMS.gob->lay, GMS.glay, 1.0, !(GMS.gob_object_mode & OB_MODE_TEXTURE_PAINT), + GMS.gviewmat, GMS.gviewinv, GMS.gviewcamtexcofac); auto_bump_scale = GMS.gob->derivedFinal != NULL ? GMS.gob->derivedFinal->auto_bump_scale : 1.0f; GPU_material_bind_uniforms(gpumat, GMS.gob->obmat, GMS.gviewmat, GMS.gob->col, auto_bump_scale, &partile_info, object_info); @@ -2064,7 +1910,7 @@ void GPU_set_material_alpha_blend(int alphablend) { if (GMS.lastalphablend == alphablend) return; - + gpu_set_alpha_blend(alphablend); GMS.lastalphablend = alphablend; } @@ -2135,13 +1981,6 @@ void GPU_end_object_materials(void) GMS.gmatbuf = NULL; GMS.alphablend = NULL; GMS.two_sided_lighting = false; - - /* resetting the texture matrix after the scaling needed for tiled textures */ - if (GTS.tilemode) { - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - } } /* Lights */ @@ -2155,13 +1994,13 @@ int GPU_default_lights(void) U.light[0].col[0] = 0.8; U.light[0].col[1] = 0.8; U.light[0].col[2] = 0.8; U.light[0].spec[0] = 0.5; U.light[0].spec[1] = 0.5; U.light[0].spec[2] = 0.5; U.light[0].spec[3] = 1.0; - + U.light[1].flag = 0; U.light[1].vec[0] = 0.5; U.light[1].vec[1] = 0.5; U.light[1].vec[2] = 0.1; U.light[1].col[0] = 0.4; U.light[1].col[1] = 0.4; U.light[1].col[2] = 0.8; U.light[1].spec[0] = 0.3; U.light[1].spec[1] = 0.3; U.light[1].spec[2] = 0.5; U.light[1].spec[3] = 1.0; - + U.light[2].flag = 0; U.light[2].vec[0] = 0.3; U.light[2].vec[1] = -0.3; U.light[2].vec[2] = -0.2; U.light[2].col[0] = 0.8; U.light[2].col[1] = 0.5; U.light[2].col[2] = 0.4; @@ -2194,31 +2033,28 @@ int GPU_default_lights(void) return count; } -int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[4][4], int ortho) +int GPU_scene_object_lights(ViewLayer *view_layer, float viewmat[4][4], int ortho) { /* disable all lights */ for (int count = 0; count < 8; count++) GPU_basic_shader_light_set(count, NULL); - + /* view direction for specular is not computed correct by default in * opengl, so we set the settings ourselves */ GPU_basic_shader_light_set_viewer(!ortho); int count = 0; - for (Base *base = scene->base.first; base; base = base->next) { + for (Base *base = FIRSTBASE(view_layer); base; base = base->next) { if (base->object->type != OB_LAMP) continue; - if (!(base->lay & lay) || !(base->lay & ob->lay)) - continue; - Lamp *la = base->object->data; - + /* setup lamp transform */ - glPushMatrix(); - glLoadMatrixf((float *)viewmat); - + gpuPushMatrix(); + gpuLoadMatrix(viewmat); + /* setup light */ GPULightData light = {0}; @@ -2237,7 +2073,7 @@ int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[4][ light.constant_attenuation = 1.0f; light.linear_attenuation = la->att1 / la->dist; light.quadratic_attenuation = la->att2 / (la->dist * la->dist); - + if (la->type == LA_SPOT) { light.type = GPU_LIGHT_SPOT; negate_v3_v3(light.direction, base->object->obmat[2]); @@ -2248,11 +2084,11 @@ int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[4][ else light.type = GPU_LIGHT_POINT; } - + GPU_basic_shader_light_set(count, &light); - - glPopMatrix(); - + + gpuPopMatrix(); + count++; if (count == 8) break; @@ -2261,7 +2097,7 @@ int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[4][ return count; } -static void gpu_multisample(bool enable) +static void gpu_disable_multisample(void) { #ifdef __linux__ /* changing multisample from the default (enabled) causes problems on some @@ -2277,16 +2113,10 @@ static void gpu_multisample(bool enable) } if (toggle_ok) { - if (enable) - glEnable(GL_MULTISAMPLE); - else - glDisable(GL_MULTISAMPLE); + glDisable(GL_MULTISAMPLE); } #else - if (enable) - glEnable(GL_MULTISAMPLE); - else - glDisable(GL_MULTISAMPLE); + glDisable(GL_MULTISAMPLE); #endif } @@ -2299,64 +2129,36 @@ static void gpu_multisample(bool enable) void GPU_state_init(void) { - float mat_ambient[] = { 0.0, 0.0, 0.0, 0.0 }; - float mat_specular[] = { 0.5, 0.5, 0.5, 1.0 }; - - glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient); - glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_specular); - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular); - glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 35); - glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); - GPU_default_lights(); - + + GPU_disable_program_point_size(); + + glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); + glDepthFunc(GL_LEQUAL); - /* scaling matrices */ - glEnable(GL_NORMALIZE); - glDisable(GL_ALPHA_TEST); glDisable(GL_BLEND); glDisable(GL_DEPTH_TEST); - glDisable(GL_FOG); - glDisable(GL_LIGHTING); - glDisable(GL_COLOR_MATERIAL); - glDisable(GL_LOGIC_OP); + glDisable(GL_COLOR_LOGIC_OP); glDisable(GL_STENCIL_TEST); - glDisable(GL_TEXTURE_1D); - glDisable(GL_TEXTURE_2D); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - - /* default disabled, enable should be local per function */ - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - - glPixelTransferi(GL_MAP_COLOR, GL_FALSE); - glPixelTransferi(GL_RED_SCALE, 1); - glPixelTransferi(GL_RED_BIAS, 0); - glPixelTransferi(GL_GREEN_SCALE, 1); - glPixelTransferi(GL_GREEN_BIAS, 0); - glPixelTransferi(GL_BLUE_SCALE, 1); - glPixelTransferi(GL_BLUE_BIAS, 0); - glPixelTransferi(GL_ALPHA_SCALE, 1); - glPixelTransferi(GL_ALPHA_BIAS, 0); - - glPixelTransferi(GL_DEPTH_BIAS, 0); - glPixelTransferi(GL_DEPTH_SCALE, 1); - glDepthRange(0.0, 1.0); - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); + glDepthRange(0.0, 1.0); glFrontFace(GL_CCW); glCullFace(GL_BACK); glDisable(GL_CULL_FACE); - gpu_multisample(false); + gpu_disable_multisample(); +} - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); +void GPU_enable_program_point_size(void) +{ + glEnable(GL_PROGRAM_POINT_SIZE); +} + +void GPU_disable_program_point_size(void) +{ + glDisable(GL_PROGRAM_POINT_SIZE); } #ifdef WITH_OPENSUBDIV @@ -2502,10 +2304,10 @@ void GPU_select_to_index_array(unsigned int *col, const unsigned int size) { #define INDEX_BUF_ARRAY(INDEX_FROM_BUF_BITS) \ for (i = size; i--; col++) { \ - if ((c = *col)) { \ - *col = INDEX_FROM_BUF_BITS(c); \ - } \ - } ((void)0) + if ((c = *col)) { \ + *col = INDEX_FROM_BUF_BITS(c); \ + } \ + } ((void)0) if (size > 0) { unsigned int i, c; @@ -2533,4 +2335,173 @@ void GPU_select_to_index_array(unsigned int *col, const unsigned int size) #undef INDEX_BUF_ARRAY } +#define STATE_STACK_DEPTH 16 + +typedef struct { + eGPUAttribMask mask; + + /* GL_ENABLE_BIT */ + unsigned int is_blend : 1; + unsigned int is_cull_face : 1; + unsigned int is_depth_test : 1; + unsigned int is_dither : 1; + unsigned int is_lighting : 1; + unsigned int is_line_smooth : 1; + unsigned int is_color_logic_op : 1; + unsigned int is_multisample : 1; + unsigned int is_polygon_offset_line : 1; + unsigned int is_polygon_offset_fill : 1; + unsigned int is_polygon_smooth : 1; + unsigned int is_sample_alpha_to_coverage : 1; + unsigned int is_scissor_test : 1; + unsigned int is_stencil_test : 1; + + bool is_clip_plane[6]; + + /* GL_DEPTH_BUFFER_BIT */ + /* unsigned int is_depth_test : 1; */ + int depth_func; + double depth_clear_value; + bool depth_write_mask; + + /* GL_SCISSOR_BIT */ + int scissor_box[4]; + /* unsigned int is_scissor_test : 1; */ + + /* GL_VIEWPORT_BIT */ + int viewport[4]; + double near_far[2]; +} GPUAttribValues; + +typedef struct { + GPUAttribValues attrib_stack[STATE_STACK_DEPTH]; + unsigned int top; +} GPUAttribStack; + +static GPUAttribStack state = { + .top = 0 +}; + +#define AttribStack state +#define Gwn_VertAttr state.attrib_stack[state.top] + +/** + * Replacement for glPush/PopAttributes + * + * We don't need to cover all the options of legacy OpenGL + * but simply the ones used by Blender. + */ +void gpuPushAttrib(eGPUAttribMask mask) +{ + Gwn_VertAttr.mask = mask; + + if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) { + Gwn_VertAttr.is_depth_test = glIsEnabled(GL_DEPTH_TEST); + glGetIntegerv(GL_DEPTH_FUNC, &Gwn_VertAttr.depth_func); + glGetDoublev(GL_DEPTH_CLEAR_VALUE, &Gwn_VertAttr.depth_clear_value); + glGetBooleanv(GL_DEPTH_WRITEMASK, (GLboolean *)&Gwn_VertAttr.depth_write_mask); + } + + if ((mask & GPU_ENABLE_BIT) != 0) { + Gwn_VertAttr.is_blend = glIsEnabled(GL_BLEND); + + for (int i = 0; i < 6; i++) { + Gwn_VertAttr.is_clip_plane[i] = glIsEnabled(GL_CLIP_PLANE0 + i); + } + + Gwn_VertAttr.is_cull_face = glIsEnabled(GL_CULL_FACE); + Gwn_VertAttr.is_depth_test = glIsEnabled(GL_DEPTH_TEST); + Gwn_VertAttr.is_dither = glIsEnabled(GL_DITHER); + Gwn_VertAttr.is_line_smooth = glIsEnabled(GL_LINE_SMOOTH); + Gwn_VertAttr.is_color_logic_op = glIsEnabled(GL_COLOR_LOGIC_OP); + Gwn_VertAttr.is_multisample = glIsEnabled(GL_MULTISAMPLE); + Gwn_VertAttr.is_polygon_offset_line = glIsEnabled(GL_POLYGON_OFFSET_LINE); + Gwn_VertAttr.is_polygon_offset_fill = glIsEnabled(GL_POLYGON_OFFSET_FILL); + Gwn_VertAttr.is_polygon_smooth = glIsEnabled(GL_POLYGON_SMOOTH); + Gwn_VertAttr.is_sample_alpha_to_coverage = glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE); + Gwn_VertAttr.is_scissor_test = glIsEnabled(GL_SCISSOR_TEST); + Gwn_VertAttr.is_stencil_test = glIsEnabled(GL_STENCIL_TEST); + } + + if ((mask & GPU_SCISSOR_BIT) != 0) { + Gwn_VertAttr.is_scissor_test = glIsEnabled(GL_SCISSOR_TEST); + glGetIntegerv(GL_SCISSOR_BOX, (GLint *)&Gwn_VertAttr.scissor_box); + } + + if ((mask & GPU_VIEWPORT_BIT) != 0) { + glGetDoublev(GL_DEPTH_RANGE, (GLdouble *)&Gwn_VertAttr.near_far); + glGetIntegerv(GL_VIEWPORT, (GLint *)&Gwn_VertAttr.viewport); + } + + if ((mask & GPU_BLEND_BIT) != 0) { + Gwn_VertAttr.is_blend = glIsEnabled(GL_BLEND); + } + + BLI_assert(AttribStack.top < STATE_STACK_DEPTH); + AttribStack.top++; +} + +static void restore_mask(GLenum cap, const bool value) +{ + if (value) { + glEnable(cap); + } + else { + glDisable(cap); + } +} + +void gpuPopAttrib(void) +{ + BLI_assert(AttribStack.top > 0); + AttribStack.top--; + + GLint mask = Gwn_VertAttr.mask; + + if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) { + restore_mask(GL_DEPTH_TEST, Gwn_VertAttr.is_depth_test); + glDepthFunc(Gwn_VertAttr.depth_func); + glClearDepth(Gwn_VertAttr.depth_clear_value); + glDepthMask(Gwn_VertAttr.depth_write_mask); + } + + if ((mask & GPU_ENABLE_BIT) != 0) { + restore_mask(GL_BLEND, Gwn_VertAttr.is_blend); + + for (int i = 0; i < 6; i++) { + restore_mask(GL_CLIP_PLANE0 + i, Gwn_VertAttr.is_clip_plane[i]); + } + + restore_mask(GL_CULL_FACE, Gwn_VertAttr.is_cull_face); + restore_mask(GL_DEPTH_TEST, Gwn_VertAttr.is_depth_test); + restore_mask(GL_DITHER, Gwn_VertAttr.is_dither); + restore_mask(GL_LINE_SMOOTH, Gwn_VertAttr.is_line_smooth); + restore_mask(GL_COLOR_LOGIC_OP, Gwn_VertAttr.is_color_logic_op); + restore_mask(GL_MULTISAMPLE, Gwn_VertAttr.is_multisample); + restore_mask(GL_POLYGON_OFFSET_LINE, Gwn_VertAttr.is_polygon_offset_line); + restore_mask(GL_POLYGON_OFFSET_FILL, Gwn_VertAttr.is_polygon_offset_fill); + restore_mask(GL_POLYGON_SMOOTH, Gwn_VertAttr.is_polygon_smooth); + restore_mask(GL_SAMPLE_ALPHA_TO_COVERAGE, Gwn_VertAttr.is_sample_alpha_to_coverage); + restore_mask(GL_SCISSOR_TEST, Gwn_VertAttr.is_scissor_test); + restore_mask(GL_STENCIL_TEST, Gwn_VertAttr.is_stencil_test); + } + + if ((mask & GPU_VIEWPORT_BIT) != 0) { + glViewport(Gwn_VertAttr.viewport[0], Gwn_VertAttr.viewport[1], Gwn_VertAttr.viewport[2], Gwn_VertAttr.viewport[3]); + glDepthRange(Gwn_VertAttr.near_far[0], Gwn_VertAttr.near_far[1]); + } + + if ((mask & GPU_SCISSOR_BIT) != 0) { + restore_mask(GL_SCISSOR_TEST, Gwn_VertAttr.is_scissor_test); + glScissor(Gwn_VertAttr.scissor_box[0], Gwn_VertAttr.scissor_box[1], Gwn_VertAttr.scissor_box[2], Gwn_VertAttr.scissor_box[3]); + } + + if ((mask & GPU_BLEND_BIT) != 0) { + restore_mask(GL_BLEND, Gwn_VertAttr.is_blend); + } +} + +#undef Gwn_VertAttr +#undef AttribStack + /** \} */ |