Beispiel #1
0
void glPushName(GLuint name) {
    ERROR_IN_BLOCK();
    if (state.render.mode != GL_SELECT) {
        return;
    }
    tack_push_int(&state.select.names, name);
}
Beispiel #2
0
void glPassThrough(GLfloat token) {
    ERROR_IN_BLOCK();
    if (feedback_overflow(2)) return;
    feedback_push(GL_PASS_THROUGH_TOKEN);
    feedback_push(token);
    state.feedback.values -= 1;
}
Beispiel #3
0
void glWindowPos3f(GLfloat x, GLfloat y, GLfloat z) {
    ERROR_IN_BLOCK();
    PUSH_IF_COMPILING(glWindowPos3f);
    PROXY_GLES(glWindowPos3f);
    raster_state_t *raster = &state.raster;
    raster->pos.x = x;
    raster->pos.y = y;
    raster->pos.z = z;
    init_raster();
    viewport_state_t *v = &state.viewport;
    if (x < v->x || x >= v->width || y < v->y || y >= v->height) {
        raster->valid = 0;
    } else {
        raster->valid = 1;
    }
    GLuint *dst = NULL;
    GLfloat *color = raster->color;
    if (pixel_convert(CURRENT->color, (GLvoid **)&dst, 1, 1, GL_RGBA, GL_FLOAT, GL_RGBA, GL_UNSIGNED_BYTE)) {
        memcpy(color, CURRENT->color, sizeof(GLfloat) * 4);
        raster->pixel = *dst;
        free(dst);
    } else {
        for (int i = 0; i < 4; i++) {
            color[i] = 1.0f;
        }
        raster->pixel = 0xFFFFFFFF;
    }
}
Beispiel #4
0
void glPopName() {
    ERROR_IN_BLOCK();
    if (state.render.mode != GL_SELECT) {
        return;
    }
    if (tack_pop(&state.select.names) == NULL) {
        ERROR(GL_STACK_UNDERFLOW);
    }
}
Beispiel #5
0
void glBegin(GLenum mode) {
    if (! gl_valid_mode(mode)) {
        ERROR(GL_INVALID_ENUM);
    }
    ERROR_IN_BLOCK();
    block_t *block = state.block.active = bl_new(mode);
    displaylist_t *list = state.list.active;
    if (list) {
        dl_append_block(list, block);
    }
}
Beispiel #6
0
void glLoadName(GLuint name) {
    if (state.render.mode != GL_SELECT) {
        return;
    }
    ERROR_IN_BLOCK();
    int len = tack_len(&state.select.names);
    if (len > 0) {
        tack_set_int(&state.select.names, len - 1, name);
    } else {
        ERROR(GL_INVALID_OPERATION);
    }
}
Beispiel #7
0
void glRasterPos3f(GLfloat x, GLfloat y, GLfloat z) {
    ERROR_IN_BLOCK();
    PUSH_IF_COMPILING(glRasterPos3f);
    PROXY_GLES(glRasterPos3f);
    GLfloat v[3] = {x, y, z};
    gl_transform_vertex(v, v);
    init_raster();
    viewport_state_t *vs = &state.viewport;
    v[0] = (((v[0] + 1.0f) * 0.5f) * vs->width) + vs->x;
    v[1] = (((-v[1] + 1.0f) * 0.5f) * vs->height) + vs->y;
    // TODO: deal with Z
    glWindowPos3f(v[0], v[1], v[2]);
}
Beispiel #8
0
void glTexGenfv(GLenum coord, GLenum pname, const GLfloat *param) {
    // pname is in: GL_TEXTURE_GEN_MODE, GL_OBJECT_PLANE, GL_EYE_PLANE
    ERROR_IN_BLOCK();

    texgen_state_t *texgen = &state.texgen[state.texture.active];
    if (pname == GL_TEXTURE_GEN_MODE) {
        switch ((GLenum)*param) {
            case GL_SPHERE_MAP:
                if (coord == GL_R || coord == GL_Q) {
                    ERROR(GL_INVALID_ENUM);
                }
            case GL_OBJECT_LINEAR:
            case GL_EYE_LINEAR:
            // TODO: missing GL_NORMAL_MAP implementation
            case GL_NORMAL_MAP:
            case GL_REFLECTION_MAP:
                break;
            default:
                ERROR(GL_INVALID_ENUM);
        }
        switch (coord) {
            case GL_R: texgen->R = *param; break;
            case GL_Q: texgen->Q = *param; break;
            case GL_S: texgen->S = *param; break;
            case GL_T: texgen->T = *param; break;
        }
    } else {
        GLfloat *target = NULL;
        switch (coord) {
            case GL_R:
                target = texgen->Rv;
                break;
            case GL_Q:
                target = texgen->Qv;
                break;
            case GL_S:
                target = texgen->Sv;
                break;
            case GL_T:
                target = texgen->Tv;
                break;
            default:
                ERROR(GL_INVALID_ENUM);
                return;
        }
        memcpy(target, param, 4 * sizeof(GLfloat));
    }
}
Beispiel #9
0
void glDeleteLists(GLuint list, GLsizei range) {
    FORWARD_IF_REMOTE(glDeleteLists);
    if (range < 0) {
        ERROR(GL_INVALID_VALUE);
    }
    ERROR_IN_BLOCK();
    for (int i = 0; i < range; i++) {
        displaylist_t *l = get_list(list);
        if (l) {
            if (state.list.active == l) {
                state.list.active = NULL;
            }
            dl_free(l);
            tack_set(&state.lists, list - 1, NULL);
        }
    }
    // lists just grow upwards, maybe use a better storage mechanism?
}
Beispiel #10
0
void glInitNames() {
    ERROR_IN_BLOCK();
    tack_clear(&state.select.names);
}
Beispiel #11
0
void glEnableClientState(GLenum array) {
    LOAD_GLES_SILENT(glEnableClientState);
    ERROR_IN_BLOCK();
    proxy_glEnable(array, true, gles_glEnableClientState);
}
Beispiel #12
0
void glDisable(GLenum cap) {
    PUSH_IF_COMPILING(glDisable);
    LOAD_GLES_SILENT(glDisable);
    ERROR_IN_BLOCK();
    proxy_glEnable(cap, false, gles_glDisable);
}
Beispiel #13
0
void gl_get(GLenum pname, GLenum type, GLvoid *params) {
    if (state.remote) {
        remote_gl_get(pname, type, params);
        return;
    }
    LOAD_GLES(glGetBooleanv);
    LOAD_GLES(glGetFloatv);
    LOAD_GLES(glGetIntegerv);
    ERROR_IN_BLOCK();

    int width = gl_getv_length(pname);
    switch (pname) {
        // GL_BOOL
        case GL_CURRENT_RASTER_POSITION_VALID:
        case GL_PACK_LSB_FIRST:
        case GL_PACK_SWAP_BYTES:
        case GL_TEXTURE_GEN_Q:
        case GL_TEXTURE_GEN_R:
        case GL_TEXTURE_GEN_S:
        case GL_TEXTURE_GEN_T:
        case GL_UNPACK_LSB_FIRST:
        case GL_UNPACK_SWAP_BYTES:
        {
            enable_state_t *enable = &state.enable;
            GLboolean tmp[4];
            GLboolean *out = tmp;
            if (type == GL_BOOL) {
                out = params;
            }
            switch (pname) {
                case GL_CURRENT_RASTER_POSITION_VALID:
                    *out = state.raster.valid;
                    break;
                case GL_TEXTURE_GEN_Q:
                    *out = enable->texgen_q[state.texture.active];
                    break;
                case GL_TEXTURE_GEN_R:
                    *out = enable->texgen_r[state.texture.active];
                    break;
                case GL_TEXTURE_GEN_S:
                    *out = enable->texgen_s[state.texture.active];
                    break;
                case GL_TEXTURE_GEN_T:
                    *out = enable->texgen_t[state.texture.active];
                    break;
                case GL_PACK_LSB_FIRST:
                    *out = state.texture.pack_lsb_first;
                    break;
                case GL_PACK_SWAP_BYTES:
                    *out = state.texture.pack_swap_bytes;
                    break;
                case GL_UNPACK_LSB_FIRST:
                    *out = state.texture.unpack_lsb_first;
                    break;
                case GL_UNPACK_SWAP_BYTES:
                    *out = state.texture.unpack_swap_bytes;
                    break;
            }
            if (type != GL_BOOL) {
                for (int i = 0; i < width; i++) {
                    if (type == GL_INT) {
                        GLint *ret = params;
                        ret[i] = out[i];
                    } else if (type == GL_FLOAT) {
                        GLfloat *ret = params;
                        ret[i] = out[i];
                    }
                }
            }
            break;
        }
        // GL_FLOAT
        case GL_CURRENT_COLOR:
        case GL_CURRENT_NORMAL:
        case GL_CURRENT_RASTER_COLOR:
        case GL_CURRENT_RASTER_POSITION:
        case GL_CURRENT_TEXTURE_COORDS:
        case GL_MODELVIEW_MATRIX:
        case GL_PROJECTION_MATRIX:
        case GL_TEXTURE_MATRIX:
        {
            bool scale = false;
            GLfloat tmp[4];
            GLfloat *out = tmp;
            if (type == GL_FLOAT) {
                out = params;
            }
            switch (pname) {
                case GL_CURRENT_COLOR:
                    memcpy(out, &CURRENT->color, sizeof(GLfloat) * 4);
                    break;
                case GL_CURRENT_NORMAL:
                    memcpy(out, &CURRENT->normal, sizeof(GLfloat) * 3);
                    break;
                case GL_CURRENT_RASTER_COLOR:
                    memcpy(out, &state.raster.color, sizeof(GLfloat) * 4);
                    break;
                case GL_CURRENT_RASTER_POSITION:
                    memcpy(out, &state.raster.pos, sizeof(GLfloat) * 4);
                    break;
                case GL_CURRENT_TEXTURE_COORDS:
                    memcpy(out, &CURRENT->tex, sizeof(GLfloat) * 2);
                    // TODO: need to update this when I track 4d texture coordinates
                    out[3] = 0;
                    out[4] = 0;
                    break;
                case GL_MODELVIEW_MATRIX:
                    gl_get_matrix(GL_MODELVIEW, out);
                    break;
                case GL_PROJECTION_MATRIX:
                    gl_get_matrix(GL_PROJECTION, out);
                    break;
                case GL_TEXTURE_MATRIX:
                    gl_get_matrix(GL_TEXTURE, out);
                    break;
            }
            if (type != GL_FLOAT) {
                for (int i = 0; i < width; i++) {
                    if (type == GL_INT) {
                        GLint *ret = params;
                        if (scale) {
                            ret[i] = out[i] * gl_max_value(type);
                        } else {
                            ret[i] = out[i];
                        }
                    } else if (type == GL_BOOL) {
                        GLboolean *ret = params;
                        ret[i] = !! out[i];
                    }
                }
            }
            break;
        }
        // GL_INT
        case GL_ATTRIB_STACK_DEPTH:
        case GL_AUX_BUFFERS:
        case GL_CLIENT_ATTRIB_STACK_DEPTH:
        case GL_MAJOR_VERSION:
        case GL_MAX_ATTRIB_STACK_DEPTH:
        case GL_MAX_CLIENT_ATTRIB_STACK_DEPTH:
        case GL_MAX_ELEMENTS_INDICES:
        case GL_MAX_MODELVIEW_STACK_DEPTH:
        case GL_MAX_NAME_STACK_DEPTH:
        case GL_MAX_PROJECTION_STACK_DEPTH:
        case GL_MAX_TEXTURE_STACK_DEPTH:
        case GL_MINOR_VERSION:
        case GL_MODELVIEW_STACK_DEPTH:
        case GL_NAME_STACK_DEPTH:
        case GL_PACK_ROW_LENGTH:
        case GL_PACK_SKIP_PIXELS:
        case GL_PACK_SKIP_ROWS:
        case GL_PROJECTION_STACK_DEPTH:
        case GL_TEXTURE_STACK_DEPTH:
        case GL_UNPACK_ROW_LENGTH:
        case GL_UNPACK_SKIP_PIXELS:
        case GL_UNPACK_SKIP_ROWS:
        {
            GLint tmp[4];
            GLint *out = tmp;
            if (type == GL_INT) {
                out = params;
            }
            switch (pname) {
                case GL_ATTRIB_STACK_DEPTH:
                    *out = tack_len(&state.stack.attrib);
                    break;
                case GL_AUX_BUFFERS:
                    *out = 0;
                    break;
                case GL_CLIENT_ATTRIB_STACK_DEPTH:
                    *out = tack_len(&state.stack.client);
                    break;
                case GL_MAX_LIST_NESTING:
                    *out = 64;
                    break;
                case GL_MAJOR_VERSION:
                    *out = 1;
                    break;
                case GL_MINOR_VERSION:
                    *out = 4;
                    break;
                case GL_MAX_ATTRIB_STACK_DEPTH:
                case GL_MAX_CLIENT_ATTRIB_STACK_DEPTH:
                case GL_MAX_ELEMENTS_INDICES:
                case GL_MAX_MODELVIEW_STACK_DEPTH:
                case GL_MAX_NAME_STACK_DEPTH:
                case GL_MAX_PROJECTION_STACK_DEPTH:
                case GL_MAX_TEXTURE_STACK_DEPTH:
                    // NOTE: GL_MAX_ELEMENTS_INDICES is *actually* 65535, the others in this group are arbitrary
                    *out = 65535;
                    break;
                case GL_MODELVIEW_STACK_DEPTH:
                    *out = tack_len(&state.matrix.model.stack);
                    break;
                case GL_NAME_STACK_DEPTH:
                    *out = tack_len(&state.select.names);
                    break;
                case GL_PROJECTION_STACK_DEPTH:
                    *out = tack_len(&state.matrix.projection.stack);
                    break;
                case GL_TEXTURE_STACK_DEPTH:
                    *out = tack_len(&state.matrix.texture[state.texture.active].stack);
                    break;
                // texture stuff
                case GL_PACK_ROW_LENGTH:
                    *out = state.texture.pack_row_length;
                    break;
                case GL_PACK_SKIP_PIXELS:
                    *out = state.texture.pack_skip_pixels;
                    break;
                case GL_PACK_SKIP_ROWS:
                    *out = state.texture.pack_skip_rows;
                    break;
                case GL_UNPACK_ROW_LENGTH:
                    *out = state.texture.unpack_row_length;
                    break;
                case GL_UNPACK_SKIP_PIXELS:
                    *out = state.texture.unpack_skip_pixels;
                    break;
                case GL_UNPACK_SKIP_ROWS:
                    *out = state.texture.unpack_skip_rows;
                    break;
            }
            if (type != GL_INT) {
                for (int i = 0; i < width; i++) {
                    if (type == GL_FLOAT) {
                        GLfloat *ret = params;
                        ret[i] = out[i];
                    } else if (type == GL_BOOL) {
                        GLboolean *ret = params;
                        ret[i] = !! out[i];
                    }
                }
            }
            break;
        }
        default:
        {
            GLenum saved = glGetError();
            switch (type) {
                case GL_BOOL:
                    gles_glGetBooleanv(pname, params);
                    break;
                case GL_FLOAT:
                    gles_glGetFloatv(pname, params);
                    break;
                case GL_INT:
                    gles_glGetIntegerv(pname, params);
                    break;
            }
            GLenum error = gl_get_error();
            if (error == GL_INVALID_ENUM) {
                fprintf(stderr, "libGL: GL_INVALID_ENUM when calling glGet<%s>(%s)\n", gl_str(type), gl_str(pname));
                GL_TYPE_SWITCH(ret, params, type, *ret = 0;,);
            }
            gl_set_error(error ? error : saved);
            break;
         }
Beispiel #14
0
void glPushAttrib(GLbitfield mask) {
    ERROR_IN_BLOCK();
    glstack_t *cur = malloc(sizeof(glstack_t));

    cur->mask = mask;
    cur->clip_planes_enabled = NULL;
    cur->clip_planes = NULL;
    cur->lights_enabled = NULL;
    cur->lights = NULL;

    // TODO: GL_ACCUM_BUFFER_BIT

    // TODO: will tracking these myself be much faster than glGet?
    if (mask & GL_COLOR_BUFFER_BIT) {
        cur->alpha_test = glIsEnabled(GL_ALPHA_TEST);
        glGetIntegerv(GL_ALPHA_TEST_FUNC, &cur->alpha_test_func);
        glGetFloatv(GL_ALPHA_TEST_REF, &cur->alpha_test_ref);

        cur->blend = glIsEnabled(GL_BLEND);
        glGetIntegerv(GL_BLEND_SRC, &cur->blend_src_func);
        glGetIntegerv(GL_BLEND_DST, &cur->blend_dst_func);

        cur->dither = glIsEnabled(GL_DITHER);
        cur->color_logic_op = glIsEnabled(GL_COLOR_LOGIC_OP);
        glGetIntegerv(GL_LOGIC_OP_MODE, &cur->logic_op);

        glGetFloatv(GL_COLOR_CLEAR_VALUE, cur->clear_color);
        glGetFloatv(GL_COLOR_WRITEMASK, cur->color_mask);
    }

    if (mask & GL_CURRENT_BIT) {
        glGetFloatv(GL_CURRENT_COLOR, cur->color);
        glGetFloatv(GL_CURRENT_NORMAL, cur->normal);
        for (int i = 0; i < MAX_TEX; i++) {
            memcpy(cur->tex[i], state.current.tex[i], 2 * sizeof(GLfloat));
        }
    }

    if (mask & GL_DEPTH_BUFFER_BIT) {
        cur->depth_test = glIsEnabled(GL_DEPTH_TEST);
        glGetIntegerv(GL_DEPTH_FUNC, &cur->depth_func);
        glGetFloatv(GL_DEPTH_CLEAR_VALUE, &cur->clear_depth);
        glGetIntegerv(GL_DEPTH_WRITEMASK, &cur->depth_mask);
    }

    if (mask & GL_ENABLE_BIT) {
        int i;
        GLint max_clip_planes;
        glGetIntegerv(GL_MAX_CLIP_PLANES, &max_clip_planes);
        cur->clip_planes_enabled = (GLboolean *)malloc(max_clip_planes * sizeof(GLboolean));
        for (i = 0; i < max_clip_planes; i++) {
            *(cur->clip_planes_enabled + i) = glIsEnabled(GL_CLIP_PLANE0 + i);
        }

        GLint max_lights;
        glGetIntegerv(GL_MAX_LIGHTS, &max_lights);
        cur->lights_enabled = (GLboolean *)malloc(max_lights * sizeof(GLboolean));
        for (i = 0; i < max_lights; i++) {
            *(cur->lights_enabled + i) = glIsEnabled(GL_LIGHT0 + i);
        }

        cur->alpha_test = glIsEnabled(GL_ALPHA_TEST);
        cur->blend = glIsEnabled(GL_BLEND);

        cur->cull_face = glIsEnabled(GL_CULL_FACE);
        cur->depth_test = glIsEnabled(GL_DEPTH_TEST);
        cur->dither = glIsEnabled(GL_DITHER);
        cur->fog = glIsEnabled(GL_FOG);
        cur->lighting = glIsEnabled(GL_LIGHTING);
        cur->line_smooth = glIsEnabled(GL_LINE_SMOOTH);
        cur->line_stipple = glIsEnabled(GL_LINE_STIPPLE);
        cur->color_logic_op = glIsEnabled(GL_COLOR_LOGIC_OP);
        cur->multisample = glIsEnabled(GL_MULTISAMPLE);
        cur->normalize = glIsEnabled(GL_NORMALIZE);
        cur->point_smooth = glIsEnabled(GL_POINT_SMOOTH);
        cur->polygon_offset_fill = glIsEnabled(GL_POLYGON_OFFSET_FILL);
        cur->sample_alpha_to_coverage = glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE);
        cur->sample_alpha_to_one = glIsEnabled(GL_SAMPLE_ALPHA_TO_ONE);
        cur->sample_coverage = glIsEnabled(GL_SAMPLE_COVERAGE);
        cur->scissor_test = glIsEnabled(GL_SCISSOR_TEST);
        cur->stencil_test = glIsEnabled(GL_STENCIL_TEST);
        cur->texture_2d = glIsEnabled(GL_TEXTURE_2D);
    }

    // TODO: GL_EVAL_BIT

    if (mask & GL_FOG_BIT) {
        cur->fog = glIsEnabled(GL_FOG);
        glGetFloatv(GL_FOG_COLOR, cur->fog_color);
        glGetFloatv(GL_FOG_DENSITY, &cur->fog_density);
        glGetFloatv(GL_FOG_START, &cur->fog_start);
        glGetFloatv(GL_FOG_END, &cur->fog_end);
        glGetIntegerv(GL_FOG_MODE, &cur->fog_mode);
    }

    if (mask & GL_HINT_BIT) {
        glGetIntegerv(GL_PERSPECTIVE_CORRECTION_HINT, &cur->perspective_hint);
        glGetIntegerv(GL_POINT_SMOOTH_HINT, &cur->point_smooth_hint);
        glGetIntegerv(GL_LINE_SMOOTH_HINT, &cur->line_smooth_hint);
        glGetIntegerv(GL_FOG_HINT, &cur->fog_hint);
        glGetIntegerv(GL_GENERATE_MIPMAP_HINT, &cur->mipmap_hint);
    }

    if (mask & GL_LIGHTING_BIT) {
        cur->lighting = glIsEnabled(GL_LIGHTING);
        glGetIntegerv(GL_LIGHT_MODEL_AMBIENT, cur->light_model_ambient);
        glGetIntegerv(GL_LIGHT_MODEL_TWO_SIDE, &cur->light_model_two_side);

        int i;
        GLint max_lights;
        glGetIntegerv(GL_MAX_LIGHTS, &max_lights);
        cur->lights_enabled = (GLboolean *)malloc(max_lights * sizeof(GLboolean));
        cur->lights = (GLfloat *)malloc(max_lights * sizeof(GLfloat));
        for (i = 0; i < max_lights; i++) {
            *(cur->lights_enabled + i) = glIsEnabled(GL_LIGHT0 + i);
            /* TODO: record all data about the lights
            glGetFloatv(GL_LIGHT0 + i, cur->lights + i);
            */
        }
        glGetIntegerv(GL_SHADE_MODEL, &cur->shade_model);
    }

    if (mask & GL_LINE_BIT) {
        cur->line_smooth = glIsEnabled(GL_LINE_SMOOTH);
        // TODO: stipple stuff here
        glGetFloatv(GL_LINE_WIDTH, &cur->line_width);
    }

    if (mask & GL_LIST_BIT) {
        // TODO: local storage of glListBase
    }

    if (mask & GL_MULTISAMPLE_BIT) {
        cur->multisample = glIsEnabled(GL_MULTISAMPLE);
        cur->sample_alpha_to_coverage = glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE);
        cur->sample_alpha_to_one = glIsEnabled(GL_SAMPLE_ALPHA_TO_ONE);
        cur->sample_coverage = glIsEnabled(GL_SAMPLE_COVERAGE);
    }

    // TODO: GL_PIXEL_MODE_BIT

    if (mask & GL_POINT_BIT) {
        cur->point_smooth = glIsEnabled(GL_POINT_SMOOTH);
        glGetFloatv(GL_POINT_SIZE, &cur->point_size);
    }

    // TODO: GL_POLYGON_BIT
    // TODO: GL_POLYGON_STIPPLE_BIT

    if (mask & GL_SCISSOR_BIT) {
        cur->scissor_test = glIsEnabled(GL_SCISSOR_TEST);
        glGetFloatv(GL_SCISSOR_BOX, cur->scissor_box);
    }

    // TODO: GL_STENCIL_BUFFER_BIT

    // TODO: incomplete
    if (mask & GL_TEXTURE_BIT) {
        glGetIntegerv(GL_TEXTURE_BINDING_2D, &cur->texture);
    }

    // TODO: GL_TRANSFORM_BIT
    // TODO: GL_VIEWPORT_BIT

    tack_push(&state.stack.attrib, cur);
}
Beispiel #15
0
void glPopAttrib() {
    ERROR_IN_BLOCK();
    glstack_t *cur = tack_pop(&state.stack.attrib);
    if (cur == NULL) {
        ERROR(GL_STACK_UNDERFLOW);
    }

    if (cur->mask & GL_COLOR_BUFFER_BIT) {
#ifndef USE_ES2
        enable_disable(GL_ALPHA_TEST, cur->alpha_test);
        glAlphaFunc(cur->alpha_test_func, cur->alpha_test_ref);
#endif

        enable_disable(GL_BLEND, cur->blend);
        glBlendFunc(cur->blend_src_func, cur->blend_dst_func);

        enable_disable(GL_DITHER, cur->dither);
#ifndef USE_ES2
        enable_disable(GL_COLOR_LOGIC_OP, cur->color_logic_op);
        glLogicOp(cur->logic_op);
#endif

        GLfloat *c;
        glClearColor(v4(cur->clear_color));
        glColorMask(v4(cur->color_mask));
    }

    if (cur->mask & GL_CURRENT_BIT) {
        glColor4f(v4(cur->color));
#ifndef USE_ES2
        glNormal3f(v3(cur->normal));
#endif
        for (int i = 0; i < MAX_TEX; i++) {
            glMultiTexCoord2f(GL_TEXTURE0 + i, v2(cur->tex[i]));
        }
    }

    if (cur->mask & GL_DEPTH_BUFFER_BIT) {
        enable_disable(GL_DEPTH_TEST, cur->depth_test);
        glDepthFunc(cur->depth_func);
        glClearDepth(cur->clear_depth);
        glDepthMask(cur->depth_mask);
    }

    if (cur->mask & GL_ENABLE_BIT) {
        int i;
        GLint max_clip_planes;
        glGetIntegerv(GL_MAX_CLIP_PLANES, &max_clip_planes);
        for (i = 0; i < max_clip_planes; i++) {
            enable_disable(GL_CLIP_PLANE0 + i, *(cur->clip_planes_enabled + i));
        }

        GLint max_lights;
        glGetIntegerv(GL_MAX_LIGHTS, &max_lights);
        for (i = 0; i < max_lights; i++) {
            enable_disable(GL_LIGHT0 + i, *(cur->lights_enabled + i));
        }

        enable_disable(GL_ALPHA_TEST, cur->alpha_test);
        enable_disable(GL_BLEND, cur->blend);
        enable_disable(GL_CULL_FACE, cur->cull_face);
        enable_disable(GL_DEPTH_TEST, cur->depth_test);
        enable_disable(GL_DITHER, cur->dither);
        enable_disable(GL_FOG, cur->fog);
        enable_disable(GL_LIGHTING, cur->lighting);
        enable_disable(GL_LINE_SMOOTH, cur->line_smooth);
        enable_disable(GL_LINE_STIPPLE, cur->line_stipple);
        enable_disable(GL_COLOR_LOGIC_OP, cur->color_logic_op);
        enable_disable(GL_MULTISAMPLE, cur->multisample);
        enable_disable(GL_NORMALIZE, cur->normalize);
        enable_disable(GL_POINT_SMOOTH, cur->point_smooth);
        enable_disable(GL_POLYGON_OFFSET_FILL, cur->polygon_offset_fill);
        enable_disable(GL_SAMPLE_ALPHA_TO_COVERAGE, cur->sample_alpha_to_coverage);
        enable_disable(GL_SAMPLE_ALPHA_TO_ONE, cur->sample_alpha_to_one);
        enable_disable(GL_SAMPLE_COVERAGE, cur->sample_coverage);
        enable_disable(GL_SCISSOR_TEST, cur->scissor_test);
        enable_disable(GL_STENCIL_TEST, cur->stencil_test);
        enable_disable(GL_TEXTURE_2D, cur->texture_2d);
    }

#ifndef USE_ES2
    if (cur->mask & GL_FOG_BIT) {
        enable_disable(GL_FOG, cur->fog);
        glFogfv(GL_FOG_COLOR, cur->fog_color);
        glFogf(GL_FOG_DENSITY, cur->fog_density);
        glFogf(GL_FOG_START, cur->fog_start);
        glFogf(GL_FOG_END, cur->fog_end);
        glFogf(GL_FOG_MODE, cur->fog_mode);
    }
#endif

    if (cur->mask & GL_HINT_BIT) {
        enable_disable(GL_PERSPECTIVE_CORRECTION_HINT, cur->perspective_hint);
        enable_disable(GL_POINT_SMOOTH_HINT, cur->point_smooth_hint);
        enable_disable(GL_LINE_SMOOTH_HINT, cur->line_smooth_hint);
        enable_disable(GL_FOG_HINT, cur->fog_hint);
        enable_disable(GL_GENERATE_MIPMAP_HINT, cur->mipmap_hint);
    }

    if (cur->mask & GL_LINE_BIT) {
        enable_disable(GL_LINE_SMOOTH, cur->line_smooth);
        // TODO: stipple stuff here
        glLineWidth(cur->line_width);
    }

    if (cur->mask & GL_MULTISAMPLE_BIT) {
        enable_disable(GL_MULTISAMPLE, cur->multisample);
        enable_disable(GL_SAMPLE_ALPHA_TO_COVERAGE, cur->sample_alpha_to_coverage);
        enable_disable(GL_SAMPLE_ALPHA_TO_ONE, cur->sample_alpha_to_one);
        enable_disable(GL_SAMPLE_COVERAGE, cur->sample_coverage);
    }

#ifndef USE_ES2
    if (cur->mask & GL_POINT_BIT) {
        enable_disable(GL_POINT_SMOOTH, cur->point_smooth);
        glPointSize(cur->point_size);
    }
#endif

    if (cur->mask & GL_SCISSOR_BIT) {
        enable_disable(GL_SCISSOR_TEST, cur->scissor_test);
        glScissor(v4(cur->scissor_box));
    }

    if (cur->mask & GL_TEXTURE_BIT) {
        glBindTexture(GL_TEXTURE_2D, cur->texture);
    }

    free(cur->clip_planes_enabled);
    free(cur->clip_planes);
    free(cur->lights_enabled);
    free(cur->lights);
    free(cur);
}