2 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
18 * The Original Code is Copyright (C) 2016 by Mike Erwin.
19 * All rights reserved.
21 * Contributor(s): Blender Foundation
23 * ***** END GPL LICENSE BLOCK *****
26 /** \file blender/gpu/intern/gpu_immediate.c
29 * GPU immediate mode work-alike
32 #include "UI_resources.h"
34 #include "GPU_attr_binding.h"
35 #include "GPU_immediate.h"
37 #include "gpu_attr_binding_private.h"
38 #include "gpu_context_private.h"
39 #include "gpu_primitive_private.h"
40 #include "gpu_shader_private.h"
41 #include "gpu_vertex_format_private.h"
46 /* necessary functions from matrix API */
47 extern void GPU_matrix_bind(const GPUShaderInterface *);
48 extern bool GPU_matrix_dirty_get(void);
51 /* TODO: organize this struct by frequency of change (run-time) */
56 /* current draw call */
59 uint buffer_bytes_mapped;
61 bool strict_vertex_len;
62 GPUPrimType prim_type;
64 GPUVertFormat vertex_format;
69 uint16_t unassigned_attrib_bits; /* which attributes of current vertex have not been given values? */
75 const GPUShaderInterface *shader_interface;
76 GPUAttrBinding attrib_binding;
77 uint16_t prev_enabled_attrib_bits; /* <-- only affects this VAO, so we're ok */
80 /* size of internal buffer -- make this adjustable? */
81 #define IMM_BUFFER_SIZE (4 * 1024 * 1024)
83 static bool initialized = false;
91 memset(&imm, 0, sizeof(Immediate));
93 imm.vbo_id = GPU_buf_alloc();
94 glBindBuffer(GL_ARRAY_BUFFER, imm.vbo_id);
95 glBufferData(GL_ARRAY_BUFFER, IMM_BUFFER_SIZE, NULL, GL_DYNAMIC_DRAW);
97 imm.prim_type = GPU_PRIM_NONE;
98 imm.strict_vertex_len = true;
100 glBindBuffer(GL_ARRAY_BUFFER, 0);
104 void immActivate(void)
108 assert(imm.prim_type == GPU_PRIM_NONE); /* make sure we're not between a Begin/End pair */
109 assert(imm.vao_id == 0);
111 imm.vao_id = GPU_vao_alloc();
112 imm.context = GPU_context_active_get();
115 void immDeactivate(void)
119 assert(imm.prim_type == GPU_PRIM_NONE); /* make sure we're not between a Begin/End pair */
120 assert(imm.vao_id != 0);
122 GPU_vao_free(imm.vao_id, imm.context);
124 imm.prev_enabled_attrib_bits = 0;
127 void immDestroy(void)
129 GPU_buf_free(imm.vbo_id);
133 GPUVertFormat *immVertexFormat(void)
135 GPU_vertformat_clear(&imm.vertex_format);
136 return &imm.vertex_format;
139 void immBindProgram(GLuint program, const GPUShaderInterface *shaderface)
142 assert(imm.bound_program == 0);
143 assert(glIsProgram(program));
146 imm.bound_program = program;
147 imm.shader_interface = shaderface;
149 if (!imm.vertex_format.packed)
150 VertexFormat_pack(&imm.vertex_format);
152 glUseProgram(program);
153 get_attrib_locations(&imm.vertex_format, &imm.attrib_binding, shaderface);
154 GPU_matrix_bind(shaderface);
157 void immBindBuiltinProgram(GPUBuiltinShader shader_id)
159 GPUShader *shader = GPU_shader_get_builtin_shader(shader_id);
160 immBindProgram(shader->program, shader->interface);
163 void immUnbindProgram(void)
166 assert(imm.bound_program != 0);
171 imm.bound_program = 0;
175 static bool vertex_count_makes_sense_for_primitive(uint vertex_len, GPUPrimType prim_type)
177 /* does vertex_len make sense for this primitive type? */
178 if (vertex_len == 0) {
183 case GPU_PRIM_POINTS:
186 return vertex_len % 2 == 0;
187 case GPU_PRIM_LINE_STRIP:
188 case GPU_PRIM_LINE_LOOP:
189 return vertex_len >= 2;
190 case GPU_PRIM_LINE_STRIP_ADJ:
191 return vertex_len >= 4;
193 return vertex_len % 3 == 0;
194 case GPU_PRIM_TRI_STRIP:
195 case GPU_PRIM_TRI_FAN:
196 return vertex_len >= 3;
203 void immBegin(GPUPrimType prim_type, uint vertex_len)
207 assert(imm.prim_type == GPU_PRIM_NONE); /* make sure we haven't already begun */
208 assert(vertex_count_makes_sense_for_primitive(vertex_len, prim_type));
210 imm.prim_type = prim_type;
211 imm.vertex_len = vertex_len;
213 imm.unassigned_attrib_bits = imm.attrib_binding.enabled_bits;
215 /* how many bytes do we need for this draw call? */
216 const uint bytes_needed = vertex_buffer_size(&imm.vertex_format, vertex_len);
219 assert(bytes_needed <= IMM_BUFFER_SIZE);
222 glBindBuffer(GL_ARRAY_BUFFER, imm.vbo_id);
224 /* does the current buffer have enough room? */
225 const uint available_bytes = IMM_BUFFER_SIZE - imm.buffer_offset;
226 /* ensure vertex data is aligned */
227 const uint pre_padding = padding(imm.buffer_offset, imm.vertex_format.stride); /* might waste a little space, but it's safe */
228 if ((bytes_needed + pre_padding) <= available_bytes) {
229 imm.buffer_offset += pre_padding;
232 /* orphan this buffer & start with a fresh one */
233 /* this method works on all platforms, old & new */
234 glBufferData(GL_ARRAY_BUFFER, IMM_BUFFER_SIZE, NULL, GL_DYNAMIC_DRAW);
236 imm.buffer_offset = 0;
239 /* printf("mapping %u to %u\n", imm.buffer_offset, imm.buffer_offset + bytes_needed - 1); */
241 imm.buffer_data = glMapBufferRange(GL_ARRAY_BUFFER, imm.buffer_offset, bytes_needed,
242 GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | (imm.strict_vertex_len ? 0 : GL_MAP_FLUSH_EXPLICIT_BIT));
245 assert(imm.buffer_data != NULL);
248 imm.buffer_bytes_mapped = bytes_needed;
249 imm.vertex_data = imm.buffer_data;
252 void immBeginAtMost(GPUPrimType prim_type, uint vertex_len)
255 assert(vertex_len > 0);
258 imm.strict_vertex_len = false;
259 immBegin(prim_type, vertex_len);
263 GPUBatch *immBeginBatch(GPUPrimType prim_type, uint vertex_len)
267 assert(imm.prim_type == GPU_PRIM_NONE); /* make sure we haven't already begun */
268 assert(vertex_count_makes_sense_for_primitive(vertex_len, prim_type));
270 imm.prim_type = prim_type;
271 imm.vertex_len = vertex_len;
273 imm.unassigned_attrib_bits = imm.attrib_binding.enabled_bits;
275 GPUVertBuf *verts = GPU_vertbuf_create_with_format(&imm.vertex_format);
276 GPU_vertbuf_data_alloc(verts, vertex_len);
278 imm.buffer_bytes_mapped = GPU_vertbuf_size_get(verts);
279 imm.vertex_data = verts->data;
281 imm.batch = GPU_batch_create_ex(prim_type, verts, NULL, GPU_BATCH_OWNS_VBO);
282 imm.batch->phase = GPU_BATCH_BUILDING;
287 GPUBatch *immBeginBatchAtMost(GPUPrimType prim_type, uint vertex_len)
289 imm.strict_vertex_len = false;
290 return immBeginBatch(prim_type, vertex_len);
293 static void immDrawSetup(void)
295 /* set up VAO -- can be done during Begin or End really */
296 glBindVertexArray(imm.vao_id);
298 /* enable/disable vertex attribs as needed */
299 if (imm.attrib_binding.enabled_bits != imm.prev_enabled_attrib_bits) {
300 for (uint loc = 0; loc < GPU_VERT_ATTR_MAX_LEN; ++loc) {
301 bool is_enabled = imm.attrib_binding.enabled_bits & (1 << loc);
302 bool was_enabled = imm.prev_enabled_attrib_bits & (1 << loc);
304 if (is_enabled && !was_enabled) {
305 glEnableVertexAttribArray(loc);
307 else if (was_enabled && !is_enabled) {
308 glDisableVertexAttribArray(loc);
312 imm.prev_enabled_attrib_bits = imm.attrib_binding.enabled_bits;
315 const uint stride = imm.vertex_format.stride;
317 for (uint a_idx = 0; a_idx < imm.vertex_format.attr_len; ++a_idx) {
318 const GPUVertAttr *a = imm.vertex_format.attribs + a_idx;
320 const uint offset = imm.buffer_offset + a->offset;
321 const GLvoid *pointer = (const GLubyte *)0 + offset;
323 const uint loc = read_attrib_location(&imm.attrib_binding, a_idx);
325 switch (a->fetch_mode) {
326 case GPU_FETCH_FLOAT:
327 case GPU_FETCH_INT_TO_FLOAT:
328 glVertexAttribPointer(loc, a->comp_len, a->gl_comp_type, GL_FALSE, stride, pointer);
330 case GPU_FETCH_INT_TO_FLOAT_UNIT:
331 glVertexAttribPointer(loc, a->comp_len, a->gl_comp_type, GL_TRUE, stride, pointer);
334 glVertexAttribIPointer(loc, a->comp_len, a->gl_comp_type, stride, pointer);
338 if (GPU_matrix_dirty_get()) {
339 GPU_matrix_bind(imm.shader_interface);
346 assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
349 uint buffer_bytes_used;
350 if (imm.strict_vertex_len) {
352 assert(imm.vertex_idx == imm.vertex_len); /* with all vertices defined */
354 buffer_bytes_used = imm.buffer_bytes_mapped;
358 assert(imm.vertex_idx <= imm.vertex_len);
360 if (imm.vertex_idx == imm.vertex_len) {
361 buffer_bytes_used = imm.buffer_bytes_mapped;
365 assert(imm.vertex_idx == 0 || vertex_count_makes_sense_for_primitive(imm.vertex_idx, imm.prim_type));
367 imm.vertex_len = imm.vertex_idx;
368 buffer_bytes_used = vertex_buffer_size(&imm.vertex_format, imm.vertex_len);
369 /* unused buffer bytes are available to the next immBegin */
371 /* tell OpenGL what range was modified so it doesn't copy the whole mapped range */
372 glFlushMappedBufferRange(GL_ARRAY_BUFFER, 0, buffer_bytes_used);
376 if (buffer_bytes_used != imm.buffer_bytes_mapped) {
377 GPU_vertbuf_data_resize(imm.batch->verts[0], imm.vertex_len);
378 /* TODO: resize only if vertex count is much smaller */
380 GPU_batch_program_set(imm.batch, imm.bound_program, imm.shader_interface);
381 imm.batch->phase = GPU_BATCH_READY_TO_DRAW;
382 imm.batch = NULL; /* don't free, batch belongs to caller */
385 glUnmapBuffer(GL_ARRAY_BUFFER);
386 if (imm.vertex_len > 0) {
388 glDrawArrays(convert_prim_type_to_gl(imm.prim_type), 0, imm.vertex_len);
390 /* These lines are causing crash on startup on some old GPU + drivers.
391 * They are not required so just comment them. (T55722) */
392 // glBindBuffer(GL_ARRAY_BUFFER, 0);
393 // glBindVertexArray(0);
394 /* prep for next immBegin */
395 imm.buffer_offset += buffer_bytes_used;
398 /* prep for next immBegin */
399 imm.prim_type = GPU_PRIM_NONE;
400 imm.strict_vertex_len = true;
403 static void setAttribValueBit(uint attrib_id)
405 uint16_t mask = 1 << attrib_id;
407 assert(imm.unassigned_attrib_bits & mask); /* not already set */
409 imm.unassigned_attrib_bits &= ~mask;
413 /* --- generic attribute functions --- */
415 void immAttr1f(uint attrib_id, float x)
417 GPUVertAttr *attr = imm.vertex_format.attribs + attrib_id;
419 assert(attrib_id < imm.vertex_format.attr_len);
420 assert(attr->comp_type == GPU_COMP_F32);
421 assert(attr->comp_len == 1);
422 assert(imm.vertex_idx < imm.vertex_len);
423 assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
425 setAttribValueBit(attrib_id);
427 float *data = (float *)(imm.vertex_data + attr->offset);
428 /* printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data); */
433 void immAttr2f(uint attrib_id, float x, float y)
435 GPUVertAttr *attr = imm.vertex_format.attribs + attrib_id;
437 assert(attrib_id < imm.vertex_format.attr_len);
438 assert(attr->comp_type == GPU_COMP_F32);
439 assert(attr->comp_len == 2);
440 assert(imm.vertex_idx < imm.vertex_len);
441 assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
443 setAttribValueBit(attrib_id);
445 float *data = (float *)(imm.vertex_data + attr->offset);
446 /* printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data); */
452 void immAttr3f(uint attrib_id, float x, float y, float z)
454 GPUVertAttr *attr = imm.vertex_format.attribs + attrib_id;
456 assert(attrib_id < imm.vertex_format.attr_len);
457 assert(attr->comp_type == GPU_COMP_F32);
458 assert(attr->comp_len == 3);
459 assert(imm.vertex_idx < imm.vertex_len);
460 assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
462 setAttribValueBit(attrib_id);
464 float *data = (float *)(imm.vertex_data + attr->offset);
465 /* printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data); */
472 void immAttr4f(uint attrib_id, float x, float y, float z, float w)
474 GPUVertAttr *attr = imm.vertex_format.attribs + attrib_id;
476 assert(attrib_id < imm.vertex_format.attr_len);
477 assert(attr->comp_type == GPU_COMP_F32);
478 assert(attr->comp_len == 4);
479 assert(imm.vertex_idx < imm.vertex_len);
480 assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
482 setAttribValueBit(attrib_id);
484 float *data = (float *)(imm.vertex_data + attr->offset);
485 /* printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data); */
493 void immAttr1u(uint attrib_id, uint x)
495 GPUVertAttr *attr = imm.vertex_format.attribs + attrib_id;
497 assert(attrib_id < imm.vertex_format.attr_len);
498 assert(attr->comp_type == GPU_COMP_U32);
499 assert(attr->comp_len == 1);
500 assert(imm.vertex_idx < imm.vertex_len);
501 assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
503 setAttribValueBit(attrib_id);
505 uint *data = (uint *)(imm.vertex_data + attr->offset);
510 void immAttr2i(uint attrib_id, int x, int y)
512 GPUVertAttr *attr = imm.vertex_format.attribs + attrib_id;
514 assert(attrib_id < imm.vertex_format.attr_len);
515 assert(attr->comp_type == GPU_COMP_I32);
516 assert(attr->comp_len == 2);
517 assert(imm.vertex_idx < imm.vertex_len);
518 assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
520 setAttribValueBit(attrib_id);
522 int *data = (int *)(imm.vertex_data + attr->offset);
528 void immAttr2s(uint attrib_id, short x, short y)
530 GPUVertAttr *attr = imm.vertex_format.attribs + attrib_id;
532 assert(attrib_id < imm.vertex_format.attr_len);
533 assert(attr->comp_type == GPU_COMP_I16);
534 assert(attr->comp_len == 2);
535 assert(imm.vertex_idx < imm.vertex_len);
536 assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
538 setAttribValueBit(attrib_id);
540 short *data = (short *)(imm.vertex_data + attr->offset);
546 void immAttr2fv(uint attrib_id, const float data[2])
548 immAttr2f(attrib_id, data[0], data[1]);
551 void immAttr3fv(uint attrib_id, const float data[3])
553 immAttr3f(attrib_id, data[0], data[1], data[2]);
556 void immAttr4fv(uint attrib_id, const float data[4])
558 immAttr4f(attrib_id, data[0], data[1], data[2], data[3]);
561 void immAttr3ub(uint attrib_id, uchar r, uchar g, uchar b)
563 GPUVertAttr *attr = imm.vertex_format.attribs + attrib_id;
565 assert(attrib_id < imm.vertex_format.attr_len);
566 assert(attr->comp_type == GPU_COMP_U8);
567 assert(attr->comp_len == 3);
568 assert(imm.vertex_idx < imm.vertex_len);
569 assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
571 setAttribValueBit(attrib_id);
573 GLubyte *data = imm.vertex_data + attr->offset;
574 /* printf("%s %td %p\n", __FUNCTION__, data - imm.buffer_data, data); */
581 void immAttr4ub(uint attrib_id, uchar r, uchar g, uchar b, uchar a)
583 GPUVertAttr *attr = imm.vertex_format.attribs + attrib_id;
585 assert(attrib_id < imm.vertex_format.attr_len);
586 assert(attr->comp_type == GPU_COMP_U8);
587 assert(attr->comp_len == 4);
588 assert(imm.vertex_idx < imm.vertex_len);
589 assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
591 setAttribValueBit(attrib_id);
593 GLubyte *data = imm.vertex_data + attr->offset;
594 /* printf("%s %td %p\n", __FUNCTION__, data - imm.buffer_data, data); */
602 void immAttr3ubv(uint attrib_id, const uchar data[3])
604 immAttr3ub(attrib_id, data[0], data[1], data[2]);
607 void immAttr4ubv(uint attrib_id, const uchar data[4])
609 immAttr4ub(attrib_id, data[0], data[1], data[2], data[3]);
612 void immAttrSkip(uint attrib_id)
615 assert(attrib_id < imm.vertex_format.attr_len);
616 assert(imm.vertex_idx < imm.vertex_len);
617 assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
619 setAttribValueBit(attrib_id);
622 static void immEndVertex(void) /* and move on to the next vertex */
625 assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
626 assert(imm.vertex_idx < imm.vertex_len);
629 /* have all attribs been assigned values?
630 * if not, copy value from previous vertex */
631 if (imm.unassigned_attrib_bits) {
633 assert(imm.vertex_idx > 0); /* first vertex must have all attribs specified */
635 for (uint a_idx = 0; a_idx < imm.vertex_format.attr_len; ++a_idx) {
636 if ((imm.unassigned_attrib_bits >> a_idx) & 1) {
637 const GPUVertAttr *a = imm.vertex_format.attribs + a_idx;
639 /* printf("copying %s from vertex %u to %u\n", a->name, imm.vertex_idx - 1, imm.vertex_idx); */
641 GLubyte *data = imm.vertex_data + a->offset;
642 memcpy(data, data - imm.vertex_format.stride, a->sz);
643 /* TODO: consolidate copy of adjacent attributes */
649 imm.vertex_data += imm.vertex_format.stride;
650 imm.unassigned_attrib_bits = imm.attrib_binding.enabled_bits;
653 void immVertex2f(uint attrib_id, float x, float y)
655 immAttr2f(attrib_id, x, y);
659 void immVertex3f(uint attrib_id, float x, float y, float z)
661 immAttr3f(attrib_id, x, y, z);
665 void immVertex4f(uint attrib_id, float x, float y, float z, float w)
667 immAttr4f(attrib_id, x, y, z, w);
671 void immVertex2i(uint attrib_id, int x, int y)
673 immAttr2i(attrib_id, x, y);
677 void immVertex2s(uint attrib_id, short x, short y)
679 immAttr2s(attrib_id, x, y);
683 void immVertex2fv(uint attrib_id, const float data[2])
685 immAttr2f(attrib_id, data[0], data[1]);
689 void immVertex3fv(uint attrib_id, const float data[3])
691 immAttr3f(attrib_id, data[0], data[1], data[2]);
695 void immVertex2iv(uint attrib_id, const int data[2])
697 immAttr2i(attrib_id, data[0], data[1]);
702 /* --- generic uniform functions --- */
706 # define GET_UNIFORM const GPUShaderInput* uniform = GPU_shaderinterface_uniform(imm.shader_interface, name); assert(uniform);
708 # define GET_UNIFORM const GPUShaderInput* uniform = GPU_shaderinterface_uniform(imm.shader_interface, name);
711 /* NOTE: It is possible to have uniform fully optimized out from the shader.
712 * In this case we can't assert failure or allow NULL-pointer dereference.
713 * TODO(sergey): How can we detect existing-but-optimized-out uniform but still
714 * catch typos in uniform names passed to immUniform*() functions? */
715 # define GET_UNIFORM const GPUShaderInput* uniform = GPU_shaderinterface_uniform(imm.shader_interface, name); if (uniform == NULL) return;
718 void immUniform1f(const char *name, float x)
721 glUniform1f(uniform->location, x);
724 void immUniform2f(const char *name, float x, float y)
727 glUniform2f(uniform->location, x, y);
730 void immUniform2fv(const char *name, const float data[2])
733 glUniform2fv(uniform->location, 1, data);
736 void immUniform3f(const char *name, float x, float y, float z)
739 glUniform3f(uniform->location, x, y, z);
742 void immUniform3fv(const char *name, const float data[3])
745 glUniform3fv(uniform->location, 1, data);
748 /* can increase this limit or move to another file */
749 #define MAX_UNIFORM_NAME_LEN 60
751 void immUniformArray3fv(const char *bare_name, const float *data, int count)
753 /* look up "name[0]" when given "name" */
754 const size_t len = strlen(bare_name);
756 assert(len <= MAX_UNIFORM_NAME_LEN);
758 char name[MAX_UNIFORM_NAME_LEN];
759 strcpy(name, bare_name);
763 name[len + 3] = '\0';
766 glUniform3fv(uniform->location, count, data);
769 void immUniform4f(const char *name, float x, float y, float z, float w)
772 glUniform4f(uniform->location, x, y, z, w);
775 void immUniform4fv(const char *name, const float data[4])
778 glUniform4fv(uniform->location, 1, data);
781 void immUniformArray4fv(const char *bare_name, const float *data, int count)
783 /* look up "name[0]" when given "name" */
784 const size_t len = strlen(bare_name);
786 assert(len <= MAX_UNIFORM_NAME_LEN);
788 char name[MAX_UNIFORM_NAME_LEN];
789 strcpy(name, bare_name);
793 name[len + 3] = '\0';
796 glUniform4fv(uniform->location, count, data);
799 void immUniformMatrix4fv(const char *name, const float data[4][4])
802 glUniformMatrix4fv(uniform->location, 1, GL_FALSE, (float *)data);
805 void immUniform1i(const char *name, int x)
808 glUniform1i(uniform->location, x);
811 void immUniform4iv(const char *name, const int data[4])
814 glUniform4iv(uniform->location, 1, data);
817 /* --- convenience functions for setting "uniform vec4 color" --- */
819 void immUniformColor4f(float r, float g, float b, float a)
821 const GPUShaderInput *uniform = GPU_shaderinterface_uniform_builtin(imm.shader_interface, GPU_UNIFORM_COLOR);
823 assert(uniform != NULL);
825 glUniform4f(uniform->location, r, g, b, a);
828 void immUniformColor4fv(const float rgba[4])
830 immUniformColor4f(rgba[0], rgba[1], rgba[2], rgba[3]);
833 void immUniformColor3f(float r, float g, float b)
835 immUniformColor4f(r, g, b, 1.0f);
838 void immUniformColor3fv(const float rgb[3])
840 immUniformColor4f(rgb[0], rgb[1], rgb[2], 1.0f);
843 void immUniformColor3fvAlpha(const float rgb[3], float a)
845 immUniformColor4f(rgb[0], rgb[1], rgb[2], a);
848 /* TODO: v-- treat as sRGB? --v */
850 void immUniformColor3ub(uchar r, uchar g, uchar b)
852 const float scale = 1.0f / 255.0f;
853 immUniformColor4f(scale * r, scale * g, scale * b, 1.0f);
856 void immUniformColor4ub(uchar r, uchar g, uchar b, uchar a)
858 const float scale = 1.0f / 255.0f;
859 immUniformColor4f(scale * r, scale * g, scale * b, scale * a);
862 void immUniformColor3ubv(const uchar rgb[3])
864 immUniformColor3ub(rgb[0], rgb[1], rgb[2]);
867 void immUniformColor3ubvAlpha(const uchar rgb[3], uchar alpha)
869 immUniformColor4ub(rgb[0], rgb[1], rgb[2], alpha);
872 void immUniformColor4ubv(const uchar rgba[4])
874 immUniformColor4ub(rgba[0], rgba[1], rgba[2], rgba[3]);
877 void immUniformThemeColor(int color_id)
880 UI_GetThemeColor4fv(color_id, color);
881 immUniformColor4fv(color);
884 void immUniformThemeColor3(int color_id)
887 UI_GetThemeColor3fv(color_id, color);
888 immUniformColor3fv(color);
891 void immUniformThemeColorShade(int color_id, int offset)
894 UI_GetThemeColorShade4fv(color_id, offset, color);
895 immUniformColor4fv(color);
898 void immUniformThemeColorShadeAlpha(int color_id, int color_offset, int alpha_offset)
901 UI_GetThemeColorShadeAlpha4fv(color_id, color_offset, alpha_offset, color);
902 immUniformColor4fv(color);
905 void immUniformThemeColorBlendShade(int color_id1, int color_id2, float fac, int offset)
908 UI_GetThemeColorBlendShade4fv(color_id1, color_id2, fac, offset, color);
909 immUniformColor4fv(color);
912 void immUniformThemeColorBlend(int color_id1, int color_id2, float fac)
915 UI_GetThemeColorBlend3ubv(color_id1, color_id2, fac, color);
916 immUniformColor3ubv(color);
919 void immThemeColorShadeAlpha(int colorid, int coloffset, int alphaoffset)
922 UI_GetThemeColorShadeAlpha4ubv(colorid, coloffset, alphaoffset, col);
923 immUniformColor4ub(col[0], col[1], col[2], col[3]);