Home | History | Annotate | Download | only in lwjgl
      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 
     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 
     81     public Statistics getStatistics() {
     82         return statistics;
     83     }
     84 
     85     public EnumSet<Caps> getCaps() {
     86         return caps;
     87     }
     88 
     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 
    119     public void invalidateState() {
    120         context.reset();
    121     }
    122 
    123     public void resetGLObjects() {
    124         logger.log(Level.INFO, "Reseting objects and invalidating state");
    125         objManager.resetObjects();
    126         statistics.clearMemory();
    127         invalidateState();
    128     }
    129 
    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 
    137     public void setDepthRange(float start, float end) {
    138         glDepthRange(start, end);
    139     }
    140 
    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 
    171     public void setBackgroundColor(ColorRGBA color) {
    172         glClearColor(color.r, color.g, color.b, color.a);
    173     }
    174 
    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      */
    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      */
    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 
    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 
    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 
    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 
    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 
    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 
    425     public void onFrame() {
    426         objManager.deleteUnused(this);
    427 //        statistics.clearFrame();
    428     }
    429 
    430     private FloatBuffer storeMatrix(Matrix4f matrix, FloatBuffer store) {
    431         store.clear();
    432         matrix.fillFloatBuffer(store, true);
    433         store.clear();
    434         return store;
    435     }
    436 
    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 
    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 
    456     public void setWorldMatrix(Matrix4f worldMatrix) {
    457         this.worldMatrix.set(worldMatrix);
    458     }
    459 
    460     public void setViewProjectionMatrices(Matrix4f viewMatrix, Matrix4f projMatrix) {
    461         this.viewMatrix.set(viewMatrix);
    462         setProjection(projMatrix);
    463     }
    464 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    975     public void setVertexAttrib(VertexBuffer vb) {
    976         setVertexAttrib(vb, null);
    977     }
    978 
    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 
    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 
   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 
   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 
   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 
   1134     public void setAlphaToCoverage(boolean value) {
   1135     }
   1136 
   1137     public void setShader(Shader shader) {
   1138     }
   1139 
   1140     public void deleteShader(Shader shader) {
   1141     }
   1142 
   1143     public void deleteShaderSource(ShaderSource source) {
   1144     }
   1145 
   1146     public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst) {
   1147     }
   1148 
   1149     public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst, boolean copyDepth) {
   1150     }
   1151 
   1152     public void setMainFrameBufferOverride(FrameBuffer fb){
   1153     }
   1154 
   1155     public void setFrameBuffer(FrameBuffer fb) {
   1156     }
   1157 
   1158     public void readFrameBuffer(FrameBuffer fb, ByteBuffer byteBuf) {
   1159     }
   1160 
   1161     public void deleteFrameBuffer(FrameBuffer fb) {
   1162     }
   1163 
   1164     public void updateBufferData(VertexBuffer vb) {
   1165     }
   1166 
   1167     public void deleteBuffer(VertexBuffer vb) {
   1168     }
   1169 }
   1170