File: SCREENDrawDots.c

package info (click to toggle)
psychtoolbox-3 3.0.19.14.dfsg1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 86,796 kB
  • sloc: ansic: 176,245; cpp: 20,103; objc: 5,393; sh: 2,753; python: 1,397; php: 384; makefile: 193; java: 113
file content (459 lines) | stat: -rw-r--r-- 23,886 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
/*
        SCREENDrawDots.c

        AUTHORS:

            kas@princeton.edu               kas     Keith Schneider
            fcalabro@bu.edu                 fjc     Finnegan Calabro
            mario.kleiner.de@gmail.com      mk      Mario Kleiner

        PLATFORMS:

            All.

        HISTORY:

            mm/dd/yy

            12/13/04        kas     Created
            12/17/04        fjc     added antialiased points
            12/17/04        kas     added dot_type flag
            1/11/04         awi     Merged into pychtoolbox.org distribution.
            1/01/05         mk      Performance optimizations and small bug-fixes
                                    - Fixes some minor bugs (or possible bugs, they would only
                                    trigger in some usage cases): GL-Calls were missing to undo
                                    parameter changes like glPointSize,
                                    glEnable(GL_POINT_SMOOTH). This can affect later
                                    invocations of DrawDots, e.g., Call DrawDots with point
                                    smoothing on --> Smoothing gets enabled, after that it
                                    would not be possible to disable point smoothing again -->
                                    any following DrawDots call would always render smooth
                                    points, regardless of setting.

                                    - Uses an optimized way of drawing the dots: Instead of
                                    looping over the 2-column vector of dots in a for-loop and
                                    submitting each Point via glVertex2d(), it now *requires* a
                                    2-row vector of dots as input and then renders all dots
                                    with one function call to glDrawArrays(). This is the most
                                    efficient way of passing a huge number of primitives
                                    (Points, rectangles, ...) to the OpenGL-System, avoiding
                                    for-loop and function call overhead and allowing possible
                                    optimizations by the graphics driver.
            1/12/05         awi     Merged mk's improvements into psychtoolbox.org distribution.
            1/30/05         mk      Bug-fixes: Adding PsychMallocTemp()'s and a few checks to avoid memory corruption
                                    crashes.
            2/25/05         awi     Added call to PsychUpdateAlphaBlendingFactorLazily().  Drawing now obeys settings by Screen('BlendFunction').
            3/22/05         mk      Added possibility to spec vectors with individual color and size spec per dot.
            4/29/05         mk      Bugfix for color vectors: They should also take values in range 0-255 instead of 0.0-1.0.
            11/14/06        mk      We now also accept color vectors in uint8 format and pass them directly for higher efficiency.
*/

#include "Screen.h"

static char PointSmoothFragmentShaderSrc[] =
"\n"
"uniform int drawRoundDots;\n"
"varying vec4 unclampedFragColor;\n"
"varying float pointSize;\n"
"\n"
"void main()\n"
"{\n"
"    /* Non-round, aliased square dots requested? */\n"
"    if (drawRoundDots == 0) {\n"
"       /* Yes. Simply passthrough unclamped color and be done: */\n"
"       gl_FragColor = unclampedFragColor;\n"
"       return;\n"
"    }\n"
"\n"
"    /* Passthrough RGB color values: */\n"
"    gl_FragColor.rgb = unclampedFragColor.rgb;\n"
"\n"
"    /* Adapt alpha value dependent on relative radius of the fragment within a dot:   */\n"
"    /* This for point smoothing on GPU's that don't support this themselves.          */\n"
"    /* Points on the border of the dot, at [radius - 0.5 ; radius + 0.5] pixels, will */\n"
"    /* get their alpha value reduced from 1.0 * alpha to 0.0, so they completely      */\n"
"    /* disappear over a distance of 1 pixel distance unit. The - 1.0 subtraction      */\n"
"    /* in clamp() accounts for the fact that pointSize is 2.0 pixels larger than user */\n"
"    /* code requested. This 1 pixel padding around true size avoids cutoff artifacts. */\n"
"    float r = length(gl_TexCoord[1].st - vec2(0.5, 0.5)) * pointSize;\n"
"    r = 1.0 - clamp(r - (0.5 * pointSize - 1.0 - 0.5), 0.0, 1.0);\n"
"    gl_FragColor.a = unclampedFragColor.a * r;\n"
"    if (r <= 0.0)\n"
"        discard;\n"
"}\n\0";

