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