void draw(int dummy) { if (tail > head) { // We're straddling the end of the array, so have to do this in two steps draw_arrays(vertexes + tail * 6 * 2, fg + tail * 6 * 4, bg + tail * 6 * 4, tex + tail * 6 * 2, buffersz - tail); draw_arrays(vertexes, fg, bg, tex, head-1); } else { draw_arrays(vertexes + tail * 6 * 2, fg + tail * 6 * 4, bg + tail * 6 * 4, tex + tail * 6 * 2, sum_erasz); } printGLError(); erasz.push_back(current_erasz); current_erasz = 0; if (erasz.size() == redraw_count) { // Right, time to retire the oldest era. tail = (tail + erasz.front()) % buffersz; sum_erasz -= erasz.front(); erasz.pop_front(); } }
/* SW TCL arrays, using Draw. */ boolean r300_swtcl_draw_arrays(struct pipe_context* pipe, unsigned mode, unsigned start, unsigned count) { struct r300_context* r300 = r300_context(pipe); int i; if (!u_trim_pipe_prim(mode, &count)) { return FALSE; } for (i = 0; i < r300->vertex_buffer_count; i++) { void* buf = pipe_buffer_map(pipe->screen, r300->vertex_buffer[i].buffer, PIPE_BUFFER_USAGE_CPU_READ); draw_set_mapped_vertex_buffer(r300->draw, i, buf); } draw_set_mapped_element_buffer(r300->draw, 0, NULL); draw_set_mapped_constant_buffer(r300->draw, r300->shader_constants[PIPE_SHADER_VERTEX].constants, r300->shader_constants[PIPE_SHADER_VERTEX].count * (sizeof(float) * 4)); draw_arrays(r300->draw, mode, start, count); for (i = 0; i < r300->vertex_buffer_count; i++) { pipe_buffer_unmap(pipe->screen, r300->vertex_buffer[i].buffer); draw_set_mapped_vertex_buffer(r300->draw, i, NULL); } return TRUE; }
void VisualizerPlot1D::draw() { glColor3f( _params.color.x, _params.color.y, _params.color.z ); draw_frame2D( _wnd_rect ); draw_axes2D( _wnd_rect ); glRasterPos2fv( _wnd_rect.minpt ); glPrint( _caption ); if( !cursor()->on_pause() ) { _coords.clear(); cursor()->snapshort( storage() ); if( cursor()->count() < 1 ) return; std::vector<float> data = storage()->read_elem( cursor()->count()-1 ); if( _coords.capacity() == 0 ) { AllocGlBuffers( data.size() ); } GLfloat dt = _wnd_rect.len[0] / data.size(); GLfloat t = _wnd_rect.len[0] * 0.5f; for( long i = 0; i < (long)data.size(); ++i ) { _coords.push_back( _wnd_rect.center[0] + t ); _coords.push_back( _wnd_rect.center[1] + _params.scale * data[i] ); _coords.push_back( 0 ); t -= dt; } } glLineWidth( 2. ); glColor3f( _params.color.x, _params.color.y, _params.color.z ); draw_arrays( &_coords[0], _coords.size() / 3 ); }
/** * Draw a rectangle using the given coordinates. * * In an ideal world, instead of using this function we would do the * drawing using piglit_draw_rect(), however that function doesn't use * VBO's or VAO's, and hence isn't compatible with core contexts. */ static void draw_rect(float x, float y, float w, float h) { float verts[4][4]; verts[0][0] = x; verts[0][1] = y; verts[0][2] = 0.0; verts[0][3] = 1.0; verts[1][0] = x + w; verts[1][1] = y; verts[1][2] = 0.0; verts[1][3] = 1.0; verts[2][0] = x; verts[2][1] = y + h; verts[2][2] = 0.0; verts[2][3] = 1.0; verts[3][0] = x + w; verts[3][1] = y + h; verts[3][2] = 0.0; verts[3][3] = 1.0; draw_arrays(verts, sizeof(verts)); }
/** * Called by VBO to draw arrays when in selection or feedback mode and * to implement glRasterPos. * This is very much like the normal draw_vbo() function above. * Look at code refactoring some day. * Might move this into the failover module some day. */ void st_feedback_draw_vbo(GLcontext *ctx, const struct gl_client_array **arrays, const struct _mesa_prim *prims, GLuint nr_prims, const struct _mesa_index_buffer *ib, GLboolean index_bounds_valid, GLuint min_index, GLuint max_index) { struct st_context *st = ctx->st; struct pipe_context *pipe = st->pipe; struct draw_context *draw = st->draw; const struct st_vertex_program *vp; const struct pipe_shader_state *vs; struct pipe_buffer *index_buffer_handle = 0; struct pipe_vertex_buffer vbuffers[PIPE_MAX_SHADER_INPUTS]; struct pipe_vertex_element velements[PIPE_MAX_ATTRIBS]; GLuint attr, i; ubyte *mapped_constants; assert(draw); st_validate_state(ctx->st); if (!index_bounds_valid) vbo_get_minmax_index(ctx, prims, ib, &min_index, &max_index); /* must get these after state validation! */ vp = ctx->st->vp; vs = &st->vp->state; if (!st->vp->draw_shader) { st->vp->draw_shader = draw_create_vertex_shader(draw, vs); } /* * Set up the draw module's state. * * We'd like to do this less frequently, but the normal state-update * code sends state updates to the pipe, not to our private draw module. */ assert(draw); draw_set_viewport_state(draw, &st->state.viewport); draw_set_clip_state(draw, &st->state.clip); draw_set_rasterizer_state(draw, &st->state.rasterizer); draw_bind_vertex_shader(draw, st->vp->draw_shader); set_feedback_vertex_format(ctx); /* loop over TGSI shader inputs to determine vertex buffer * and attribute info */ for (attr = 0; attr < vp->num_inputs; attr++) { const GLuint mesaAttr = vp->index_to_input[attr]; struct gl_buffer_object *bufobj = arrays[mesaAttr]->BufferObj; void *map; if (bufobj && bufobj->Name) { /* Attribute data is in a VBO. * Recall that for VBOs, the gl_client_array->Ptr field is * really an offset from the start of the VBO, not a pointer. */ struct st_buffer_object *stobj = st_buffer_object(bufobj); assert(stobj->buffer); vbuffers[attr].buffer = NULL; pipe_buffer_reference(&vbuffers[attr].buffer, stobj->buffer); vbuffers[attr].buffer_offset = pointer_to_offset(arrays[0]->Ptr); velements[attr].src_offset = arrays[mesaAttr]->Ptr - arrays[0]->Ptr; } else { /* attribute data is in user-space memory, not a VBO */ uint bytes = (arrays[mesaAttr]->Size * _mesa_sizeof_type(arrays[mesaAttr]->Type) * (max_index + 1)); /* wrap user data */ vbuffers[attr].buffer = pipe_user_buffer_create(pipe->screen, (void *) arrays[mesaAttr]->Ptr, bytes); vbuffers[attr].buffer_offset = 0; velements[attr].src_offset = 0; } /* common-case setup */ vbuffers[attr].stride = arrays[mesaAttr]->StrideB; /* in bytes */ vbuffers[attr].max_index = max_index; velements[attr].vertex_buffer_index = attr; velements[attr].nr_components = arrays[mesaAttr]->Size; velements[attr].src_format = st_pipe_vertex_format(arrays[mesaAttr]->Type, arrays[mesaAttr]->Size, arrays[mesaAttr]->Format, arrays[mesaAttr]->Normalized); assert(velements[attr].src_format); /* tell draw about this attribute */ #if 0 draw_set_vertex_buffer(draw, attr, &vbuffer[attr]); #endif /* map the attrib buffer */ map = pipe_buffer_map(pipe->screen, vbuffers[attr].buffer, PIPE_BUFFER_USAGE_CPU_READ); draw_set_mapped_vertex_buffer(draw, attr, map); } draw_set_vertex_buffers(draw, vp->num_inputs, vbuffers); draw_set_vertex_elements(draw, vp->num_inputs, velements); if (ib) { struct gl_buffer_object *bufobj = ib->obj; unsigned indexSize; void *map; switch (ib->type) { case GL_UNSIGNED_INT: indexSize = 4; break; case GL_UNSIGNED_SHORT: indexSize = 2; break; default: assert(0); return; } if (bufobj && bufobj->Name) { struct st_buffer_object *stobj = st_buffer_object(bufobj); index_buffer_handle = stobj->buffer; map = pipe_buffer_map(pipe->screen, index_buffer_handle, PIPE_BUFFER_USAGE_CPU_READ); draw_set_mapped_element_buffer(draw, indexSize, map); } else { draw_set_mapped_element_buffer(draw, indexSize, (void *) ib->ptr); } } else { /* no index/element buffer */ draw_set_mapped_element_buffer(draw, 0, NULL); } /* map constant buffers */ mapped_constants = pipe_buffer_map(pipe->screen, st->state.constants[PIPE_SHADER_VERTEX].buffer, PIPE_BUFFER_USAGE_CPU_READ); draw_set_mapped_constant_buffer(st->draw, mapped_constants, st->state.constants[PIPE_SHADER_VERTEX].buffer->size); /* draw here */ for (i = 0; i < nr_prims; i++) { draw_arrays(draw, prims[i].mode, prims[i].start, prims[i].count); } /* unmap constant buffers */ pipe_buffer_unmap(pipe->screen, st->state.constants[PIPE_SHADER_VERTEX].buffer); /* * unmap vertex/index buffers */ for (i = 0; i < PIPE_MAX_ATTRIBS; i++) { if (draw->pt.vertex_buffer[i].buffer) { pipe_buffer_unmap(pipe->screen, draw->pt.vertex_buffer[i].buffer); pipe_buffer_reference(&draw->pt.vertex_buffer[i].buffer, NULL); draw_set_mapped_vertex_buffer(draw, i, NULL); } } if (index_buffer_handle) { pipe_buffer_unmap(pipe->screen, index_buffer_handle); draw_set_mapped_element_buffer(draw, 0, NULL); } }
/** * Called by VBO to draw arrays when in selection or feedback mode and * to implement glRasterPos. * This is very much like the normal draw_vbo() function above. * Look at code refactoring some day. */ void st_feedback_draw_vbo(struct gl_context *ctx, const struct gl_client_array **arrays, const struct _mesa_prim *prims, GLuint nr_prims, const struct _mesa_index_buffer *ib, GLboolean index_bounds_valid, GLuint min_index, GLuint max_index, struct gl_transform_feedback_object *tfb_vertcount) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct draw_context *draw = st->draw; const struct st_vertex_program *vp; const struct pipe_shader_state *vs; struct pipe_vertex_buffer vbuffers[PIPE_MAX_SHADER_INPUTS]; struct pipe_vertex_element velements[PIPE_MAX_ATTRIBS]; struct pipe_index_buffer ibuffer; struct pipe_transfer *vb_transfer[PIPE_MAX_ATTRIBS]; struct pipe_transfer *ib_transfer = NULL; GLuint attr, i; const GLubyte *low_addr = NULL; const void *mapped_indices = NULL; assert(draw); st_validate_state(st); if (!index_bounds_valid) vbo_get_minmax_indices(ctx, prims, ib, &min_index, &max_index, nr_prims); /* must get these after state validation! */ vp = st->vp; vs = &st->vp_variant->tgsi; if (!st->vp_variant->draw_shader) { st->vp_variant->draw_shader = draw_create_vertex_shader(draw, vs); } /* * Set up the draw module's state. * * We'd like to do this less frequently, but the normal state-update * code sends state updates to the pipe, not to our private draw module. */ assert(draw); draw_set_viewport_state(draw, &st->state.viewport); draw_set_clip_state(draw, &st->state.clip); draw_set_rasterizer_state(draw, &st->state.rasterizer, NULL); draw_bind_vertex_shader(draw, st->vp_variant->draw_shader); set_feedback_vertex_format(ctx); /* Find the lowest address of the arrays we're drawing */ if (vp->num_inputs) { low_addr = arrays[vp->index_to_input[0]]->Ptr; for (attr = 1; attr < vp->num_inputs; attr++) { const GLubyte *start = arrays[vp->index_to_input[attr]]->Ptr; low_addr = MIN2(low_addr, start); } } /* loop over TGSI shader inputs to determine vertex buffer * and attribute info */ for (attr = 0; attr < vp->num_inputs; attr++) { const GLuint mesaAttr = vp->index_to_input[attr]; struct gl_buffer_object *bufobj = arrays[mesaAttr]->BufferObj; void *map; if (bufobj && bufobj->Name) { /* Attribute data is in a VBO. * Recall that for VBOs, the gl_client_array->Ptr field is * really an offset from the start of the VBO, not a pointer. */ struct st_buffer_object *stobj = st_buffer_object(bufobj); assert(stobj->buffer); vbuffers[attr].buffer = NULL; pipe_resource_reference(&vbuffers[attr].buffer, stobj->buffer); vbuffers[attr].buffer_offset = pointer_to_offset(low_addr); velements[attr].src_offset = arrays[mesaAttr]->Ptr - low_addr; } else { /* attribute data is in user-space memory, not a VBO */ uint bytes = (arrays[mesaAttr]->Size * _mesa_sizeof_type(arrays[mesaAttr]->Type) * (max_index + 1)); /* wrap user data */ vbuffers[attr].buffer = pipe_user_buffer_create(pipe->screen, (void *) arrays[mesaAttr]->Ptr, bytes, PIPE_BIND_VERTEX_BUFFER); vbuffers[attr].buffer_offset = 0; velements[attr].src_offset = 0; } /* common-case setup */ vbuffers[attr].stride = arrays[mesaAttr]->StrideB; /* in bytes */ velements[attr].instance_divisor = 0; velements[attr].vertex_buffer_index = attr; velements[attr].src_format = st_pipe_vertex_format(arrays[mesaAttr]->Type, arrays[mesaAttr]->Size, arrays[mesaAttr]->Format, arrays[mesaAttr]->Normalized, arrays[mesaAttr]->Integer); assert(velements[attr].src_format); /* tell draw about this attribute */ #if 0 draw_set_vertex_buffer(draw, attr, &vbuffer[attr]); #endif /* map the attrib buffer */ map = pipe_buffer_map(pipe, vbuffers[attr].buffer, PIPE_TRANSFER_READ, &vb_transfer[attr]); draw_set_mapped_vertex_buffer(draw, attr, map); } draw_set_vertex_buffers(draw, vp->num_inputs, vbuffers); draw_set_vertex_elements(draw, vp->num_inputs, velements); memset(&ibuffer, 0, sizeof(ibuffer)); if (ib) { struct gl_buffer_object *bufobj = ib->obj; ibuffer.index_size = vbo_sizeof_ib_type(ib->type); if (ibuffer.index_size == 0) goto out_unref_vertex; if (bufobj && bufobj->Name) { struct st_buffer_object *stobj = st_buffer_object(bufobj); pipe_resource_reference(&ibuffer.buffer, stobj->buffer); ibuffer.offset = pointer_to_offset(ib->ptr); mapped_indices = pipe_buffer_map(pipe, stobj->buffer, PIPE_TRANSFER_READ, &ib_transfer); } else { /* skip setting ibuffer.buffer as the draw module does not use it */ mapped_indices = ib->ptr; } draw_set_index_buffer(draw, &ibuffer); draw_set_mapped_index_buffer(draw, mapped_indices); } /* set the constant buffer */ draw_set_mapped_constant_buffer(st->draw, PIPE_SHADER_VERTEX, 0, st->state.constants[PIPE_SHADER_VERTEX].ptr, st->state.constants[PIPE_SHADER_VERTEX].size); /* draw here */ for (i = 0; i < nr_prims; i++) { draw_arrays(draw, prims[i].mode, prims[i].start, prims[i].count); } /* * unmap vertex/index buffers */ if (ib) { draw_set_mapped_index_buffer(draw, NULL); draw_set_index_buffer(draw, NULL); if (ib_transfer) pipe_buffer_unmap(pipe, ib_transfer); pipe_resource_reference(&ibuffer.buffer, NULL); } out_unref_vertex: for (attr = 0; attr < vp->num_inputs; attr++) { pipe_buffer_unmap(pipe, vb_transfer[attr]); draw_set_mapped_vertex_buffer(draw, attr, NULL); pipe_resource_reference(&vbuffers[attr].buffer, NULL); } draw_set_vertex_buffers(draw, 0, NULL); }
static boolean i915_draw_range_elements(struct pipe_context *pipe, struct pipe_buffer *indexBuffer, unsigned indexSize, unsigned min_index, unsigned max_index, unsigned prim, unsigned start, unsigned count) { struct i915_context *i915 = i915_context(pipe); struct draw_context *draw = i915->draw; unsigned i; if (i915->dirty) i915_update_derived(i915); /* * Map vertex buffers */ for (i = 0; i < i915->num_vertex_buffers; i++) { void *buf = pipe_buffer_map(pipe->screen, i915->vertex_buffer[i].buffer, PIPE_BUFFER_USAGE_CPU_READ); draw_set_mapped_vertex_buffer(draw, i, buf); } /* * Map index buffer, if present */ if (indexBuffer) { void *mapped_indexes = pipe_buffer_map(pipe->screen, indexBuffer, PIPE_BUFFER_USAGE_CPU_READ); draw_set_mapped_element_buffer_range(draw, indexSize, min_index, max_index, mapped_indexes); } else { draw_set_mapped_element_buffer(draw, 0, NULL); } draw_set_mapped_constant_buffer(draw, i915->current.constants[PIPE_SHADER_VERTEX], (i915->current.num_user_constants[PIPE_SHADER_VERTEX] * 4 * sizeof(float))); /* * Do the drawing */ draw_arrays(i915->draw, prim, start, count); /* * unmap vertex/index buffers */ for (i = 0; i < i915->num_vertex_buffers; i++) { pipe_buffer_unmap(pipe->screen, i915->vertex_buffer[i].buffer); draw_set_mapped_vertex_buffer(draw, i, NULL); } if (indexBuffer) { pipe_buffer_unmap(pipe->screen, indexBuffer); draw_set_mapped_element_buffer_range(draw, 0, start, start + count - 1, NULL); } return TRUE; }
enum pipe_error svga_swtnl_draw_range_elements(struct svga_context *svga, struct pipe_buffer *indexBuffer, unsigned indexSize, unsigned min_index, unsigned max_index, unsigned prim, unsigned start, unsigned count) { struct draw_context *draw = svga->swtnl.draw; unsigned i; const void *map; enum pipe_error ret; assert(!svga->dirty); assert(svga->state.sw.need_swtnl); assert(draw); ret = svga_update_state(svga, SVGA_STATE_SWTNL_DRAW); if (ret) { svga_context_flush(svga, NULL); ret = svga_update_state(svga, SVGA_STATE_SWTNL_DRAW); svga->swtnl.new_vbuf = TRUE; assert(ret == PIPE_OK); } /* * Map vertex buffers */ for (i = 0; i < svga->curr.num_vertex_buffers; i++) { map = pipe_buffer_map(svga->pipe.screen, svga->curr.vb[i].buffer, PIPE_BUFFER_USAGE_CPU_READ); draw_set_mapped_vertex_buffer(draw, i, map); } /* Map index buffer, if present */ if (indexBuffer) { map = pipe_buffer_map(svga->pipe.screen, indexBuffer, PIPE_BUFFER_USAGE_CPU_READ); draw_set_mapped_element_buffer_range(draw, indexSize, min_index, max_index, map); } if (svga->curr.cb[PIPE_SHADER_VERTEX]) { map = pipe_buffer_map(svga->pipe.screen, svga->curr.cb[PIPE_SHADER_VERTEX], PIPE_BUFFER_USAGE_CPU_READ); assert(map); draw_set_mapped_constant_buffer( draw, PIPE_SHADER_VERTEX, 0, map, svga->curr.cb[PIPE_SHADER_VERTEX]->size); } draw_arrays(svga->swtnl.draw, prim, start, count); draw_flush(svga->swtnl.draw); /* Ensure the draw module didn't touch this */ assert(i == svga->curr.num_vertex_buffers); /* * unmap vertex/index buffers */ for (i = 0; i < svga->curr.num_vertex_buffers; i++) { pipe_buffer_unmap(svga->pipe.screen, svga->curr.vb[i].buffer); draw_set_mapped_vertex_buffer(draw, i, NULL); } if (indexBuffer) { pipe_buffer_unmap(svga->pipe.screen, indexBuffer); draw_set_mapped_element_buffer(draw, 0, NULL); } if (svga->curr.cb[PIPE_SHADER_VERTEX]) { pipe_buffer_unmap(svga->pipe.screen, svga->curr.cb[PIPE_SHADER_VERTEX]); } return ret; }
void fbo::draw_arrays(const vao& buffer, rsx::primitive_type mode, GLsizei count, GLint first) const { buffer.bind(); draw_arrays(mode, count, first); }
void fbo::draw_arrays(const buffer& buffer, rsx::primitive_type mode, GLsizei count, GLint first) const { buffer.bind(buffer::target::array); draw_arrays(mode, count, first); }
/** * Draw vertex arrays, with optional indexing. * Basically, map the vertex buffers (and drawing surfaces), then hand off * the drawing to the 'draw' module. */ boolean llvmpipe_draw_range_elements(struct pipe_context *pipe, struct pipe_buffer *indexBuffer, unsigned indexSize, unsigned min_index, unsigned max_index, unsigned mode, unsigned start, unsigned count) { struct llvmpipe_context *lp = llvmpipe_context(pipe); struct draw_context *draw = lp->draw; unsigned i; lp->reduced_api_prim = u_reduced_prim(mode); if (lp->dirty) llvmpipe_update_derived( lp ); llvmpipe_map_transfers(lp); /* * Map vertex buffers */ for (i = 0; i < lp->num_vertex_buffers; i++) { void *buf = llvmpipe_buffer(lp->vertex_buffer[i].buffer)->data; draw_set_mapped_vertex_buffer(draw, i, buf); } /* Map index buffer, if present */ if (indexBuffer) { void *mapped_indexes = llvmpipe_buffer(indexBuffer)->data; draw_set_mapped_element_buffer_range(draw, indexSize, min_index, max_index, mapped_indexes); } else { /* no index/element buffer */ draw_set_mapped_element_buffer_range(draw, 0, start, start + count - 1, NULL); } /* draw! */ draw_arrays(draw, mode, start, count); /* * unmap vertex/index buffers */ for (i = 0; i < lp->num_vertex_buffers; i++) { draw_set_mapped_vertex_buffer(draw, i, NULL); } if (indexBuffer) { draw_set_mapped_element_buffer(draw, 0, NULL); } /* * TODO: Flush only when a user vertex/index buffer is present * (or even better, modify draw module to do this * internally when this condition is seen?) */ draw_flush(draw); /* Note: leave drawing surfaces mapped */ lp->dirty_render_cache = TRUE; return TRUE; }
/** * Draw vertex arrays, with optional indexing. * Basically, map the vertex buffers (and drawing surfaces), then hand off * the drawing to the 'draw' module. * * XXX should the element buffer be specified/bound with a separate function? */ static boolean cell_draw_range_elements(struct pipe_context *pipe, struct pipe_buffer *indexBuffer, unsigned indexSize, unsigned min_index, unsigned max_index, unsigned mode, unsigned start, unsigned count) { struct cell_context *sp = cell_context(pipe); struct draw_context *draw = sp->draw; unsigned i; if (sp->dirty) cell_update_derived( sp ); #if 0 cell_map_surfaces(sp); #endif cell_map_constant_buffers(sp); /* * Map vertex buffers */ for (i = 0; i < sp->num_vertex_buffers; i++) { void *buf = pipe_buffer_map(pipe->screen, sp->vertex_buffer[i].buffer, PIPE_BUFFER_USAGE_CPU_READ); cell_flush_buffer_range(sp, buf, sp->vertex_buffer[i].buffer->size); draw_set_mapped_vertex_buffer(draw, i, buf); } /* Map index buffer, if present */ if (indexBuffer) { void *mapped_indexes = pipe_buffer_map(pipe->screen, indexBuffer, PIPE_BUFFER_USAGE_CPU_READ); draw_set_mapped_element_buffer(draw, indexSize, mapped_indexes); } else { /* no index/element buffer */ draw_set_mapped_element_buffer(draw, 0, NULL); } /* draw! */ draw_arrays(draw, mode, start, count); /* * unmap vertex/index buffers - will cause draw module to flush */ for (i = 0; i < sp->num_vertex_buffers; i++) { draw_set_mapped_vertex_buffer(draw, i, NULL); pipe_buffer_unmap(pipe->screen, sp->vertex_buffer[i].buffer); } if (indexBuffer) { draw_set_mapped_element_buffer(draw, 0, NULL); pipe_buffer_unmap(pipe->screen, indexBuffer); } /* Note: leave drawing surfaces mapped */ cell_unmap_constant_buffers(sp); return TRUE; }
static void draw_galaxy(int i, int j, int f, float a) { struct galaxy *g = get_galaxy(i); float V[6][4]; float p[4] = { 0.0, 0.0, 0.0, 1.0 }; init_galaxy(i); glPushMatrix(); { /* Apply the local coordinate system transformation. */ transform_entity(j); get_viewfrust(V); get_viewpoint(p); /* Supply the view position as a vertex program parameter. */ if (GL_has_vertex_program) glProgramEnvParameter4fARB(GL_VERTEX_PROGRAM_ARB, 0, p[0], p[1], p[2], p[3]); glPushAttrib(GL_ENABLE_BIT | GL_TEXTURE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); { /* Set up the GL state for star rendering. */ draw_brush(g->brush, a * get_entity_alpha(j)); glBindTexture(GL_TEXTURE_2D, g->texture); glDisable(GL_TEXTURE_2D); glDisable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); glDepthMask(GL_FALSE); glBlendFunc(GL_ONE, GL_ONE); if (GL_has_vertex_program) glEnable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB); if (GL_has_point_sprite) { glEnable(GL_POINT_SPRITE_ARB); glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE); } draw_arrays(i); /* Render all stars. */ node_draw(g->N, 0, 0, V); } glPopClientAttrib(); glPopAttrib(); /* Render all child entities in this coordinate system. */ draw_entity_tree(j, f, a * get_entity_alpha(j)); } glPopMatrix(); }