1
2 /*
3 Copyright (C) 2007 by David White <dave@whitevine.net>
4 Part of the Silver Tree Project
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License version 2 or later.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY.
10
11 See the COPYING file for more details.
12 */
13 #include "graphics.hpp"
14
15 #include "asserts.hpp"
16 #include "foreach.hpp"
17 #include "preferences.hpp"
18 #include "raster.hpp"
19 #include "raster_distortion.hpp"
20 #include "rectangle_rotator.hpp"
21
22 #include <boost/shared_array.hpp>
23 #include <iostream>
24 #include <cmath>
25
26 namespace graphics
27 {
28
29 namespace {
30
transform_point(GLfloat out[4],const GLfloat m[16],const GLfloat in[4])31 static void transform_point(GLfloat out[4], const GLfloat m[16], const GLfloat in[4])
32 {
33 #define M(row,col) m[col*4+row]
34 out[0] = M(0, 0) * in[0] + M(0, 1) * in[1] + M(0, 2) * in[2] + M(0, 3) * in[3];
35 out[1] = M(1, 0) * in[0] + M(1, 1) * in[1] + M(1, 2) * in[2] + M(1, 3) * in[3];
36 out[2] = M(2, 0) * in[0] + M(2, 1) * in[1] + M(2, 2) * in[2] + M(2, 3) * in[3];
37 out[3] = M(3, 0) * in[0] + M(3, 1) * in[1] + M(3, 2) * in[2] + M(3, 3) * in[3];
38 #undef M
39 }
40
gluProjectf(GLfloat objx,GLfloat objy,GLfloat objz,const GLfloat model[16],const GLfloat proj[16],const GLint viewport[4],GLfloat * winx,GLfloat * winy,GLfloat * winz)41 static GLboolean gluProjectf(GLfloat objx, GLfloat objy, GLfloat objz,
42 const GLfloat model[16], const GLfloat proj[16],
43 const GLint viewport[4],
44 GLfloat * winx, GLfloat * winy, GLfloat * winz)
45 {
46 // transformation matrix
47 GLfloat in[4], out[4];
48
49 // Initialise transformation matrix with vector
50 in[0] = objx;
51 in[1] = objy;
52 in[2] = objz;
53 in[3] = 1.0f;
54 transform_point(out, model, in);
55 transform_point(in, proj, out);
56
57 // Normalise
58 if (in[3] == 0.0f)
59 return GL_FALSE;
60
61 in[0] /= in[3];
62 in[1] /= in[3];
63 in[2] /= in[3];
64
65 *winx = viewport[0] + (1.0f + in[0]) * viewport[2] / 2.0f;
66 *winy = viewport[1] + (1.0f + in[1]) * viewport[3] / 2.0f;
67 *winz = (1.0f + in[2]) / 2.0f;
68 return GL_TRUE;
69 }
70
71 }
72
reset_opengl_state()73 void reset_opengl_state()
74 {
75 glShadeModel(GL_SMOOTH);
76 glEnable(GL_BLEND);
77 glEnable(GL_TEXTURE_2D);
78 #if !defined(USE_GLES2)
79 glEnableClientState(GL_VERTEX_ARRAY);
80 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
81 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
82 #endif
83
84 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
85
86 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
87 #if defined(USE_GLES2)
88 glClearColor(0.0,0.0,0.0,0.0);
89 gles2::init_default_shader();
90 #endif
91 }
92
set_video_mode(int w,int h)93 bool set_video_mode(int w, int h)
94 {
95 #ifdef TARGET_OS_HARMATTAN
96 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1);
97 return set_video_mode(w,h,0,SDL_OPENGLES | SDL_FULLSCREEN);
98 #else
99 return set_video_mode(w,h,0,SDL_OPENGL|(preferences::resizable() ? SDL_RESIZABLE : 0)|(preferences::fullscreen() ? SDL_FULLSCREEN : 0)) != NULL;
100 #endif
101 }
102
set_video_mode(int w,int h,int bitsperpixel,int flags)103 SDL_Surface* set_video_mode(int w, int h, int bitsperpixel, int flags)
104 {
105 graphics::texture::unbuild_all();
106 SDL_Surface* result = SDL_SetVideoMode(w,h,bitsperpixel,flags);
107 reset_opengl_state();
108 graphics::texture::rebuild_all();
109
110 return result;
111 }
112
113 /* unavoidable global variable to store global clip
114 rectangle changes */
115 std::vector<boost::shared_array<GLint> > clip_rectangles;
116
global_vertex_array()117 std::vector<GLfloat>& global_vertex_array()
118 {
119 static std::vector<GLfloat> v;
120 return v;
121 }
122
global_texcoords_array()123 std::vector<GLfloat>& global_texcoords_array()
124 {
125 static std::vector<GLfloat> v;
126 return v;
127 }
128
global_vertex_color_array()129 std::vector<GLbyte>& global_vertex_color_array()
130 {
131 static std::vector<GLbyte> v;
132 return v;
133 }
134
135 #if defined(SDL_VIDEO_OPENGL_ES) && !defined(__native_client__)
136 #define glOrtho glOrthof
137 #endif
138
prepare_raster()139 void prepare_raster()
140 {
141 // int real_w, real_h;
142 // bool rotated;
143
144 #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
145 // real_w = 320;
146 // real_h = 480;
147 // rotated = true;
148 #elif defined(__native_client__)
149 // do nothing.
150 #else
151 const SDL_Surface* fb = SDL_GetVideoSurface();
152 if(fb == NULL) {
153 std::cerr << "Framebuffer was null in prepare_raster\n";
154 return;
155 }
156 // real_w = fb->w;
157 // real_h = fb->h;
158 // rotated = false;
159 #endif
160
161 glViewport(0, 0, preferences::actual_screen_width(), preferences::actual_screen_height());
162 // glClearColor(0.0, 0.0, 0.0, 0.0);
163 // glClear(GL_COLOR_BUFFER_BIT);
164 glShadeModel(GL_FLAT);
165 glMatrixMode(GL_PROJECTION);
166 glLoadIdentity();
167
168 if(preferences::screen_rotated()) {
169 // glOrtho(0, 640, 960, 0, -1.0, 1.0);
170 #if defined(USE_GLES2) && defined(GL_ES_VERSION_2_0)
171 glOrthof(0, screen_height(), screen_width(), 0, -1.0, 1.0);
172 #else
173 glOrtho(0, screen_height(), screen_width(), 0, -1.0, 1.0);
174 #endif
175 } else {
176 #if defined(USE_GLES2) && defined(GL_ES_VERSION_2_0)
177 glOrthof(0, screen_width(), screen_height(), 0, -1.0, 1.0);
178 #else
179 glOrtho(0, screen_width(), screen_height(), 0, -1.0, 1.0);
180 #endif
181 }
182
183 //glOrtho(0, real_w, real_h, 0, -1.0, 1.0);
184 if(preferences::screen_rotated()) {
185 // Rotate 90 degrees ccw, then move real_h pixels down
186 // This has to be in opposite order since A(); B(); means A(B(x))
187 glTranslatef(screen_height(), 0.0f, 0.0f);
188 glRotatef(90.0f, 0.0f, 0.0f, 1.0f);
189 //glTranslatef(0.0f, 0.5f, 0.0f);
190 //glScalef(0.5f, 0.5f, 1.0f);
191 }
192
193 glMatrixMode(GL_MODELVIEW);
194 glLoadIdentity();
195
196 glDisable(GL_DEPTH_TEST);
197 #if !defined(USE_GLES2)
198 glDisable(GL_LIGHTING);
199 glDisable(GL_LIGHT0);
200 #endif
201
202 glColor4f(1.0, 1.0, 1.0, 1.0);
203 }
204
205 /*void prepare_raster()
206 {
207 #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
208 int w = 320;
209 int h = 480;
210 #else
211 const SDL_Surface* fb = SDL_GetVideoSurface();
212 if(fb == NULL) {
213 std::cerr << "Framebuffer was null in prepare_raster\n";
214 return;
215 }
216 int w = fb->w;
217 int h = fb->h;
218 #endif
219
220 glViewport(0,0,w,h);
221 glClearColor(0.0,0.0,0.0,0.0);
222 glClear(GL_COLOR_BUFFER_BIT);
223 glShadeModel(GL_FLAT);
224 glMatrixMode(GL_PROJECTION);
225 glLoadIdentity();
226 #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
227 glScalef(0.25f, 0.25f, 1.0f);
228 glRotatef(-90.0f, 0.0f, 0.0f, 1.0f);
229 #endif
230 #ifdef SDL_VIDEO_OPENGL_ES
231 #define glOrtho glOrthof
232 #endif
233 glOrtho(0,screen_width(),screen_height(),0,-1.0,1.0);
234 glMatrixMode(GL_MODELVIEW);
235 glLoadIdentity();
236
237 glDisable(GL_DEPTH_TEST);
238 glDisable(GL_LIGHTING);
239 glDisable(GL_LIGHT0);
240
241 glColor4f(1.0, 1.0, 1.0, 1.0);
242 }*/
243
244 namespace {
245 struct draw_detection_rect {
246 rect area;
247 char* buf;
248 };
249
250 std::vector<draw_detection_rect> draw_detection_rects_;
251 rect draw_detection_rect_;
252 char* draw_detection_buf_;
253
254 std::vector<const raster_distortion*> distortions_;
255 }
256
blit_texture(const texture & tex,int x,int y,GLfloat rotate)257 void blit_texture(const texture& tex, int x, int y, GLfloat rotate)
258 {
259 if(!tex.valid()) {
260 return;
261 }
262
263 x &= preferences::xypos_draw_mask;
264 y &= preferences::xypos_draw_mask;
265
266 int h = tex.height();
267 int w = tex.width();
268 const int w_odd = w % 2;
269 const int h_odd = h % 2;
270 h /= 2;
271 w /= 2;
272
273 glPushMatrix();
274
275 glTranslatef(x+w,y+h,0.0);
276 glRotatef(rotate,0.0,0.0,1.0);
277
278 tex.set_as_current_texture();
279
280 GLfloat varray[] = {
281 -w, -h,
282 -w, h+h_odd,
283 w+w_odd, -h,
284 w+w_odd, h+h_odd
285 };
286 GLfloat tcarray[] = {
287 texture::get_coord_x(0.0), texture::get_coord_y(0.0),
288 texture::get_coord_x(0.0), texture::get_coord_y(1.0),
289 texture::get_coord_x(1.0), texture::get_coord_y(0.0),
290 texture::get_coord_x(1.0), texture::get_coord_y(1.0)
291 };
292 #if defined(USE_GLES2)
293 gles2::active_shader()->prepare_draw();
294 gles2::active_shader()->shader()->vertex_array(2, GL_FLOAT, 0, 0, varray);
295 gles2::active_shader()->shader()->texture_array(2, GL_FLOAT, 0, 0, tcarray);
296 #else
297 glVertexPointer(2, GL_FLOAT, 0, varray);
298 glTexCoordPointer(2, GL_FLOAT, 0, tcarray);
299 #endif
300 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
301
302 glPopMatrix();
303 }
304
305 namespace {
306
307 //function which marks the draw detection buffer with pixels drawn.
detect_draw(const texture & tex,int x,int y,int orig_w,int orig_h,GLfloat x1,GLfloat y1,GLfloat x2,GLfloat y2)308 void detect_draw(const texture& tex, int x, int y, int orig_w, int orig_h, GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
309 {
310 if(draw_detection_rects_.empty()) {
311 return;
312 }
313
314 rect draw_rect(x, y, std::abs(orig_w), std::abs(orig_h));
315
316 foreach(const draw_detection_rect& detect, draw_detection_rects_) {
317 if(rects_intersect(draw_rect, detect.area)) {
318 rect r = intersection_rect(draw_rect, detect.area);
319 for(int ypos = r.y(); ypos != r.y2(); ++ypos) {
320 for(int xpos = r.x(); xpos != r.x2(); ++xpos) {
321 const GLfloat u = (GLfloat(draw_rect.x2() - xpos)*x1 + GLfloat(xpos - draw_rect.x())*x2)/GLfloat(draw_rect.w());
322 const GLfloat v = (GLfloat(draw_rect.y2() - ypos)*y1 + GLfloat(ypos - draw_rect.y())*y2)/GLfloat(draw_rect.h());
323 const int texture_x = u*tex.width();
324 const int texture_y = v*tex.height();
325 ASSERT_GE(texture_x, 0);
326 ASSERT_GE(texture_y, 0);
327 ASSERT_LOG(texture_x < tex.width(), texture_x << " < " << tex.width() << " " << r.x() << " " << r.x2() << " " << xpos << " x: " << x1 << " x2: " << x2 << " u: " << u << "\n");
328 ASSERT_LT(texture_x, tex.width());
329 ASSERT_LT(texture_y, tex.height());
330 const bool alpha = tex.is_alpha(texture_x, texture_y);
331 if(!alpha) {
332 const int buf_x = xpos - detect.area.x();
333 const int buf_y = ypos - detect.area.y();
334 const int buf_index = buf_y*detect.area.w() + buf_x;
335 ASSERT_LOG(buf_index >= 0, xpos << ", " << ypos << " -> " << buf_x << ", " << buf_y << " -> " << buf_index << " in " << detect.area << "\n");
336 ASSERT_GE(buf_index, 0);
337 ASSERT_LT(buf_index, detect.area.w()*detect.area.h());
338 detect.buf[buf_index] = true;
339 }
340 }
341 }
342 }
343 }
344 }
345
blit_texture_internal(const texture & tex,int x,int y,int w,int h,GLfloat rotate,GLfloat x1,GLfloat y1,GLfloat x2,GLfloat y2)346 void blit_texture_internal(const texture& tex, int x, int y, int w, int h, GLfloat rotate, GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
347 {
348 if(!tex.valid()) {
349 return;
350 }
351
352 const int w_odd = w % 2;
353 const int h_odd = h % 2;
354
355 w /= 2;
356 h /= 2;
357 glPushMatrix();
358 tex.set_as_current_texture();
359 glTranslatef(x+abs(w),y+abs(h),0.0);
360 glRotatef(rotate,0.0,0.0,1.0);
361 GLfloat varray[] = {
362 -w, -h,
363 -w, h+h_odd,
364 w+w_odd, -h,
365 w+w_odd, h+h_odd
366 };
367 GLfloat tcarray[] = {
368 texture::get_coord_x(x1), texture::get_coord_y(y1),
369 texture::get_coord_x(x1), texture::get_coord_y(y2),
370 texture::get_coord_x(x2), texture::get_coord_y(y1),
371 texture::get_coord_x(x2), texture::get_coord_y(y2)
372 };
373 #if defined(USE_GLES2)
374 gles2::active_shader()->prepare_draw();
375 gles2::active_shader()->shader()->vertex_array(2, GL_FLOAT, 0, 0, varray);
376 gles2::active_shader()->shader()->texture_array(2, GL_FLOAT, 0, 0, tcarray);
377 #else
378 glVertexPointer(2, GL_FLOAT, 0, varray);
379 glTexCoordPointer(2, GL_FLOAT, 0, tcarray);
380 #endif
381 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
382 glPopMatrix();
383 }
384
blit_texture_with_distortion(const texture & tex,int x,int y,int w,int h,GLfloat rotate,GLfloat x1,GLfloat y1,GLfloat x2,GLfloat y2,const raster_distortion & distort)385 void blit_texture_with_distortion(const texture& tex, int x, int y, int w, int h, GLfloat rotate, GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2, const raster_distortion& distort)
386 {
387 const rect& area = distort.area();
388 if(x < area.x()) {
389 const int new_x = area.x();
390 const GLfloat new_x1 = (x1*(x + w - new_x) + x2*(new_x - x))/w;
391
392 blit_texture(tex, x, y, new_x - x, h, rotate, x1, y1, new_x1, y2);
393
394 x1 = new_x1;
395 w -= new_x - x;
396 x = new_x;
397 }
398
399 if(y < area.y()) {
400 const int new_y = area.y();
401 const GLfloat new_y1 = (y1*(y + h - new_y) + y2*(new_y - y))/h;
402
403 blit_texture(tex, x, y, w, new_y - y, rotate, x1, y1, x2, new_y1);
404
405 y1 = new_y1;
406 h -= new_y - y;
407 y = new_y;
408 }
409
410 if(x + w > area.x2()) {
411 const int new_w = area.x2() - x;
412 const int new_xpos = x + new_w;
413 const GLfloat new_x2 = (x1*(x + w - new_xpos) + x2*(new_xpos - x))/w;
414
415 blit_texture(tex, new_xpos, y, x + w - new_xpos, h, rotate, new_x2, y1, x2, y2);
416
417 x2 = new_x2;
418 w = new_w;
419 }
420
421 if(y + h > area.y2()) {
422 const int new_h = area.y2() - y;
423 const int new_ypos = y + new_h;
424 const GLfloat new_y2 = (y1*(y + h - new_ypos) + y2*(new_ypos - y))/h;
425
426 blit_texture(tex, x, new_ypos, w, y + h - new_ypos, rotate, x1, new_y2, x2, y2);
427
428 y2 = new_y2;
429 h = new_h;
430 }
431
432 tex.set_as_current_texture();
433
434 const int xdiff = distort.granularity_x();
435 const int ydiff = distort.granularity_y();
436 for(int xpos = 0; xpos < w; xpos += xdiff) {
437 const int xbegin = x + xpos;
438 const int xend = std::min<int>(x + w, xbegin + xdiff);
439
440 const GLfloat u1 = (x1*(x+w - xbegin) + x2*(xbegin - x))/w;
441 const GLfloat u2 = (x1*(x+w - xend) + x2*(xend - x))/w;
442 for(int ypos = 0; ypos < h; ypos += ydiff) {
443 const int ybegin = y + ypos;
444 const int yend = std::min<int>(y + h, ybegin + ydiff);
445
446 const GLfloat v1 = (y1*(y+h - ybegin) + y2*(ybegin - y))/h;
447 const GLfloat v2 = (y1*(y+h - yend) + y2*(yend - y))/h;
448
449 GLfloat points[8] = { xbegin, ybegin, xend, ybegin, xbegin, yend, xend, yend };
450 GLfloat uv[8] = { u1, v1, u2, v1, u1, v2, u2, v2 };
451
452 for(int n = 0; n != 4; ++n) {
453 distort.distort_point(&points[n*2], &points[n*2 + 1]);
454 }
455
456 #if defined(USE_GLES2)
457 gles2::active_shader()->prepare_draw();
458 gles2::active_shader()->shader()->vertex_array(2, GL_FLOAT, 0, 0, points);
459 gles2::active_shader()->shader()->texture_array(2, GL_FLOAT, 0, 0, uv);
460 #else
461 glVertexPointer(2, GL_FLOAT, 0, points);
462 glTexCoordPointer(2, GL_FLOAT, 0, uv);
463 #endif
464 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
465 }
466 }
467 }
468
469 int blit_texture_translate_x = 0;
470 int blit_texture_translate_y = 0;
471
472 } // namespace
473
distortion_translation()474 distortion_translation::distortion_translation()
475 : x_(0), y_(0)
476 {
477 }
478
~distortion_translation()479 distortion_translation::~distortion_translation()
480 {
481 if(x_ || y_) {
482 foreach(const raster_distortion* distort, distortions_) {
483 rect r = distort->area();
484 r = rect(r.x() + x_, r.y() + y_, r.w(), r.h());
485 const_cast<raster_distortion*>(distort)->set_area(r);
486 }
487 }
488 }
489
translate(int x,int y)490 void distortion_translation::translate(int x, int y)
491 {
492 x_ += x;
493 y_ += y;
494
495 foreach(const raster_distortion* distort, distortions_) {
496 rect r = distort->area();
497 r = rect(r.x() - x, r.y() - y, r.w(), r.h());
498 const_cast<raster_distortion*>(distort)->set_area(r);
499 }
500 }
501
blit_texture(const texture & tex,int x,int y,int w,int h,GLfloat rotate,GLfloat x1,GLfloat y1,GLfloat x2,GLfloat y2)502 void blit_texture(const texture& tex, int x, int y, int w, int h, GLfloat rotate, GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
503 {
504 x &= preferences::xypos_draw_mask;
505 y &= preferences::xypos_draw_mask;
506
507 if(w < 0) {
508 std::swap(x1, x2);
509 w *= -1;
510 }
511
512 if(h < 0) {
513 std::swap(y1, y2);
514 h *= -1;
515 }
516
517 detect_draw(tex, x, y, w, h, x1, y1, x2, y2);
518
519 for(std::vector<const raster_distortion*>::const_iterator i = distortions_.begin(); i != distortions_.end() && rotate == 0.0; ++i) {
520 const raster_distortion& distort = **i;
521 if(rects_intersect(rect(x, y, w, h), distort.area())) {
522 blit_texture_with_distortion(tex, x, y, w, h, rotate, x1, y1, x2, y2, distort);
523 return;
524 }
525 }
526 blit_texture_internal(tex, x, y, w, h, rotate, x1, y1, x2, y2);
527 }
528
529 namespace {
530 const texture* blit_current_texture;
531 std::vector<GLfloat> blit_tcqueue;
532 std::vector<GLshort> blit_vqueue;
533 }
534
queue_blit_texture(const texture & tex,int x,int y,int w,int h,GLfloat x1,GLfloat y1,GLfloat x2,GLfloat y2)535 void queue_blit_texture(const texture& tex, int x, int y, int w, int h,
536 GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
537 {
538 x &= preferences::xypos_draw_mask;
539 y &= preferences::xypos_draw_mask;
540
541 if(&tex != blit_current_texture) {
542 flush_blit_texture();
543 blit_current_texture = &tex;
544 }
545
546 x1 = tex.translate_coord_x(x1);
547 y1 = tex.translate_coord_y(y1);
548 x2 = tex.translate_coord_x(x2);
549 y2 = tex.translate_coord_y(y2);
550
551 if(w < 0) {
552 std::swap(x1, x2);
553 w *= -1;
554 }
555
556 if(h < 0) {
557 std::swap(y1, y2);
558 h *= -1;
559 }
560
561 blit_tcqueue.push_back(x1);
562 blit_tcqueue.push_back(y1);
563 blit_tcqueue.push_back(x2);
564 blit_tcqueue.push_back(y1);
565 blit_tcqueue.push_back(x1);
566 blit_tcqueue.push_back(y2);
567 blit_tcqueue.push_back(x2);
568 blit_tcqueue.push_back(y2);
569
570 blit_vqueue.push_back(x);
571 blit_vqueue.push_back(y);
572 blit_vqueue.push_back(x + w);
573 blit_vqueue.push_back(y);
574 blit_vqueue.push_back(x);
575 blit_vqueue.push_back(y + h);
576 blit_vqueue.push_back(x + w);
577 blit_vqueue.push_back(y + h);
578 }
579
queue_blit_texture(const texture & tex,int x,int y,int w,int h,GLfloat rotate,GLfloat x1,GLfloat y1,GLfloat x2,GLfloat y2)580 void queue_blit_texture(const texture& tex, int x, int y, int w, int h, GLfloat rotate,
581 GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
582 {
583 x &= preferences::xypos_draw_mask;
584 y &= preferences::xypos_draw_mask;
585
586 if(&tex != blit_current_texture) {
587 flush_blit_texture();
588 blit_current_texture = &tex;
589 }
590
591 x1 = tex.translate_coord_x(x1);
592 y1 = tex.translate_coord_y(y1);
593 x2 = tex.translate_coord_x(x2);
594 y2 = tex.translate_coord_y(y2);
595
596 if(w < 0) {
597 std::swap(x1, x2);
598 w *= -1;
599 }
600
601 if(h < 0) {
602 std::swap(y1, y2);
603 h *= -1;
604 }
605
606 blit_tcqueue.push_back(x1);
607 blit_tcqueue.push_back(y1);
608 blit_tcqueue.push_back(x2);
609 blit_tcqueue.push_back(y1);
610 blit_tcqueue.push_back(x1);
611 blit_tcqueue.push_back(y2);
612 blit_tcqueue.push_back(x2);
613 blit_tcqueue.push_back(y2);
614
615
616
617 blit_vqueue.push_back(x);
618 blit_vqueue.push_back(y);
619 blit_vqueue.push_back(x + w);
620 blit_vqueue.push_back(y);
621 blit_vqueue.push_back(x);
622 blit_vqueue.push_back(y + h);
623 blit_vqueue.push_back(x + w);
624 blit_vqueue.push_back(y + h);
625
626 rect r(x,y,w,h);
627 GLshort* varray = &blit_vqueue[blit_vqueue.size()-8];
628 rotate_rect(x+(w/2), y+(h/2), rotate, varray);
629
630 }
631
flush_blit_texture()632 void flush_blit_texture()
633 {
634 if(!blit_current_texture) {
635 return;
636 }
637
638 blit_current_texture->set_as_current_texture();
639 #if defined(USE_GLES2)
640 gles2::active_shader()->prepare_draw();
641 gles2::active_shader()->shader()->vertex_array(2, GL_SHORT, 0, 0, &blit_vqueue.front());
642 gles2::active_shader()->shader()->texture_array(2, GL_FLOAT, 0, 0, &blit_tcqueue.front());
643 #else
644 glVertexPointer(2, GL_SHORT, 0, &blit_vqueue.front());
645 glTexCoordPointer(2, GL_FLOAT, 0, &blit_tcqueue.front());
646 #endif
647 glDrawArrays(GL_TRIANGLE_STRIP, 0, blit_tcqueue.size()/2);
648
649 blit_current_texture = NULL;
650 blit_tcqueue.clear();
651 blit_vqueue.clear();
652 }
653
clear()654 void blit_queue::clear()
655 {
656 texture_ = 0;
657 vertex_.clear();
658 uv_.clear();
659 }
660
do_blit() const661 void blit_queue::do_blit() const
662 {
663 if(vertex_.empty()) {
664 return;
665 }
666
667 texture::set_current_texture(texture_);
668
669 #if defined(USE_GLES2)
670 gles2::active_shader()->prepare_draw();
671 gles2::active_shader()->shader()->vertex_array(2, GL_SHORT, 0, 0, &vertex_.front());
672 gles2::active_shader()->shader()->texture_array(2, GL_FLOAT, 0, 0, &uv_.front());
673 #else
674 glVertexPointer(2, GL_SHORT, 0, &vertex_.front());
675 glTexCoordPointer(2, GL_FLOAT, 0, &uv_.front());
676 #endif
677 glDrawArrays(GL_TRIANGLE_STRIP, 0, uv_.size()/2);
678 }
679
do_blit_range(short begin,short end) const680 void blit_queue::do_blit_range(short begin, short end) const
681 {
682 if(vertex_.empty()) {
683 return;
684 }
685
686 texture::set_current_texture(texture_);
687
688 #if defined(USE_GLES2)
689 gles2::active_shader()->prepare_draw();
690 gles2::active_shader()->shader()->vertex_array(2, GL_SHORT, 0, 0, &vertex_[begin]);
691 gles2::active_shader()->shader()->texture_array(2, GL_FLOAT, 0, 0, &uv_[begin]);
692 #else
693 glVertexPointer(2, GL_SHORT, 0, &vertex_[begin]);
694 glTexCoordPointer(2, GL_FLOAT, 0, &uv_[begin]);
695 #endif
696 glDrawArrays(GL_TRIANGLE_STRIP, 0, (end - begin)/2);
697 }
698
merge(const blit_queue & q,short begin,short end)699 bool blit_queue::merge(const blit_queue& q, short begin, short end)
700 {
701 if(vertex_.empty()) {
702 texture_ = q.texture_;
703 vertex_.insert(vertex_.end(), q.vertex_.begin()+begin, q.vertex_.begin()+end);
704 uv_.insert(uv_.end(), q.uv_.begin()+begin, q.uv_.begin()+end);
705 return true;
706 }
707
708 if(texture_ != q.texture_) {
709 return false;
710 }
711
712 repeat_last();
713 vertex_.push_back(q.vertex_[begin]);
714 vertex_.push_back(q.vertex_[begin+1]);
715 uv_.push_back(q.uv_[begin]);
716 uv_.push_back(q.uv_[begin+1]);
717
718 vertex_.insert(vertex_.end(), q.vertex_.begin()+begin, q.vertex_.begin()+end);
719 uv_.insert(uv_.end(), q.uv_.begin()+begin, q.uv_.begin()+end);
720
721 return true;
722 }
723
set_draw_detection_rect(const rect & rect,char * buf)724 void set_draw_detection_rect(const rect& rect, char* buf)
725 {
726 draw_detection_rect new_rect = { rect, buf };
727 draw_detection_rects_.push_back(new_rect);
728 }
729
clear_draw_detection_rect()730 void clear_draw_detection_rect()
731 {
732 draw_detection_rects_.clear();
733 }
734
add_raster_distortion(const raster_distortion * distortion)735 void add_raster_distortion(const raster_distortion* distortion)
736 {
737 //TODO: distortions currently disabled
738 // distortion->next_cycle();
739 // distortions_.push_back(distortion);
740 }
741
remove_raster_distortion(const raster_distortion * distortion)742 void remove_raster_distortion(const raster_distortion* distortion)
743 {
744 // distortions_.erase(std::remove(distortions_.begin(), distortions_.end(), distortion), distortions_.end());
745 }
746
clear_raster_distortion()747 void clear_raster_distortion()
748 {
749 distortions_.clear();
750 }
751
draw_rect(const SDL_Rect & r,const SDL_Color & color,unsigned char alpha)752 void draw_rect(const SDL_Rect& r, const SDL_Color& color,
753 unsigned char alpha)
754 {
755 GLfloat varray[] = {
756 r.x, r.y,
757 r.x+r.w, r.y,
758 r.x, r.y+r.h,
759 r.x+r.w, r.y+r.h
760 };
761 #if defined(USE_GLES2)
762 glColor4ub(color.r,color.g,color.b,alpha);
763 gles2::manager gles2_manager(gles2::get_simple_shader());
764 gles2::active_shader()->shader()->vertex_array(2, GL_FLOAT, 0, 0, varray);
765 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
766 glColor4f(1.0, 1.0, 1.0, 1.0);
767 #else
768 glDisable(GL_TEXTURE_2D);
769 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
770 glColor4ub(color.r,color.g,color.b,alpha);
771 glVertexPointer(2, GL_FLOAT, 0, varray);
772 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
773 //glRecti(r.x,r.y,r.x+r.w,r.y+r.h);
774 glColor4ub(255, 255, 255, 255);
775 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
776 glEnable(GL_TEXTURE_2D);
777 #endif
778 }
779
draw_rect(const rect & r,const graphics::color & color)780 void draw_rect(const rect& r, const graphics::color& color)
781 {
782 GLfloat varray[] = {
783 r.x(), r.y(),
784 r.x()+r.w(), r.y(),
785 r.x(), r.y()+r.h(),
786 r.x()+r.w(), r.y()+r.h()
787 };
788 #if defined(USE_GLES2)
789 glColor4ub(color.r(),color.g(),color.b(),color.a());
790 gles2::manager gles2_manager(gles2::get_simple_shader());
791 gles2::active_shader()->shader()->vertex_array(2, GL_FLOAT, 0, 0, varray);
792 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
793 glColor4f(1.0, 1.0, 1.0, 1.0);
794 #else
795 glDisable(GL_TEXTURE_2D);
796 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
797 glColor4ub(color.r(),color.g(),color.b(),color.a());
798 glVertexPointer(2, GL_FLOAT, 0, varray);
799 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
800 //glRecti(r.x(),r.y(),r.x()+r.w(),r.y()+r.h());
801 glColor4ub(255, 255, 255, 255);
802 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
803 glEnable(GL_TEXTURE_2D);
804 #endif
805 }
806
807
draw_hollow_rect(const SDL_Rect & r,const SDL_Color & color,unsigned char alpha)808 void draw_hollow_rect(const SDL_Rect& r, const SDL_Color& color,
809 unsigned char alpha)
810 {
811 GLfloat varray[] = {
812 r.x, r.y,
813 r.x + r.w, r.y,
814 r.x + r.w, r.y + r.h,
815 r.x, r.y + r.h
816 };
817 #if defined(USE_GLES2)
818 glColor4ub(color.r, color.g, color.b, alpha);
819 gles2::manager gles2_manager(gles2::get_simple_shader());
820 gles2::active_shader()->shader()->vertex_array(2, GL_FLOAT, 0, 0, varray);
821 glDrawArrays(GL_LINE_LOOP, 0, sizeof(varray)/sizeof(GLfloat)/2);
822 glColor4f(1.0, 1.0, 1.0, 1.0);
823 #else
824 glDisable(GL_TEXTURE_2D);
825 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
826 glColor4ub(color.r, color.g, color.b, alpha);
827 glVertexPointer(2, GL_FLOAT, 0, varray);
828 glDrawArrays(GL_LINE_LOOP, 0, sizeof(varray)/sizeof(GLfloat)/2);
829 glColor4ub(255, 255, 255, 255);
830 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
831 glEnable(GL_TEXTURE_2D);
832 #endif
833 }
834
draw_circle(int x,int y,int radius)835 void draw_circle(int x, int y, int radius)
836 {
837 static std::vector<GLfloat> varray;
838 varray.clear();
839 varray.push_back(x);
840 varray.push_back(y);
841 for(double angle = 0; angle < 3.1459*2.0; angle += 0.1) {
842 const double xpos = x + radius*cos(angle);
843 const double ypos = y + radius*sin(angle);
844 varray.push_back(xpos);
845 varray.push_back(ypos);
846 }
847
848 //repeat the first coordinate to complete the circle.
849 varray.push_back(varray[2]);
850 varray.push_back(varray[3]);
851
852 #if defined(USE_GLES2)
853 gles2::manager gles2_manager(gles2::get_simple_shader());
854 gles2::active_shader()->shader()->vertex_array(2, GL_FLOAT, 0, 0, &varray.front());
855 glDrawArrays(GL_TRIANGLE_FAN, 0, varray.size()/2);
856 #else
857 glDisable(GL_TEXTURE_2D);
858 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
859 glVertexPointer(2, GL_FLOAT, 0, &varray.front());
860 glDrawArrays(GL_TRIANGLE_FAN, 0, varray.size()/2);
861 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
862 glEnable(GL_TEXTURE_2D);
863 #endif
864 }
865
coords_to_screen(GLfloat sx,GLfloat sy,GLfloat sz,GLfloat * dx,GLfloat * dy,GLfloat * dz)866 void coords_to_screen(GLfloat sx, GLfloat sy, GLfloat sz,
867 GLfloat* dx, GLfloat* dy, GLfloat* dz)
868 {
869 GLfloat model[16], proj[16];
870 GLint view[4];
871
872 #if defined(USE_GLES2) && defined(GL_ES_VERSION_2_0)
873 glGetFloatv_1(GL_MODELVIEW_MATRIX, model);
874 glGetFloatv_1(GL_PROJECTION_MATRIX, proj);
875 #else
876 glGetFloatv(GL_MODELVIEW_MATRIX, model);
877 glGetFloatv(GL_PROJECTION_MATRIX, proj);
878 #endif
879 glGetIntegerv(GL_VIEWPORT, view);
880
881 gluProjectf(sx, sy, sz, model, proj, view, dx, dy, dz);
882 }
883
push_clip(const SDL_Rect & r)884 void push_clip(const SDL_Rect& r)
885 {
886 glEnable(GL_STENCIL_TEST);
887 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
888 glStencilMask(0xff);
889 glClear(GL_STENCIL_BUFFER_BIT);
890
891 GLfloat varray[] = {
892 r.x, r.y,
893 r.x+r.w, r.y,
894 r.x, r.y+r.h,
895 r.x+r.w, r.y+r.h
896 };
897 glStencilFunc(GL_NEVER, 0x1, 0xff);
898 glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);
899 #if defined(USE_GLES2)
900 glColor4f(1.0f,1.0f,1.0f,1.0f);
901 gles2::manager gles2_manager(gles2::get_simple_shader());
902 gles2::active_shader()->shader()->vertex_array(2, GL_FLOAT, 0, 0, varray);
903 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
904 #else
905 glColor4ub(255, 255, 255, 255);
906 glDisable(GL_TEXTURE_2D);
907 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
908 glVertexPointer(2, GL_FLOAT, 0, varray);
909 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
910 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
911 glEnable(GL_TEXTURE_2D);
912 #endif
913 glStencilMask(0);
914 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
915 glStencilFunc(GL_EQUAL, 0x1, 0x1);
916 }
917
pop_clip()918 void pop_clip() {
919 glDisable(GL_STENCIL_TEST);
920 }
921
922 namespace {
923 int zoom_level = 1;
924 }
925
screen_width()926 int screen_width()
927 {
928 return preferences::virtual_screen_width()*zoom_level;
929 /*
930 SDL_Surface* surf = SDL_GetVideoSurface();
931 if(surf) {
932 return SDL_GetVideoSurface()->w;
933 } else {
934 return 1024;
935 }*/
936 }
937
screen_height()938 int screen_height()
939 {
940 return preferences::virtual_screen_height()*zoom_level;
941 /*
942 SDL_Surface* surf = SDL_GetVideoSurface();
943 if(surf) {
944 return SDL_GetVideoSurface()->h;
945 } else {
946 return 768;
947 }*/
948 }
949
zoom_in()950 void zoom_in()
951 {
952 --zoom_level;
953 if(zoom_level < 1) {
954 zoom_level = 1;
955 }
956 }
957
zoom_out()958 void zoom_out()
959 {
960 ++zoom_level;
961 if(zoom_level > 5) {
962 zoom_level = 5;
963 }
964 }
965
zoom_default()966 void zoom_default()
967 {
968 zoom_level = 1;
969 }
970
971 }
972