Workbench: Option to use Object color
[blender.git] / source / blender / draw / engines / workbench / workbench_materials.c
1 /*
2  * Copyright 2016, Blender Foundation.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Blender Institute
19  *
20  */
21
22 /** \file workbench_materials.c
23  *  \ingroup draw_engine
24  */
25
26 #include "workbench_private.h"
27 #include "GPU_shader.h"
28
29 /* *********** STATIC *********** */
30 static struct {
31         struct GPUShader *depth_sh;
32
33         /* Solid flat mode */
34         struct GPUShader *solid_flat_sh;
35
36         /* Solid studio mode */
37         struct GPUShader *solid_studio_sh;
38
39 } e_data = {NULL};
40
41 /* Shaders */
42 extern char datatoc_solid_flat_frag_glsl[];
43 extern char datatoc_solid_studio_frag_glsl[];
44 extern char datatoc_workbench_vert_glsl[];
45 extern char datatoc_workbench_studio_vert_glsl[];
46 extern char datatoc_workbench_diffuse_lib_glsl[];
47
48 /* Functions */
49 static uint get_material_hash(const float color[3])
50 {
51         uint r = (uint)(color[0] * 512);
52         uint g = (uint)(color[1] * 512);
53         uint b = (uint)(color[2] * 512);
54
55         return r + g * 4096 + b * 4096 * 4096;
56 }
57
58 static const float* get_material_solid_color(Object *ob)
59 {
60         IDProperty *props = BKE_layer_collection_engine_evaluated_get(ob, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_WORKBENCH);
61         int object_color_option = BKE_collection_engine_property_value_get_int(props, "object_color_type");
62         switch (object_color_option)
63         {
64                 default:
65                 case V3D_OBJECT_COLOR_COLLECTION:
66                         return BKE_collection_engine_property_value_get_float_array(props, "object_color");
67
68                 case V3D_OBJECT_COLOR_OBJECT:
69                         return ob->col;
70         }
71 }
72
73 void workbench_materials_engine_init(void)
74 {
75         if (!e_data.depth_sh) {
76                 /* Depth pass */
77                 e_data.depth_sh = DRW_shader_create_3D_depth_only();
78
79                 /* Solid flat */
80                 e_data.solid_flat_sh = DRW_shader_create(datatoc_workbench_vert_glsl, NULL, datatoc_solid_flat_frag_glsl, "\n");
81                 e_data.solid_studio_sh = DRW_shader_create(datatoc_workbench_studio_vert_glsl, NULL, datatoc_solid_studio_frag_glsl, datatoc_workbench_diffuse_lib_glsl);
82         }
83 }
84
85 void workbench_materials_engine_finish(void)
86 {
87         DRW_SHADER_FREE_SAFE(e_data.solid_flat_sh);
88         DRW_SHADER_FREE_SAFE(e_data.solid_studio_sh);
89 }
90
91 void workbench_materials_cache_init(WORKBENCH_Data *vedata)
92 {
93         WORKBENCH_StorageList *stl = vedata->stl;
94         WORKBENCH_PassList *psl = vedata->psl;
95         WORKBENCH_PrivateData *wpd = stl->g_data;
96
97         wpd->depth_shgrp = DRW_shgroup_create(e_data.depth_sh, psl->depth_pass);
98         wpd->material_hash = BLI_ghash_ptr_new("Workbench material_hash");
99 }
100
101 void workbench_materials_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob, int lighting_mode)
102 {
103         WORKBENCH_StorageList *stl = vedata->stl;
104         WORKBENCH_PassList *psl = vedata->psl;
105         WORKBENCH_PrivateData *wpd = stl->g_data;
106
107         if (!DRW_object_is_renderable(ob))
108                 return;
109
110         struct Gwn_Batch *geom = DRW_cache_object_surface_get(ob);
111         WORKBENCH_MaterialData *material;
112         if (geom) {
113                 /* Depth */
114                 DRW_shgroup_call_add(stl->g_data->depth_shgrp, geom, ob->obmat);
115
116                 /* Solid */
117                 GPUShader *shader = lighting_mode == V3D_LIGHTING_FLAT?e_data.solid_flat_sh:e_data.solid_studio_sh;
118
119                 const float *color = get_material_solid_color(ob);
120                 uint hash = get_material_hash(color);
121                 WORKBENCH_MaterialData *material;
122
123                 material = BLI_ghash_lookup(wpd->material_hash, SET_UINT_IN_POINTER(hash));
124                 if (material == NULL) {
125                         material = MEM_mallocN(sizeof(WORKBENCH_MaterialData), "WORKBENCH_MaterialData");
126                         material->shgrp = DRW_shgroup_create(shader, psl->solid_pass);
127                         material->color[0] = color[0];
128                         material->color[1] = color[1];
129                         material->color[2] = color[2];
130                         DRW_shgroup_uniform_vec3(material->shgrp, "color", material->color, 1);
131                         BLI_ghash_insert(wpd->material_hash, SET_UINT_IN_POINTER(hash), material);
132                 }
133
134                 DRW_shgroup_call_add(material->shgrp, geom, ob->obmat);
135         }
136
137 }
138
139 void workbench_materials_cache_finish(WORKBENCH_Data *vedata)
140 {
141         WORKBENCH_StorageList *stl = vedata->stl;
142         WORKBENCH_PrivateData *wpd = stl->g_data;
143         BLI_ghash_free(wpd->material_hash, NULL, MEM_freeN);
144 }