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