/*
 * $RCSfile$
 *
 * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
 *
 * Use is subject to license terms.
 *
 * $Revision$
 * $Date$
 * $State$
 */

#include "Stdafx.h"

// return true if device is capable of hardware accelerated

D3dDeviceInfo::D3dDeviceInfo()
{
}

D3dDeviceInfo::~D3dDeviceInfo()
{
}

VOID D3dDeviceInfo::setCaps(D3DCAPS9 *d3dCaps)
{
    if (deviceType == D3DDEVTYPE_HAL ){
    	isHardware = true;		
    	isHardwareTnL = (d3dCaps->DevCaps &  D3DDEVCAPS_HWTRANSFORMANDLIGHT);
    }
    else // D3DDEVTYPE_REF
    {
    	 isHardware = false;
    	 isHardwareTnL = false;
    }

    
	// D3DTEXTURECAPS_NONPOW2CONDITIONAL caps-bit indicates "conditional" 
	// Non Power of Two (NPOT) 
	// textures that only support CLAMP addressing and don't 
	// support mipmaps or compressed textures.
	// But some new vcards supports NP2 unconditional (GF6 and above). 
	// Correct test for any kind of NP2 support:
    // If both unconditional and conditional support is 
    // unavailable then NP2 is not possible anyway.
	//  -------------------------------------------
	//  POW2 |  NP2_CONDITIONAL | result
	//  -------------------------------------------
	//  true |      true        | CONDITIONAL NPOT(*)
	//  true |      false       | POW2 Only
	//  false|      any         | UNConditional NPOT (**)	//  
	// ---------------------------------------------
	// (**)OpenGL like,  Java3D preferred.
	// (*) below test:
    /*
	 * if (((d3dCaps->TextureCaps & D3DPTEXTURECAPS_POW2) != 0) &&  // POW2 is true
     *     ((d3dCaps->TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) == 0)){ //NPOT_Cond is false
     *      //Pow2 Only
	 *      supportNPOT = false;
     *   }
     * else{
	 *      // both conditional and unconditional
     *      supportNPOT = true;
     * }
   */
	if(d3dCaps->TextureCaps & D3DPTEXTURECAPS_POW2){
        supportNPOT = false;
        if(d3dCaps->TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL){
           // NPOT conditionl But, in certain cases textures can ignore the power of 2 limitation
           // As OpenGL is UNCONDITIONAL, it is not used by Java3D
		   //supportNPOT = true;
        }
   }else{
      //UNconditional: Textures do not need to be a power of 2 in size
	    supportNPOT = true;
   }
     




	// check if it supports at least vertex shader 1.1
    if(d3dCaps->VertexShaderVersion < D3DVS_VERSION(1,1))
	{
	  supportShaders11 = false;
	}
	else
	{
     supportShaders11 = true;
	}
	DWORD vsVersion = d3dCaps->VertexShaderVersion;
    if (debug)
	   {
		   char* dt;
		   if (isHardware) 
			   dt = "HAL";
		   else 
			   dt ="REL";

		   printf("Java3D: Supported Shaders = %d.%d in mode %s ", 
		          HIBYTE(LOWORD(vsVersion)),
                  LOBYTE(LOWORD(vsVersion)),
				  dt);
		   
	   }   
	
	//supportStreamOffset = 
    
	supportDepthBias = (d3dCaps->RasterCaps & D3DPRASTERCAPS_DEPTHBIAS) != 0;

    maxTextureBlendStages = d3dCaps->MaxTextureBlendStages;
    maxSimultaneousTextures = d3dCaps->MaxSimultaneousTextures;
	
    maxTextureUnitStageSupport = min(maxTextureBlendStages,  maxSimultaneousTextures);
    
    supportMipmap = ((d3dCaps->TextureCaps & D3DPTEXTURECAPS_MIPMAP) != 0);

    texturePow2Only =  ((d3dCaps->TextureCaps &  D3DPTEXTURECAPS_POW2) != 0);

    textureSquareOnly = ((d3dCaps->TextureCaps &   D3DPTEXTURECAPS_SQUAREONLY) != 0);

    linePatternSupport = false; //((d3dCaps->PrimitiveMiscCaps &   D3DPMISCCAPS_LINEPATTERNREP) != 0);

    texBorderModeSupport = ((d3dCaps->TextureAddressCaps & D3DPTADDRESSCAPS_BORDER) != 0);

    texLerpSupport = ((d3dCaps->TextureOpCaps &    D3DTEXOPCAPS_LERP) != 0);

    canRenderWindowed = true;//((d3dCaps->Caps2 &  D3DCAPS2_CANRENDERWINDOWED) != 0);

    maxPrimitiveCount = d3dCaps->MaxPrimitiveCount;
    maxVertexIndex = min(vertexBufferMaxVertexLimit, d3dCaps->MaxVertexIndex);

    maxTextureHeight = d3dCaps->MaxTextureHeight;
    maxTextureWidth =  d3dCaps->MaxTextureWidth;
    maxTextureDepth =  d3dCaps->MaxVolumeExtent;

    maxActiveLights = d3dCaps->MaxActiveLights;
    maxPointSize = DWORD(d3dCaps->MaxPointSize);
    maxAnisotropy = d3dCaps->MaxAnisotropy;

    maxVertexCount[GEO_TYPE_QUAD_SET] = min(vertexBufferMaxVertexLimit,
					    maxPrimitiveCount << 1);

    // Since index is used, we need to make sure than index range
    // is also support.
    maxVertexCount[GEO_TYPE_QUAD_SET] = min(maxVertexCount[GEO_TYPE_QUAD_SET],   maxVertexIndex);

    maxVertexCount[GEO_TYPE_TRI_SET] = min(vertexBufferMaxVertexLimit,   maxPrimitiveCount*3);

    maxVertexCount[GEO_TYPE_POINT_SET] = min(vertexBufferMaxVertexLimit,   maxPrimitiveCount);

    maxVertexCount[GEO_TYPE_LINE_SET] = min(vertexBufferMaxVertexLimit, maxPrimitiveCount << 1);

    maxVertexCount[GEO_TYPE_TRI_STRIP_SET] = min(vertexBufferMaxVertexLimit, maxPrimitiveCount + 2);

    maxVertexCount[GEO_TYPE_TRI_FAN_SET] = min(vertexBufferMaxVertexLimit,	 maxPrimitiveCount + 2);

    maxVertexCount[GEO_TYPE_LINE_STRIP_SET] = min(vertexBufferMaxVertexLimit,
						 maxPrimitiveCount +1);
    maxVertexCount[GEO_TYPE_INDEXED_QUAD_SET] = maxVertexCount[GEO_TYPE_QUAD_SET];
    maxVertexCount[GEO_TYPE_INDEXED_TRI_SET] = maxVertexCount[GEO_TYPE_TRI_SET];
    maxVertexCount[GEO_TYPE_INDEXED_POINT_SET] = maxVertexCount[GEO_TYPE_POINT_SET];
    maxVertexCount[GEO_TYPE_INDEXED_LINE_SET] = maxVertexCount[GEO_TYPE_LINE_SET];
    maxVertexCount[GEO_TYPE_INDEXED_TRI_STRIP_SET] = maxVertexCount[GEO_TYPE_TRI_STRIP_SET];
    maxVertexCount[GEO_TYPE_INDEXED_TRI_FAN_SET] = maxVertexCount[GEO_TYPE_TRI_FAN_SET];
    maxVertexCount[GEO_TYPE_INDEXED_LINE_STRIP_SET] = maxVertexCount[GEO_TYPE_LINE_STRIP_SET];

	if ( (d3dCaps->PresentationIntervals & D3DPRESENT_INTERVAL_IMMEDIATE) != 0) 
	    supportRasterPresImmediate = true;
	else 
		supportRasterPresImmediate = false;

    if (((d3dCaps->RasterCaps & D3DPRASTERCAPS_FOGTABLE) != 0) &&
	   ((d3dCaps->RasterCaps & D3DPRASTERCAPS_WFOG) != 0))
	{
	// use pixel w-fog
	fogMode = D3DRS_FOGTABLEMODE;
	rangeFogEnable = false;
    }
     else
         if (((d3dCaps->RasterCaps & D3DPRASTERCAPS_FOGVERTEX) != 0) &&
	        ((d3dCaps->RasterCaps & D3DPRASTERCAPS_FOGRANGE) != 0))

	        {
	          // use vertex range based fog
	          fogMode = D3DRS_FOGVERTEXMODE;
	          rangeFogEnable = true;
             }
             else
                 if ((d3dCaps->RasterCaps & D3DPRASTERCAPS_FOGTABLE) != 0)
                    {
	                   // use pixel z-fog
	                  fogMode = D3DRS_FOGTABLEMODE;
	                  rangeFogEnable = false;
                    }
                    else
                     if (D3DPRASTERCAPS_FOGVERTEX)
                     {
                        // use vertex z-fog
	                   fogMode = D3DRS_FOGVERTEXMODE;
	                   rangeFogEnable = false;
                      }
                      else
                          {
	                        if (debug)
	                        {
	                          printf("[Java 3D] Fog not support in this device !\n");
	                         }
    }


    texMask = 0;

	if(supportNPOT){
		texMask |= javax_media_j3d_Canvas3D_TEXTURE_NON_POWER_OF_TWO;
	}

    if ((d3dCaps->TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP) &&
	    (maxTextureDepth > 0))
	{
	texMask |= javax_media_j3d_Canvas3D_TEXTURE_3D;
    }

    if (d3dCaps->TextureCaps & D3DPTEXTURECAPS_CUBEMAP) {
	texMask |= javax_media_j3d_Canvas3D_TEXTURE_CUBE_MAP;
    }

    if (maxTextureUnitStageSupport > 1) {
	texMask |= javax_media_j3d_Canvas3D_TEXTURE_MULTI_TEXTURE;
    }

    if (d3dCaps->TextureOpCaps & D3DTEXOPCAPS_DOTPRODUCT3) {
	texMask |= javax_media_j3d_Canvas3D_TEXTURE_COMBINE_DOT3;
    }

    if (d3dCaps->TextureOpCaps & D3DTEXOPCAPS_SUBTRACT) {
	texMask |= javax_media_j3d_Canvas3D_TEXTURE_COMBINE_SUBTRACT;
    }

    if (d3dCaps->TextureOpCaps & D3DTEXOPCAPS_LERP) {
	texMask |= (javax_media_j3d_Canvas3D_TEXTURE_LERP|
		    javax_media_j3d_Canvas3D_TEXTURE_COMBINE);
    } else if (d3dCaps->TextureOpCaps &
	       (D3DTEXOPCAPS_DOTPRODUCT3|D3DTEXOPCAPS_SUBTRACT|
		D3DTEXOPCAPS_MODULATE|D3DTEXOPCAPS_ADD|
		D3DTEXOPCAPS_ADDSIGNED)) {
	texMask |= javax_media_j3d_Canvas3D_TEXTURE_COMBINE;
    }


    if (maxAnisotropy > 1) {
	texMask |= javax_media_j3d_Canvas3D_TEXTURE_ANISOTROPIC_FILTER;
    }
}

