Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/gpu/intern/gpu_buffers.c')
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c163
1 files changed, 87 insertions, 76 deletions
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index 524c05fdc73..7d45640da63 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -1,4 +1,4 @@
-/**
+/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
@@ -38,8 +38,9 @@
#include "MEM_guardedalloc.h"
-#include "BLI_ghash.h"
#include "BLI_math.h"
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
#include "BLI_threads.h"
#include "DNA_meshdata_types.h"
@@ -58,13 +59,16 @@
#define MAX_GPU_ATTRIB_DATA 32
+/* material number is an 16-bit short and the range of short is from -16383 to 16383 (assume material number is non-negative) */
+#define MAX_MATERIALS 16384
+
/* -1 - undefined, 0 - vertex arrays, 1 - VBOs */
-int useVBOs = -1;
-GPUBufferPool *globalPool = 0;
-int GLStates = 0;
-GPUAttrib attribData[MAX_GPU_ATTRIB_DATA] = { { -1, 0, 0 } };
+static int useVBOs = -1;
+static GPUBufferPool *globalPool = 0;
+static int GLStates = 0;
+static GPUAttrib attribData[MAX_GPU_ATTRIB_DATA] = { { -1, 0, 0 } };
-GPUBufferPool *GPU_buffer_pool_new()
+GPUBufferPool *GPU_buffer_pool_new(void)
{
GPUBufferPool *pool;
@@ -88,7 +92,7 @@ GPUBufferPool *GPU_buffer_pool_new()
return pool;
}
-void GPU_buffer_pool_remove( int index, GPUBufferPool *pool )
+static void GPU_buffer_pool_remove( int index, GPUBufferPool *pool )
{
int i;
@@ -107,7 +111,7 @@ void GPU_buffer_pool_remove( int index, GPUBufferPool *pool )
pool->size--;
}
-void GPU_buffer_pool_delete_last( GPUBufferPool *pool )
+static void GPU_buffer_pool_delete_last( GPUBufferPool *pool )
{
int last;
@@ -241,7 +245,7 @@ void GPU_buffer_free( GPUBuffer *buffer, GPUBufferPool *pool )
if( pool == 0 )
pool = globalPool;
if( pool == 0 )
- globalPool = GPU_buffer_pool_new();
+ pool = globalPool = GPU_buffer_pool_new();
/* free the last used buffer in the queue if no more space, but only
if we are in the main thread. for e.g. rendering or baking it can
@@ -268,10 +272,9 @@ void GPU_buffer_free( GPUBuffer *buffer, GPUBufferPool *pool )
GPUDrawObject *GPU_drawobject_new( DerivedMesh *dm )
{
GPUDrawObject *object;
- MVert *mvert;
MFace *mface;
- int numverts[32768]; /* material number is an 16-bit short so there's at most 32768 materials */
- int redir[32768]; /* material number is an 16-bit short so there's at most 32768 materials */
+ int numverts[MAX_MATERIALS];
+ int redir[MAX_MATERIALS];
int *index;
int i;
int curmat, curverts, numfaces;
@@ -288,20 +291,19 @@ GPUDrawObject *GPU_drawobject_new( DerivedMesh *dm )
object->indices[i].next = 0;
}
/*object->legacy = 1;*/
- memset(numverts,0,sizeof(int)*32768);
+ memset(numverts,0,sizeof(int)*MAX_MATERIALS);
- mvert = dm->getVertArray(dm);
mface = dm->getTessFaceArray(dm);
numfaces= dm->getNumTessFaces(dm);
for( i=0; i < numfaces; i++ ) {
if( mface[i].v4 )
- numverts[mface[i].mat_nr+16383] += 6; /* split every quad into two triangles */
+ numverts[mface[i].mat_nr] += 6; /* split every quad into two triangles */
else
- numverts[mface[i].mat_nr+16383] += 3;
+ numverts[mface[i].mat_nr] += 3;
}
- for( i = 0; i < 32768; i++ ) {
+ for( i = 0; i < MAX_MATERIALS; i++ ) {
if( numverts[i] > 0 ) {
object->nmaterials++;
object->nelements += numverts[i];
@@ -311,9 +313,9 @@ GPUDrawObject *GPU_drawobject_new( DerivedMesh *dm )
index = MEM_mallocN(sizeof(int)*object->nmaterials,"GPU_drawobject_new_index");
curmat = curverts = 0;
- for( i = 0; i < 32768; i++ ) {
+ for( i = 0; i < MAX_MATERIALS; i++ ) {
if( numverts[i] > 0 ) {
- object->materials[curmat].mat_nr = i-16383;
+ object->materials[curmat].mat_nr = i;
object->materials[curmat].start = curverts;
index[curmat] = curverts/3;
object->materials[curmat].end = curverts+numverts[i];
@@ -323,7 +325,7 @@ GPUDrawObject *GPU_drawobject_new( DerivedMesh *dm )
}
object->faceRemap = MEM_mallocN(sizeof(int)*object->nelements/3,"GPU_drawobject_new_faceRemap");
for( i = 0; i < object->nmaterials; i++ ) {
- redir[object->materials[i].mat_nr+16383] = i; /* material number -> material index */
+ redir[object->materials[i].mat_nr] = i; /* material number -> material index */
}
object->indexMem = MEM_callocN(sizeof(IndexLink)*object->nelements,"GPU_drawobject_new_indexMem");
@@ -341,7 +343,7 @@ GPUDrawObject *GPU_drawobject_new( DerivedMesh *dm )
}
for( i=0; i < numfaces; i++ ) {
- int curInd = index[redir[mface[i].mat_nr+16383]];
+ int curInd = index[redir[mface[i].mat_nr]];
object->faceRemap[curInd] = i;
ADDLINK( mface[i].v1, curInd*3 );
ADDLINK( mface[i].v2, curInd*3+1 );
@@ -352,10 +354,10 @@ GPUDrawObject *GPU_drawobject_new( DerivedMesh *dm )
ADDLINK( mface[i].v4, curInd*3+4 );
ADDLINK( mface[i].v1, curInd*3+5 );
- index[redir[mface[i].mat_nr+16383]]+=2;
+ index[redir[mface[i].mat_nr]]+=2;
}
else {
- index[redir[mface[i].mat_nr+16383]]++;
+ index[redir[mface[i].mat_nr]]++;
}
}
@@ -491,7 +493,11 @@ void *GPU_build_mesh_buffers(GHash *map, MVert *mvert, MFace *mface,
if(tri_data) {
for(i = 0; i < totface; ++i) {
MFace *f = mface + face_indices[i];
- int v[3] = {f->v1, f->v2, f->v3};
+ int v[3];
+
+ v[0]= f->v1;
+ v[1]= f->v2;
+ v[2]= f->v3;
for(j = 0; j < (f->v4 ? 2 : 1); ++j) {
for(k = 0; k < 3; ++k) {
@@ -592,8 +598,8 @@ void GPU_update_grid_buffers(void *buffers_v, DMGridData **grids,
//printf("node updated %p\n", buffers_v);
}
-void *GPU_build_grid_buffers(DMGridData **grids,
- int *grid_indices, int totgrid, int gridsize)
+void *GPU_build_grid_buffers(DMGridData **UNUSED(grids), int *UNUSED(grid_indices),
+ int totgrid, int gridsize)
{
GPU_Buffers *buffers;
int i, j, k, totquad, offset= 0;
@@ -770,11 +776,11 @@ void GPU_free_buffers(void *buffers_v)
}
}
-GPUBuffer *GPU_buffer_setup( DerivedMesh *dm, GPUDrawObject *object, int size, GLenum target, void *user, void (*copy_f)(DerivedMesh *, float *, int *, int *, void *) )
+static GPUBuffer *GPU_buffer_setup( DerivedMesh *dm, GPUDrawObject *object, int vector_size, int size, GLenum target, void *user, void (*copy_f)(DerivedMesh *, float *, int *, int *, void *) )
{
GPUBuffer *buffer;
float *varray;
- int redir[32768];
+ int redir[MAX_MATERIALS];
int *index;
int i;
int success;
@@ -795,8 +801,8 @@ GPUBuffer *GPU_buffer_setup( DerivedMesh *dm, GPUDrawObject *object, int size, G
index = MEM_mallocN(sizeof(int)*object->nmaterials,"GPU_buffer_setup");
for( i = 0; i < object->nmaterials; i++ ) {
- index[i] = object->materials[i].start*3;
- redir[object->materials[i].mat_nr+16383] = i;
+ index[i] = object->materials[i].start*vector_size;
+ redir[object->materials[i].mat_nr] = i;
}
if( useVBOs ) {
@@ -852,7 +858,7 @@ GPUBuffer *GPU_buffer_setup( DerivedMesh *dm, GPUDrawObject *object, int size, G
return buffer;
}
-void GPU_buffer_copy_vertex( DerivedMesh *dm, float *varray, int *index, int *redir, void *user )
+static void GPU_buffer_copy_vertex(DerivedMesh *dm, float *varray, int *index, int *redir, void *UNUSED(user))
{
int start;
int i, j, numfaces;
@@ -867,11 +873,11 @@ void GPU_buffer_copy_vertex( DerivedMesh *dm, float *varray, int *index, int *re
numfaces= dm->getNumTessFaces(dm);
for( i=0; i < numfaces; i++ ) {
- start = index[redir[mface[i].mat_nr+16383]];
+ start = index[redir[mface[i].mat_nr]];
if( mface[i].v4 )
- index[redir[mface[i].mat_nr+16383]] += 18;
+ index[redir[mface[i].mat_nr]] += 18;
else
- index[redir[mface[i].mat_nr+16383]] += 9;
+ index[redir[mface[i].mat_nr]] += 9;
/* v1 v2 v3 */
VECCOPY(&varray[start],mvert[mface[i].v1].co);
@@ -894,14 +900,14 @@ void GPU_buffer_copy_vertex( DerivedMesh *dm, float *varray, int *index, int *re
}
}
-GPUBuffer *GPU_buffer_vertex( DerivedMesh *dm )
+static GPUBuffer *GPU_buffer_vertex( DerivedMesh *dm )
{
DEBUG_VBO("GPU_buffer_vertex\n");
- return GPU_buffer_setup( dm, dm->drawObject, sizeof(float)*3*(dm->drawObject->nelements+dm->drawObject->nlooseverts), GL_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_vertex);
+ return GPU_buffer_setup( dm, dm->drawObject, 3, sizeof(float)*3*(dm->drawObject->nelements+dm->drawObject->nlooseverts), GL_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_vertex);
}
-void GPU_buffer_copy_normal( DerivedMesh *dm, float *varray, int *index, int *redir, void *user )
+static void GPU_buffer_copy_normal(DerivedMesh *dm, float *varray, int *index, int *redir, void *UNUSED(user))
{
int i, numfaces;
int start;
@@ -915,14 +921,16 @@ void GPU_buffer_copy_normal( DerivedMesh *dm, float *varray, int *index, int *re
numfaces= dm->getNumTessFaces(dm);
for( i=0; i < numfaces; i++ ) {
- start = index[redir[mface[i].mat_nr+16383]];
+ const int smoothnormal = (mface[i].flag & ME_SMOOTH);
+
+ start = index[redir[mface[i].mat_nr]];
if( mface[i].v4 )
- index[redir[mface[i].mat_nr+16383]] += 18;
+ index[redir[mface[i].mat_nr]] += 18;
else
- index[redir[mface[i].mat_nr+16383]] += 9;
+ index[redir[mface[i].mat_nr]] += 9;
/* v1 v2 v3 */
- if( mface[i].flag & ME_SMOOTH ) {
+ if(smoothnormal) {
VECCOPY(&varray[start],mvert[mface[i].v1].no);
VECCOPY(&varray[start+3],mvert[mface[i].v2].no);
VECCOPY(&varray[start+6],mvert[mface[i].v3].no);
@@ -944,7 +952,7 @@ void GPU_buffer_copy_normal( DerivedMesh *dm, float *varray, int *index, int *re
if( mface[i].v4 ) {
/* v3 v4 v1 */
- if( mface[i].flag & ME_SMOOTH ) {
+ if(smoothnormal) {
VECCOPY(&varray[start+9],mvert[mface[i].v3].no);
VECCOPY(&varray[start+12],mvert[mface[i].v4].no);
VECCOPY(&varray[start+15],mvert[mface[i].v1].no);
@@ -958,14 +966,14 @@ void GPU_buffer_copy_normal( DerivedMesh *dm, float *varray, int *index, int *re
}
}
-GPUBuffer *GPU_buffer_normal( DerivedMesh *dm )
+static GPUBuffer *GPU_buffer_normal( DerivedMesh *dm )
{
DEBUG_VBO("GPU_buffer_normal\n");
- return GPU_buffer_setup( dm, dm->drawObject, sizeof(float)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_normal);
+ return GPU_buffer_setup( dm, dm->drawObject, 3, sizeof(float)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_normal);
}
-void GPU_buffer_copy_uv( DerivedMesh *dm, float *varray, int *index, int *redir, void *user )
+static void GPU_buffer_copy_uv(DerivedMesh *dm, float *varray, int *index, int *redir, void *UNUSED(user))
{
int start;
int i, numfaces;
@@ -985,11 +993,11 @@ void GPU_buffer_copy_uv( DerivedMesh *dm, float *varray, int *index, int *redir,
numfaces= dm->getNumTessFaces(dm);
for( i=0; i < numfaces; i++ ) {
- start = index[redir[mface[i].mat_nr+16383]];
+ start = index[redir[mface[i].mat_nr]];
if( mface[i].v4 )
- index[redir[mface[i].mat_nr+16383]] += 12;
+ index[redir[mface[i].mat_nr]] += 12;
else
- index[redir[mface[i].mat_nr+16383]] += 6;
+ index[redir[mface[i].mat_nr]] += 6;
/* v1 v2 v3 */
VECCOPY2D(&varray[start],mtface[i].uv[0]);
@@ -1005,16 +1013,16 @@ void GPU_buffer_copy_uv( DerivedMesh *dm, float *varray, int *index, int *redir,
}
}
-GPUBuffer *GPU_buffer_uv( DerivedMesh *dm )
+static GPUBuffer *GPU_buffer_uv( DerivedMesh *dm )
{
DEBUG_VBO("GPU_buffer_uv\n");
- if( DM_get_face_data_layer(dm, CD_MTFACE) != 0 ) /* was sizeof(float)*2 but caused buffer overrun */
- return GPU_buffer_setup( dm, dm->drawObject, sizeof(float)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_uv);
+ if( DM_get_face_data_layer(dm, CD_MTFACE) != 0 )
+ return GPU_buffer_setup( dm, dm->drawObject, 2, sizeof(float)*2*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_uv);
else
return 0;
}
-void GPU_buffer_copy_color3( DerivedMesh *dm, float *varray_, int *index, int *redir, void *user )
+static void GPU_buffer_copy_color3( DerivedMesh *dm, float *varray_, int *index, int *redir, void *user )
{
int i, numfaces;
unsigned char *varray = (unsigned char *)varray_;
@@ -1025,11 +1033,11 @@ void GPU_buffer_copy_color3( DerivedMesh *dm, float *varray_, int *index, int *r
numfaces= dm->getNumTessFaces(dm);
for( i=0; i < numfaces; i++ ) {
- int start = index[redir[mface[i].mat_nr+16383]];
+ int start = index[redir[mface[i].mat_nr]];
if( mface[i].v4 )
- index[redir[mface[i].mat_nr+16383]] += 18;
+ index[redir[mface[i].mat_nr]] += 18;
else
- index[redir[mface[i].mat_nr+16383]] += 9;
+ index[redir[mface[i].mat_nr]] += 9;
/* v1 v2 v3 */
VECCOPY(&varray[start],&mcol[i*12]);
@@ -1044,7 +1052,7 @@ void GPU_buffer_copy_color3( DerivedMesh *dm, float *varray_, int *index, int *r
}
}
-void GPU_buffer_copy_color4( DerivedMesh *dm, float *varray_, int *index, int *redir, void *user )
+static void GPU_buffer_copy_color4( DerivedMesh *dm, float *varray_, int *index, int *redir, void *user )
{
int i, numfaces;
unsigned char *varray = (unsigned char *)varray_;
@@ -1055,11 +1063,11 @@ void GPU_buffer_copy_color4( DerivedMesh *dm, float *varray_, int *index, int *r
numfaces= dm->getNumTessFaces(dm);
for( i=0; i < numfaces; i++ ) {
- int start = index[redir[mface[i].mat_nr+16383]];
+ int start = index[redir[mface[i].mat_nr]];
if( mface[i].v4 )
- index[redir[mface[i].mat_nr+16383]] += 18;
+ index[redir[mface[i].mat_nr]] += 18;
else
- index[redir[mface[i].mat_nr+16383]] += 9;
+ index[redir[mface[i].mat_nr]] += 9;
/* v1 v2 v3 */
VECCOPY(&varray[start],&mcol[i*16]);
@@ -1074,7 +1082,7 @@ void GPU_buffer_copy_color4( DerivedMesh *dm, float *varray_, int *index, int *r
}
}
-GPUBuffer *GPU_buffer_color( DerivedMesh *dm )
+static GPUBuffer *GPU_buffer_color( DerivedMesh *dm )
{
unsigned char *colors;
int i, numfaces;
@@ -1101,24 +1109,22 @@ GPUBuffer *GPU_buffer_color( DerivedMesh *dm )
colors[i*3+2] = mcol[i].r;
}
- result = GPU_buffer_setup( dm, dm->drawObject, sizeof(char)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, colors, GPU_buffer_copy_color3 );
+ result = GPU_buffer_setup( dm, dm->drawObject, 3, sizeof(char)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, colors, GPU_buffer_copy_color3 );
MEM_freeN(colors);
return result;
}
-void GPU_buffer_copy_edge( DerivedMesh *dm, float *varray, int *index, int *redir, void *user )
+static void GPU_buffer_copy_edge(DerivedMesh *dm, float *varray, int *UNUSED(index), int *UNUSED(redir), void *UNUSED(user))
{
int i;
- MVert *mvert;
MEdge *medge;
unsigned int *varray_ = (unsigned int *)varray;
int numedges;
DEBUG_VBO("GPU_buffer_copy_edge\n");
- mvert = dm->getVertArray(dm);
medge = dm->getEdgeArray(dm);
numedges= dm->getNumEdges(dm);
@@ -1128,14 +1134,14 @@ void GPU_buffer_copy_edge( DerivedMesh *dm, float *varray, int *index, int *redi
}
}
-GPUBuffer *GPU_buffer_edge( DerivedMesh *dm )
+static GPUBuffer *GPU_buffer_edge( DerivedMesh *dm )
{
DEBUG_VBO("GPU_buffer_edge\n");
- return GPU_buffer_setup( dm, dm->drawObject, sizeof(int)*2*dm->drawObject->nedges, GL_ELEMENT_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_edge);
+ return GPU_buffer_setup( dm, dm->drawObject, 2, sizeof(int)*2*dm->drawObject->nedges, GL_ELEMENT_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_edge);
}
-void GPU_buffer_copy_uvedge( DerivedMesh *dm, float *varray, int *index, int *redir, void *user )
+static void GPU_buffer_copy_uvedge(DerivedMesh *dm, float *varray, int *UNUSED(index), int *UNUSED(redir), void *UNUSED(user))
{
MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE);
int i, j=0;
@@ -1172,11 +1178,16 @@ void GPU_buffer_copy_uvedge( DerivedMesh *dm, float *varray, int *index, int *re
}
}
-GPUBuffer *GPU_buffer_uvedge( DerivedMesh *dm )
+static GPUBuffer *GPU_buffer_uvedge( DerivedMesh *dm )
{
DEBUG_VBO("GPU_buffer_uvedge\n");
-
- return GPU_buffer_setup( dm, dm->drawObject, sizeof(float)*2*(dm->drawObject->nelements/3)*2, GL_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_uvedge);
+ /* logic here:
+ * ...each face gets 3 'nelements'
+ * ...3 edges per triangle
+ * ...each edge has its own, non-shared coords.
+ * so each tri corner needs minimum of 4 floats, quads used less so here we can over allocate and assume all tris.
+ * */
+ return GPU_buffer_setup( dm, dm->drawObject, 4, 4 * sizeof(float) * dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_uvedge);
}
@@ -1487,7 +1498,7 @@ void GPU_interleaved_attrib_setup( GPUBuffer *buffer, GPUAttrib data[], int numd
glBindBufferARB( GL_ARRAY_BUFFER_ARB, buffer->id );
for( i = 0; i < numdata; i++ ) {
glEnableVertexAttribArrayARB( data[i].index );
- glVertexAttribPointerARB( data[i].index, data[i].size, data[i].type, GL_TRUE, elementsize, (void *)offset );
+ glVertexAttribPointerARB( data[i].index, data[i].size, data[i].type, GL_FALSE, elementsize, (void *)offset );
offset += data[i].size*GPU_typesize(data[i].type);
attribData[i].index = data[i].index;
@@ -1499,14 +1510,14 @@ void GPU_interleaved_attrib_setup( GPUBuffer *buffer, GPUAttrib data[], int numd
else {
for( i = 0; i < numdata; i++ ) {
glEnableVertexAttribArrayARB( data[i].index );
- glVertexAttribPointerARB( data[i].index, data[i].size, data[i].type, GL_TRUE, elementsize, (char *)buffer->pointer + offset );
+ glVertexAttribPointerARB( data[i].index, data[i].size, data[i].type, GL_FALSE, elementsize, (char *)buffer->pointer + offset );
offset += data[i].size*GPU_typesize(data[i].type);
}
}
}
-void GPU_buffer_unbind()
+void GPU_buffer_unbind(void)
{
int i;
DEBUG_VBO("GPU_buffer_unbind\n");
@@ -1545,14 +1556,14 @@ void GPU_color3_upload( DerivedMesh *dm, unsigned char *data )
if( dm->drawObject == 0 )
dm->drawObject = GPU_drawobject_new(dm);
GPU_buffer_free(dm->drawObject->colors,globalPool);
- dm->drawObject->colors = GPU_buffer_setup( dm, dm->drawObject, sizeof(char)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, data, GPU_buffer_copy_color3 );
+ dm->drawObject->colors = GPU_buffer_setup( dm, dm->drawObject, 3, sizeof(char)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, data, GPU_buffer_copy_color3 );
}
void GPU_color4_upload( DerivedMesh *dm, unsigned char *data )
{
if( dm->drawObject == 0 )
dm->drawObject = GPU_drawobject_new(dm);
GPU_buffer_free(dm->drawObject->colors,globalPool);
- dm->drawObject->colors = GPU_buffer_setup( dm, dm->drawObject, sizeof(char)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, data, GPU_buffer_copy_color4 );
+ dm->drawObject->colors = GPU_buffer_setup( dm, dm->drawObject, 3, sizeof(char)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, data, GPU_buffer_copy_color4 );
}
void GPU_color_switch( int mode )