diff options
Diffstat (limited to 'source/blender/gpu/intern')
-rw-r--r-- | source/blender/gpu/intern/gpu_buffers.c | 128 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_codegen.c | 4 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_draw.c | 8 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_select.c | 246 |
4 files changed, 366 insertions, 20 deletions
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index f5256f18897..91eb2a43132 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -46,11 +46,13 @@ #include "BLI_ghash.h" #include "BLI_threads.h" +#include "DNA_material_types.h" #include "DNA_meshdata_types.h" #include "BKE_ccg.h" #include "BKE_DerivedMesh.h" #include "BKE_paint.h" +#include "BKE_material.h" #include "BKE_pbvh.h" #include "DNA_userdef_types.h" @@ -63,13 +65,16 @@ typedef enum { GPU_BUFFER_VERTEX_STATE = 1, GPU_BUFFER_NORMAL_STATE = 2, - GPU_BUFFER_TEXCOORD_STATE = 4, - GPU_BUFFER_COLOR_STATE = 8, - GPU_BUFFER_ELEMENT_STATE = 16, + GPU_BUFFER_TEXCOORD_UNIT_0_STATE = 4, + GPU_BUFFER_TEXCOORD_UNIT_1_STATE = 8, + GPU_BUFFER_COLOR_STATE = 16, + GPU_BUFFER_ELEMENT_STATE = 32, } GPUBufferState; #define MAX_GPU_ATTRIB_DATA 32 +#define BUFFER_OFFSET(n) ((GLubyte *)NULL + (n)) + /* -1 - undefined, 0 - vertex arrays, 1 - VBOs */ static int useVBOs = -1; static GPUBufferState GLStates = 0; @@ -611,7 +616,7 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object, } mat_orig_to_new = MEM_mallocN(sizeof(*mat_orig_to_new) * dm->totmat, - "GPU_buffer_setup.mat_orig_to_new"); + "GPU_buffer_setup.mat_orig_to_new"); cur_index_per_mat = MEM_mallocN(sizeof(int) * object->totmaterial, "GPU_buffer_setup.cur_index_per_mat"); for (i = 0; i < object->totmaterial; i++) { @@ -836,6 +841,61 @@ static void GPU_buffer_copy_uv(DerivedMesh *dm, float *varray, int *index, int * } } + +static void GPU_buffer_copy_uv_texpaint(DerivedMesh *dm, float *varray, int *index, int *mat_orig_to_new, void *UNUSED(user)) +{ + int start; + int i, totface; + + int totmaterial = dm->totmat; + MTFace **mtface_base; + MTFace *stencil_base; + int stencil; + MFace *mf; + + /* should have been checked for before, reassert */ + BLI_assert(DM_get_tessface_data_layer(dm, CD_MTFACE)); + mf = dm->getTessFaceArray(dm); + mtface_base = MEM_mallocN(totmaterial * sizeof(*mtface_base), "texslots"); + + for (i = 0; i < totmaterial; i++) { + mtface_base[i] = DM_paint_uvlayer_active_get(dm, i); + } + + stencil = CustomData_get_stencil_layer(&dm->faceData, CD_MTFACE); + stencil_base = CustomData_get_layer_n(&dm->faceData, CD_MTFACE, stencil); + + totface = dm->getNumTessFaces(dm); + + for (i = 0; i < totface; i++, mf++) { + int mat_i = mf->mat_nr; + start = index[mat_orig_to_new[mat_i]]; + + /* v1 v2 v3 */ + copy_v2_v2(&varray[start], mtface_base[mat_i][i].uv[0]); + copy_v2_v2(&varray[start + 2], stencil_base[i].uv[0]); + copy_v2_v2(&varray[start + 4], mtface_base[mat_i][i].uv[1]); + copy_v2_v2(&varray[start + 6], stencil_base[i].uv[1]); + copy_v2_v2(&varray[start + 8], mtface_base[mat_i][i].uv[2]); + copy_v2_v2(&varray[start + 10], stencil_base[i].uv[2]); + index[mat_orig_to_new[mat_i]] += 12; + + if (mf->v4) { + /* v3 v4 v1 */ + copy_v2_v2(&varray[start + 12], mtface_base[mat_i][i].uv[2]); + copy_v2_v2(&varray[start + 14], stencil_base[i].uv[2]); + copy_v2_v2(&varray[start + 16], mtface_base[mat_i][i].uv[3]); + copy_v2_v2(&varray[start + 18], stencil_base[i].uv[3]); + copy_v2_v2(&varray[start + 20], mtface_base[mat_i][i].uv[0]); + copy_v2_v2(&varray[start + 22], stencil_base[i].uv[0]); + index[mat_orig_to_new[mat_i]] += 12; + } + } + + MEM_freeN(mtface_base); +} + + static void copy_mcol_uc3(unsigned char *v, unsigned char *col) { v[0] = col[3]; @@ -925,6 +985,7 @@ typedef enum { GPU_BUFFER_NORMAL, GPU_BUFFER_COLOR, GPU_BUFFER_UV, + GPU_BUFFER_UV_TEXPAINT, GPU_BUFFER_EDGE, GPU_BUFFER_UVEDGE, } GPUBufferType; @@ -940,6 +1001,7 @@ const GPUBufferTypeSettings gpu_buffer_type_settings[] = { {GPU_buffer_copy_normal, GL_ARRAY_BUFFER_ARB, 3}, {GPU_buffer_copy_mcol, GL_ARRAY_BUFFER_ARB, 3}, {GPU_buffer_copy_uv, GL_ARRAY_BUFFER_ARB, 2}, + {GPU_buffer_copy_uv_texpaint, GL_ARRAY_BUFFER_ARB, 4}, {GPU_buffer_copy_edge, GL_ELEMENT_ARRAY_BUFFER_ARB, 2}, {GPU_buffer_copy_uvedge, GL_ELEMENT_ARRAY_BUFFER_ARB, 4} }; @@ -956,6 +1018,8 @@ static GPUBuffer **gpu_drawobject_buffer_from_type(GPUDrawObject *gdo, GPUBuffer return &gdo->colors; case GPU_BUFFER_UV: return &gdo->uv; + case GPU_BUFFER_UV_TEXPAINT: + return &gdo->uv; case GPU_BUFFER_EDGE: return &gdo->edges; case GPU_BUFFER_UVEDGE: @@ -977,6 +1041,8 @@ static int gpu_buffer_size_from_type(DerivedMesh *dm, GPUBufferType type) return sizeof(char) * 3 * dm->drawObject->tot_triangle_point; case GPU_BUFFER_UV: return sizeof(float) * 2 * dm->drawObject->tot_triangle_point; + case GPU_BUFFER_UV_TEXPAINT: + return sizeof(float) * 4 * dm->drawObject->tot_triangle_point; case GPU_BUFFER_EDGE: return sizeof(int) * 2 * dm->drawObject->totedge; case GPU_BUFFER_UVEDGE: @@ -1005,7 +1071,7 @@ static GPUBuffer *gpu_buffer_setup_type(DerivedMesh *dm, GPUBufferType type) if (!(user_data = DM_get_tessface_data_layer(dm, dm->drawObject->colType))) return NULL; } - else if (type == GPU_BUFFER_UV) { + else if (ELEM(type, GPU_BUFFER_UV, GPU_BUFFER_UV_TEXPAINT)) { if (!DM_get_tessface_data_layer(dm, CD_MTFACE)) return NULL; } @@ -1081,9 +1147,35 @@ void GPU_uv_setup(DerivedMesh *dm) glTexCoordPointer(2, GL_FLOAT, 0, dm->drawObject->uv->pointer); } - GLStates |= GPU_BUFFER_TEXCOORD_STATE; + GLStates |= GPU_BUFFER_TEXCOORD_UNIT_0_STATE; } +void GPU_texpaint_uv_setup(DerivedMesh *dm) +{ + if (!gpu_buffer_setup_common(dm, GPU_BUFFER_UV_TEXPAINT)) + return; + + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + if (useVBOs) { + glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->uv->id); + glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), 0); + glClientActiveTexture(GL_TEXTURE1); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), BUFFER_OFFSET(2 * sizeof(float))); + glClientActiveTexture(GL_TEXTURE0); + } + else { + glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), dm->drawObject->uv->pointer); + glClientActiveTexture(GL_TEXTURE1); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), (char *)dm->drawObject->uv->pointer + 2 * sizeof(float)); + glClientActiveTexture(GL_TEXTURE0); + } + + GLStates |= GPU_BUFFER_TEXCOORD_UNIT_0_STATE | GPU_BUFFER_TEXCOORD_UNIT_1_STATE; +} + + void GPU_color_setup(DerivedMesh *dm, int colType) { if (!dm->drawObject) { @@ -1241,8 +1333,13 @@ void GPU_buffer_unbind(void) glDisableClientState(GL_VERTEX_ARRAY); if (GLStates & GPU_BUFFER_NORMAL_STATE) glDisableClientState(GL_NORMAL_ARRAY); - if (GLStates & GPU_BUFFER_TEXCOORD_STATE) + if (GLStates & GPU_BUFFER_TEXCOORD_UNIT_0_STATE) + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + if (GLStates & GPU_BUFFER_TEXCOORD_UNIT_1_STATE) { + glClientActiveTexture(GL_TEXTURE1); glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glClientActiveTexture(GL_TEXTURE0); + } if (GLStates & GPU_BUFFER_COLOR_STATE) glDisableClientState(GL_COLOR_ARRAY); if (GLStates & GPU_BUFFER_ELEMENT_STATE) { @@ -1251,8 +1348,8 @@ void GPU_buffer_unbind(void) } } GLStates &= ~(GPU_BUFFER_VERTEX_STATE | GPU_BUFFER_NORMAL_STATE | - GPU_BUFFER_TEXCOORD_STATE | GPU_BUFFER_COLOR_STATE | - GPU_BUFFER_ELEMENT_STATE); + GPU_BUFFER_TEXCOORD_UNIT_0_STATE | GPU_BUFFER_TEXCOORD_UNIT_1_STATE | + GPU_BUFFER_COLOR_STATE | GPU_BUFFER_ELEMENT_STATE); for (i = 0; i < MAX_GPU_ATTRIB_DATA; i++) { if (attribData[i].index != -1) { @@ -2577,11 +2674,14 @@ bool GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, GSet *bm_faces, } else if (buffers->use_bmesh) { /* due to dynamc nature of dyntopo, only get first material */ - GSetIterator gs_iter; - BMFace *f; - BLI_gsetIterator_init(&gs_iter, bm_faces); - f = BLI_gsetIterator_getKey(&gs_iter); - GPU_material_diffuse_get(f->mat_nr + 1, diffuse_color); + if (BLI_gset_size(bm_faces) > 0) { + GSetIterator gs_iter; + BMFace *f; + + BLI_gsetIterator_init(&gs_iter, bm_faces); + f = BLI_gsetIterator_getKey(&gs_iter); + GPU_material_diffuse_get(f->mat_nr + 1, diffuse_color); + } } else { const DMFlagMat *flags = &buffers->grid_flag_mats[buffers->grid_indices[0]]; diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index b3155f0ad50..d60525dd34a 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -97,7 +97,7 @@ static char *gpu_str_skip_token(char *str, char *token, int max) /* skip a variable/function name */ while (*str) { - if (ELEM7(*str, ' ', '(', ')', ',', '\t', '\n', '\r')) + if (ELEM(*str, ' ', '(', ')', ',', '\t', '\n', '\r')) break; else { if (token && len < max-1) { @@ -115,7 +115,7 @@ static char *gpu_str_skip_token(char *str, char *token, int max) /* skip the next special characters: * note the missing ')' */ while (*str) { - if (ELEM6(*str, ' ', '(', ',', '\t', '\n', '\r')) + if (ELEM(*str, ' ', '(', ',', '\t', '\n', '\r')) str++; else break; diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index 68b8492926b..fa9bc73dcbe 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -370,9 +370,9 @@ static void gpu_make_repbind(Image *ima) BKE_image_release_ibuf(ima, ibuf, NULL); } -static void gpu_clear_tpage(void) +void GPU_clear_tpage(bool force) { - if (GTS.lasttface==NULL) + if (GTS.lasttface==NULL && !force) return; GTS.lasttface= NULL; @@ -866,7 +866,7 @@ int GPU_set_tpage(MTFace *tface, int mipmap, int alphablend) /* check if we need to clear the state */ if (tface==NULL) { - gpu_clear_tpage(); + GPU_clear_tpage(false); return 0; } @@ -1548,7 +1548,7 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O /* 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)) + if (ELEM(alphablend, GPU_BLEND_ALPHA, GPU_BLEND_ADD, GPU_BLEND_ALPHA_SORT)) *do_alpha_after = true; GMS.alphablend[a]= alphablend; diff --git a/source/blender/gpu/intern/gpu_select.c b/source/blender/gpu/intern/gpu_select.c new file mode 100644 index 00000000000..2df9e603903 --- /dev/null +++ b/source/blender/gpu/intern/gpu_select.c @@ -0,0 +1,246 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2014 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Antony Riakiotakis. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/intern/gpu_select.c + * \ingroup gpu + * + * Interface for accessing gpu-related methods for selection. The semantics will be + * similar to glRenderMode(GL_SELECT) since the goal is to maintain compatibility. + */ +#include "GPU_select.h" +#include "GPU_extensions.h" + +#include "BLI_utildefines.h" + +#include "MEM_guardedalloc.h" + +#include "DNA_userdef_types.h" + +#include <GL/glew.h> + +/* Ad hoc number of queries to allocate to skip doing many glGenQueries */ +#define ALLOC_QUERIES 200 + +typedef struct GPUQueryState { + /* To ignore selection id calls when not initialized */ + bool select_is_active; + /* Tracks whether a query has been issued so that gpu_load_id can end the previous one */ + bool query_issued; + /* array holding the OpenGL query identifiers */ + unsigned int *queries; + /* array holding the id corresponding to each query */ + unsigned int *id; + /* number of queries in *queries and *id */ + unsigned int num_of_queries; + /* index to the next query to start */ + unsigned int active_query; + /* flag to cache user preference for occlusion based selection */ + bool use_gpu_select; + /* cache on initialization */ + unsigned int *buffer; + unsigned int bufsize; + /* mode of operation */ + char mode; + unsigned int index; + int oldhits; +} GPUQueryState; + +static GPUQueryState g_query_state = {0}; + +void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, rctf *input, char mode, int oldhits) +{ + g_query_state.select_is_active = true; + g_query_state.query_issued = false; + g_query_state.active_query = 0; + g_query_state.use_gpu_select = GPU_select_query_check_active(); + g_query_state.num_of_queries = 0; + g_query_state.bufsize = bufsize; + g_query_state.buffer = buffer; + g_query_state.mode = mode; + g_query_state.index = 0; + g_query_state.oldhits = oldhits; + + if (!g_query_state.use_gpu_select) { + glSelectBuffer( bufsize, (GLuint *)buffer); + glRenderMode(GL_SELECT); + glInitNames(); + glPushName(-1); + } + else { + float viewport[4]; + + g_query_state.num_of_queries = ALLOC_QUERIES; + + g_query_state.queries = MEM_mallocN(g_query_state.num_of_queries * sizeof(*g_query_state.queries) , "gpu selection queries"); + g_query_state.id = MEM_mallocN(g_query_state.num_of_queries * sizeof(*g_query_state.id) , "gpu selection ids"); + glGenQueriesARB(g_query_state.num_of_queries, g_query_state.queries); + + glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_VIEWPORT_BIT); + /* disable writing to the framebuffer */ + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + + /* In order to save some fill rate we minimize the viewport using rect. + * We need to get the region of the scissor so that our geometry doesn't + * get rejected before the depth test. Should probably cull rect against + * scissor for viewport but this is a rare case I think */ + glGetFloatv(GL_SCISSOR_BOX, viewport); + if (!input || input->xmin == input->xmax) { + glViewport(viewport[0], viewport[1], 24, 24); + } + else { + glViewport(viewport[0], viewport[1], (int)(input->xmax - input->xmin), (int)(input->ymax - input->ymin)); + } + + /* occlusion queries operates on fragments that pass tests and since we are interested on all + * objects in the view frustum independently of their order, we need to disable the depth test */ + if (mode == GPU_SELECT_ALL) { + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + } + else if (mode == GPU_SELECT_NEAREST_FIRST_PASS) { + glClear(GL_DEPTH_BUFFER_BIT); + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + glDepthFunc(GL_LEQUAL); + } + else if (mode == GPU_SELECT_NEAREST_SECOND_PASS) { + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + glDepthFunc(GL_EQUAL); + } + } +} + +bool GPU_select_load_id(unsigned int id) +{ + /* if no selection mode active, ignore */ + if(!g_query_state.select_is_active) + return true; + + if (!g_query_state.use_gpu_select) { + glLoadName(id); + } + else { + if (g_query_state.query_issued) { + glEndQueryARB(GL_SAMPLES_PASSED_ARB); + } + /* if required, allocate extra queries */ + if (g_query_state.active_query == g_query_state.num_of_queries) { + g_query_state.num_of_queries += ALLOC_QUERIES; + g_query_state.queries = MEM_reallocN(g_query_state.queries, g_query_state.num_of_queries * sizeof(*g_query_state.queries)); + g_query_state.id = MEM_reallocN(g_query_state.id, g_query_state.num_of_queries * sizeof(*g_query_state.id)); + glGenQueriesARB(ALLOC_QUERIES, &g_query_state.queries[g_query_state.active_query]); + } + + glBeginQueryARB(GL_SAMPLES_PASSED_ARB, g_query_state.queries[g_query_state.active_query]); + g_query_state.id[g_query_state.active_query] = id; + g_query_state.active_query++; + g_query_state.query_issued = true; + + if (g_query_state.mode == GPU_SELECT_NEAREST_SECOND_PASS) { + if (g_query_state.buffer[g_query_state.index * 4 + 3] == id) { + g_query_state.index++; + return true; + } + else { + return false; + } + } + } + + return true; +} + +unsigned int GPU_select_end(void) +{ + unsigned int hits = 0; + if (!g_query_state.use_gpu_select) { + glPopName(); + hits = glRenderMode(GL_RENDER); + } + else { + int i; + + if (g_query_state.query_issued) { + glEndQueryARB(GL_SAMPLES_PASSED_ARB); + } + + for (i = 0; i < g_query_state.active_query; i++) { + unsigned int result; + glGetQueryObjectuivARB(g_query_state.queries[i], GL_QUERY_RESULT_ARB, &result); + if (result > 0) { + if (g_query_state.mode != GPU_SELECT_NEAREST_SECOND_PASS) { + if(hits < g_query_state.bufsize) { + g_query_state.buffer[hits * 4] = 1; + g_query_state.buffer[hits * 4 + 1] = 0xFFFF; + g_query_state.buffer[hits * 4 + 2] = 0xFFFF; + g_query_state.buffer[hits * 4 + 3] = g_query_state.id[i]; + + hits++; + } + else { + hits = -1; + break; + } + } + else { + int j; + /* search in buffer and make selected object first */ + for (j = 0; j < g_query_state.oldhits; j++) { + if (g_query_state.buffer[j * 4 + 3] == g_query_state.id[i]) { + g_query_state.buffer[j * 4 + 1] = 0; + g_query_state.buffer[j * 4 + 2] = 0; + } + } + break; + } + } + } + + glDeleteQueriesARB(g_query_state.num_of_queries, g_query_state.queries); + MEM_freeN(g_query_state.queries); + MEM_freeN(g_query_state.id); + glPopAttrib(); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + } + + g_query_state.select_is_active = false; + + return hits; +} + + +bool GPU_select_query_check_support(void) +{ + return GLEW_ARB_occlusion_query; +} + + +bool GPU_select_query_check_active(void) +{ + return GLEW_ARB_occlusion_query && + ((U.gpu_select_method == USER_SELECT_USE_OCCLUSION_QUERY) || + ((U.gpu_select_method == USER_SELECT_AUTO) && GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY))); +} |