• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.jme3.renderer.lwjgl;
2 
3 import com.jme3.light.*;
4 import com.jme3.material.FixedFuncBinding;
5 import com.jme3.material.RenderState;
6 import com.jme3.math.ColorRGBA;
7 import com.jme3.math.FastMath;
8 import com.jme3.math.Matrix4f;
9 import com.jme3.math.Vector3f;
10 import com.jme3.renderer.Caps;
11 import com.jme3.renderer.GL1Renderer;
12 import com.jme3.renderer.RenderContext;
13 import com.jme3.renderer.Statistics;
14 import com.jme3.scene.Mesh;
15 import com.jme3.scene.Mesh.Mode;
16 import com.jme3.scene.VertexBuffer;
17 import com.jme3.scene.VertexBuffer.Type;
18 import com.jme3.scene.VertexBuffer.Usage;
19 import com.jme3.shader.Shader;
20 import com.jme3.shader.Shader.ShaderSource;
21 import com.jme3.texture.FrameBuffer;
22 import com.jme3.texture.Image;
23 import com.jme3.texture.Texture;
24 import com.jme3.texture.Texture.WrapAxis;
25 import com.jme3.util.BufferUtils;
26 import com.jme3.util.IntMap;
27 import com.jme3.util.IntMap.Entry;
28 import com.jme3.util.NativeObjectManager;
29 import java.nio.*;
30 import java.util.ArrayList;
31 import java.util.EnumSet;
32 import java.util.logging.Level;
33 import java.util.logging.Logger;
34 import jme3tools.converters.MipMapGenerator;
35 import static org.lwjgl.opengl.GL11.*;
36 import org.lwjgl.opengl.GL12;
37 import org.lwjgl.opengl.GL14;
38 import org.lwjgl.opengl.GLContext;
39 
40 public class LwjglGL1Renderer implements GL1Renderer {
41 
42     private static final Logger logger = Logger.getLogger(LwjglRenderer.class.getName());
43     private final ByteBuffer nameBuf = BufferUtils.createByteBuffer(250);
44     private final StringBuilder stringBuf = new StringBuilder(250);
45     private final IntBuffer ib1 = BufferUtils.createIntBuffer(1);
46     private final IntBuffer intBuf16 = BufferUtils.createIntBuffer(16);
47     private final FloatBuffer fb16 = BufferUtils.createFloatBuffer(16);
48     private final FloatBuffer fb4Null = BufferUtils.createFloatBuffer(4);
49     private final RenderContext context = new RenderContext();
50     private final NativeObjectManager objManager = new NativeObjectManager();
51     private final EnumSet<Caps> caps = EnumSet.noneOf(Caps.class);
52     private int maxTexSize;
53     private int maxCubeTexSize;
54     private int maxVertCount;
55     private int maxTriCount;
56     private int maxLights;
57     private boolean gl12 = false;
58     private final Statistics statistics = new Statistics();
59     private int vpX, vpY, vpW, vpH;
60     private int clipX, clipY, clipW, clipH;
61 
62     private Matrix4f worldMatrix = new Matrix4f();
63     private Matrix4f viewMatrix = new Matrix4f();
64 
65     private ArrayList<Light> lightList = new ArrayList<Light>(8);
66     private ColorRGBA materialAmbientColor = new ColorRGBA();
67     private Vector3f tempVec = new Vector3f();
68 
updateNameBuffer()69     protected void updateNameBuffer() {
70         int len = stringBuf.length();
71 
72         nameBuf.position(0);
73         nameBuf.limit(len);
74         for (int i = 0; i < len; i++) {
75             nameBuf.put((byte) stringBuf.charAt(i));
76         }
77 
78         nameBuf.rewind();
79     }
80 
getStatistics()81     public Statistics getStatistics() {
82         return statistics;
83     }
84 
getCaps()85     public EnumSet<Caps> getCaps() {
86         return caps;
87     }
88 
initialize()89     public void initialize() {
90         if (GLContext.getCapabilities().OpenGL12){
91             gl12 = true;
92         }
93 
94         // Default values for certain GL state.
95         glShadeModel(GL_SMOOTH);
96         glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
97         glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
98 
99 		// Enable rescaling/normaling of normal vectors.
100 		// Fixes lighting issues with scaled models.
101         if (gl12){
102             glEnable(GL12.GL_RESCALE_NORMAL);
103         }else{
104             glEnable(GL_NORMALIZE);
105         }
106 
107         if (GLContext.getCapabilities().GL_ARB_texture_non_power_of_two) {
108             caps.add(Caps.NonPowerOfTwoTextures);
109         } else {
110             logger.log(Level.WARNING, "Your graphics card does not "
111                     + "support non-power-of-2 textures. "
112                     + "Some features might not work.");
113         }
114 
115         maxLights = glGetInteger(GL_MAX_LIGHTS);
116 
117     }
118 
invalidateState()119     public void invalidateState() {
120         context.reset();
121     }
122 
resetGLObjects()123     public void resetGLObjects() {
124         logger.log(Level.INFO, "Reseting objects and invalidating state");
125         objManager.resetObjects();
126         statistics.clearMemory();
127         invalidateState();
128     }
129 
cleanup()130     public void cleanup() {
131         logger.log(Level.INFO, "Deleting objects and invalidating state");
132         objManager.deleteAllObjects(this);
133         statistics.clearMemory();
134         invalidateState();
135     }
136 
setDepthRange(float start, float end)137     public void setDepthRange(float start, float end) {
138         glDepthRange(start, end);
139     }
140 
clearBuffers(boolean color, boolean depth, boolean stencil)141     public void clearBuffers(boolean color, boolean depth, boolean stencil) {
142         int bits = 0;
143         if (color) {
144             //See explanations of the depth below, we must enable color write to be able to clear the color buffer
145             if (context.colorWriteEnabled == false) {
146                 glColorMask(true, true, true, true);
147                 context.colorWriteEnabled = true;
148             }
149             bits = GL_COLOR_BUFFER_BIT;
150         }
151         if (depth) {
152 
153             //glClear(GL_DEPTH_BUFFER_BIT) seems to not work when glDepthMask is false
154             //here s some link on openl board
155             //http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=257223
156             //if depth clear is requested, we enable the depthMask
157             if (context.depthWriteEnabled == false) {
158                 glDepthMask(true);
159                 context.depthWriteEnabled = true;
160             }
161             bits |= GL_DEPTH_BUFFER_BIT;
162         }
163         if (stencil) {
164             bits |= GL_STENCIL_BUFFER_BIT;
165         }
166         if (bits != 0) {
167             glClear(bits);
168         }
169     }
170 
setBackgroundColor(ColorRGBA color)171     public void setBackgroundColor(ColorRGBA color) {
172         glClearColor(color.r, color.g, color.b, color.a);
173     }
174 
setMaterialColor(int type, ColorRGBA color, ColorRGBA defaultColor)175     private void setMaterialColor(int type, ColorRGBA color, ColorRGBA defaultColor) {
176         if (color != null){
177             fb16.put(color.r).put(color.g).put(color.b).put(color.a).flip();
178         }else{
179             fb16.put(defaultColor.r).put(defaultColor.g).put(defaultColor.b).put(defaultColor.a).flip();
180         }
181         glMaterial(GL_FRONT_AND_BACK, type, fb16);
182     }
183 
184     /**
185      * Applies fixed function bindings from the context to OpenGL
186      */
applyFixedFuncBindings(boolean forLighting)187     private void applyFixedFuncBindings(boolean forLighting){
188         if (forLighting){
189             glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, context.shininess);
190             setMaterialColor(GL_AMBIENT,  context.ambient,  ColorRGBA.DarkGray);
191             setMaterialColor(GL_DIFFUSE,  context.diffuse,  ColorRGBA.White);
192             setMaterialColor(GL_SPECULAR, context.specular, ColorRGBA.Black);
193 
194             if (context.useVertexColor){
195                 glEnable(GL_COLOR_MATERIAL);
196             }else{
197                 glDisable(GL_COLOR_MATERIAL);
198             }
199         }else{
200             // Ignore other values as they have no effect when
201             // GL_LIGHTING is disabled.
202             ColorRGBA color = context.color;
203             if (color != null){
204                 glColor4f(color.r, color.g, color.b, color.a);
205             }else{
206                 glColor4f(1,1,1,1);
207             }
208         }
209     }
210 
211     /**
212      * Reset fixed function bindings to default values.
213      */
resetFixedFuncBindings()214     private void resetFixedFuncBindings(){
215         context.color = null;
216         context.ambient = null;
217         context.diffuse = null;
218         context.specular = null;
219         context.shininess = 0;
220         context.useVertexColor = false;
221     }
222 
setFixedFuncBinding(FixedFuncBinding ffBinding, Object val)223     public void setFixedFuncBinding(FixedFuncBinding ffBinding, Object val) {
224         switch (ffBinding) {
225             case Color:
226                 context.color = (ColorRGBA) val;
227                 break;
228             case MaterialAmbient:
229                 context.ambient = (ColorRGBA) val;
230                 break;
231             case MaterialDiffuse:
232                 context.diffuse = (ColorRGBA) val;
233                 break;
234             case MaterialSpecular:
235                 context.specular = (ColorRGBA) val;
236                 break;
237             case MaterialShininess:
238                 context.shininess = (Float) val;
239                 break;
240             case UseVertexColor:
241                 context.useVertexColor = (Boolean) val;
242                 break;
243         }
244     }
245 
applyRenderState(RenderState state)246     public void applyRenderState(RenderState state) {
247         if (state.isWireframe() && !context.wireframe) {
248             glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
249             context.wireframe = true;
250         } else if (!state.isWireframe() && context.wireframe) {
251             glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
252             context.wireframe = false;
253         }
254 
255         if (state.isDepthTest() && !context.depthTestEnabled) {
256             glEnable(GL_DEPTH_TEST);
257             glDepthFunc(GL_LEQUAL);
258             context.depthTestEnabled = true;
259         } else if (!state.isDepthTest() && context.depthTestEnabled) {
260             glDisable(GL_DEPTH_TEST);
261             context.depthTestEnabled = false;
262         }
263 
264         if (state.isAlphaTest() && !context.alphaTestEnabled) {
265             glEnable(GL_ALPHA_TEST);
266             glAlphaFunc(GL_GREATER, state.getAlphaFallOff());
267             context.alphaTestEnabled = true;
268         } else if (!state.isAlphaTest() && context.alphaTestEnabled) {
269             glDisable(GL_ALPHA_TEST);
270             context.alphaTestEnabled = false;
271         }
272 
273         if (state.isDepthWrite() && !context.depthWriteEnabled) {
274             glDepthMask(true);
275             context.depthWriteEnabled = true;
276         } else if (!state.isDepthWrite() && context.depthWriteEnabled) {
277             glDepthMask(false);
278             context.depthWriteEnabled = false;
279         }
280 
281         if (state.isColorWrite() && !context.colorWriteEnabled) {
282             glColorMask(true, true, true, true);
283             context.colorWriteEnabled = true;
284         } else if (!state.isColorWrite() && context.colorWriteEnabled) {
285             glColorMask(false, false, false, false);
286             context.colorWriteEnabled = false;
287         }
288 
289         if (state.isPointSprite()) {
290             logger.log(Level.WARNING, "Point Sprite unsupported!");
291         }
292 
293         if (state.isPolyOffset()) {
294             if (!context.polyOffsetEnabled) {
295                 glEnable(GL_POLYGON_OFFSET_FILL);
296                 glPolygonOffset(state.getPolyOffsetFactor(),
297                         state.getPolyOffsetUnits());
298                 context.polyOffsetEnabled = true;
299                 context.polyOffsetFactor = state.getPolyOffsetFactor();
300                 context.polyOffsetUnits = state.getPolyOffsetUnits();
301             } else {
302                 if (state.getPolyOffsetFactor() != context.polyOffsetFactor
303                         || state.getPolyOffsetUnits() != context.polyOffsetUnits) {
304                     glPolygonOffset(state.getPolyOffsetFactor(),
305                             state.getPolyOffsetUnits());
306                     context.polyOffsetFactor = state.getPolyOffsetFactor();
307                     context.polyOffsetUnits = state.getPolyOffsetUnits();
308                 }
309             }
310         } else {
311             if (context.polyOffsetEnabled) {
312                 glDisable(GL_POLYGON_OFFSET_FILL);
313                 context.polyOffsetEnabled = false;
314                 context.polyOffsetFactor = 0;
315                 context.polyOffsetUnits = 0;
316             }
317         }
318         if (state.getFaceCullMode() != context.cullMode) {
319             if (state.getFaceCullMode() == RenderState.FaceCullMode.Off) {
320                 glDisable(GL_CULL_FACE);
321             } else {
322                 glEnable(GL_CULL_FACE);
323             }
324 
325             switch (state.getFaceCullMode()) {
326                 case Off:
327                     break;
328                 case Back:
329                     glCullFace(GL_BACK);
330                     break;
331                 case Front:
332                     glCullFace(GL_FRONT);
333                     break;
334                 case FrontAndBack:
335                     glCullFace(GL_FRONT_AND_BACK);
336                     break;
337                 default:
338                     throw new UnsupportedOperationException("Unrecognized face cull mode: "
339                             + state.getFaceCullMode());
340             }
341 
342             context.cullMode = state.getFaceCullMode();
343         }
344 
345         if (state.getBlendMode() != context.blendMode) {
346             if (state.getBlendMode() == RenderState.BlendMode.Off) {
347                 glDisable(GL_BLEND);
348             } else {
349                 glEnable(GL_BLEND);
350                 switch (state.getBlendMode()) {
351                     case Off:
352                         break;
353                     case Additive:
354                         glBlendFunc(GL_ONE, GL_ONE);
355                         break;
356                     case AlphaAdditive:
357                         glBlendFunc(GL_SRC_ALPHA, GL_ONE);
358                         break;
359                     case Color:
360                         glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR);
361                         break;
362                     case Alpha:
363                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
364                         break;
365                     case PremultAlpha:
366                         glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
367                         break;
368                     case Modulate:
369                         glBlendFunc(GL_DST_COLOR, GL_ZERO);
370                         break;
371                     case ModulateX2:
372                         glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
373                         break;
374                     default:
375                         throw new UnsupportedOperationException("Unrecognized blend mode: "
376                                 + state.getBlendMode());
377                 }
378             }
379 
380             context.blendMode = state.getBlendMode();
381         }
382 
383         if (state.isStencilTest()) {
384             throw new UnsupportedOperationException("OpenGL 1.1 doesn't support two sided stencil operations.");
385         }
386 
387     }
388 
setViewPort(int x, int y, int w, int h)389     public void setViewPort(int x, int y, int w, int h) {
390         if (x != vpX || vpY != y || vpW != w || vpH != h) {
391             glViewport(x, y, w, h);
392             vpX = x;
393             vpY = y;
394             vpW = w;
395             vpH = h;
396         }
397     }
398 
setClipRect(int x, int y, int width, int height)399     public void setClipRect(int x, int y, int width, int height) {
400         if (!context.clipRectEnabled) {
401             glEnable(GL_SCISSOR_TEST);
402             context.clipRectEnabled = true;
403         }
404         if (clipX != x || clipY != y || clipW != width || clipH != height) {
405             glScissor(x, y, width, height);
406             clipX = x;
407             clipY = y;
408             clipW = width;
409             clipH = height;
410         }
411     }
412 
clearClipRect()413     public void clearClipRect() {
414         if (context.clipRectEnabled) {
415             glDisable(GL_SCISSOR_TEST);
416             context.clipRectEnabled = false;
417 
418             clipX = 0;
419             clipY = 0;
420             clipW = 0;
421             clipH = 0;
422         }
423     }
424 
onFrame()425     public void onFrame() {
426         objManager.deleteUnused(this);
427 //        statistics.clearFrame();
428     }
429 
storeMatrix(Matrix4f matrix, FloatBuffer store)430     private FloatBuffer storeMatrix(Matrix4f matrix, FloatBuffer store) {
431         store.clear();
432         matrix.fillFloatBuffer(store, true);
433         store.clear();
434         return store;
435     }
436 
setModelView(Matrix4f modelMatrix, Matrix4f viewMatrix)437     private void setModelView(Matrix4f modelMatrix, Matrix4f viewMatrix){
438         if (context.matrixMode != GL_MODELVIEW) {
439             glMatrixMode(GL_MODELVIEW);
440             context.matrixMode = GL_MODELVIEW;
441         }
442 
443         glLoadMatrix(storeMatrix(viewMatrix, fb16));
444         glMultMatrix(storeMatrix(modelMatrix, fb16));
445     }
446 
setProjection(Matrix4f projMatrix)447     private void setProjection(Matrix4f projMatrix){
448         if (context.matrixMode != GL_PROJECTION) {
449             glMatrixMode(GL_PROJECTION);
450             context.matrixMode = GL_PROJECTION;
451         }
452 
453         glLoadMatrix(storeMatrix(projMatrix, fb16));
454     }
455 
setWorldMatrix(Matrix4f worldMatrix)456     public void setWorldMatrix(Matrix4f worldMatrix) {
457         this.worldMatrix.set(worldMatrix);
458     }
459 
setViewProjectionMatrices(Matrix4f viewMatrix, Matrix4f projMatrix)460     public void setViewProjectionMatrices(Matrix4f viewMatrix, Matrix4f projMatrix) {
461         this.viewMatrix.set(viewMatrix);
462         setProjection(projMatrix);
463     }
464 
setLighting(LightList list)465     public void setLighting(LightList list) {
466         // XXX: This is abuse of setLighting() to
467 		// apply fixed function bindings
468         // and do other book keeping.
469         if (list == null || list.size() == 0){
470             glDisable(GL_LIGHTING);
471             applyFixedFuncBindings(false);
472             setModelView(worldMatrix, viewMatrix);
473             return;
474         }
475 
476         // Number of lights set previously
477         int numLightsSetPrev = lightList.size();
478 
479         // If more than maxLights are defined, they will be ignored.
480         // The GL1 renderer is not permitted to crash due to a
481         // GL1 limitation. It must render anything that the GL2 renderer
482         // can render (even incorrectly).
483         lightList.clear();
484         materialAmbientColor.set(0, 0, 0, 0);
485 
486         for (int i = 0; i < list.size(); i++){
487             Light l = list.get(i);
488             if (l.getType() == Light.Type.Ambient){
489                 // Gather
490                 materialAmbientColor.addLocal(l.getColor());
491             }else{
492                 // Add to list
493                 lightList.add(l);
494 
495                 // Once maximum lights reached, exit loop.
496                 if (lightList.size() >= maxLights){
497                     break;
498                 }
499             }
500         }
501 
502         applyFixedFuncBindings(true);
503 
504         glEnable(GL_LIGHTING);
505 
506         fb16.clear();
507         fb16.put(materialAmbientColor.r)
508             .put(materialAmbientColor.g)
509             .put(materialAmbientColor.b)
510             .put(1).flip();
511 
512         glLightModel(GL_LIGHT_MODEL_AMBIENT, fb16);
513 
514         if (context.matrixMode != GL_MODELVIEW) {
515             glMatrixMode(GL_MODELVIEW);
516             context.matrixMode = GL_MODELVIEW;
517         }
518         // Lights are already in world space, so just convert
519         // them to view space.
520         glLoadMatrix(storeMatrix(viewMatrix, fb16));
521 
522         for (int i = 0; i < lightList.size(); i++){
523             int glLightIndex = GL_LIGHT0 + i;
524             Light light = lightList.get(i);
525             Light.Type lightType = light.getType();
526             ColorRGBA col = light.getColor();
527             Vector3f pos;
528 
529             // Enable the light
530             glEnable(glLightIndex);
531 
532             // OGL spec states default value for light ambient is black
533             switch (lightType){
534                 case Directional:
535                     DirectionalLight dLight = (DirectionalLight) light;
536 
537                     fb16.clear();
538                     fb16.put(col.r).put(col.g).put(col.b).put(col.a).flip();
539                     glLight(glLightIndex, GL_DIFFUSE, fb16);
540                     glLight(glLightIndex, GL_SPECULAR, fb16);
541 
542                     pos = tempVec.set(dLight.getDirection()).negateLocal().normalizeLocal();
543                     fb16.clear();
544                     fb16.put(pos.x).put(pos.y).put(pos.z).put(0.0f).flip();
545                     glLight(glLightIndex, GL_POSITION, fb16);
546                     glLightf(glLightIndex, GL_SPOT_CUTOFF, 180);
547                     break;
548                 case Point:
549                     PointLight pLight = (PointLight) light;
550 
551                     fb16.clear();
552                     fb16.put(col.r).put(col.g).put(col.b).put(col.a).flip();
553                     glLight(glLightIndex, GL_DIFFUSE, fb16);
554                     glLight(glLightIndex, GL_SPECULAR, fb16);
555 
556                     pos = pLight.getPosition();
557                     fb16.clear();
558                     fb16.put(pos.x).put(pos.y).put(pos.z).put(1.0f).flip();
559                     glLight(glLightIndex, GL_POSITION, fb16);
560                     glLightf(glLightIndex, GL_SPOT_CUTOFF, 180);
561 
562                     if (pLight.getRadius() > 0) {
563                         // Note: this doesn't follow the same attenuation model
564                         // as the one used in the lighting shader.
565                         glLightf(glLightIndex, GL_CONSTANT_ATTENUATION,  1);
566                         glLightf(glLightIndex, GL_LINEAR_ATTENUATION,    pLight.getInvRadius() * 2);
567                         glLightf(glLightIndex, GL_QUADRATIC_ATTENUATION, pLight.getInvRadius() * pLight.getInvRadius());
568                     }else{
569                         glLightf(glLightIndex, GL_CONSTANT_ATTENUATION,  1);
570                         glLightf(glLightIndex, GL_LINEAR_ATTENUATION,    0);
571                         glLightf(glLightIndex, GL_QUADRATIC_ATTENUATION, 0);
572                     }
573 
574                     break;
575                 case Spot:
576                     SpotLight sLight = (SpotLight) light;
577 
578                     fb16.clear();
579                     fb16.put(col.r).put(col.g).put(col.b).put(col.a).flip();
580                     glLight(glLightIndex, GL_DIFFUSE, fb16);
581                     glLight(glLightIndex, GL_SPECULAR, fb16);
582 
583                     pos = sLight.getPosition();
584                     fb16.clear();
585                     fb16.put(pos.x).put(pos.y).put(pos.z).put(1.0f).flip();
586                     glLight(glLightIndex, GL_POSITION, fb16);
587 
588                     Vector3f dir = sLight.getDirection();
589                     fb16.clear();
590                     fb16.put(dir.x).put(dir.y).put(dir.z).put(1.0f).flip();
591                     glLight(glLightIndex, GL_SPOT_DIRECTION, fb16);
592 
593                     float outerAngleRad = sLight.getSpotOuterAngle();
594                     float innerAngleRad = sLight.getSpotInnerAngle();
595                     float spotCut = outerAngleRad * FastMath.RAD_TO_DEG;
596                     float spotExpo = 0.0f;
597                     if (outerAngleRad > 0) {
598                         spotExpo = (1.0f - (innerAngleRad / outerAngleRad)) * 128.0f;
599                     }
600 
601                     glLightf(glLightIndex, GL_SPOT_CUTOFF, spotCut);
602                     glLightf(glLightIndex, GL_SPOT_EXPONENT, spotExpo);
603 
604                     if (sLight.getSpotRange() > 0) {
605                         glLightf(glLightIndex, GL_LINEAR_ATTENUATION, sLight.getInvSpotRange());
606                     }else{
607                         glLightf(glLightIndex, GL_LINEAR_ATTENUATION, 0);
608                     }
609 
610                     break;
611                 default:
612                     throw new UnsupportedOperationException(
613                             "Unrecognized light type: " + lightType);
614             }
615         }
616 
617         // Disable lights after the index
618         for (int i = lightList.size(); i < numLightsSetPrev; i++){
619             glDisable(GL_LIGHT0 + i);
620         }
621 
622         // This will set view matrix as well.
623         setModelView(worldMatrix, viewMatrix);
624     }
625 
convertTextureType(Texture.Type type)626     private int convertTextureType(Texture.Type type) {
627         switch (type) {
628             case TwoDimensional:
629                 return GL_TEXTURE_2D;
630 //            case ThreeDimensional:
631 //                return GL_TEXTURE_3D;
632 //            case CubeMap:
633 //                return GL_TEXTURE_CUBE_MAP;
634             default:
635                 throw new UnsupportedOperationException("Unknown texture type: " + type);
636         }
637     }
638 
convertMagFilter(Texture.MagFilter filter)639     private int convertMagFilter(Texture.MagFilter filter) {
640         switch (filter) {
641             case Bilinear:
642                 return GL_LINEAR;
643             case Nearest:
644                 return GL_NEAREST;
645             default:
646                 throw new UnsupportedOperationException("Unknown mag filter: " + filter);
647         }
648     }
649 
convertMinFilter(Texture.MinFilter filter)650     private int convertMinFilter(Texture.MinFilter filter) {
651         switch (filter) {
652             case Trilinear:
653                 return GL_LINEAR_MIPMAP_LINEAR;
654             case BilinearNearestMipMap:
655                 return GL_LINEAR_MIPMAP_NEAREST;
656             case NearestLinearMipMap:
657                 return GL_NEAREST_MIPMAP_LINEAR;
658             case NearestNearestMipMap:
659                 return GL_NEAREST_MIPMAP_NEAREST;
660             case BilinearNoMipMaps:
661                 return GL_LINEAR;
662             case NearestNoMipMaps:
663                 return GL_NEAREST;
664             default:
665                 throw new UnsupportedOperationException("Unknown min filter: " + filter);
666         }
667     }
668 
convertWrapMode(Texture.WrapMode mode)669     private int convertWrapMode(Texture.WrapMode mode) {
670         switch (mode) {
671             case EdgeClamp:
672             case Clamp:
673             case BorderClamp:
674                 return GL_CLAMP;
675             case Repeat:
676                 return GL_REPEAT;
677             default:
678                 throw new UnsupportedOperationException("Unknown wrap mode: " + mode);
679         }
680     }
681 
setupTextureParams(Texture tex)682     private void setupTextureParams(Texture tex) {
683         int target = convertTextureType(tex.getType());
684 
685         // filter things
686         int minFilter = convertMinFilter(tex.getMinFilter());
687         int magFilter = convertMagFilter(tex.getMagFilter());
688         glTexParameteri(target, GL_TEXTURE_MIN_FILTER, minFilter);
689         glTexParameteri(target, GL_TEXTURE_MAG_FILTER, magFilter);
690 
691         // repeat modes
692         switch (tex.getType()) {
693 //            case ThreeDimensional:
694 //            case CubeMap:
695 //                glTexParameteri(target, GL_TEXTURE_WRAP_R, convertWrapMode(tex.getWrap(WrapAxis.R)));
696             case TwoDimensional:
697                 glTexParameteri(target, GL_TEXTURE_WRAP_T, convertWrapMode(tex.getWrap(WrapAxis.T)));
698                 // fall down here is intentional..
699 //            case OneDimensional:
700                 glTexParameteri(target, GL_TEXTURE_WRAP_S, convertWrapMode(tex.getWrap(WrapAxis.S)));
701                 break;
702             default:
703                 throw new UnsupportedOperationException("Unknown texture type: " + tex.getType());
704         }
705     }
706 
updateTexImageData(Image img, Texture.Type type, boolean mips, int unit)707     public void updateTexImageData(Image img, Texture.Type type, boolean mips, int unit) {
708         int texId = img.getId();
709         if (texId == -1) {
710             // create texture
711             glGenTextures(ib1);
712             texId = ib1.get(0);
713             img.setId(texId);
714             objManager.registerForCleanup(img);
715 
716             statistics.onNewTexture();
717         }
718 
719         // bind texture
720         int target = convertTextureType(type);
721 //        if (context.boundTextureUnit != unit) {
722 //            glActiveTexture(GL_TEXTURE0 + unit);
723 //            context.boundTextureUnit = unit;
724 //        }
725         if (context.boundTextures[unit] != img) {
726             glEnable(target);
727             glBindTexture(target, texId);
728             context.boundTextures[unit] = img;
729 
730             statistics.onTextureUse(img, true);
731         }
732 
733         // Check sizes if graphics card doesn't support NPOT
734         if (!GLContext.getCapabilities().GL_ARB_texture_non_power_of_two) {
735             if (img.getWidth() != 0 && img.getHeight() != 0) {
736                 if (!FastMath.isPowerOfTwo(img.getWidth())
737                         || !FastMath.isPowerOfTwo(img.getHeight())) {
738 
739                     // Resize texture to Power-of-2 size
740                     MipMapGenerator.resizeToPowerOf2(img);
741 
742                 }
743             }
744         }
745 
746         if (!img.hasMipmaps() && mips) {
747             // No pregenerated mips available,
748             // generate from base level if required
749 
750             // Check if hardware mips are supported
751             if (GLContext.getCapabilities().OpenGL14) {
752                 glTexParameteri(target, GL14.GL_GENERATE_MIPMAP, GL_TRUE);
753             } else {
754                 MipMapGenerator.generateMipMaps(img);
755             }
756         } else {
757         }
758 
759         /*
760         if (target == GL_TEXTURE_CUBE_MAP) {
761         List<ByteBuffer> data = img.getData();
762         if (data.size() != 6) {
763         logger.log(Level.WARNING, "Invalid texture: {0}\n"
764         + "Cubemap textures must contain 6 data units.", img);
765         return;
766         }
767         for (int i = 0; i < 6; i++) {
768         TextureUtil.uploadTexture(img, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, i, 0, tdc);
769         }
770         } else if (target == EXTTextureArray.GL_TEXTURE_2D_ARRAY_EXT) {
771         List<ByteBuffer> data = img.getData();
772         // -1 index specifies prepare data for 2D Array
773         TextureUtil.uploadTexture(img, target, -1, 0, tdc);
774         for (int i = 0; i < data.size(); i++) {
775         // upload each slice of 2D array in turn
776         // this time with the appropriate index
777         TextureUtil.uploadTexture(img, target, i, 0, tdc);
778         }
779         } else {*/
780         TextureUtil.uploadTexture(img, target, 0, 0, false);
781         //}
782 
783         img.clearUpdateNeeded();
784     }
785 
setTexture(int unit, Texture tex)786     public void setTexture(int unit, Texture tex) {
787         if (unit != 0 || tex.getType() != Texture.Type.TwoDimensional) {
788             //throw new UnsupportedOperationException();
789             return;
790         }
791 
792         Image image = tex.getImage();
793         if (image.isUpdateNeeded()) {
794             updateTexImageData(image, tex.getType(), tex.getMinFilter().usesMipMapLevels(), unit);
795         }
796 
797         int texId = image.getId();
798         assert texId != -1;
799 
800         Image[] textures = context.boundTextures;
801 
802         int type = convertTextureType(tex.getType());
803 //        if (!context.textureIndexList.moveToNew(unit)) {
804 //             if (context.boundTextureUnit != unit){
805 //                glActiveTexture(GL_TEXTURE0 + unit);
806 //                context.boundTextureUnit = unit;
807 //             }
808 //             glEnable(type);
809 //        }
810 
811 //        if (context.boundTextureUnit != unit) {
812 //            glActiveTexture(GL_TEXTURE0 + unit);
813 //            context.boundTextureUnit = unit;
814 //        }
815 
816         if (textures[unit] != image) {
817             glEnable(type);
818             glBindTexture(type, texId);
819             textures[unit] = image;
820 
821             statistics.onTextureUse(image, true);
822         } else {
823             statistics.onTextureUse(image, false);
824         }
825 
826         setupTextureParams(tex);
827     }
828 
clearTextureUnits()829     private void clearTextureUnits() {
830         Image[] textures = context.boundTextures;
831         if (textures[0] != null) {
832             glDisable(GL_TEXTURE_2D);
833             textures[0] = null;
834         }
835     }
836 
deleteImage(Image image)837     public void deleteImage(Image image) {
838         int texId = image.getId();
839         if (texId != -1) {
840             ib1.put(0, texId);
841             ib1.position(0).limit(1);
842             glDeleteTextures(ib1);
843             image.resetObject();
844         }
845     }
846 
convertArrayType(VertexBuffer.Type type)847     private int convertArrayType(VertexBuffer.Type type) {
848         switch (type) {
849             case Position:
850                 return GL_VERTEX_ARRAY;
851             case Normal:
852                 return GL_NORMAL_ARRAY;
853             case TexCoord:
854                 return GL_TEXTURE_COORD_ARRAY;
855             case Color:
856                 return GL_COLOR_ARRAY;
857             default:
858                 return -1; // unsupported
859         }
860     }
861 
convertVertexFormat(VertexBuffer.Format fmt)862     private int convertVertexFormat(VertexBuffer.Format fmt) {
863         switch (fmt) {
864             case Byte:
865                 return GL_BYTE;
866             case Float:
867                 return GL_FLOAT;
868             case Int:
869                 return GL_INT;
870             case Short:
871                 return GL_SHORT;
872             case UnsignedByte:
873                 return GL_UNSIGNED_BYTE;
874             case UnsignedInt:
875                 return GL_UNSIGNED_INT;
876             case UnsignedShort:
877                 return GL_UNSIGNED_SHORT;
878             default:
879                 throw new UnsupportedOperationException("Unrecognized vertex format: " + fmt);
880         }
881     }
882 
convertElementMode(Mesh.Mode mode)883     private int convertElementMode(Mesh.Mode mode) {
884         switch (mode) {
885             case Points:
886                 return GL_POINTS;
887             case Lines:
888                 return GL_LINES;
889             case LineLoop:
890                 return GL_LINE_LOOP;
891             case LineStrip:
892                 return GL_LINE_STRIP;
893             case Triangles:
894                 return GL_TRIANGLES;
895             case TriangleFan:
896                 return GL_TRIANGLE_FAN;
897             case TriangleStrip:
898                 return GL_TRIANGLE_STRIP;
899             default:
900                 throw new UnsupportedOperationException("Unrecognized mesh mode: " + mode);
901         }
902     }
903 
drawTriangleArray(Mesh.Mode mode, int count, int vertCount)904     public void drawTriangleArray(Mesh.Mode mode, int count, int vertCount) {
905         if (count > 1) {
906             throw new UnsupportedOperationException();
907         }
908 
909         glDrawArrays(convertElementMode(mode), 0, vertCount);
910     }
911 
setVertexAttrib(VertexBuffer vb, VertexBuffer idb)912     public void setVertexAttrib(VertexBuffer vb, VertexBuffer idb) {
913         int arrayType = convertArrayType(vb.getBufferType());
914         if (arrayType == -1) {
915             return; // unsupported
916         }
917         glEnableClientState(arrayType);
918         context.boundAttribs[vb.getBufferType().ordinal()] = vb;
919 
920         if (vb.getBufferType() == Type.Normal) {
921             // normalize if requested
922             if (vb.isNormalized() && !context.normalizeEnabled) {
923                 glEnable(GL_NORMALIZE);
924                 context.normalizeEnabled = true;
925             } else if (!vb.isNormalized() && context.normalizeEnabled) {
926                 glDisable(GL_NORMALIZE);
927                 context.normalizeEnabled = false;
928             }
929         }
930 
931         // NOTE: Use data from interleaved buffer if specified
932         Buffer data = idb != null ? idb.getData() : vb.getData();
933         int comps = vb.getNumComponents();
934         int type = convertVertexFormat(vb.getFormat());
935 
936         data.rewind();
937 
938         switch (vb.getBufferType()) {
939             case Position:
940                 if (!(data instanceof FloatBuffer)) {
941                     throw new UnsupportedOperationException();
942                 }
943 
944                 glVertexPointer(comps, vb.getStride(), (FloatBuffer) data);
945                 break;
946             case Normal:
947                 if (!(data instanceof FloatBuffer)) {
948                     throw new UnsupportedOperationException();
949                 }
950 
951                 glNormalPointer(vb.getStride(), (FloatBuffer) data);
952                 break;
953             case Color:
954                 if (data instanceof FloatBuffer) {
955                     glColorPointer(comps, vb.getStride(), (FloatBuffer) data);
956                 } else if (data instanceof ByteBuffer) {
957                     glColorPointer(comps, true, vb.getStride(), (ByteBuffer) data);
958                 } else {
959                     throw new UnsupportedOperationException();
960                 }
961                 break;
962             case TexCoord:
963                 if (!(data instanceof FloatBuffer)) {
964                     throw new UnsupportedOperationException();
965                 }
966 
967                 glTexCoordPointer(comps, vb.getStride(), (FloatBuffer) data);
968                 break;
969             default:
970                 // Ignore, this is an unsupported attribute for OpenGL1.
971                 break;
972         }
973     }
974 
setVertexAttrib(VertexBuffer vb)975     public void setVertexAttrib(VertexBuffer vb) {
976         setVertexAttrib(vb, null);
977     }
978 
drawElements(int mode, int format, Buffer data)979     private void drawElements(int mode, int format, Buffer data) {
980         switch (format) {
981             case GL_UNSIGNED_BYTE:
982                 glDrawElements(mode, (ByteBuffer) data);
983                 break;
984             case GL_UNSIGNED_SHORT:
985                 glDrawElements(mode, (ShortBuffer) data);
986                 break;
987             case GL_UNSIGNED_INT:
988                 glDrawElements(mode, (IntBuffer) data);
989                 break;
990             default:
991                 throw new UnsupportedOperationException();
992         }
993     }
994 
drawTriangleList(VertexBuffer indexBuf, Mesh mesh, int count)995     public void drawTriangleList(VertexBuffer indexBuf, Mesh mesh, int count) {
996         Mesh.Mode mode = mesh.getMode();
997 
998         Buffer indexData = indexBuf.getData();
999         indexData.rewind();
1000 
1001         if (mesh.getMode() == Mode.Hybrid) {
1002             throw new UnsupportedOperationException();
1003             /*
1004             int[] modeStart = mesh.getModeStart();
1005             int[] elementLengths = mesh.getElementLengths();
1006 
1007             int elMode = convertElementMode(Mode.Triangles);
1008             int fmt = convertVertexFormat(indexBuf.getFormat());
1009             //            int elSize = indexBuf.getFormat().getComponentSize();
1010             //            int listStart = modeStart[0];
1011             int stripStart = modeStart[1];
1012             int fanStart = modeStart[2];
1013             int curOffset = 0;
1014             for (int i = 0; i < elementLengths.length; i++) {
1015             if (i == stripStart) {
1016             elMode = convertElementMode(Mode.TriangleStrip);
1017             } else if (i == fanStart) {
1018             elMode = convertElementMode(Mode.TriangleStrip);
1019             }
1020             int elementLength = elementLengths[i];
1021             indexData.position(curOffset);
1022 
1023             drawElements(elMode,
1024             fmt,
1025             indexData);
1026 
1027             curOffset += elementLength;
1028             }*/
1029         } else {
1030             drawElements(convertElementMode(mode),
1031                     convertVertexFormat(indexBuf.getFormat()),
1032                     indexData);
1033         }
1034     }
1035 
clearVertexAttribs()1036     public void clearVertexAttribs() {
1037         for (int i = 0; i < 16; i++) {
1038             VertexBuffer vb = context.boundAttribs[i];
1039             if (vb != null) {
1040                 int arrayType = convertArrayType(vb.getBufferType());
1041                 glDisableClientState(arrayType);
1042                 context.boundAttribs[vb.getBufferType().ordinal()] = null;
1043             }
1044         }
1045     }
1046 
renderMeshDefault(Mesh mesh, int lod, int count)1047     private void renderMeshDefault(Mesh mesh, int lod, int count) {
1048         VertexBuffer indices = null;
1049 
1050         VertexBuffer interleavedData = mesh.getBuffer(Type.InterleavedData);
1051         if (interleavedData != null && interleavedData.isUpdateNeeded()) {
1052             updateBufferData(interleavedData);
1053         }
1054 
1055         IntMap<VertexBuffer> buffers = mesh.getBuffers();
1056         if (mesh.getNumLodLevels() > 0) {
1057             indices = mesh.getLodLevel(lod);
1058         } else {
1059             indices = buffers.get(Type.Index.ordinal());
1060         }
1061         for (Entry<VertexBuffer> entry : buffers) {
1062             VertexBuffer vb = entry.getValue();
1063 
1064             if (vb.getBufferType() == Type.InterleavedData
1065                     || vb.getUsage() == Usage.CpuOnly // ignore cpu-only buffers
1066                     || vb.getBufferType() == Type.Index) {
1067                 continue;
1068             }
1069 
1070             if (vb.getStride() == 0) {
1071                 // not interleaved
1072                 setVertexAttrib(vb);
1073             } else {
1074                 // interleaved
1075                 setVertexAttrib(vb, interleavedData);
1076             }
1077         }
1078 
1079         if (indices != null) {
1080             drawTriangleList(indices, mesh, count);
1081         } else {
1082             glDrawArrays(convertElementMode(mesh.getMode()), 0, mesh.getVertexCount());
1083         }
1084 
1085         // TODO: Fix these to use IDList??
1086         clearVertexAttribs();
1087         clearTextureUnits();
1088         resetFixedFuncBindings();
1089     }
1090 
renderMesh(Mesh mesh, int lod, int count)1091     public void renderMesh(Mesh mesh, int lod, int count) {
1092         if (mesh.getVertexCount() == 0) {
1093             return;
1094         }
1095 
1096         if (context.pointSize != mesh.getPointSize()) {
1097             glPointSize(mesh.getPointSize());
1098             context.pointSize = mesh.getPointSize();
1099         }
1100         if (context.lineWidth != mesh.getLineWidth()) {
1101             glLineWidth(mesh.getLineWidth());
1102             context.lineWidth = mesh.getLineWidth();
1103         }
1104 
1105         boolean dynamic = false;
1106         if (mesh.getBuffer(Type.InterleavedData) != null) {
1107             throw new UnsupportedOperationException("Interleaved meshes are not supported");
1108         }
1109 
1110         if (mesh.getNumLodLevels() == 0) {
1111             IntMap<VertexBuffer> bufs = mesh.getBuffers();
1112             for (Entry<VertexBuffer> entry : bufs) {
1113                 if (entry.getValue().getUsage() != VertexBuffer.Usage.Static) {
1114                     dynamic = true;
1115                     break;
1116                 }
1117             }
1118         } else {
1119             dynamic = true;
1120         }
1121 
1122         statistics.onMeshDrawn(mesh, lod);
1123 
1124 //        if (!dynamic) {
1125         // dealing with a static object, generate display list
1126 //            renderMeshDisplayList(mesh);
1127 //        } else {
1128         renderMeshDefault(mesh, lod, count);
1129 //        }
1130 
1131 
1132     }
1133 
setAlphaToCoverage(boolean value)1134     public void setAlphaToCoverage(boolean value) {
1135     }
1136 
setShader(Shader shader)1137     public void setShader(Shader shader) {
1138     }
1139 
deleteShader(Shader shader)1140     public void deleteShader(Shader shader) {
1141     }
1142 
deleteShaderSource(ShaderSource source)1143     public void deleteShaderSource(ShaderSource source) {
1144     }
1145 
copyFrameBuffer(FrameBuffer src, FrameBuffer dst)1146     public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst) {
1147     }
1148 
copyFrameBuffer(FrameBuffer src, FrameBuffer dst, boolean copyDepth)1149     public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst, boolean copyDepth) {
1150     }
1151 
setMainFrameBufferOverride(FrameBuffer fb)1152     public void setMainFrameBufferOverride(FrameBuffer fb){
1153     }
1154 
setFrameBuffer(FrameBuffer fb)1155     public void setFrameBuffer(FrameBuffer fb) {
1156     }
1157 
readFrameBuffer(FrameBuffer fb, ByteBuffer byteBuf)1158     public void readFrameBuffer(FrameBuffer fb, ByteBuffer byteBuf) {
1159     }
1160 
deleteFrameBuffer(FrameBuffer fb)1161     public void deleteFrameBuffer(FrameBuffer fb) {
1162     }
1163 
updateBufferData(VertexBuffer vb)1164     public void updateBufferData(VertexBuffer vb) {
1165     }
1166 
deleteBuffer(VertexBuffer vb)1167     public void deleteBuffer(VertexBuffer vb) {
1168     }
1169 }
1170