char PointSmoothVertexShaderSrc[] =
"/* Vertex shader: Emulates fixed function pipeline, but in HDR color mode passes    */ \n"
"/* gl_MultiTexCoord0 as varying unclampedFragColor to circumvent vertex color       */ \n"
"/* clamping on gfx-hardware / OS combos that don't support unclamped operation:     */ \n"
"/* PTBs color handling is expected to pass the vertex color in gl_MultiTexCoord0    */ \n"
"/* for unclamped drawing for this reason in unclamped color mode. gl_MultiTexCoord2 */ \n"
"/* delivers individual point size (diameter) information for each point.            */ \n"
"\n"
"uniform int useUnclampedFragColor;\n"
"uniform int drawRoundDots;\n"
"varying float pointSize;\n"
"varying vec4 unclampedFragColor;\n"
"\n"
"void main()\n"
"{\n"
"    if (useUnclampedFragColor > 0) {\n"
"       /* Simply copy input unclamped RGBA pixel color into output varying color: */\n"
"       unclampedFragColor = gl_MultiTexCoord0;\n"
"    }\n"
"    else {\n"
"       /* Simply copy regular RGBA pixel color into output varying color: */\n"
"       unclampedFragColor = gl_Color;\n"
"    }\n"
"\n"
"    /* Output position is the same as fixed function pipeline: */\n"
"    gl_Position = ftransform();\n"
"\n"
"    /* Point size comes via texture coordinate set 2: Make diameter 2 pixels bigger    */\n"
"    /* than requested, to have some 1 pixel security margin around the dot, to avoid   */\n"
"    /* cutoff artifacts for the rendered point-sprite quad. Compensate in frag-shader. */\n"
"    /* Only apply the margin to round dots. */\n"
"    float margin = drawRoundDots > 0 ? 2.0 : 0.0;\n"
"    pointSize = gl_MultiTexCoord2[0] + margin;\n"
"    gl_PointSize = pointSize;\n"
"}\n\0";

// If you change the useString then also change the corresponding synopsis string in ScreenSynopsis.c
static char useString[] = "[minSmoothPointSize, maxSmoothPointSize, minAliasedPointSize, maxAliasedPointSize] = Screen('DrawDots', windowPtr, xy [,size] [,color] [,center] [,dot_type][, lenient]);";
//                          1                   2                   3                    4                                         1          2    3       4        5         6           7
static char synopsisString[] =
"Quickly draw an array of dots.  "
"\"xy\" is a two-row vector containing the x and y coordinates of the dot centers, "
"relative to \"center\" (default center is [0 0]).\n"
"\"size\" is the diameter of each dot in pixels (default is 1). "
"Instead of a common size for all dots you can also provide a "
"vector which defines a different dot size for each dot. Different graphics cards do "
"have different limits on the maximum size of dots, 10 or 63 are typical limits.\n"
"\"color\" is the the clut index (scalar or [r g b a] vector) "
"that you want to poke into each dot pixel (default is black).  "
"Instead of a single \"color\" you can also provide a 3 or 4 row vector,"
"which specifies an individual RGB or RGBA color for each corresponding point.\n"
"\"dot_type\" is a flag that determines what type of dot is drawn: "
"0 (default) and 4 draw square dots, whereas 1, 2 and 3 draw round dots (circles) with anti-aliasing: "
"1 favors performance, 2 tries to use high-quality anti-aliasing, if supported by your hardware. "
"3 Uses a builtin shader-based implementation. "
"dot_type 1 and 2 may not be supported by all graphics cards and drivers. On some systems "
"Screen() will then automatically switch to dot_type 3 - our own implementation - in such a case. "
"If you use round dot_type 1, 2 or 3 you'll also need to set a proper blending mode with the "
"Screen('BlendFunction') command, e.g., GL_SRC_ALPHA + GL_ONE_MINUS_SRC_ALPHA. A dot_type of 4 will "
"draw square dots like dot_type 0, but may be faster when drawing lots of dots of different sizes by "
"use of an efficient shader based path.\n"
"\"lenient\" If set to 1, will not check the sizes of dots for validity, so you can try requesting "
"sizes bigger than what the hardware claims to support.\n\n"
"The optional return arguments [minSmoothPointSize, maxSmoothPointSize, minAliasedPointSize, maxAliasedPointSize] "
"allow you to query the minimum and maximum allowed 'size' for smooth anti-aliased dots (dot_type 1,2,3) and for "
"non anti-aliased square dots (dot_type 0 and 4). Calling [...] = Screen('DrawDots', windowPtr) will only query "
"these point size limits without drawing any dots.\n";

