annabunches.net/content/posts/2011-12-18-project-treewars-going-in-circles.md

21 lines
8.8 KiB
Markdown
Raw Normal View History

2016-04-11 22:01:00 +00:00
---
2020-05-15 21:15:51 +00:00
deprecated: true
2016-05-04 18:41:25 +00:00
excerpt_separator: <br/>
category: technology
2016-04-11 22:01:00 +00:00
layout: post
title: 'Project Treewars: Going in Circles'
date: '2011-12-18T09:00:00.000-05:00'
author: Anna Wiggins
tags:
- Programming
- OpenGL
- C++
- TreeWars
- circles
- GLSL
modified_time: '2013-10-22T11:19:51.866-04:00'
blogger_id: tag:blogger.com,1999:blog-4209116010564764361.post-1786093955840700947
blogger_orig_url: http://www.stringofbits.net/2011/12/project-treewars-going-in-circles.html
---
It's been quite a while since I actually worked on TreeWars. Various things have distracted me, including some other programming projects. But I actually made some progress way back in July, before I shelved the project temporarily. So, let's talk about circles.<br/><br/>OpenGL gives us a few different ways to draw things, which I've talked about before. When we were using the fixed-pipeline functions (glBegin(), glEnd(), etc), I could draw a circle the same way I drew it in SDL: draw a bunch of same-sized rectangles, shifting the coordinates around a central point so that they overlap. Do enough of them (using small enough increments), and it makes a very smooth-looking circle. I never did this in OpenGL, but the SDL code looked like this:<br/><br/>[sourcecode language="cpp" gutter="false"]<br/>void DrawUtils::draw_circle_filled(SDL_Surface* dest, Sint16 int_x, Sint16 int_y, Uint16 int_r, Uint32 colour)<br/>{<br/> float x = static_cast&lt;float&gt; (int_x);<br/> float y = static_cast&lt;float&gt; (int_y);<br/> float r = static_cast&lt;float&gt; (int_r);<br/><br/> SDL_Rect pen;<br/> float i;<br/><br/> for (i=0; i &lt; 6.28318531; i += 0.0034906585)<br/> {<br/> pen.x = static_cast&lt;int&gt; (x + cos(i) * r);<br/> pen.y = static_cast&lt;int&gt; (y + sin(i) * r);<br/> int w = static_cast&lt;int&gt; (x - pen.x);<br/> int h = static_cast&lt;int&gt; (y - pen.y);<br/><br/> if (w == 0) pen.w = 1;<br/> else if (w &lt; 0)<br/> {<br/> pen.x = x;<br/> pen.w = abs(w);<br/> }<br/> else pen.w = w;<br/><br/> if (h == 0) pen.h = 1;<br/> else if (h &lt; 0)<br/> {<br/> pen.y = y;<br/> pen.h = abs(h);<br/> }<br/> else pen.h = h;<br/> if (pen.x &gt;= dest-&gt;clip_rect.x &amp;&amp;<br/> pen.y &gt;= dest-&gt;clip_rect.y &amp;&amp;<br/> pen.x + pen.w &lt;= dest-&gt;clip_rect.w &amp;&amp;<br/> pen.y + pen.h &lt;= dest-&gt;clip_rect.h)<br/> SDL_FillRect(dest, &amp;pen,<br/> SDL_MapRGBA(dest-&gt;format,<br/> (colour &gt;&gt; 16) &amp; 0xff,<br/> (colour &gt;&gt; 8) &amp; 0xff,<br/> colour &amp; 0xff, 1));<br/> }<br/>}<br/>[/sourcecode]<br/><br/>I was pretty proud of this code when I wrote it. The magic is at the top of the <code>for</code> loop: from 0 to 2π, it increments a tiny bit and finds a new rectangle that has one vertex at the center of the circle, and the opposing vertex at some point along the circle. It does this 1800 times per circle, which isn't terribly efficient, but it got the job done.<br/><br/>With OpenGL and the shader pipeline, we *could* still do that. We could do the following in a loop, 1800 times:<br/><br/>[sourcecode lang="cpp" gutter="false"]<br/> GLushort Quad::rect_elements[] = {0, 1, 2, 3};<br/> GLfloat buffer_data[] = {x1f, y1f, x2f, y1f, x1f, y2f, x2f, y2f};<br/><br/> GLuint vertex_buffer;<br/> glGenBuffers(1, &amp;vertex_buffer);<br/> glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);<br/> glBufferData(GL_ARRAY_BUFFER, sizeof(buffer_data), buffer_data, GL_STATIC_DRAW);<br/><br/> GLuint element_buffer;<br/> glGenBuffers(1, &amp;element_buffer);<br/> glBindBuffer(GL_ELEMENT_BUFFER, element_buffer);<br/> glBufferData(GL_ELEMENT_BUFFER, sizeof(rect_elements), rect_elements, GL_STATIC_DRAW);<br/><br/> glUseProgram(program); // the shader program, created earlier<br/> glUniform4f(shader-&gt;uniforms.colour,<br/> GLUtils::convert_colour((colour &gt;&gt; 16) &amp; 0xff),<br/> GLUtils::convert_colour((colour &gt;&gt; 8) &amp; 0xff),<br/> GLUtils::convert_colour(colour &amp; 0xff), 1.0);<br/><br/> // Put the vertices in an attribute<br/> glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);<br/> glVertexAttribPointer(shader-&gt;attributes.position, 2, GL_FLOAT,<br/> GL_FALSE, sizeof(GLfloat)*2, (void*)0);<br/>