diff options
Diffstat (limited to 'source/blender/gpu/intern/gpu_draw.c')
-rw-r--r-- | source/blender/gpu/intern/gpu_draw.c | 210 |
1 files changed, 122 insertions, 88 deletions
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index f4810c540c3..33402426b62 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -52,6 +52,9 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" +#include "BLI_threads.h" +#include "BLI_blenlib.h" + #include "BKE_bmfont.h" #include "BKE_global.h" #include "BKE_image.h" @@ -62,9 +65,6 @@ #include "BKE_scene.h" #include "BKE_DerivedMesh.h" -#include "BLI_threads.h" -#include "BLI_blenlib.h" - #include "GPU_buffers.h" #include "GPU_draw.h" #include "GPU_extensions.h" @@ -92,7 +92,7 @@ void GPU_render_text(MTFace *tface, int mode, float *v1, float *v2, float *v3, float *v4, int glattrib) { if ((mode & GEMAT_TEXT) && (textlen>0) && tface->tpage) { - Image* ima = (Image*)tface->tpage; + Image* ima = (Image *)tface->tpage; int index, character; float centerx, centery, sizex, sizey, transx, transy, movex, movey, advance; float advance_tab; @@ -101,9 +101,9 @@ void GPU_render_text(MTFace *tface, int mode, float line_start= 0.0f, line_height; if (v4) - line_height= MAX4(v1[1], v2[1], v3[1], v4[2]) - MIN4(v1[1], v2[1], v3[1], v4[2]); + line_height = max_ffff(v1[1], v2[1], v3[1], v4[2]) - min_ffff(v1[1], v2[1], v3[1], v4[2]); else - line_height= MAX3(v1[1], v2[1], v3[1]) - MIN3(v1[1], v2[1], v3[1]); + line_height = max_fff(v1[1], v2[1], v3[1]) - min_fff(v1[1], v2[1], v3[1]); line_height *= 1.2f; /* could be an option? */ /* end multiline */ @@ -189,30 +189,21 @@ void GPU_render_text(MTFace *tface, int mode, /* Checking powers of two for images since opengl 1.x requires it */ -static int is_pow2_limit(int num) +static bool is_power_of_2_resolution(int w, int h) { - /* take texture clamping into account */ - - /* XXX: texturepaint not global! */ -#if 0 - if (G.f & G_TEXTUREPAINT) - return 1;*/ -#endif + return is_power_of_2_i(w) && is_power_of_2_i(h); +} - if (U.glreslimit != 0 && num > U.glreslimit) - return 0; +static bool is_over_resolution_limit(int w, int h) +{ + if (U.glreslimit != 0) + return (w > U.glreslimit || h > U.glreslimit); - return is_power_of_2_i(num); + return false; } -static int smaller_pow2_limit(int num) +static int smaller_power_of_2_limit(int num) { - /* XXX: texturepaint not global! */ -#if 0 - if (G.f & G_TEXTUREPAINT) - return 1;*/ -#endif - /* take texture clamping into account */ if (U.glreslimit != 0 && num > U.glreslimit) return U.glreslimit; @@ -252,6 +243,25 @@ void GPU_set_gpu_mipmapping(int gpu_mipmap) } } +static void gpu_generate_mipmap(GLenum target) +{ + int 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); + } + + glGenerateMipmapEXT(target); + + if (is_ati && !target_enabled) + glDisable(target); +} + void GPU_set_mipmap(int mipmap) { if (GTS.domipmap != (mipmap != 0)) { @@ -376,7 +386,12 @@ static void gpu_set_alpha_blend(GPUBlendMode alphablend) } else if (ELEM(alphablend, GPU_BLEND_ALPHA, GPU_BLEND_ALPHA_SORT)) { glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + /* for OpenGL render we use the alpha channel, this makes alpha blend correct */ + if (GLEW_VERSION_1_4) + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + else + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); /* if U.glalphaclip == 1.0, some cards go bonkers... * turn off alpha test in this case */ @@ -424,7 +439,7 @@ static void gpu_verify_reflection(Image *ima) } } -int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, int compare, int mipmap, int is_data) +int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, int compare, int mipmap, bool is_data) { ImBuf *ibuf = NULL; unsigned int *bind = NULL; @@ -537,8 +552,9 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, int compare, int if (do_color_management) { srgb_frect = MEM_mallocN(ibuf->x*ibuf->y*sizeof(float)*4, "floar_buf_col_cor"); IMB_buffer_float_from_float(srgb_frect, ibuf->rect_float, - ibuf->channels, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, 0, + ibuf->channels, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, TRUE, ibuf->x, ibuf->y, ibuf->x, ibuf->x); + IMB_buffer_float_unpremultiply(srgb_frect, ibuf->x, ibuf->y); /* clamp buffer colors to 1.0 to avoid artifacts due to glu for hdr images */ IMB_buffer_float_clamp(srgb_frect, ibuf->x, ibuf->y); frect= srgb_frect + texwinsy*ibuf->x + texwinsx; @@ -562,8 +578,9 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, int compare, int if (do_color_management) { frect = srgb_frect = MEM_mallocN(ibuf->x*ibuf->y*sizeof(*srgb_frect)*4, "floar_buf_col_cor"); IMB_buffer_float_from_float(srgb_frect, ibuf->rect_float, - ibuf->channels, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, 0, + ibuf->channels, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, TRUE, ibuf->x, ibuf->y, ibuf->x, ibuf->x); + IMB_buffer_float_unpremultiply(srgb_frect, ibuf->x, ibuf->y); /* clamp buffer colors to 1.0 to avoid artifacts due to glu for hdr images */ IMB_buffer_float_clamp(srgb_frect, ibuf->x, ibuf->y); } @@ -643,7 +660,8 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, int compare, int return *bind; } -void GPU_create_gl_tex(unsigned int *bind, unsigned int *pix, float * frect, int rectw, int recth, int mipmap, int use_high_bit_depth, Image *ima) +/* Image *ima can be NULL */ +void GPU_create_gl_tex(unsigned int *bind, unsigned int *pix, float *frect, int rectw, int recth, int mipmap, int use_high_bit_depth, Image *ima) { unsigned int *scalerect = NULL; float *fscalerect = NULL; @@ -654,9 +672,10 @@ void GPU_create_gl_tex(unsigned int *bind, unsigned int *pix, float * frect, int /* 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 (!GPU_non_power_of_two_support() && (!is_pow2_limit(rectw) || !is_pow2_limit(recth))) { - rectw= smaller_pow2_limit(rectw); - recth= smaller_pow2_limit(recth); + if ((!GPU_non_power_of_two_support() && !is_power_of_2_resolution(rectw, recth)) || + is_over_resolution_limit(rectw, recth)) { + rectw= smaller_power_of_2_limit(rectw); + recth= smaller_power_of_2_limit(recth); if (use_high_bit_depth) { fscalerect= MEM_mallocN(rectw*recth*sizeof(*fscalerect)*4, "fscalerect"); @@ -691,7 +710,7 @@ void GPU_create_gl_tex(unsigned int *bind, unsigned int *pix, float * frect, int else glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, pix); - glGenerateMipmapEXT(GL_TEXTURE_2D); + gpu_generate_mipmap(GL_TEXTURE_2D); } else { if (use_high_bit_depth) @@ -702,7 +721,8 @@ void GPU_create_gl_tex(unsigned int *bind, unsigned int *pix, float * frect, int glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0)); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1)); - ima->tpageflag |= IMA_MIPMAP_COMPLETE; + if (ima) + ima->tpageflag |= IMA_MIPMAP_COMPLETE; } if (GLEW_EXT_texture_filter_anisotropic) @@ -744,16 +764,19 @@ int GPU_upload_dxt_texture(ImBuf *ibuf) return FALSE; } - if (!is_power_of_2_i(width) || !is_power_of_2_i(height)) { + if (!is_power_of_2_resolution(width, height)) { printf("Unable to load non-power-of-two DXT image resolution, falling back to uncompressed\n"); return FALSE; } - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0)); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1)); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + if (GLEW_EXT_texture_filter_anisotropic) + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, GPU_get_anisotropic()); + blocksize = (ibuf->dds_data.fourcc == FOURCC_DXT1) ? 8 : 16; for (i=0; i<ibuf->dds_data.nummipmaps && (width||height); ++i) { if (width == 0) @@ -791,7 +814,7 @@ void GPU_create_gl_tex_compressed(unsigned int *bind, unsigned int *pix, int x, glBindTexture(GL_TEXTURE_2D, *bind); if (GPU_upload_dxt_texture(ibuf) == 0) { - glDeleteTextures(1, (GLuint*)bind); + glDeleteTextures(1, (GLuint *)bind); GPU_create_gl_tex(bind, pix, NULL, x, y, mipmap, 0, ima); } #endif @@ -904,8 +927,7 @@ void GPU_paint_update_image(Image *ima, int x, int y, int w, int h) ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); if (ima->repbind || (GPU_get_mipmap() && !GTS.gpu_mipmap) || !ima->bindcode || !ibuf || - (!is_power_of_2_i(ibuf->x) || !is_power_of_2_i(ibuf->y)) || - (w == 0) || (h == 0)) + (w == 0) || (h == 0)) { /* these cases require full reload still */ GPU_free_image(ima); @@ -934,7 +956,7 @@ void GPU_paint_update_image(Image *ima, int x, int y, int w, int h) /* 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()) { - glGenerateMipmapEXT(GL_TEXTURE_2D); + gpu_generate_mipmap(GL_TEXTURE_2D); } else { ima->tpageflag &= ~IMA_MIPMAP_COMPLETE; @@ -959,7 +981,7 @@ void GPU_paint_update_image(Image *ima, int x, int y, int w, int h) /* see comment above as to why we are using gpu mipmap generation here */ if (GPU_get_mipmap()) { - glGenerateMipmapEXT(GL_TEXTURE_2D); + gpu_generate_mipmap(GL_TEXTURE_2D); } else { ima->tpageflag &= ~IMA_MIPMAP_COMPLETE; @@ -1242,7 +1264,7 @@ static void gpu_material_to_fixed(GPUMaterialFixed *smat, const Material *bmat, static Material *gpu_active_node_material(Material *ma) { if (ma && ma->use_nodes && ma->nodetree) { - bNode *node= nodeGetActiveID(ma->nodetree, ID_MA); + bNode *node = nodeGetActiveID(ma->nodetree, ID_MA); if (node) return (Material *)node->id; @@ -1253,16 +1275,15 @@ static Material *gpu_active_node_material(Material *ma) return ma; } -void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, Object *ob, int glsl, int *do_alpha_after) +void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, Object *ob, bool glsl, bool *do_alpha_after) { Material *ma; GPUMaterial *gpumat; GPUBlendMode alphablend; int a; - int gamma = BKE_scene_check_color_management_enabled(scene); - int new_shading_nodes = BKE_scene_use_new_shading_nodes(scene); + int use_matcap = (v3d->flag2 & V3D_SHOW_SOLID_MATCAP); /* assumes v3d->defmaterial->preview is set */ /* initialize state */ memset(&GMS, 0, sizeof(GMS)); @@ -1274,7 +1295,7 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O GMS.gob = ob; GMS.gscene = scene; - GMS.totmat= ob->totcol+1; /* materials start from 1, default material is 0 */ + 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.gviewmat= rv3d->viewmat; GMS.gviewinv= rv3d->viewinv; @@ -1287,7 +1308,7 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O GMS.use_alpha_pass = (do_alpha_after != NULL); GMS.is_alpha_pass = (v3d->transp != FALSE); if (GMS.use_alpha_pass) - *do_alpha_after = FALSE; + *do_alpha_after = false; if (GMS.totmat > FIXEDMAT) { GMS.matbuf= MEM_callocN(sizeof(GPUMaterialFixed)*GMS.totmat, "GMS.matbuf"); @@ -1300,59 +1321,72 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O GMS.alphablend= GMS.alphablend_fixed; } - /* no materials assigned? */ - if (ob->totcol==0) { - gpu_material_to_fixed(&GMS.matbuf[0], &defmaterial, 0, ob, new_shading_nodes); - + /* viewport material, setup in space_view3d, defaults to matcap using ma->preview now */ + if (use_matcap) { + GMS.gmatbuf[0] = v3d->defmaterial; + GPU_material_matcap(scene, v3d->defmaterial); + /* do material 1 too, for displists! */ memcpy(&GMS.matbuf[1], &GMS.matbuf[0], sizeof(GPUMaterialFixed)); - - if (glsl) { - GMS.gmatbuf[0]= &defmaterial; - GPU_material_from_blender(GMS.gscene, &defmaterial); - } - + GMS.alphablend[0]= GPU_BLEND_SOLID; } + else { - /* setup materials */ - for (a=1; a<=ob->totcol; a++) { - /* find a suitable material */ - ma= give_current_material(ob, a); - if (!glsl && !new_shading_nodes) ma= gpu_active_node_material(ma); - if (ma==NULL) ma= &defmaterial; - - /* create glsl material if requested */ - gpumat = (glsl)? GPU_material_from_blender(GMS.gscene, ma): NULL; - - if (gpumat) { - /* do glsl only if creating it succeed, else fallback */ - GMS.gmatbuf[a]= ma; - alphablend = GPU_material_alpha_blend(gpumat, ob->col); - } - else { - /* fixed function opengl materials */ - gpu_material_to_fixed(&GMS.matbuf[a], ma, gamma, ob, new_shading_nodes); + /* no materials assigned? */ + if (ob->totcol==0) { + gpu_material_to_fixed(&GMS.matbuf[0], &defmaterial, 0, ob, new_shading_nodes); - if (GMS.use_alpha_pass) { - GMS.matbuf[a].diff[3]= ma->alpha; - alphablend = (ma->alpha == 1.0f)? GPU_BLEND_SOLID: GPU_BLEND_ALPHA; + /* do material 1 too, for displists! */ + memcpy(&GMS.matbuf[1], &GMS.matbuf[0], sizeof(GPUMaterialFixed)); + + if (glsl) { + GMS.gmatbuf[0]= &defmaterial; + GPU_material_from_blender(GMS.gscene, &defmaterial); + } + + GMS.alphablend[0]= GPU_BLEND_SOLID; + } + + /* setup materials */ + for (a=1; a<=ob->totcol; a++) { + /* find a suitable material */ + ma= give_current_material(ob, a); + if (!glsl && !new_shading_nodes) ma= gpu_active_node_material(ma); + if (ma==NULL) ma= &defmaterial; + + /* create glsl material if requested */ + gpumat = (glsl)? GPU_material_from_blender(GMS.gscene, ma): NULL; + + if (gpumat) { + /* do glsl only if creating it succeed, else fallback */ + GMS.gmatbuf[a]= ma; + alphablend = GPU_material_alpha_blend(gpumat, ob->col); } else { - GMS.matbuf[a].diff[3]= 1.0f; - alphablend = GPU_BLEND_SOLID; + /* fixed function opengl materials */ + gpu_material_to_fixed(&GMS.matbuf[a], ma, gamma, ob, new_shading_nodes); + + if (GMS.use_alpha_pass) { + GMS.matbuf[a].diff[3]= ma->alpha; + alphablend = (ma->alpha == 1.0f)? GPU_BLEND_SOLID: GPU_BLEND_ALPHA; + } + else { + GMS.matbuf[a].diff[3]= 1.0f; + alphablend = GPU_BLEND_SOLID; + } } - } - /* setting 'do_alpha_after = TRUE' indicates this object needs to be - * drawn in a second alpha pass for improved blending */ - if (do_alpha_after && !GMS.is_alpha_pass) - if (ELEM3(alphablend, GPU_BLEND_ALPHA, GPU_BLEND_ADD, GPU_BLEND_ALPHA_SORT)) - *do_alpha_after = TRUE; + /* setting 'do_alpha_after = TRUE' indicates this object needs to be + * drawn in a second alpha pass for improved blending */ + if (do_alpha_after && !GMS.is_alpha_pass) + if (ELEM3(alphablend, GPU_BLEND_ALPHA, GPU_BLEND_ADD, GPU_BLEND_ALPHA_SORT)) + *do_alpha_after = true; - GMS.alphablend[a]= alphablend; + GMS.alphablend[a]= alphablend; + } } - + /* let's start with a clean state */ GPU_disable_material(); } |