BOOL D3dDeviceInfo::supportAntialiasing() {
    return (multiSampleSupport != 0);
}


void D3dDeviceInfo::findDepthStencilFormat(int minZDepth, int minZDepthStencil)
{
    depthStencilFormat = D3DFMT_UNKNOWN;
    for (int i=0; i < D3DDEPTHFORMATSIZE; i++) 
	{
		//printf("\ndepthFormatSupport %s, %b",getPixelFormatName(d3dDepthFormat[i]), depthFormatSupport[i]);
	  if (depthFormatSupport[i]){
	    // prefer one with stencil buffer, follow by D3DFMT_D16_LOCKABLE,
		 // printf("\n ZDepth %d, Stencil %d ",d3dDepthTable[i],d3dStencilDepthTable[i]);
	    if (d3dDepthTable[i] >= minZDepth && d3dStencilDepthTable[i] >= minZDepthStencil ) 
		{
		  depthStencilFormat = (D3DFORMAT) d3dDepthFormat[i];
		  break;
	    }
	  }//if
    }// for
	// if none suitable found
   
}


D3DMULTISAMPLE_TYPE D3dDeviceInfo::getBestMultiSampleType()
{
    DWORD bitmask = 0;
    UINT i;

    // start with 4, if none found, try 3 and 2
    for (i=4; i < 16; i++) {
	bitmask = (1 << i);
	if (multiSampleSupport & bitmask) {
	    return (D3DMULTISAMPLE_TYPE) i;
	}
    }

    for (i=3; i >= 2; i--) {
	bitmask = (1 << i);
	if (multiSampleSupport & bitmask) {
	    return (D3DMULTISAMPLE_TYPE) i;
	}
    }

    // Should not happen
    return D3DMULTISAMPLE_NONE;
}

int D3dDeviceInfo::getTextureFeaturesMask()
{
    return texMask;
}