new PixelBuffer API (mainly tons of renames)
[org.ibex.core.git] / src / org / ibex / plat / OpenGL.cc
1 // Copyright 2003 Adam Megacz, see the COPYING file for licensing [LGPL]
2 // Author: Brian Alliet
3
4 // IMPROVMENT: use alpha testing? might be faster
5
6 #include <org/ibex/plat/OpenGL.h>
7 #include <org/ibex/graphics/PixelBuffer.h>
8 #include <org/ibex/graphics/Polygon.h>
9 #include <org/ibex/plat/OpenGL$GLPixelBuffer.h>
10 #include <org/ibex/plat/OpenGL$GLPicture.h>
11 #include <org/ibex/plat/OpenGL$RectGLPicture.h>
12 #include <org/ibex/plat/OpenGL$SquareGLPicture.h>
13 #include <org/ibex/plat/OpenGL$MosaicGLPicture.h>
14
15 #include <java/lang/Error.h>
16
17 #ifdef __APPLE__
18 #include <OpenGL/gl.h>
19 #include <OpenGL/glu.h>
20 #include <OpenGL/glext.h>
21 #else
22 #warning I am not sure if these are correct
23 #include <gl/gl.h>
24 #include <gl/glu.h>
25 #include <gl/glext.h>
26 #endif
27
28 #include <stdio.h>
29
30 #define min(a,b) ((a)<(b)?(a):(b)) 
31 #define max(a,b) ((a)>(b)?(a):(b)) 
32
33 namespace org { namespace ibex { namespace plat {
34
35 #define checkGLError() checkGLError2(__FILE__,__LINE__)
36 static void checkGLError2(const char *file,int line) {
37     GLenum err = glGetError();
38     if(err == GL_NO_ERROR) return;
39
40     fprintf(stderr,"%s:%d: GL Error: %s",file,line,(char *) gluErrorString(err));
41     exit(EXIT_FAILURE);
42 }
43
44 void OpenGL::natInit() {
45     GLint i;
46     const GLubyte *s;
47     activateSharedContext();
48     s = glGetString(GL_EXTENSIONS);
49     rectangularTextures = (jboolean) gluCheckExtension((GLubyte*)"GL_EXT_texture_rectangle",s);
50     glGetIntegerv(GL_MAX_TEXTURE_SIZE,&i);
51     maxTexSize = (jint) i;
52     if(rectangularTextures) {
53         glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE_EXT,&i);
54         maxRectTexSize = (jint) i;
55     }
56     s = glGetString(GL_VENDOR);
57     vendor = JvNewStringLatin1(s==0 ? "" : (char*)s);
58     s = glGetString(GL_RENDERER);
59     renderer = JvNewStringLatin1(s==0 ? "" : (char*)s);
60     s = glGetString(GL_VERSION);
61     version = JvNewStringLatin1(s==0 ? "" : (char*)s);
62 }
63
64 void OpenGL$GLPixelBuffer::drawableInit(jint width, jint height) {
65     glClearColor (0.3f, 0.7f, 1.0f, 1.0f);
66     glClearDepth( 0.0f );
67     glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
68     glShadeModel(GL_SMOOTH);
69     glEnable(GL_BLEND);
70     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
71
72     glViewport(0,0,width,height);
73     glMatrixMode(GL_PROJECTION);
74     glLoadIdentity(); 
75     glOrtho(0,width,height,0,-1,1);
76     // CHECKME: This causes textures to be blurry, but something like this
77     // (but not this) might be required to draw straight lines   
78     //glMatrixMode(GL_MODELVIEW);
79     //glLoadIdentity(); 
80     //glTranslatef(0.375, 0.375, 0.0);    
81     
82     checkGLError();
83 }
84
85 void OpenGL$GLPixelBuffer::setColor(jint argb) {
86     float alpha = ((argb >> 24) & 0xff) / 255.0;
87     float red   = ((argb >> 16) & 0xff) / 255.0;
88     float green = ((argb >>  8) & 0xff) / 255.0;
89     float blue  = ((argb >>  0) & 0xff) / 255.0;
90     glColor4f(red,green,blue,alpha);
91 }
92
93 void OpenGL$GLPixelBuffer::fillTrapezoid(jint x1, jint x2, jint y1, jint x3, jint x4, jint y2, jint color) {
94     activateContext();
95     setColor(color);
96     glBegin(GL_QUADS); {
97         glVertex3f(x1,y1,0.0f );   
98         glVertex3f(x3,y2,0.0f );  
99         glVertex3f(x4,y2,0.0f ); 
100         glVertex3f(x2,y1,0.0f ); 
101     } glEnd();
102 }
103
104 void OpenGL$GLPixelBuffer::natFill(org::ibex::graphics::Polygon* p, jint argb) {
105     activateContext();
106     setColor(argb);
107     for(jint contour=0; contour < p->numcontours; contour++) {
108         glBegin(GL_POLYGON); {
109         for(jint i = elements(p->contours)[contour]; i < elements(p->contours)[contour+1]; i++) {
110             glVertex3f(elements(p->x)[i], elements(p->y)[i], 0.0f );   
111         } glEnd();
112         }
113     }
114 }
115
116 void OpenGL$GLPixelBuffer::setClip(jint x1, jint y1, jint x2, jint y2) {
117     //fprintf(stderr,"setClip: %d %d %d %d\n",x1,y1,x2,y2);
118     if(x1==0 && y1==0 && x2==width && y2==height) {
119         if(glScissorEnabled) {
120             activateContext();
121             glDisable(GL_SCISSOR_TEST);
122             glScissorEnabled = false;
123         }
124         return;
125     }
126     activateContext();
127     if(!glScissorEnabled) {
128         glEnable(GL_SCISSOR_TEST);
129         glScissorEnabled = true;
130     }
131     if((x1 >= x2) || (y1 >= y2))
132         glScissor(0,0,0,0);
133     else
134         glScissor(x1,height-y2,x2-x1,y2-y1);
135     checkGLError();
136 }
137
138 void OpenGL$GLPixelBuffer::resetClip() {
139     activateContext();
140     if(glScissorEnabled) {
141         glDisable(GL_SCISSOR_TEST);
142         glScissorEnabled = false;
143     }    
144 }
145
146 // FEATURE: Eliminate duplicate code in RectGLPicture and SquareGLPicture
147 void OpenGL$RectGLPicture::natInit(Object *data_, jboolean alphaOnly) {
148     unsigned char *buf;
149     int i,j;
150     int size = width*height;
151     GLuint tex;
152
153     if(alphaOnly) {
154         jbyte *data = elements((JArray<jbyte> *)data_);
155         buf = (unsigned char *) data;
156     } else {
157         jint *data = elements((JArray<jint> *)data_);
158         buf = new unsigned char[size*4];
159         for(i=0,j=0;i<size;i++,j+=4) {
160             jint pixel = data[i];
161             buf[j+0] = (pixel >> 16) & 0xff;
162             buf[j+1] = (pixel >>  8) & 0xff;
163             buf[j+2] = (pixel >>  0) & 0xff;
164             buf[j+3] = (pixel >> 24) & 0xff;
165         }
166     }
167     
168     gl->activateSharedContext();
169     glEnable(GL_TEXTURE_RECTANGLE_EXT);
170     glGenTextures(1,&tex);
171     glBindTexture(GL_TEXTURE_RECTANGLE_EXT,tex);
172     glPixelStorei(GL_PACK_ALIGNMENT,1);
173     glTexImage2D(
174         GL_TEXTURE_RECTANGLE_EXT,0,
175         alphaOnly ? GL_ALPHA : GL_RGBA,width,height,0,
176         alphaOnly ? GL_ALPHA : GL_RGBA,GL_UNSIGNED_BYTE,buf);
177     if(!alphaOnly)
178         delete buf;
179
180     if(gl->glVersion >= 1.2) {
181         glTexParameteri(GL_TEXTURE_RECTANGLE_EXT,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
182         glTexParameteri(GL_TEXTURE_RECTANGLE_EXT,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
183         glTexParameterf(GL_TEXTURE_RECTANGLE_EXT,GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
184         glTexParameterf(GL_TEXTURE_RECTANGLE_EXT,GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
185     } else {
186         glTexParameteri(GL_TEXTURE_RECTANGLE_EXT,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
187         glTexParameteri(GL_TEXTURE_RECTANGLE_EXT,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
188     }
189     
190     glDisable(GL_TEXTURE_RECTANGLE_EXT);
191     checkGLError();
192   
193     textureName = (jint)tex;
194 }
195
196 void OpenGL$RectGLPicture::draw(jint dx, jint dy, jint cx1, jint cy1, jint cx2, jint cy2) { 
197     cx1 = max(dx, cx1);
198     cy1 = max(dy, cy1);
199     cx2 = min(cx2, dx + width);
200     cy2 = min(cy2, dy + height);
201     if (cy2 <= cy1 || cx2 <= cx1) return;
202     glEnable(GL_TEXTURE_RECTANGLE_EXT);
203     glBindTexture(GL_TEXTURE_RECTANGLE_EXT, textureName);    
204     glBegin(GL_QUADS); {
205       glTexCoord2i (cx1 - dx, cy1 - dy   );
206       glVertex3i   (cx1,      cy1,      0);
207       glTexCoord2i (cx2 - dx, cy1 - dy   );
208       glVertex3i   (cx2,      cy1,      0);
209       glTexCoord2i (cx2 - dx, cy2 - dy   );
210       glVertex3i   (cx2,      cy2,      0);
211       glTexCoord2i (cx1 - dx, cy2 - dy   );
212       glVertex3i   (cx1,      cy2,      0);
213     } glEnd();
214     glDisable(GL_TEXTURE_RECTANGLE_EXT);
215     checkGLError();
216 }
217
218 void OpenGL::natDeleteTexture(jint tex_) {
219     activateSharedContext();
220     GLuint tex = (GLuint) tex_;
221     glDeleteTextures(1,&tex);
222 }
223
224 void OpenGL$SquareGLPicture::natInit(Object *data_, jboolean alphaOnly) {
225     unsigned char *buf;
226     int row,col,p;
227     GLuint tex;
228
229     if(alphaOnly) {
230         jbyte *data = elements((JArray<jbyte>*) data_);
231         if(texWidth == width && texHeight == height) {
232             buf = (unsigned char*) data;
233         } else {
234             buf = new unsigned char[texWidth*texHeight];
235             p=0;
236             for(row=0;row<height;row++) {
237                 for(col=0;col<width;col++)
238                     buf[p++] = data[row*width+col];
239                 for(;col<texWidth;col++)
240                     buf[p++] = 0;
241             }
242             for(;row<texHeight;row++)
243                 for(col=0;col<texWidth;col++)
244                     buf[p++] = 0;
245         }
246     } else {
247         jint *data = elements((JArray<jint>*) data_);
248         buf = new unsigned char[texWidth*texHeight*4];
249         p=0;
250         for(row=0;row<height;row++) {
251             for(col=0;col<width;col++) {
252                 jint pixel = data[row*width+col];
253                 buf[p+0] = (pixel >> 16) & 0xff;
254                 buf[p+1] = (pixel >>  8) & 0xff;
255                 buf[p+2] = (pixel >>  0) & 0xff;
256                 buf[p+3] = (pixel >> 24) & 0xff;
257                 p+=4;
258             }
259             for(;col < texWidth;col++,p+=4)
260                 buf[p+0] = buf[p+1] = buf[p+2] = buf[p+3] = 0;
261         }
262         for(;row < texHeight;row++) 
263             for(col=0;col<texWidth;col++,p+=4)
264                 buf[p+0] = buf[p+1] = buf[p+2] = buf[p+3] = 0;
265     }
266     
267     gl->activateSharedContext();
268     glEnable(GL_TEXTURE_2D);
269     glGenTextures(1,&tex);
270     glBindTexture(GL_TEXTURE_2D,tex);
271     glPixelStorei(GL_PACK_ALIGNMENT,1);
272     glTexImage2D(GL_TEXTURE_2D,0,alphaOnly ? GL_ALPHA : GL_RGBA,texWidth,texHeight,0,alphaOnly ? GL_ALPHA : GL_RGBA,GL_UNSIGNED_BYTE,buf);
273     checkGLError();    
274     if(!alphaOnly || width != texWidth || height != texHeight) delete buf;
275
276     if(gl->glVersion >= 1.2) {
277         glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
278         glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
279         glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
280         glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
281     } else {
282         glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
283         glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
284     }
285
286     glDisable(GL_TEXTURE_2D);
287     checkGLError();
288   
289     textureName = (jint)tex;
290 }
291
292 void OpenGL$SquareGLPicture::draw(jint dx, jint dy, jint cx1, jint cy1, jint cx2, jint cy2) {
293     cx1 = max(dx, cx1);
294     cy1 = max(dy, cy1);
295     cx2 = min(cx2, dx + width);
296     cy2 = min(cy2, dy + height);
297     if (cy2 <= cy1 || cx2 <= cx1) return;
298     float tx1 = (float) (cx1 - dx) / (float) texWidth;
299     float ty1 = (float) (cy1 - dy) / (float) texHeight;
300     float tx2 = (float) (cx2 - dx) / (float) texWidth;
301     float ty2 = (float) (cy2 - dy) / (float) texHeight;
302     glEnable(GL_TEXTURE_2D);
303     glBindTexture(GL_TEXTURE_2D, textureName);    
304     checkGLError();
305     glBegin(GL_QUADS); {
306         glTexCoord2f (tx1,      ty1        );    
307         glVertex3i   (cx1,      cy1,      0);
308         glTexCoord2f (tx2,      ty1        );    
309         glVertex3i   (cx2,      cy1,      0);
310         glTexCoord2f (tx2,      ty2        );    
311         glVertex3i   (cx2,      cy2,      0);
312         glTexCoord2f (tx1,      ty2        );    
313         glVertex3i   (cx1,      cy2,      0);
314     } glEnd();
315     glDisable(GL_TEXTURE_2D);
316     checkGLError();
317 }
318
319 } } } // end org::ibex::plat