static char seeAlsoString[] = "BlendFunction";

PsychError SCREENDrawDots(void)
{
    PsychWindowRecordType                   *windowRecord, *parentWindowRecord;
    int                                     m,n,p,mc,nc,idot_type;
    int                                     i, nrpoints, nrsize;
    psych_bool                              isArgThere, usecolorvector;
    double                                  *xy, *size, *center, *dot_type, *colors;
    float                                   *sizef;
    unsigned char                           *bytecolors;
    GLfloat                                 pointsizerange[2];
    psych_bool                              lenient = FALSE;
    psych_bool                              usePointSizeArray = FALSE;
    static psych_bool                       nocando = FALSE;
    int                                     oldverbosity;

    // All sub functions should have these two lines
    PsychPushHelp(useString, synopsisString,seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};

    // Check for superfluous arguments
    PsychErrorExit(PsychCapNumInputArgs(7));   //The maximum number of inputs
    PsychErrorExit(PsychCapNumOutputArgs(4));  //The maximum number of outputs

    // Get the window record from the window record argument and get info from the window record
    PsychAllocInWindowRecordArg(1, kPsychArgRequired, &windowRecord);

    // Get dot_type argument, if any, as it is already needed for a pure point size range query below:
    isArgThere = PsychIsArgPresent(PsychArgIn, 6);
    if(!isArgThere){
        idot_type = 0;
    } else {
        PsychAllocInDoubleMatArg(6, TRUE, &m, &n, &p, &dot_type);
        if(p != 1 || n != 1 || m != 1 || (dot_type[0] < 0 || dot_type[0] > 4))
            PsychErrorExitMsg(PsychError_user, "dot_type must be 0, 1, 2, 3 or 4");
        idot_type = (int) dot_type[0];
    }

    // Query for supported point size range?
    if (PsychGetNumOutputArgs() > 0) {
        PsychSetDrawingTarget(windowRecord);

        // Always query and return aliased range:
        glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, (GLfloat*) &pointsizerange);
        PsychCopyOutDoubleArg(3, FALSE, (double) pointsizerange[0]);
        PsychCopyOutDoubleArg(4, FALSE, (double) pointsizerange[1]);

        // If driver supports smooth points and usercode doesn't specify a dot type (idot_type 0)
        // or does not request shader + point-sprite based drawing then return smooth point
        // size range as "smooth point size range" - query and assign it. Otherwise, ie., code
        // explicitely wants to use a shader (idot_type >= 3) or has to use one, we will use
        // point-sprites and that means the GL_ALIASED_POINT_SIZE_RANGE limits apply also to
        // our shader based smooth dots, so return those:
        if ((windowRecord->gfxcaps & kPsychGfxCapSmoothPrimitives) && (idot_type < 3))
            glGetFloatv(GL_POINT_SIZE_RANGE, (GLfloat*) &pointsizerange);

        // Whatever the final choice for smooth dots is, return its limits:
        PsychCopyOutDoubleArg(1, FALSE, (double) pointsizerange[0]);
        PsychCopyOutDoubleArg(2, FALSE, (double) pointsizerange[1]);

        // If this was only a query then we are done:
        if (PsychGetNumInputArgs() < 2)
            return(PsychError_none);
    }

    // Query, allocate and copy in all vectors...
    nrpoints = 2;
    nrsize = 0;
    colors = NULL;
    bytecolors = NULL;

    PsychPrepareRenderBatch(windowRecord, 2, &nrpoints, &xy, 4, &nc, &mc, &colors, &bytecolors, 3, &nrsize, &size, (GL_FLOAT == PsychGLFloatType(windowRecord)));
    usecolorvector = (nc>1) ? TRUE:FALSE;

    // Assign sizef as float-type array of sizes, if float mode active, NULL otherwise:
    sizef = (GL_FLOAT == PsychGLFloatType(windowRecord)) ? (float*) size : NULL;

    // Get center argument
    isArgThere = PsychIsArgPresent(PsychArgIn, 5);
    if(!isArgThere){
        center = (double *) PsychMallocTemp(2 * sizeof(double));
        center[0] = 0;
        center[1] = 0;
    } else {
        PsychAllocInDoubleMatArg(5, TRUE, &m, &n, &p, &center);
        if(p!=1 || n!=2 || m!=1) PsychErrorExitMsg(PsychError_user, "center must be a 1-by-2 vector");
    }

    // Turn on antialiasing to draw circles? Or idot_type 4 for shader based square dots?
    if (idot_type) {
        // Smooth point rendering supported by gfx-driver and hardware? And user does not request our own stuff?
        if ((idot_type == 3) || (idot_type == 4) || !(windowRecord->gfxcaps & kPsychGfxCapSmoothPrimitives)) {
            // No. Need to roll our own shader + point sprite solution.
            if (!windowRecord->smoothPointShader && !nocando) {
                parentWindowRecord = PsychGetParentWindow(windowRecord);
                if (!parentWindowRecord->smoothPointShader) {
                    // Build and assign shader to parent window, but allow this to silently fail:
                    oldverbosity = PsychPrefStateGet_Verbosity();
                    PsychPrefStateSet_Verbosity(0);
                    parentWindowRecord->smoothPointShader = PsychCreateGLSLProgram(PointSmoothFragmentShaderSrc, PointSmoothVertexShaderSrc, NULL);
                    PsychPrefStateSet_Verbosity(oldverbosity);
                }

                if (parentWindowRecord->smoothPointShader) {
                    // Got one compiled - assign it for use:
                    windowRecord->smoothPointShader = parentWindowRecord->smoothPointShader;
                }
                else {
                    // Failed. Record this failure so we can avoid retrying at next DrawDots invocation:
                    nocando = TRUE;
                }
            }

            if (windowRecord->smoothPointShader) {
                // Activate point smooth shader, and point sprite operation on texunit 1 for coordinates on set 1:
                PsychSetShader(windowRecord, windowRecord->smoothPointShader);
                glActiveTexture(GL_TEXTURE1);
                glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE);
                glActiveTexture(GL_TEXTURE0);
                glEnable(GL_POINT_SPRITE);

                // Tell shader from where to get its color information: Unclamped high precision colors from texture coordinate set 0, or regular colors from vertex color attribute?
                glUniform1i(glGetUniformLocation(windowRecord->smoothPointShader, "useUnclampedFragColor"), (windowRecord->defaultDrawShader) ? 1 : 0);

                // Tell shader if it should shade smooth round dots, or square dots:
                glUniform1i(glGetUniformLocation(windowRecord->smoothPointShader, "drawRoundDots"), (idot_type != 4) ? 1 : 0);

                // Tell shader about current point size in pointSize uniform:
                glEnable(GL_PROGRAM_POINT_SIZE);
                usePointSizeArray = TRUE;
            }
            else if (idot_type != 4) {
                // Game over for round dot drawing:
                PsychErrorExitMsg(PsychError_user, "Point smoothing unsupported on your system and our shader based implementation failed as well in Screen('DrawDots').");
            }
            else {
                // Type 4 requested but unsupported. Fallback to type 0, which is the same, just slower:
                idot_type = 0;
            }

            // Request square dots, without anti-aliasing: Better compatibility with
            // shader + point sprite operation, and needed for idot_type 0 fallback.
            glDisable(GL_POINT_SMOOTH);
            glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, (GLfloat*) &pointsizerange);
        }
        else {
            // User wants hw anti-aliased round smooth dots (idot_type = 1 or 2) and
            // hardware + driver support this. Request smooth points from hardware:
            glEnable(GL_POINT_SMOOTH);
            glGetFloatv(GL_POINT_SIZE_RANGE, (GLfloat*) &pointsizerange);

            // A dot type of 2 requests highest quality point smoothing:
            glHint(GL_POINT_SMOOTH_HINT, (idot_type > 1) ? GL_NICEST : GL_DONT_CARE);
        }
    }
    else {
        glDisable(GL_POINT_SMOOTH);
        glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, (GLfloat*) &pointsizerange);
    }

    // Does ES-GPU only support a fixed point diameter of 1 pixel?
    if ((pointsizerange[1] <= 1) && PsychIsGLES(windowRecord)) {
        // Yes. Not much point bailing on this, as it should be easily visible
        // during testing of a studies code on a OpenGL-ES device.
        lenient = TRUE;
    }

    // Accept optional 'lenient' flag, if provided:
    PsychCopyInFlagArg(7, FALSE, &lenient);

    // Set size of a single dot:
    if (!lenient && ((sizef && (sizef[0] > pointsizerange[1] || sizef[0] < pointsizerange[0])) ||
        (!sizef && (size[0] > pointsizerange[1] || size[0] < pointsizerange[0])))) {
        printf("PTB-ERROR: You requested a point size of %f units, which is not in the range (%f to %f) supported by your graphics hardware.\n",
                (sizef) ? sizef[0] : size[0], pointsizerange[0], pointsizerange[1]);
        PsychErrorExitMsg(PsychError_user, "Unsupported point size requested in Screen('DrawDots').");
    }

    // Setup initial common point size for all points:
    if (!usePointSizeArray) glPointSize((sizef) ? sizef[0] : (float) size[0]);
    if (usePointSizeArray) glMultiTexCoord1f(GL_TEXTURE2, (sizef) ? sizef[0] : (float) size[0]);

    // Setup modelview matrix to perform translation by 'center':
    glMatrixMode(GL_MODELVIEW);

    // Make a backup copy of the matrix:
    glPushMatrix();

    // Apply a global translation of (center(x,y)) pixels to all following points:
    glTranslatef((float) center[0], (float) center[1], 0);

    // Render the array of 2D-Points - Efficient version:
    // This command sequence allows fast processing of whole arrays
    // of vertices (or points, in this case). It saves the call overhead
    // associated with the original implementation below and is potentially
    // optimized in specific OpenGL implementations.

    // Pass a pointer to the start of the point-coordinate array:
    glVertexPointer(2, PSYCHGLFLOAT, 0, &xy[0]);

    // Enable fast rendering of arrays:
    glEnableClientState(GL_VERTEX_ARRAY);

    if (usecolorvector) {
        PsychSetupVertexColorArrays(windowRecord, TRUE, mc, colors, bytecolors);
    }

    // Render all n points, starting at point 0, render them as POINTS:
    if ((nrsize == 1) || usePointSizeArray) {
        // Only one common size provided, or efficient shader based
        // path in use. We can use the fast path of only submitting
        // one glDrawArrays call to draw all GL_POINTS. For a single
        // common size, no further setup is needed.
        if (nrsize > 1) {
            // Individual size for each dot provided. Setup texture unit 2
            // with a 1D texcoord array that stores per point size info in
            // texture coordinate set 2. But first validate point sizes:
            for (i = 0; i < nrpoints; i++) {
                if (!lenient && ((sizef && (sizef[i] > pointsizerange[1] || sizef[i] < pointsizerange[0])) ||
                    (!sizef && (size[i] > pointsizerange[1] || size[i] < pointsizerange[0])))) {
                    printf("PTB-ERROR: You requested a point size of %f units, which is not in the range (%f to %f) supported by your graphics hardware.\n",
                           (sizef) ? sizef[i] : size[i], pointsizerange[0], pointsizerange[1]);
                    PsychErrorExitMsg(PsychError_user, "Unsupported point size requested in Screen('DrawDots').");
                }
            }

            // Do we need the GL_FLOAT data glTexCoordPointer(1, ...) workaround?
            // See explanation in PsychWindowSupport.c: PsychDetectAndAssignGfxCapabilities():
            if (windowRecord->specialflags & kPsychNeedVBODouble12Workaround) {
                // Yes: Convert double size buffer to a float sizef buffer and then
                // submit that as GL_FLOAT:
                sizef = (float*) PsychMallocTemp(nrpoints * sizeof(float));
                for (i = 0; i < nrpoints; i++)
                    sizef[i] = (float) size[i];
            }

            // Sizes are fine, setup texunit 2:
            glClientActiveTexture(GL_TEXTURE2);
            glEnableClientState(GL_TEXTURE_COORD_ARRAY);
            glTexCoordPointer(1, (sizef) ? GL_FLOAT : GL_DOUBLE, 0, (sizef) ? (const GLvoid*) sizef : (const GLvoid*) size);
        }

        // Draw all points:
        glDrawArrays(GL_POINTS, 0, nrpoints);

        if (nrsize > 1) {
            // Individual size for each dot provided. Reset texture unit 2:
            glTexCoordPointer(1, (sizef) ? GL_FLOAT : GL_DOUBLE, 0, (const GLvoid*) NULL);
            glDisableClientState(GL_TEXTURE_COORD_ARRAY);

            // Back to default texunit 0:
            glClientActiveTexture(GL_TEXTURE0);
        }
    }
    else {
        // Different size for each dot provided and we can't use our shader based implementation:
        // We have to do One GL - call per dot:
        for (i = 0; i < nrpoints; i++) {
            if (!lenient && ((sizef && (sizef[i] > pointsizerange[1] || sizef[i] < pointsizerange[0])) ||
                (!sizef && (size[i] > pointsizerange[1] || size[i] < pointsizerange[0])))) {
                printf("PTB-ERROR: You requested a point size of %f units, which is not in the range (%f to %f) supported by your graphics hardware.\n",
                        (sizef) ? sizef[i] : size[i], pointsizerange[0], pointsizerange[1]);
                PsychErrorExitMsg(PsychError_user, "Unsupported point size requested in Screen('DrawDots').");
            }

            // Setup point size for this point:
            glPointSize((sizef) ? sizef[i] : (float) size[i]);

            // Render point:
            glDrawArrays(GL_POINTS, i, 1);
        }
    }

    // Disable fast rendering of arrays:
    glDisableClientState(GL_VERTEX_ARRAY);
    glVertexPointer(2, PSYCHGLFLOAT, 0, NULL);

    if (usecolorvector) PsychSetupVertexColorArrays(windowRecord, FALSE, 0, NULL, NULL);

    // Restore old matrix from backup copy, undoing the global translation:
    glPopMatrix();

    // turn off antialiasing again
    if (idot_type) {
        glDisable(GL_POINT_SMOOTH);

        if (windowRecord->smoothPointShader) {
            // Deactivate point smooth shader and point sprite operation on texunit 1:
            PsychSetShader(windowRecord, 0);
            glActiveTexture(GL_TEXTURE1);
            glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_FALSE);
            glActiveTexture(GL_TEXTURE0);
            glDisable(GL_POINT_SPRITE);
            glDisable(GL_PROGRAM_POINT_SIZE);
        }
    }

    // Reset pointsize to 1.0
    glPointSize(1);

    // Mark end of drawing op. This is needed for single buffered drawing:
    PsychFlushGL(windowRecord);

    //All psychfunctions require this.
    return(PsychError_none);
}