1 #include "AppHdr.h"
2 
3 #ifdef USE_TILE_LOCAL
4 #ifdef USE_GL
5 
6 #include "glwrapper-ogl.h"
7 
8 // How do we get access to the GL calls?
9 // If other UI types use the -ogl wrapper they should
10 // include more conditional includes here.
11 #ifdef USE_SDL
12 # ifdef USE_GLES
13 #  ifdef __ANDROID__
14 #   include <SDL.h>
15 #  else
16 #   include <SDL2/SDL.h>
17 #   include <SDL_gles.h>
18 #  endif
19 #  include <GLES/gl.h>
20 # else
21 #  ifdef __ANDROID__
22 #   include <SDL.h>
23 #   include <GLES/gl.h>
24 #  else
25 #   include <SDL_opengl.h>
26 #   if defined(__MACOSX__)
27 #    include <OpenGL/glu.h>
28 #   else
29 #    include <GL/glu.h>
30 #   endif
31 #  endif
32 # endif
33 #endif
34 
35 #include "options.h"
36 #include "stringutil.h"
37 #include "tilesdl.h"
38 
39 #ifdef __ANDROID__
40 # include <android/log.h>
41 #endif
42 
43 // TODO: if this gets big enough, pull out into opengl-utils.cc/h or sth
44 namespace opengl
45 {
check_texture_size(const char * name,int width,int height)46     bool check_texture_size(const char *name, int width, int height)
47     {
48         int max_texture_size;
49         glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
50         if (width > max_texture_size || height > max_texture_size)
51         {
52             mprf(MSGCH_ERROR,
53                 "Texture %s is bigger than maximum driver texture size "
54                 "(%d,%d vs. %d). Sprites from this texture will not display "
55                 "properly.",
56                 name, width, height, max_texture_size);
57             return false;
58         }
59         return true;
60     }
61 
_gl_error_to_string(GLenum e)62     static string _gl_error_to_string(GLenum e)
63     {
64         switch (e)
65         {
66         case GL_NO_ERROR:
67             return "GL_NO_ERROR";
68         case GL_INVALID_ENUM:
69             return "GL_INVALID_ENUM";
70         case GL_INVALID_VALUE:
71             return "GL_INVALID_VALUE";
72         case GL_INVALID_OPERATION:
73             return "GL_INVALID_OPERATION";
74         case GL_INVALID_FRAMEBUFFER_OPERATION:
75             return "GL_INVALID_FRAMEBUFFER_OPERATION";
76         case GL_OUT_OF_MEMORY:
77             return "GL_OUT_OF_MEMORY (fatal)";
78         case GL_STACK_UNDERFLOW:
79             return "GL_STACK_UNDERFLOW";
80         case GL_STACK_OVERFLOW:
81             return "GL_STACK_OVERFLOW";
82         default:
83             return make_stringf("Unknown OpenGL error %d", e);
84         }
85     }
86 
87     /**
88      * Log any opengl errors to console. Will crash if a really bad one occurs.
89      *
90      * @return true if there were any errors.
91      */
flush_opengl_errors()92     bool flush_opengl_errors()
93     {
94         GLenum e = GL_NO_ERROR;
95         bool fatal = false;
96         bool errors = false;
97         do
98         {
99             e = glGetError();
100             if (e != GL_NO_ERROR)
101             {
102                 errors = true;
103                 if (e == GL_OUT_OF_MEMORY)
104                     fatal = true;
105                 mprf(MSGCH_ERROR, "OpenGL error %s",
106                                         _gl_error_to_string(e).c_str());
107             }
108         } while (e != GL_NO_ERROR);
109         if (fatal)
110             die("Fatal OpenGL error; giving up");
111         return errors;
112     }
113 }
114 
115 /////////////////////////////////////////////////////////////////////////////
116 // Static functions from GLStateManager
117 
118 GLStateManager *glmanager = nullptr;
119 
init()120 void GLStateManager::init()
121 {
122     if (glmanager)
123         return;
124 
125     glmanager = new OGLStateManager();
126 }
127 
shutdown()128 void GLStateManager::shutdown()
129 {
130     delete glmanager;
131     glmanager = nullptr;
132 }
133 
134 /////////////////////////////////////////////////////////////////////////////
135 // Static functions from GLShapeBuffer
136 
create(bool texture,bool colour,drawing_modes prim)137 GLShapeBuffer *GLShapeBuffer::create(bool texture, bool colour,
138                                      drawing_modes prim)
139 {
140     return new OGLShapeBuffer(texture, colour, prim);
141 }
142 
143 /////////////////////////////////////////////////////////////////////////////
144 // OGLStateManager
145 
OGLStateManager()146 OGLStateManager::OGLStateManager()
147 {
148     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
149     glClearColor(0.0, 0.0, 0.0, 1.0f);
150     glDepthFunc(GL_LEQUAL);
151 
152 #ifdef __ANDROID__
153     m_last_tex = 0;
154 #endif
155     m_window_height = 0;
156 }
157 
set(const GLState & state)158 void OGLStateManager::set(const GLState& state)
159 {
160     if (state.array_vertex != m_current_state.array_vertex)
161     {
162         if (state.array_vertex)
163         {
164             glEnableClientState(GL_VERTEX_ARRAY);
165             glDebug("glEnableClientState(GL_VERTEX_ARRAY)");
166         }
167         else
168         {
169             glDisableClientState(GL_VERTEX_ARRAY);
170             glDebug("glDisableClientState(GL_VERTEX_ARRAY)");
171         }
172     }
173 
174     if (state.array_texcoord != m_current_state.array_texcoord)
175     {
176         if (state.array_texcoord)
177         {
178             glEnableClientState(GL_TEXTURE_COORD_ARRAY);
179             glDebug("glEnableClientState(GL_TEXTURE_COORD_ARRAY)");
180         }
181         else
182         {
183             glDisableClientState(GL_TEXTURE_COORD_ARRAY);
184             glDebug("glDisableClientState(GL_TEXTURE_COORD_ARRAY)");
185         }
186     }
187 
188     if (state.array_colour != m_current_state.array_colour)
189     {
190         if (state.array_colour)
191         {
192             glEnableClientState(GL_COLOR_ARRAY);
193             glDebug("glEnableClientState(GL_COLOR_ARRAY)");
194         }
195         else
196         {
197             glDisableClientState(GL_COLOR_ARRAY);
198             glDebug("glDisableClientState(GL_COLOR_ARRAY)");
199 
200             // [enne] This should *not* be necessary, but the Linux OpenGL
201             // driver that I'm using sets this to the last colour of the
202             // colour array. So, we need to unset it here.
203             glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
204             glDebug("glColor4f(1.0f, 1.0f, 1.0f, 1.0f)");
205         }
206     }
207 
208     if (state.texture != m_current_state.texture)
209     {
210         if (state.texture)
211         {
212             glEnable(GL_TEXTURE_2D);
213             glDebug("glEnable(GL_TEXTURE_2D)");
214         }
215         else
216         {
217             glDisable(GL_TEXTURE_2D);
218             glDebug("glDisable(GL_TEXTURE_2D)");
219         }
220     }
221 
222     if (state.blend != m_current_state.blend)
223     {
224         if (state.blend)
225         {
226             glEnable(GL_BLEND);
227             glDebug("glEnable(GL_BLEND)");
228         }
229         else
230         {
231             glDisable(GL_BLEND);
232             glDebug("glDisable(GL_BLEND)");
233         }
234     }
235 
236     if (state.depthtest != m_current_state.depthtest)
237     {
238         if (state.depthtest)
239         {
240             glEnable(GL_DEPTH_TEST);
241             glDebug("glEnable(GL_DEPTH_TEST)");
242         }
243         else
244         {
245             glDisable(GL_DEPTH_TEST);
246             glDebug("glEnable(GL_DEPTH_TEST)");
247         }
248     }
249 
250     if (state.alphatest != m_current_state.alphatest
251         || state.alpharef != m_current_state.alpharef)
252     {
253         if (state.alphatest)
254         {
255             glEnable(GL_ALPHA_TEST);
256             glAlphaFunc(GL_NOTEQUAL, state.alpharef);
257             glDebug("glAlphaFunc(GL_NOTEQUAL, state.alpharef)");
258         }
259         else
260         {
261             glDisable(GL_ALPHA_TEST);
262             glDebug("glDisable(GL_ALPHA_TEST)");
263         }
264     }
265 
266     if (state.colour != m_current_state.colour)
267     {
268         glColor4f(state.colour.r, state.colour.g,
269                   state.colour.b, state.colour.a);
270         glDebug("glColor4f");
271     }
272 
273     m_current_state = state;
274 }
275 
276 struct {
277     GLW_3VF trans, scale;
278 } current_transform;
279 
set_transform(const GLW_3VF & trans,const GLW_3VF & scale)280 void OGLStateManager::set_transform(const GLW_3VF &trans, const GLW_3VF &scale)
281 {
282     glLoadIdentity();
283     glTranslatef(trans.x, trans.y, trans.z);
284     glScalef(scale.x, scale.y, scale.z);
285     current_transform = { trans, scale };
286 }
287 
reset_transform()288 void OGLStateManager::reset_transform()
289 {
290     set_transform({0,0,0}, {1,1,1});
291 }
292 
get_transform(GLW_3VF * trans,GLW_3VF * scale)293 void OGLStateManager::get_transform(GLW_3VF *trans, GLW_3VF *scale)
294 {
295     if (trans) *trans = current_transform.trans;
296     if (scale) *scale = current_transform.scale;
297 }
298 
logical_to_device(int n) const299 int OGLStateManager::logical_to_device(int n) const
300 {
301     return display_density.logical_to_device(n);
302 }
303 
device_to_logical(int n,bool round) const304 int OGLStateManager::device_to_logical(int n, bool round) const
305 {
306     return display_density.device_to_logical(n, round);
307 }
308 
set_scissor(int x,int y,unsigned int w,unsigned int h)309 void OGLStateManager::set_scissor(int x, int y, unsigned int w, unsigned int h)
310 {
311     glEnable(GL_SCISSOR_TEST);
312     glScissor(logical_to_device(x), logical_to_device(m_window_height-y-h),
313                 logical_to_device(w), logical_to_device(h));
314 }
315 
reset_scissor()316 void OGLStateManager::reset_scissor()
317 {
318     glDisable(GL_SCISSOR_TEST);
319 }
320 
reset_view_for_resize(const coord_def & m_windowsz,const coord_def & m_drawablesz)321 void OGLStateManager::reset_view_for_resize(const coord_def &m_windowsz,
322                                             const coord_def &m_drawablesz)
323 {
324     glViewport(0, 0, m_drawablesz.x, m_drawablesz.y);
325     m_window_height = m_windowsz.y;
326 
327     glMatrixMode(GL_PROJECTION);
328     glLoadIdentity();
329 
330     // For ease, vertex positions are pixel positions.
331 #ifdef USE_GLES
332 # ifdef __ANDROID__
333     glOrthof(0, m_windowsz.x, m_windowsz.y, 0, -1000, 1000);
334 # else
335     glOrthox(0, m_windowsz.x, m_windowsz.y, 0, -1000, 1000);
336 # endif
337 #else
338     glOrtho(0, m_windowsz.x, m_windowsz.y, 0, -1000, 1000);
339 #endif
340     glDebug("glOrthof");
341 }
342 
pixelstore_unpack_alignment(unsigned int bpp)343 void OGLStateManager::pixelstore_unpack_alignment(unsigned int bpp)
344 {
345     glPixelStorei(GL_UNPACK_ALIGNMENT, bpp);
346     glDebug("glPixelStorei");
347 }
348 
delete_textures(size_t count,unsigned int * textures)349 void OGLStateManager::delete_textures(size_t count, unsigned int *textures)
350 {
351     glDeleteTextures(count, (GLuint*)textures);
352     glDebug("glDeleteTextures");
353 }
354 
generate_textures(size_t count,unsigned int * textures)355 void OGLStateManager::generate_textures(size_t count, unsigned int *textures)
356 {
357     glGenTextures(count, (GLuint*)textures);
358     glDebug("glGenTextures");
359 }
360 
bind_texture(unsigned int texture)361 void OGLStateManager::bind_texture(unsigned int texture)
362 {
363     glBindTexture(GL_TEXTURE_2D, texture);
364     glDebug("glBindTexture");
365 #ifdef __ANDROID__
366     m_last_tex = texture;
367 #endif
368 }
369 
load_texture(unsigned char * pixels,unsigned int width,unsigned int height,MipMapOptions mip_opt,int xoffset,int yoffset)370 void OGLStateManager::load_texture(unsigned char *pixels, unsigned int width,
371                                    unsigned int height, MipMapOptions mip_opt,
372                                    int xoffset, int yoffset)
373 {
374     // Assumptions...
375 #ifdef __ANDROID__
376     const GLenum bpp = GL_RGBA;
377 #else
378     const unsigned int bpp = 4;
379 #endif
380     const GLenum texture_format = GL_RGBA;
381     const GLenum format = GL_UNSIGNED_BYTE;
382     // Also assume that the texture is already bound using bind_texture
383 
384     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
385     glDebug("glTexEnvf");
386 
387 #ifdef GL_CLAMP
388     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
389     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
390 #else
391     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
392     glDebug("glTexParameterf GL_TEXTURE_WRAP_S");
393     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
394     glDebug("glTexParameterf GL_TEXTURE_WRAP_T");
395 #endif
396 #ifndef USE_GLES
397     if (mip_opt == MIPMAP_CREATE)
398     {
399         // TODO: should min react to Options.tile_filter_scaling?
400         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
401                         GL_LINEAR_MIPMAP_NEAREST);
402         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
403                         Options.tile_filter_scaling ? GL_LINEAR : GL_NEAREST);
404         gluBuild2DMipmaps(GL_TEXTURE_2D, bpp, width, height,
405                           texture_format, format, pixels);
406     }
407     else
408 #endif
409     {
410         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
411                         Options.tile_filter_scaling ? GL_LINEAR : GL_NEAREST);
412         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
413                         Options.tile_filter_scaling ? GL_LINEAR : GL_NEAREST);
414         if (xoffset >= 0 && yoffset >= 0)
415         {
416             glTexSubImage2D(GL_TEXTURE_2D, 0, xoffset, yoffset, width, height,
417                          texture_format, format, pixels);
418             glDebug("glTexSubImage2D");
419         }
420         else
421         {
422             glTexImage2D(GL_TEXTURE_2D, 0, bpp, width, height, 0,
423                          texture_format, format, pixels);
424             glDebug("glTexImage2D");
425         }
426     }
427 }
428 
reset_view_for_redraw()429 void OGLStateManager::reset_view_for_redraw()
430 {
431     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
432     glMatrixMode(GL_MODELVIEW);
433     glLoadIdentity();
434 
435     glTranslatef(0.0f, 0.0f, 1.0f);
436     glDebug("glTranslatef");
437 }
438 
439 #ifdef __ANDROID__
fixup_gl_state()440 void OGLStateManager::fixup_gl_state()
441 {
442     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
443     glClearColor(0.0, 0.0, 0.0, 1.0f);
444     glDepthFunc(GL_LEQUAL);
445 
446     glEnable(GL_TEXTURE_2D);
447     glBindTexture(GL_TEXTURE_2D, m_last_tex);
448     glDebug("glBindTexture (REBIND)");
449     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
450     glDebug("glTexEnvf (REBIND)");
451 
452     if (m_current_state.array_vertex)
453     {
454         glEnableClientState(GL_VERTEX_ARRAY);
455         glDebug("glEnableClientState(GL_VERTEX_ARRAY)");
456     }
457     else
458     {
459         glDisableClientState(GL_VERTEX_ARRAY);
460         glDebug("glDisableClientState(GL_VERTEX_ARRAY)");
461     }
462     if (m_current_state.array_texcoord)
463     {
464         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
465         glDebug("glEnableClientState(GL_TEXTURE_COORD_ARRAY)");
466     }
467     else
468     {
469         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
470         glDebug("glDisableClientState(GL_TEXTURE_COORD_ARRAY)");
471     }
472     if (m_current_state.array_colour)
473     {
474         glEnableClientState(GL_COLOR_ARRAY);
475         glDebug("glEnableClientState(GL_COLOR_ARRAY)");
476         glColor4f(m_current_state.colour.r, m_current_state.colour.g,
477                   m_current_state.colour.b, m_current_state.colour.a);
478         glDebug("glColor4f");
479     }
480     else
481     {
482         glDisableClientState(GL_COLOR_ARRAY);
483         glDebug("glDisableClientState(GL_COLOR_ARRAY)");
484 
485         // [enne] This should *not* be necessary, but the Linux OpenGL
486         // driver that I'm using sets this to the last colour of the
487         // colour array. So, we need to unset it here.
488         glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
489         glDebug("glColor4f(1.0f, 1.0f, 1.0f, 1.0f)");
490     }
491     if (m_current_state.texture)
492     {
493         // glEnable(GL_TEXTURE_2D);
494         // glDebug("glEnable(GL_TEXTURE_2D)");
495     }
496     else
497     {
498         glDisable(GL_TEXTURE_2D);
499         glDebug("glDisable(GL_TEXTURE_2D)");
500     }
501     if (m_current_state.blend)
502     {
503         glEnable(GL_BLEND);
504         glDebug("glEnable(GL_BLEND)");
505     }
506     else
507     {
508         glDisable(GL_BLEND);
509         glDebug("glDisable(GL_BLEND)");
510     }
511     if (m_current_state.depthtest)
512     {
513         glEnable(GL_DEPTH_TEST);
514         glDebug("glEnable(GL_DEPTH_TEST)");
515     }
516     else
517     {
518         glDisable(GL_DEPTH_TEST);
519         glDebug("glEnable(GL_DEPTH_TEST)");
520     }
521     if (m_current_state.alphatest)
522     {
523         glEnable(GL_ALPHA_TEST);
524         glAlphaFunc(GL_NOTEQUAL, m_current_state.alpharef);
525         glDebug("glAlphaFunc(GL_NOTEQUAL, state.alpharef)");
526     }
527     else
528     {
529         glDisable(GL_ALPHA_TEST);
530         glDebug("glDisable(GL_ALPHA_TEST)");
531     }
532 }
533 #endif
534 
glDebug(const char * msg) const535 bool OGLStateManager::glDebug(const char* msg) const
536 {
537 #if defined(__ANDROID__) || defined(DEBUG_DIAGNOSTICS)
538     int e = glGetError();
539     if (e > 0)
540     {
541 # ifdef __ANDROID__
542         __android_log_print(ANDROID_LOG_INFO, "Crawl.gl", "ERROR %x: %s", e, msg);
543 # else
544         fprintf(stderr, "OGLStateManager ERROR %x: %s\n", e, msg);
545 # endif
546         return true;
547     }
548 #else
549     UNUSED(msg);
550 #endif
551     return false;
552 }
553 
554 /////////////////////////////////////////////////////////////////////////////
555 // OGLShapeBuffer
556 
OGLShapeBuffer(bool texture,bool colour,drawing_modes prim)557 OGLShapeBuffer::OGLShapeBuffer(bool texture, bool colour, drawing_modes prim) :
558     m_prim_type(prim),
559     m_texture_verts(texture),
560     m_colour_verts(colour)
561 {
562     ASSERT(prim == GLW_RECTANGLE || prim == GLW_LINES);
563 }
564 
print_statistics() const565 const char *OGLShapeBuffer::print_statistics() const
566 {
567     return nullptr;
568 }
569 
size() const570 unsigned int OGLShapeBuffer::size() const
571 {
572     return m_position_buffer.size();
573 }
574 
add(const GLWPrim & rect)575 void OGLShapeBuffer::add(const GLWPrim &rect)
576 {
577     switch (m_prim_type)
578     {
579     case GLW_RECTANGLE:
580         add_rect(rect);
581         break;
582     case GLW_LINES:
583         add_line(rect);
584         break;
585     default:
586         die("Invalid primitive type");
587         break;
588     }
589 }
590 
add_rect(const GLWPrim & rect)591 void OGLShapeBuffer::add_rect(const GLWPrim &rect)
592 {
593     // Copy vert positions
594     size_t last = m_position_buffer.size();
595     m_position_buffer.resize(last + 4);
596     m_position_buffer[last    ].set(rect.pos_sx, rect.pos_sy, rect.pos_z);
597     m_position_buffer[last + 1].set(rect.pos_sx, rect.pos_ey, rect.pos_z);
598     m_position_buffer[last + 2].set(rect.pos_ex, rect.pos_sy, rect.pos_z);
599     m_position_buffer[last + 3].set(rect.pos_ex, rect.pos_ey, rect.pos_z);
600 
601     // Copy texture coords if necessary
602     if (m_texture_verts)
603     {
604         last = m_texture_buffer.size();
605         m_texture_buffer.resize(last + 4);
606         m_texture_buffer[last    ].set(rect.tex_sx, rect.tex_sy);
607         m_texture_buffer[last + 1].set(rect.tex_sx, rect.tex_ey);
608         m_texture_buffer[last + 2].set(rect.tex_ex, rect.tex_sy);
609         m_texture_buffer[last + 3].set(rect.tex_ex, rect.tex_ey);
610     }
611 
612     // Copy vert colours if necessary
613     if (m_colour_verts)
614     {
615         last = m_colour_buffer.size();
616         m_colour_buffer.resize(last + 4);
617         m_colour_buffer[last    ].set(rect.col_s);
618         m_colour_buffer[last + 1].set(rect.col_e);
619         m_colour_buffer[last + 2].set(rect.col_s);
620         m_colour_buffer[last + 3].set(rect.col_e);
621     }
622 
623     // build indices
624     last = m_ind_buffer.size();
625 
626     if (last > 3)
627     {
628         // This is not the first box so make FOUR degenerate triangles
629         m_ind_buffer.resize(last + 6);
630         unsigned short int val = m_ind_buffer[last - 1];
631 
632         // the first three degens finish the previous box and move
633         // to the first position of the new one we just added and
634         // the fourth degen creates a triangle that is a line from p1 to p3
635         m_ind_buffer[last    ] = val++;
636         m_ind_buffer[last + 1] = val;
637 
638         // Now add as normal
639         m_ind_buffer[last + 2] = val++;
640         m_ind_buffer[last + 3] = val++;
641         m_ind_buffer[last + 4] = val++;
642         m_ind_buffer[last + 5] = val;
643     }
644     else
645     {
646         // This is the first box so don't bother making any degenerate triangles
647         m_ind_buffer.resize(last + 4);
648         m_ind_buffer[0] = 0;
649         m_ind_buffer[1] = 1;
650         m_ind_buffer[2] = 2;
651         m_ind_buffer[3] = 3;
652     }
653 }
654 
add_line(const GLWPrim & rect)655 void OGLShapeBuffer::add_line(const GLWPrim &rect)
656 {
657     // Copy vert positions
658     size_t last = m_position_buffer.size();
659     m_position_buffer.resize(last + 2);
660     m_position_buffer[last    ].set(rect.pos_sx, rect.pos_sy, rect.pos_z);
661     m_position_buffer[last + 1].set(rect.pos_ex, rect.pos_ey, rect.pos_z);
662 
663     // Copy texture coords if necessary
664     if (m_texture_verts)
665     {
666         last = m_texture_buffer.size();
667         m_texture_buffer.resize(last + 2);
668         m_texture_buffer[last    ].set(rect.tex_sx, rect.tex_sy);
669         m_texture_buffer[last + 1].set(rect.tex_ex, rect.tex_ey);
670     }
671 
672     // Copy vert colours if necessary
673     if (m_colour_verts)
674     {
675         last = m_colour_buffer.size();
676         m_colour_buffer.resize(last + 2);
677         m_colour_buffer[last    ].set(rect.col_s);
678         m_colour_buffer[last + 1].set(rect.col_e);
679     }
680 }
681 
682 // Draw the buffer
draw(const GLState & state)683 void OGLShapeBuffer::draw(const GLState &state)
684 {
685     if (m_position_buffer.empty())
686         return;
687 
688     if (!state.array_vertex)
689         return;
690 
691     glmanager->set(state);
692 
693     glVertexPointer(3, GL_FLOAT, 0, &m_position_buffer[0]);
694     glDebug("glVertexPointer");
695 
696     if (state.array_texcoord && m_texture_verts)
697         glTexCoordPointer(2, GL_FLOAT, 0, &m_texture_buffer[0]);
698     glDebug("glTexCoordPointer");
699 
700     if (state.array_colour && m_colour_verts)
701         glColorPointer(4, GL_UNSIGNED_BYTE, 0, &m_colour_buffer[0]);
702     glDebug("glColorPointer");
703 
704     switch (m_prim_type)
705     {
706     case GLW_RECTANGLE:
707         glDrawElements(GL_TRIANGLE_STRIP, m_ind_buffer.size(),
708                        GL_UNSIGNED_SHORT, &m_ind_buffer[0]);
709         break;
710     case GLW_LINES:
711         glDrawArrays(GL_LINES, 0, m_position_buffer.size());
712         break;
713     default:
714         die("Invalid primitive type");
715         break;
716     }
717     glDebug("glDrawElements");
718 }
719 
clear()720 void OGLShapeBuffer::clear()
721 {
722     m_position_buffer.clear();
723     m_ind_buffer.clear();
724     m_texture_buffer.clear();
725     m_colour_buffer.clear();
726 }
727 
glDebug(const char * msg) const728 bool OGLShapeBuffer::glDebug(const char* msg) const
729 {
730 #if defined(__ANDROID__) || defined(DEBUG_DIAGNOSTICS)
731     int e = glGetError();
732     if (e > 0)
733     {
734 # ifdef __ANDROID__
735         __android_log_print(ANDROID_LOG_INFO, "Crawl.gl", "ERROR %x: %s", e, msg);
736 # else
737         fprintf(stderr, "OGLShapeBuffer ERROR %x: %s\n", e, msg);
738 # endif
739         return true;
740     }
741 #else
742     UNUSED(msg);
743 #endif
744     return false;
745 }
746 
747 #endif // USE_GL
748 #endif // USE_TILE_LOCAL
749