1/***************************************************************************
2    PluginGLView.m
3    PeopsSoftGPU
4
5    Created by Gil Pedersen on Sun April 18 2004.
6    Copyright (c) 2004 Gil Pedersen.
7 ***************************************************************************/
8
9/***************************************************************************
10 *                                                                         *
11 *   This program is free software; you can redistribute it and/or modify  *
12 *   it under the terms of the GNU General Public License as published by  *
13 *   the Free Software Foundation; either version 2 of the License, or     *
14 *   (at your option) any later version. See also the license.txt file for *
15 *   additional informations.                                              *
16 *                                                                         *
17 ***************************************************************************/
18
19#import <Cocoa/Cocoa.h>
20#include <OpenGL/gl.h>
21#include <OpenGL/glext.h>
22#include <OpenGL/glu.h>
23#include <GLUT/glut.h>
24#import "PluginGLView.h"
25#import "SGPUPreferences.h"
26#include "externals.h"
27#undef BOOL
28#include "gpu.h"
29#include "swap.h"
30
31#include <time.h>
32extern time_t tStart;
33
34static int mylog2(int val)
35{
36	int i;
37	for (i=1; i<31; i++)
38		if (val <= (1 << i))
39			return (1 << i);
40
41	return -1;
42}
43
44
45@implementation PluginGLView
46{
47	GLubyte  *image_base;
48	GLubyte  *image[IMAGE_COUNT];
49
50	GLboolean useShader;
51	float	  shaderQuality;
52	GLint     buffers;
53	GLuint    vertexShader;
54	GLuint    fragmentShader;
55	GLuint	  program;
56	//GLint     frame_rate;
57
58	GLenum    texture_hint;
59	GLboolean rect_texture;
60	GLboolean client_storage;
61	GLboolean texture_range;
62
63	struct timeval cycle_time;
64
65	BOOL noDisplay;
66	BOOL drawBG;
67
68	int image_width;
69	int image_height;
70	int image_width2;
71	int image_height2;
72	int image_depth;
73	int image_type;
74	float image_tx;
75	float image_ty;
76	int whichImage;
77	BOOL isFullscreen;
78}
79@synthesize glLock;
80
81//- (id)initWithFrame:(NSRect)frameRect
82- (id) initWithCoder: (NSCoder *) coder
83{
84	if ((self = [super initWithCoder:coder]) == nil)
85		return nil;
86
87	glLock = [[NSLock alloc] init];
88	if (nil == glLock) {
89		return nil;
90	}
91
92	const GLubyte * strExt;
93
94	// Init pixel format attribs
95	static const NSOpenGLPixelFormatAttribute attrs[] =
96	{
97		NSOpenGLPFAAccelerated,
98		NSOpenGLPFANoRecovery,
99		NSOpenGLPFADoubleBuffer,
100		0
101	};
102
103	// Get pixel format from OpenGL
104	NSOpenGLPixelFormat* pixFmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
105	if (!pixFmt)
106	{
107		NSLog(@"No Accelerated OpenGL pixel format found\n");
108
109		static const NSOpenGLPixelFormatAttribute attrs2[] =
110		{
111			NSOpenGLPFANoRecovery,
112			0
113		};
114
115		// Get pixel format from OpenGL
116		pixFmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs2];
117		if (!pixFmt) {
118			NSLog(@"No OpenGL pixel format found!\n");
119
120			return nil;
121		}
122	}
123
124	[self setPixelFormat:pixFmt];
125
126	/*
127	 long swapInterval = 1 ;
128	 [[self openGLContext]
129	 setValues:&swapInterval
130	 forParameter:NSOpenGLCPSwapInterval];
131	 */
132	[glLock lock];
133	[[self openGLContext] makeCurrentContext];
134
135	// Init object members
136	strExt = glGetString (GL_EXTENSIONS);
137	texture_range  = gluCheckExtension ((const unsigned char *)"GL_APPLE_texture_range", strExt) ? GL_TRUE : GL_FALSE;
138	texture_hint   = GL_STORAGE_SHARED_APPLE ;
139	client_storage = gluCheckExtension ((const unsigned char *)"GL_APPLE_client_storage", strExt) ? GL_TRUE : GL_FALSE;
140	rect_texture   = gluCheckExtension((const unsigned char *)"GL_EXT_texture_rectangle", strExt) ? GL_TRUE : GL_FALSE;
141
142	// Setup some basic OpenGL stuff
143	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
144	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
145	glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
146	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
147	glClear(GL_COLOR_BUFFER_BIT);
148
149	// Loads the shaders
150
151	if(isShaderEnabled()){
152		rect_texture = GL_FALSE;
153		// --- Params ---
154		shaderQuality = PSXShaderQuality();
155		vertexShader = [self loadShader:GL_VERTEX_SHADER location:PSXVertexShader()];
156		fragmentShader = [self loadShader:GL_FRAGMENT_SHADER location:PSXFragmentShader()];
157
158		//--- shader loading ---
159		program = glCreateProgram();
160		glAttachShader(program, vertexShader);
161		glAttachShader(program, fragmentShader);
162		glLinkProgram(program);
163		glUseProgram(program);
164	}
165
166
167	[NSOpenGLContext clearCurrentContext];
168	[glLock unlock];
169
170	image_width = 1024;
171	image_height = 512;
172	image_depth = 16;
173
174	image_type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
175	image_base = (GLubyte *) calloc(((IMAGE_COUNT * image_width * image_height) / 3) * 4, image_depth >> 3);
176	if (image_base == nil) {
177		return nil;
178	}
179
180	// Create and load textures for the first time
181	[self loadTextures:GL_TRUE];
182
183	// Init fps timer
184	//gettimeofday(&cycle_time, NULL);
185
186	drawBG = YES;
187
188	// Call for a redisplay
189	noDisplay = YES;
190	PSXDisplay.Disabled = 1;
191	[self setNeedsDisplay:YES];
192
193	return self;
194}
195
196- (void)dealloc
197{
198	int i;
199
200	[glLock lock];
201
202	[[self openGLContext] makeCurrentContext];
203	for(i = 0; i < IMAGE_COUNT; i++)
204	{
205		GLuint dt = i+1;
206		glDeleteTextures(1, &dt);
207	}
208	if(texture_range)
209		glTextureRangeAPPLE(GL_TEXTURE_RECTANGLE_EXT, IMAGE_COUNT * image_width * image_height * (image_depth >> 3), image_base);
210
211	[NSOpenGLContext clearCurrentContext];
212	[glLock unlock];
213
214	if (image_base) {
215		free(image_base);
216	}
217}
218
219- (BOOL)isOpaque
220{
221	return YES;
222}
223
224- (BOOL)acceptsFirstResponder
225{
226	return NO;
227}
228
229- (void)drawRect:(NSRect)aRect
230{
231	// Check if an update has occured to the buffer
232	if ([self lockFocusIfCanDraw]) {
233
234		// Make this context current
235		if (drawBG) {
236			[[NSColor blackColor] setFill];
237			[NSBezierPath fillRect:[self visibleRect]];
238		}
239
240		//glFinish() ;
241		// Swap buffer to screen
242		//[[self openGLContext] flushBuffer];
243
244		[self unlockFocus];
245	}
246}
247
248#if 0
249- (void)update  // moved or resized
250{
251	NSRect rect;
252
253	[super update];
254
255	[[self openGLContext] makeCurrentContext];
256	[[self openGLContext] update];
257
258	rect = [self bounds];
259
260	glViewport(0, 0, (int) rect.size.width, (int) rect.size.height);
261
262	glMatrixMode(GL_PROJECTION);
263	glLoadIdentity();
264
265	glMatrixMode(GL_MODELVIEW);
266	glLoadIdentity();
267
268	//[self setNeedsDisplay:true];
269}
270#endif
271
272- (void)reshape	// scrolled, moved or resized
273{
274	[glLock lock];
275
276	[super reshape];
277
278	NSOpenGLContext *oglContext = [self openGLContext];
279	NSRect rect;
280
281	[oglContext makeCurrentContext];
282	[oglContext update];
283
284	rect = [[oglContext view] bounds];
285
286	glViewport(0, 0, (int) rect.size.width, (int) rect.size.height);
287
288	glMatrixMode(GL_PROJECTION);
289	glLoadIdentity();
290
291	glMatrixMode(GL_MODELVIEW);
292	glLoadIdentity();
293
294	drawBG = YES;
295
296	[NSOpenGLContext clearCurrentContext];
297
298	//[self setNeedsDisplay:true];
299	[self renderScreen];
300	[glLock unlock];
301}
302
303- (void)renderScreen
304{
305	int bufferIndex = whichImage;
306
307	if (1/*[glLock tryLock]*/) {
308		// Make this context current
309		[[self openGLContext] makeCurrentContext];
310
311		if (PSXDisplay.Disabled) {
312			glClear(GL_COLOR_BUFFER_BIT);
313		} else {
314			// Bind, update and draw new image
315			if(rect_texture && isShaderEnabled() == NO) // cant go in there if we use shaders
316			{
317				//printf("Texture Rectangle\n");
318				//glActiveTexture(bufferIndex+1);
319				glActiveTexture(GL_TEXTURE0);
320				glBindTexture(GL_TEXTURE_RECTANGLE_EXT, bufferIndex+1);
321
322				glTexSubImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, image_width, image_height, GL_BGRA, image_type, image[bufferIndex]);
323
324
325				glBegin(GL_QUADS);
326				{
327					glTexCoord2f(0.0f, 0.0f);
328					glVertex2f(-1.0f, 1.0f);
329
330					glTexCoord2f(0.0f, image_height);
331					glVertex2f(-1.0f, -1.0f);
332
333					glTexCoord2f(image_width, image_height);
334					glVertex2f(1.0f, -1.0f);
335
336					glTexCoord2f(image_width, 0.0f);
337					glVertex2f(1.0f, 1.0f);
338				}
339				glEnd();
340			}
341			else
342			{
343				NSRect rect = [[[self openGLContext] view] bounds];
344				//printf("Texture 2D normale de taille : %d, %d sur un ecran : %f x %f \n",image_width,image_height,rect.size.width,rect.size.height);
345				//glActiveTexture(whichImage+1);
346				glBindTexture(GL_TEXTURE_2D, whichImage+1);
347
348				glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image_width2, image_height2, GL_BGRA, image_type, image[bufferIndex]);
349
350
351				if(isShaderEnabled()){
352					glUseProgram(program);
353
354					int loc = glGetUniformLocation(program, "OGL2Texture");
355					glUniform1i(loc,0);
356					int loc2 = glGetUniformLocation(program, "OGL2Param");
357					float param[4];
358					param[2] = shaderQuality;
359					param[0] = param[2] / image_width;
360					param[1] = param[2] / image_height;
361					//param[2]=2.0;
362					param[3] = 0.0;
363					int loc3 = glGetUniformLocation(program, "OGL2Size");
364					float size[4];
365					//NSRect rect = [[[self openGLContext] view] bounds];
366					size[0] = image_width;
367					size[1] = image_height;
368					size[2] = rect.size.width;
369					size[3] = rect.size.height;
370					int loc4 = glGetUniformLocation(program, "OGL2InvSize");
371					float invSize[4];
372					invSize[0] = 1.0/size[0];
373					invSize[1] = 1.0/size[1];
374					invSize[2] = 1.0/size[2];
375					invSize[3] = 1.0/size[3];
376					//invSize[4]=1.0/size[4]; //Did we goof here?
377					glUniform4fv(loc2, 1, param);
378					glUniform4fv(loc3, 1, size);
379					glUniform4fv(loc4, 1, invSize);
380				}
381
382				glBegin(GL_QUADS);
383				{
384					glTexCoord2f(0.0f, 0.0f);
385					glVertex2f(-1.0f, 1.0f);
386
387					glTexCoord2f(0.0f, image_ty);
388					glVertex2f(-1.0f, -1.0f);
389
390					glTexCoord2f(image_tx, image_ty);
391					glVertex2f(1.0f, -1.0f);
392
393					glTexCoord2f(image_tx, 0.0f);
394					glVertex2f(1.0f, 1.0f);
395				}
396				glEnd();
397			}
398		}
399
400		// FPS Display
401		if(ulKeybits&KEY_SHOWFPS)
402		{
403			int len, i;
404			if(szDebugText[0] && ((time(NULL) - tStart) < 2))
405			{
406				strlcpy(szDispBuf, szDebugText, 63);
407			}
408			else
409			{
410				szDebugText[0]=0;
411				if (szMenuBuf) {
412					strncat(szDispBuf, szMenuBuf, 63 - strlen(szDispBuf));
413				}
414			}
415
416			NSRect rect = [[[self openGLContext] view] bounds];
417			len = (int) strlen(szDispBuf);
418
419			glMatrixMode(GL_PROJECTION);
420			glPushMatrix();
421
422			gluOrtho2D(0.0, rect.size.width, 0.0, rect.size.height);
423			glDisable(rect_texture ? GL_TEXTURE_RECTANGLE_EXT : GL_TEXTURE_2D);
424
425			glColor4f(0.0, 0.0, 0.0, 0.5);
426			glRasterPos2f(3.0, rect.size.height - 14.0);
427			for (i = 0; i < len; i++) {
428				glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, szDispBuf[i]);
429			}
430
431			glColor3f(1.0, 1.0, 1.0);
432			glRasterPos2f(2.0, rect.size.height - 13.0);
433			for (i = 0; i < len; i++) {
434				glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, szDispBuf[i]);
435			}
436
437			glEnable(rect_texture ? GL_TEXTURE_RECTANGLE_EXT : GL_TEXTURE_2D);
438			glPopMatrix();
439		}
440
441		//printProgramInfoLog(program);
442		//printf("\n\n\n");
443		[[self openGLContext] flushBuffer];
444		[NSOpenGLContext clearCurrentContext];
445		//[glLock unlock];
446	}
447}
448
449- (void)loadTextures:(GLboolean)first
450{
451	GLint i;
452	printf("Loading texture\n");
453	//[glLock lock];
454	[[self openGLContext] makeCurrentContext];
455
456	image_width = PreviousPSXDisplay.Range.x1;
457	image_height = PreviousPSXDisplay.DisplayMode.y;
458	if (PSXDisplay.RGB24) {
459		image_depth = 32;
460		image_type = GL_UNSIGNED_INT_8_8_8_8_REV;
461	} else {
462		image_depth = 16;
463		image_type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
464		//image_width >>= 1;
465	}
466
467	if (image_width * image_height * (image_depth >> 3) > ((1024*512*2)/3)*4)
468		printf("Fatal error: desired dimension are too large! (%ix%i %ibpp)\n",
469			   image_width, image_height, image_depth);
470
471	for(i = 0; i < IMAGE_COUNT; i++)
472		image[i] = image_base + i * image_width * image_height * (image_depth >> 3);
473
474	if(rect_texture)
475	{
476		image_width2 = image_width;
477		image_height2 = image_height;
478		image_tx = (float)image_width;
479		image_ty = (float)image_height;
480
481		if(texture_range) glTextureRangeAPPLE(GL_TEXTURE_RECTANGLE_EXT, IMAGE_COUNT * image_width * image_height * (image_depth >> 3), image_base);
482		else              glTextureRangeAPPLE(GL_TEXTURE_RECTANGLE_EXT, 0, NULL);
483
484		for(i = 0; i < IMAGE_COUNT; i++)
485		{
486			if(!first)
487			{
488				GLuint dt = i+1;
489				glDeleteTextures(1, &dt);
490			}
491
492			glDisable(GL_TEXTURE_2D);
493			glActiveTexture(GL_TEXTURE0);
494			glEnable(GL_TEXTURE_RECTANGLE_EXT);
495			glBindTexture(GL_TEXTURE_RECTANGLE_EXT, i+1);
496
497
498			glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_STORAGE_HINT_APPLE , texture_hint);
499			glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, client_storage);
500			glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
501			glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
502			glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
503			glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
504			glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
505
506			glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGBA, image_width,
507						 image_height, 0, GL_BGRA, image_type, image[i]);
508		}
509	}
510	else
511	{
512		image_width2 = mylog2(image_width);
513		image_height2 = mylog2(image_height);
514		image_tx = (float)image_width/(float)image_width2;
515		image_ty = (float)image_height/(float)image_height2;
516
517		glTextureRangeAPPLE(GL_TEXTURE_RECTANGLE_EXT, 0, NULL);
518		if(texture_range) glTextureRangeAPPLE(GL_TEXTURE_2D, IMAGE_COUNT * image_width2 * image_height2 * (image_depth >> 3), image_base);
519		else              glTextureRangeAPPLE(GL_TEXTURE_2D, 0, NULL);
520
521		for(i = 0; i < IMAGE_COUNT; i++)
522		{
523			if(!first)
524			{
525				GLuint dt = i+1;
526				glDeleteTextures(1, &dt);
527			}
528
529			glDisable(GL_TEXTURE_RECTANGLE_EXT);
530			glEnable(GL_TEXTURE_2D);
531			glBindTexture(GL_TEXTURE_2D, i+1);
532
533			//if(texture_range) glTextureRangeAPPLE(GL_TEXTURE_2D, IMAGE_COUNT * image_width2 * image_height2 * (image_depth >> 3), image_base);
534			//else              glTextureRangeAPPLE(GL_TEXTURE_2D, 0, NULL);
535
536			glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_STORAGE_HINT_APPLE , texture_hint);
537			glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, client_storage);
538			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
539			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
540			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
541			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
542			glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
543
544			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image_width2,
545						 image_height2, 0, GL_BGRA, image_type, image[i]);
546		}
547	}
548
549	[NSOpenGLContext clearCurrentContext];
550	//[glLock unlock];
551}
552
553- (void)swapBuffer
554{
555	RunOnMainThreadSync(^{
556		//printf("y=%i",PSXDisplay.DisplayPosition.y);
557
558		unsigned char * surf;
559		long x = PSXDisplay.DisplayPosition.x;
560		long y = PSXDisplay.DisplayPosition.y;
561		GLuint lu;
562		unsigned short row,column;
563		unsigned short dx=PreviousPSXDisplay.Range.x1;
564		unsigned short dy=PreviousPSXDisplay.DisplayMode.y;
565		long lPitch;
566
567		if ([glLock tryLock]) {
568			// make sure the texture area is ready to be written to
569			glFinishObjectAPPLE(GL_TEXTURE, 2-whichImage);
570
571			if ((image_width != PreviousPSXDisplay.Range.x1) ||
572				(image_height != PreviousPSXDisplay.DisplayMode.y) ||
573				((PSXDisplay.RGB24 ? 32 : 16) != image_depth)) {
574				[self loadTextures:GL_FALSE];
575			}
576
577			surf = image[1-whichImage];
578			lPitch=image_width2<<(image_depth >> 4);
579
580			if(PreviousPSXDisplay.Range.y0)                       // centering needed?
581			{
582				surf+=PreviousPSXDisplay.Range.y0*lPitch;
583				dy-=PreviousPSXDisplay.Range.y0;
584			}
585
586			if(PSXDisplay.RGB24)
587			{
588				unsigned char * pD;
589				size_t startxy;
590
591				surf+=PreviousPSXDisplay.Range.x0<<2;
592
593				for(column=0;column<dy;column++)
594				{
595					startxy = (1024 * (column + y)) + x;
596					pD = (unsigned char *)&psxVuw[startxy];
597
598					row = 0;
599					// make sure the reads are aligned
600					while ((intptr_t)pD & 0x3) {
601						*((unsigned long *)((surf)+(column*lPitch)+(row<<2))) =
602						(*(pD+0)<<16)|(*(pD+1)<<8)|*(pD+2);
603
604						pD+=3;
605						row++;
606					}
607
608					for(;row<dx;row+=4)
609					{
610						GLuint lu1 = *((GLuint *)pD);
611						GLuint lu2 = *((GLuint *)pD+1);
612						GLuint lu3 = *((GLuint *)pD+2);
613						GLuint *dst = ((GLuint *)((surf)+(column*lPitch)+(row<<2)));
614#ifdef __BIG_ENDIAN__
615						*(dst)=
616						(((lu1>>24)&0xff)<<16)|(((lu1>>16)&0xff)<<8)|(((lu1>>8)&0xff));
617						*(dst+1)=
618						(((lu1>>0)&0xff)<<16)|(((lu2>>24)&0xff)<<8)|(((lu2>>16)&0xff));
619						*(dst+2)=
620						(((lu2>>8)&0xff)<<16)|(((lu2>>0)&0xff)<<8)|(((lu3>>24)&0xff));
621						*(dst+3)=
622						(((lu3>>16)&0xff)<<16)|(((lu3>>8)&0xff)<<8)|(((lu3>>0)&0xff));
623#else
624						*(dst)=
625						(((lu1>>0)&0xff)<<16)|(((lu1>>8)&0xff)<<8)|(((lu1>>16)&0xff));
626						*(dst+1)=
627						(((lu1>>24)&0xff)<<16)|(((lu2>>0)&0xff)<<8)|(((lu2>>8)&0xff));
628						*(dst+2)=
629						(((lu2>>16)&0xff)<<16)|(((lu2>>24)&0xff)<<8)|(((lu3>>0)&0xff));
630						*(dst+3)=
631						(((lu3>>8)&0xff)<<16)|(((lu3>>16)&0xff)<<8)|(((lu3>>24)&0xff));
632#endif
633						pD+=12;
634					}
635
636					//for(;row<dx;row+=4)
637					/*while (pD&0x3) {
638					 *((unsigned long *)((surf)+(column*lPitch)+(row<<2)))=
639					 (*(pD+0)<<16)|(*(pD+1)<<8)|(*(pD+2)&0xff));
640					 pD+=3;
641					 row++;
642					 }*/
643				}
644			}
645			else
646			{
647				long LineOffset,SurfOffset;
648				GLuint * SRCPtr = (GLuint *)(psxVuw + (y << 10) + x);
649				GLuint * DSTPtr =
650				((GLuint *)surf) + (PreviousPSXDisplay.Range.x0 >> 1);
651
652				dx >>= 1;
653
654				LineOffset = 512 - dx;
655				SurfOffset = (lPitch >> 2) - dx;
656
657				for(column=0;column<dy;column++)
658				{
659					for(row=0;row<dx;row++)
660					{
661#ifdef __BIG_ENDIAN__
662						lu=GETLE16D(SRCPtr++);
663#else
664						lu=*SRCPtr++;
665#endif
666						*DSTPtr++=
667						((lu << 10) & 0x7c007c00)|
668						((lu) & 0x3e003e0)|
669						((lu >> 10) & 0x1f001f);
670					}
671					SRCPtr += LineOffset;
672					DSTPtr += SurfOffset;
673				}
674			}
675
676			// Swap image buffer
677			whichImage = 1 - whichImage;
678
679			[self renderScreen];
680			[glLock unlock];
681		}
682
683	});
684}
685
686- (void)clearBuffer:(BOOL)display
687{
688	if (display == NO) {
689		//[[self openGLContext] makeCurrentContext];
690		//glClear(GL_COLOR_BUFFER_BIT);
691		//[self loadTextures:NO];
692	} else {
693		noDisplay = YES;
694		//[self setNeedsDisplay:true];
695	}
696}
697
698- (GLuint)loadShader:(GLenum)type location:(NSURL*)filename
699{
700	GLuint myShader = 0;
701
702	GLsizei logsize = 0;
703	GLint compile_status = GL_TRUE;
704	char *log = NULL;
705	char *src = NULL;
706
707	/* creation d'un shader de sommet */
708	myShader = glCreateShader(type);
709	if(myShader == 0)
710	{
711		NSLog(@"impossible de creer le shader");
712		return 0;
713	}
714
715	/* chargement du code source */
716	src = [PluginGLView loadSource:filename];
717	if(src == NULL)
718	{
719		/* theoriquement, la fonction LoadSource a deja affiche un message
720		 d'erreur, nous nous contenterons de supprimer notre shader
721		 et de retourner 0 */
722
723		glDeleteShader(myShader);
724		return 0;
725	}
726
727	/* assignation du code source */
728	glShaderSource(myShader, 1, (const GLchar**)&src, NULL);
729
730	/* compilation du shader */
731	glCompileShader(myShader);
732
733	/* liberation de la memoire du code source */
734	free(src);
735	src = NULL;
736
737	/* verification du succes de la compilation */
738	glGetShaderiv(myShader, GL_COMPILE_STATUS, &compile_status);
739	if(compile_status != GL_TRUE)
740	{
741		/* erreur a la compilation recuperation du log d'erreur */
742
743		/* on recupere la taille du message d'erreur */
744		glGetShaderiv(myShader, GL_INFO_LOG_LENGTH, &logsize);
745
746		/* on alloue un espace memoire dans lequel OpenGL ecrira le message */
747		log = calloc(logsize + 1, 1);
748		if(log == NULL)
749		{
750			NSLog(@"impossible d'allouer de la memoire!");
751			return 0;
752		}
753
754		glGetShaderInfoLog(myShader, logsize, &logsize, log);
755		NSLog(@"impossible de compiler le shader '%@' :\n%s",
756			  [filename path], log);
757
758		/* ne pas oublier de liberer la memoire et notre shader */
759		free(log);
760		glDeleteShader(myShader);
761
762		return 0;
763	}
764	return myShader;
765}
766
767+ (char*)loadSource:(NSURL *)filename
768{
769	//Since we're passing Cocoa NSURLs, let's use Cocoa's methods
770	if (filename == nil) {
771		return NULL;
772	}
773
774	NSUInteger len;
775	NSMutableData *shaderData = [[NSMutableData alloc] initWithContentsOfURL:filename];
776	[shaderData appendBytes:"\0" length:1];
777	len = [shaderData length];
778	char *shaderText = malloc(len);
779	[shaderData getBytes:shaderText length:len];
780	return shaderText;
781}
782
783@end
784