//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#pragma once
#ifndef _GFXDEVICE_H_
#define _GFXDEVICE_H_
#ifndef _GFXADAPTER_H_
#include "gfx/gfxAdapter.h"
#endif
#ifndef _GFXTARGET_H_
#include "gfx/gfxTarget.h"
#endif
#ifndef _GFXVERTEXBUFFER_H_
#include "gfx/gfxVertexBuffer.h"
#endif
#ifndef _GFXSTATEBLOCK_H_
#include "gfx/gfxStateBlock.h"
#endif
#ifndef _GFXSHADER_H_
#include "gfx/gfxShader.h"
#endif
#ifndef _GFXCUBEMAP_H_
#include "gfx/gfxCubemap.h"
#endif
#ifndef _TDICTIONARY_H_
#include "core/util/tDictionary.h"
#endif
#ifndef _TSIGNAL_H_
#include "core/util/tSignal.h"
#endif
#ifndef _GFXDEVICESTATISTICS_H_
#include "gfx/gfxDeviceStatistics.h"
#endif
#ifndef _MATHUTIL_FRUSTUM_H_
#include "math/util/frustum.h"
#endif
#ifndef _PLATFORM_PLATFORMTIMER_H_
#include "platform/platformTimer.h"
#endif
#include "gfxTextureArray.h"
class FontRenderBatcher;
class GFont;
class GFXCardProfiler;
class GFXDrawUtil;
class GFXFence;
class GFXOcclusionQuery;
class GFXPrimitiveBuffer;
class GFXShader;
class GFXStateBlock;
class GFXShaderConstBuffer;
class GFXTextureManager;
// Global macro
#define GFX GFXDevice::get()
//-----------------------------------------------------------------------------
/// GFXDevice is the TSE graphics interface layer. This allows the TSE to
/// do many things, such as use multiple render devices for multi-head systems,
/// and allow a game to render in DirectX 9, OpenGL or any other API which has
/// a GFX implementation seamlessly. There are many concepts in GFX device which
/// may not be familiar to you, especially if you have not used DirectX.
/// @n
/// Buffers
/// There are three types of buffers in GFX: vertex, index and primitive. Please
/// note that index buffers are not accessable outside the GFX layer, they are wrapped
/// by primitive buffers. Primitive buffers will be explained in detail later.
/// Buffers are allocated and deallocated using their associated allocXBuffer and
/// freeXBuffer methods on the device. When a buffer is allocated you pass in a
/// pointer to, depending on the buffer, a vertex type pointer or a U16 pointer.
/// During allocation, this pointer is set to the address of where you should
/// copy in the information for this buffer. You must the tell the GFXDevice
/// that the information is in, and it should prepare the buffer for use by calling
/// the prepare method on it. Dynamic vertex buffer example:
/// @code
/// GFXVertexP *verts; // Making a buffer containing verticies with only position
///
/// // Allocate a dynamic vertex buffer to hold 3 vertices and use *verts as the location to copy information into
/// GFXVertexBufferHandle vb = GFX->allocVertexBuffer( 3, &verts, true );
///
/// // Now set the information, we're making a triangle
/// verts[0].point = Point3F( 200.f, 200.f, 0.f );
/// verts[1].point = Point3F( 200.f, 400.f, 0.f );
/// verts[2].point = Point3F( 400.f, 200.f, 0.f );
///
/// // Tell GFX that the information is in and it should be made ready for use
/// // Note that nothing is done with verts, this should not and MUST NOT be deleted
/// // stored, or otherwise used after prepare is called.
/// GFX->prepare( vb );
///
/// // Because this is a dynamic vertex buffer, it is only assured to be valid until someone
/// // else allocates a dynamic vertex buffer, so we will render it now
/// GFX->setVertexBuffer( vb );
/// GFX->drawPrimitive( GFXTriangleStrip, 0, 1 );
///
/// // Now because this is a dynamic vertex buffer it MUST NOT BE FREED you are only
/// // given a handle to a vertex buffer which belongs to the device
/// @endcode
///
/// To use a static vertex buffer, it is very similar, this is an example using a
/// static primitive buffer:
/// @n
/// This takes place inside a constructor for a class which has a member variable
/// called mPB which is the primitive buffer for the class instance.
/// @code
/// U16 *idx; // This is going to be where to write indices
/// GFXPrimitiveInfo *primitiveInfo; // This will be where to write primitive information
///
/// // Allocate a primitive buffer with 4 indices, and 1 primitive described for use
/// mPB = GFX->allocPrimitiveBuffer( 4, &idx, 1, &primitiveInfo );
///
/// // Write the index information, this is going to be for the outline of a triangle using
/// // a line strip
/// idx[0] = 0;
/// idx[1] = 1;
/// idx[2] = 2;
/// idx[3] = 0;
///
/// // Write the information for the primitive
/// primitiveInfo->indexStart = 0; // Starting with index 0
/// primitiveInfo->minVertex = 0; // The minimum vertex index is 0
/// primitiveInfo->maxVertex = 3; // The maximum vertex index is 3
/// primitiveInfo->primitiveCount = 3; // There are 3 lines we are drawing
/// primitiveInfo->type = GFXLineStrip; // This primitive info describes a line strip
/// @endcode
/// The following code takes place in the destructor for the same class
/// @code
/// // Because this is a static buffer it's our responsibility to free it when we are done
/// GFX->freePrimitiveBuffer( mPB );
/// @endcode
/// This last bit takes place in the rendering function for the class
/// @code
/// // You need to set a vertex buffer as well, primitive buffers contain indexing
/// // information, not vertex information. This is so you could have, say, a static
/// // vertex buffer, and a dynamic primitive buffer.
///
/// // This sets the primitive buffer to the static buffer we allocated in the constructor
/// GFX->setPrimitiveBuffer( mPB );
///
/// // Draw the first primitive contained in the set primitive buffer, our primitive buffer
/// // has only one primitive, so we could also technically call GFX->drawPrimitives(); and
/// // get the same result.
/// GFX->drawPrimitive( 0 );
/// @endcode
/// If you need any more examples on how to use these buffers please see the rest of the engine.
/// @n
/// Primitive Buffers
/// @n
/// Primitive buffers wrap and extend the concept of index buffers. The purpose of a primitive
/// buffer is to let objects store all information they have to render their primitives in
/// a central place. Say that a shape is made up of triangle strips and triangle fans, it would
/// still have only one primitive buffer which contained primitive information for each strip
/// and fan. It could then draw itself with one call.
///
/// TO BE FINISHED LATER
class GFXDevice
{
private:
friend class GFXInit;
friend class GFXPrimitiveBufferHandle;
friend class GFXVertexBufferHandleBase;
friend class GFXTextureObject;
friend class GFXTexHandle;
friend class GFXVertexFormat;
friend class GFXResource;
friend class LightMatInstance; // For stencil interface
//--------------------------------------------------------------------------
// Static GFX interface
//--------------------------------------------------------------------------
public:
enum GFXDeviceEventType
{
/// The device has been created, but not initialized
deCreate,
/// The device has been initialized
deInit,
/// The device is about to be destroyed.
deDestroy,
/// The device has started rendering a frame
deStartOfFrame,
/// The device is about to finish rendering a frame
deEndOfFrame,
/// The device has rendered a frame and ended the scene
dePostFrame,
/// The device has started rendering a frame's field (such as for side-by-side rendering)
deStartOfField,
/// left stereo frame has been rendered
deLeftStereoFrameRendered,
/// right stereo frame has been rendered
deRightStereoFrameRendered,
/// The device is about to finish rendering a frame's field
deEndOfField,
};
typedef Signal DeviceEventSignal;
static DeviceEventSignal& getDeviceEventSignal();
static GFXDevice *get() { return smGFXDevice; }
static void initConsole();
static bool destroy();
static bool devicePresent() { return (smGFXDevice && smGFXDevice->getAdapterType() != NullDevice); }
private:
/// @name Device management variables
/// @{
static GFXDevice * smGFXDevice; ///< Global GFXDevice
/// @}
//--------------------------------------------------------------------------
// Core GFX interface
//--------------------------------------------------------------------------
public:
enum GFXDeviceRenderStyles
{
RS_Standard = 0,
RS_StereoSideBySide = (1<<0), // Render into current Render Target side-by-side
RS_StereoSeparate = (1<<1) // Render in two separate passes (then combined by vr compositor)
};
enum GFXDeviceLimits
{
NumStereoPorts = 2
};
private:
/// Adapter for this device.
GFXAdapter mAdapter;
protected:
/// List of valid video modes for this device.
Vector mVideoModes;
/// The CardProfiler for this device.
GFXCardProfiler *mCardProfiler;
/// Head of the resource list.
///
/// @see GFXResource
GFXResource *mResourceListHead;
/// Set once the device is active.
bool mCanCurrentlyRender;
/// Set if we're in a mode where we want rendering to occur.
bool mAllowRender;
/// The style of rendering that is to be performed, based on GFXDeviceRenderStyles
U32 mCurrentRenderStyle;
/// Current stereo target being rendered to
S32 mCurrentStereoTarget;
/// Eye offset used when using a stereo rendering style
Point3F mStereoEyeOffset[NumStereoPorts];
/// Center matrix for head
MatrixF mStereoHeadTransform;
/// Left and right matrix for eyes
MatrixF mStereoEyeTransforms[NumStereoPorts];
/// Inverse of mStereoEyeTransforms
MatrixF mInverseStereoEyeTransforms[NumStereoPorts];
/// Fov port settings
FovPort mFovPorts[NumStereoPorts];
/// Destination viewports for stereo rendering
RectI mStereoViewports[NumStereoPorts];
/// Destination targets for stereo rendering
GFXTextureTarget* mStereoTargets[NumStereoPorts];
/// This will allow querying to see if a device is initialized and ready to
/// have operations performed on it.
bool mInitialized;
bool mReset;
/// This is called before this, or any other device, is deleted in the global destroy()
/// method. It allows the device to clean up anything while everything is still valid.
virtual void preDestroy();
/// Set the adapter that this device is using. For use by GFXInit::createDevice only.
virtual void setAdapter(const GFXAdapter& adapter) { mAdapter = adapter; }
/// Notify GFXDevice that we are initialized
virtual void deviceInited();
public:
GFXDevice();
virtual ~GFXDevice();
/// Initialize this GFXDevice, optionally specifying a platform window to
/// bind to.
virtual void init( const GFXVideoMode &mode, PlatformWindow *window = NULL ) = 0;
/// Returns true if the scene has begun and its
/// safe to make rendering calls.
/// @see beginScene
/// @see endScene
bool canCurrentlyRender() const { return mCanCurrentlyRender; }
bool recentlyReset(){ return mReset; }
void beginReset(){ mReset = true; }
void finalizeReset(){ mReset = false; }
void setAllowRender( bool render ) { mAllowRender = render; }
inline bool allowRender() const { return mAllowRender; }
/// Retrieve the current rendering style based on GFXDeviceRenderStyles
U32 getCurrentRenderStyle() const { return mCurrentRenderStyle; }
/// Retrieve the current stereo target being rendered to
S32 getCurrentStereoTarget() const { return mCurrentStereoTarget; }
/// Set the current rendering style, based on GFXDeviceRenderStyles
void setCurrentRenderStyle(U32 style) { mCurrentRenderStyle = style; }
/// Set the current stereo target being rendered to (in case we're doing anything with postfx)
void setCurrentStereoTarget(const F32 targetId) { mCurrentStereoTarget = targetId; }
/// Get the current eye offset used during stereo rendering
const Point3F* getStereoEyeOffsets() { return mStereoEyeOffset; }
const MatrixF& getStereoHeadTransform() { return mStereoHeadTransform; }
const MatrixF* getStereoEyeTransforms() { return mStereoEyeTransforms; }
const MatrixF* getInverseStereoEyeTransforms() { return mInverseStereoEyeTransforms; }
/// Sets the head matrix for stereo rendering
void setStereoHeadTransform(const MatrixF &mat) { mStereoHeadTransform = mat; }
/// Set the current eye offset used during stereo rendering
void setStereoEyeOffsets(Point3F *offsets) { dMemcpy(mStereoEyeOffset, offsets, sizeof(Point3F) * NumStereoPorts); }
void setStereoEyeTransforms(MatrixF *transforms) { dMemcpy(mStereoEyeTransforms, transforms, sizeof(mStereoEyeTransforms)); dMemcpy(mInverseStereoEyeTransforms, transforms, sizeof(mInverseStereoEyeTransforms)); mInverseStereoEyeTransforms[0].inverse(); mInverseStereoEyeTransforms[1].inverse(); }
/// Set the current eye offset used during stereo rendering. Assumes NumStereoPorts are available.
void setStereoFovPort(const FovPort *ports) { dMemcpy(mFovPorts, ports, sizeof(mFovPorts)); }
/// Get the current eye offset used during stereo rendering
const FovPort* getStereoFovPort() { return mFovPorts; }
/// Sets stereo viewports
void setSteroViewports(const RectI *ports) { dMemcpy(mStereoViewports, ports, sizeof(RectI) * NumStereoPorts); }
/// Sets stereo render targets
void setStereoTargets(GFXTextureTarget **targets) { mStereoTargets[0] = targets[0]; mStereoTargets[1] = targets[1]; }
RectI* getStereoViewports() { return mStereoViewports; }
/// Activates a stereo render target, setting the correct viewport to render eye contents.
/// If eyeId is -1, set a viewport encompassing the entire size of the render targets.
void activateStereoTarget(S32 eyeId)
{
if (eyeId == -1)
{
if (mStereoTargets[0])
{
setActiveRenderTarget(mStereoTargets[0], true);
}
}
else
{
if (mStereoTargets[eyeId])
{
setActiveRenderTarget(mStereoTargets[eyeId], false);
}
setViewport(mStereoViewports[eyeId]);
}
mCurrentStereoTarget = eyeId;
}
GFXCardProfiler* getCardProfiler() const { return mCardProfiler; }
/// Returns active graphics adapter type.
virtual GFXAdapterType getAdapterType()=0;
/// Returns the Adapter that was used to create this device
virtual const GFXAdapter& getAdapter() { return mAdapter; }
/// @}
/// @name Debug Methods
/// @{
virtual void enterDebugEvent(ColorI color, const char *name) = 0;
virtual void leaveDebugEvent() = 0;
virtual void setDebugMarker(ColorI color, const char *name) = 0;
virtual const char* interpretDebugResult(long result) { return "Not Implemented"; };
/// @}
/// @name Resource debug methods
/// @{
/// Lists how many of each GFX resource (e.g. textures, texture targets, shaders, etc.) GFX is aware of
/// @param unflaggedOnly If true, this method only counts unflagged resources
virtual void listResources(bool unflaggedOnly);
/// Flags all resources GFX is currently aware of
virtual void flagCurrentResources();
/// Clears the flag on all resources GFX is currently aware of
virtual void clearResourceFlags();
/// Dumps a description of the specified resource types to the console
/// @param resNames A string of space separated class names (e.g. "GFXTextureObject GFXTextureTarget GFXShader")
/// to describe to the console
/// @param file A path to the file to write the descriptions to. If it is NULL or "", descriptions are
/// written to the console.
/// @param unflaggedOnly If true, this method only counts unflagged resources
/// @note resNames is case sensitive because there is no dStristr function.
virtual void describeResources(const char* resName, const char* file, bool unflaggedOnly);
/// Returns the current GFXDeviceStatistics, stats are cleared every ::beginScene call.
GFXDeviceStatistics* getDeviceStatistics() { return &mDeviceStatistics; }
protected:
GFXDeviceStatistics mDeviceStatistics;
/// This is a helper method for describeResourcesToFile. It walks through the
/// GFXResource list and sorts it by item type, putting the resources into the proper vector.
/// @see describeResources
virtual void fillResourceVectors(const char* resNames, bool unflaggedOnly, Vector &textureObjects,
Vector &textureTargets, Vector &windowTargets, Vector &vertexBuffers,
Vector &primitiveBuffers, Vector &fences, Vector &cubemaps,
Vector &shaders, Vector &stateblocks);
public:
/// @}
/// @name Video Mode Functions
/// @{
/// Enumerates the supported video modes of the device
virtual void enumerateVideoModes() = 0;
/// Returns the video mode list.
/// @see GFXVideoMode
const Vector* const getVideoModeList() const { return &mVideoModes; }
/// Returns the first format from the list which meets all
/// the criteria of the texture profile and query options.
virtual GFXFormat selectSupportedFormat(GFXTextureProfile *profile,
const Vector &formats, bool texture, bool mustblend, bool mustfilter) = 0;
/// @}
//-----------------------------------------------------------------------------
protected:
/// @name State tracking variables
/// @{
/// Set if ANY state is dirty, including matrices or primitive buffers.
bool mStateDirty;
enum TexDirtyType
{
GFXTDT_Normal,
GFXTDT_Cube,
GFXTDT_CubeArray,
GFXTDT_TextureArray
};
GFXTexHandle mCurrentTexture[GFX_TEXTURE_STAGE_COUNT];
GFXTexHandle mNewTexture[GFX_TEXTURE_STAGE_COUNT];
GFXCubemapHandle mCurrentCubemap[GFX_TEXTURE_STAGE_COUNT];
GFXCubemapHandle mNewCubemap[GFX_TEXTURE_STAGE_COUNT];
GFXCubemapArrayHandle mCurrentCubemapArray[GFX_TEXTURE_STAGE_COUNT];
GFXCubemapArrayHandle mNewCubemapArray[GFX_TEXTURE_STAGE_COUNT];
GFXTextureArrayHandle mCurrentTextureArray[GFX_TEXTURE_STAGE_COUNT];
GFXTextureArrayHandle mNewTextureArray[GFX_TEXTURE_STAGE_COUNT];
TexDirtyType mTexType[GFX_TEXTURE_STAGE_COUNT];
bool mTextureDirty[GFX_TEXTURE_STAGE_COUNT];
bool mTexturesDirty;
// This maps a GFXStateBlockDesc hash value to a GFXStateBlockRef
typedef Map StateBlockMap;
StateBlockMap mCurrentStateBlocks;
// This tracks whether or not our state block is dirty.
bool mStateBlockDirty;
GFXStateBlockRef mCurrentStateBlock;
GFXStateBlockRef mNewStateBlock;
GFXShaderConstBuffer *mCurrentShaderConstBuffer;
/// A global forced wireframe mode.
static bool smWireframe;
/// The global vsync state.
static bool smEnableVSync;
/// The forced shader model version if non-zero.
static F32 smForcedPixVersion;
/// Disable all hardware occlusion queries causing
/// them to return only the visibile state.
static bool smDisableOcclusionQuery;
/// @}
/// @see getDeviceSwizzle32
Swizzle *mDeviceSwizzle32;
/// @see getDeviceSwizzle24
Swizzle *mDeviceSwizzle24;
//-----------------------------------------------------------------------------
/// @name Matrix managing variables
/// @{
///
MatrixF mWorldMatrix[GFX_WORLD_STACK_MAX];
S32 mWorldStackSize;
MatrixF mProjectionMatrix;
MatrixF mViewMatrix;
/// @}
/// @name Current frustum planes
/// @{
///
Frustum mFrustum;
//-----------------------------------------------------------------------------
/// @name Stateblock functions
/// @{
/// Called by GFXDevice to create a device specific stateblock
virtual GFXStateBlockRef createStateBlockInternal(const GFXStateBlockDesc& desc) = 0;
/// Called by GFXDevice to actually set a stateblock.
/// @param force If true, set all states
virtual void setStateBlockInternal(GFXStateBlock* block, bool force) = 0;
/// @}
/// Called by base GFXDevice to actually set a const buffer
virtual void setShaderConstBufferInternal(GFXShaderConstBuffer* buffer) = 0;
virtual void setTextureInternal(U32 textureUnit, const GFXTextureObject*texture) = 0;
virtual bool beginSceneInternal() = 0;
virtual void endSceneInternal() = 0;
/// @name State Initialization.
/// @{
/// State initialization. This MUST BE CALLED in setVideoMode after the device
/// is created.
virtual void initStates() = 0;
/// @}
//-----------------------------------------------------------------------------
protected:
/// @name Buffer Allocation
/// These methods are implemented per-device and are called by the GFX layer
/// when a user calls an alloc
///
/// @note Primitive Buffers are NOT implemented per device, they wrap index buffers
/// @{
/// This allocates a vertex buffer and returns a pointer to the allocated buffer.
/// This function should not be called directly - rather it should be used by
/// the GFXVertexBufferHandle class.
virtual GFXVertexBuffer *allocVertexBuffer( U32 numVerts,
const GFXVertexFormat *vertexFormat,
U32 vertSize,
GFXBufferType bufferType,
void* data = NULL ) = 0;
/// Called from GFXVertexFormat to allocate the hardware
/// specific vertex declaration for rendering.
virtual GFXVertexDecl* allocVertexDecl( const GFXVertexFormat *vertexFormat ) = 0;
/// Sets the current vertex declaration on the device.
virtual void setVertexDecl( const GFXVertexDecl *decl ) = 0;
/// Sets the vertex buffer on the device.
virtual void setVertexStream( U32 stream, GFXVertexBuffer *buffer ) = 0;
/// Set the vertex stream frequency on the device.
virtual void setVertexStreamFrequency( U32 stream, U32 frequency ) = 0;
/// The maximum number of supported vertex streams which
/// may be more than the device supports.
static const U32 VERTEX_STREAM_COUNT = 4;
StrongRefPtr mCurrentVertexBuffer[VERTEX_STREAM_COUNT];
bool mVertexBufferDirty[VERTEX_STREAM_COUNT];
U32 mVertexBufferFrequency[VERTEX_STREAM_COUNT];
bool mVertexBufferFrequencyDirty[VERTEX_STREAM_COUNT];
const GFXVertexDecl *mCurrVertexDecl;
bool mVertexDeclDirty;
StrongRefPtr mCurrentPrimitiveBuffer;
bool mPrimitiveBufferDirty;
/// This allocates a primitive buffer and returns a pointer to the allocated buffer.
/// A primitive buffer's type argument refers to the index data - the primitive data will
/// always be preserved from call to call.
///
/// @note All index buffers use unsigned 16-bit indices.
virtual GFXPrimitiveBuffer *allocPrimitiveBuffer( U32 numIndices,
U32 numPrimitives,
GFXBufferType bufferType,
void* data = NULL ) = 0;
/// @}
protected:
//---------------------------------------
// Render target related
//---------------------------------------
/// A stack of previously active render targets.
Vector mRTStack;
/// The current render target which may or may not
/// not be yet activated.
/// @see mRTDirty
GFXTargetRef mCurrentRT;
/// This tracks a previously activated render target
/// which need to be deactivated.
GFXTargetRef mRTDeactivate;
/// This is set when the current and/or deactivate render
/// targets have changed and the device need to update
/// its state on the next draw/clear.
bool mRTDirty;
/// Updates the render targets and viewport in a device
/// specific manner when they are dirty.
virtual void _updateRenderTargets() = 0;
/// The current viewport rect.
RectI mViewport;
/// If true the viewport has been changed and
/// it must be updated on the next draw/clear.
bool mViewportDirty;
public:
/// @name Texture functions
/// @{
protected:
GFXTextureManager * mTextureManager;
public:
virtual GFXCubemap * createCubemap() = 0;
virtual GFXCubemapArray *createCubemapArray() = 0;
virtual GFXTextureArray *createTextureArray() = 0;
inline GFXTextureManager *getTextureManager()
{
return mTextureManager;
}
///@}
/// Swizzle to convert 32bpp bitmaps from RGBA to the native device format.
const Swizzle *getDeviceSwizzle32() const
{
return mDeviceSwizzle32;
}
/// Swizzle to convert 24bpp bitmaps from RGB to the native device format.
const Swizzle *getDeviceSwizzle24() const
{
return mDeviceSwizzle24;
}
/// @name Render Target functions
/// @{
/// Allocate a target for doing render to texture operations, with no
/// depth/stencil buffer.
virtual GFXTextureTarget *allocRenderToTextureTarget(bool genMips = true) = 0;
/// Allocate a target for a given window.
virtual GFXWindowTarget *allocWindowTarget(PlatformWindow *window)=0;
/// Store the current render target to restore later.
void pushActiveRenderTarget();
/// Restore the previous render target.
void popActiveRenderTarget();
/// Assign a new active render target.
void setActiveRenderTarget( GFXTarget *target, bool updateViewport=true );
/// Returns the current active render target.
inline GFXTarget* getActiveRenderTarget() { return mCurrentRT; }
///@}
/// @name Shader functions
/// @{
virtual F32 getPixelShaderVersion() const = 0;
virtual void setPixelShaderVersion( F32 version ) = 0;
/// Returns the number of texture samplers that can be used in a shader rendering pass
virtual U32 getNumSamplers() const = 0;
/// Returns the number of simultaneous render targets supported by the device.
virtual U32 getNumRenderTargets() const = 0;
virtual void setShader( GFXShader *shader, bool force = false ) {}
/// Set the buffer! (Actual set happens on the next draw call, just like textures, state blocks, etc)
void setShaderConstBuffer(GFXShaderConstBuffer* buffer);
/// Creates a new empty shader which must be initialized
/// and deleted by the caller.
/// @see GFXShader::init
virtual GFXShader* createShader() = 0;
/// @}
//-----------------------------------------------------------------------------
/// @name Copying methods
/// @{
virtual void copyResource(GFXTextureObject *pDst, GFXCubemap *pSrc, const U32 face) = 0;
/// @}
/// @name Rendering methods
/// @{
///
virtual void clear( U32 flags, const LinearColorF& color, F32 z, U32 stencil ) = 0;
virtual void clearColorAttachment(const U32 attachment, const LinearColorF& color) = 0;
virtual bool beginScene();
virtual void endScene();
virtual void beginField();
virtual void endField();
PlatformTimer *mFrameTime;
void setPrimitiveBuffer( GFXPrimitiveBuffer *buffer );
/// Sets the vertex buffer.
///
/// When setting the stream 0 vertex buffer it will automatically
/// set its associated vertex format as the active format.
///
/// @param buffer The vertex buffer or NULL to clear the buffer.
/// @param stream The stream index of the vertex source stream to place the buffer.
/// @param frequency The stream frequency of the vertex buffer.
void setVertexBuffer( GFXVertexBuffer *buffer, U32 stream = 0, U32 frequency = 0 );
/// Sets the current vertex format.
///
/// This should only be used if the vertex format of the stream 0 vertex
/// buffer is different from the one associated to it. Typically this
/// is used when rendering from multiple vertex streams.
///
void setVertexFormat( const GFXVertexFormat *vertexFormat );
virtual void drawPrimitive( GFXPrimitiveType primType, U32 vertexStart, U32 primitiveCount ) = 0;
/// The parameters to drawIndexedPrimitive are somewhat complicated. From a raw-data stand point
/// they evaluate to something like the following:
/// @code
/// U16 indicies[] = { 0, 1, 2, 1, 0, 0, 2 };
/// Point3F verts[] = { Point3F( 0.0f, 0.0f, 0.0f ), Point3F( 0.0f, 1.0f, 0.0f ), Point3F( 0.0f, 0.0f, 1.0f ) };
///
/// GFX->drawIndexedPrimitive( GFXLineList, // Drawing a list of lines, each line is two verts
/// 0, // vertex 0 will be referenced so minIndex = 0
/// 3, // 3 verticies will be used for this draw call
/// 1, // We want index 1 to be the first index used, so indicies 1-6 will be used
/// 3 // Drawing 3 LineList primitives, meaning 6 verts will be drawn
/// );
///
/// U16 *idxPtr = &indicies[1]; // 1 = startIndex, so the pointer is offset such that:
/// // idxPtr[0] is the same as indicies[1]
///
/// U32 numVertsToDrawFromBuffer = primitiveCount * 2; // 2 verts define a line in the GFXLineList primitive type (6)
/// @endcode
///
/// @param primType Type of primitive to draw
///
/// @param startVertex This defines index zero. Its the offset from the start of
/// the vertex buffer to the first vertex.
///
/// @param minIndex The smallest index into the vertex stream which will be used for this draw call.
/// This is a zero based index relative to startVertex. It is strictly a performance
/// hint for implementations. No vertex below minIndex will be referenced by this draw
/// call. For device implementors, this should _not_ be used to offset the vertex buffer,
/// or index buffer.
///
/// @param numVerts The number of verticies which will be referenced in this draw call. This is not
/// the number of verticies which will be drawn. That is a function of 'primType' and
/// 'primitiveCount'.
///
/// @param startIndex An offset from the start of the index buffer to specify where to start. If
/// 'idxBuffer' is a pointer to an array of integers, this could be written as
/// int *offsetIdx = idxBuffer + startIndex;
///
/// @param primitiveCount The number of primitives of type 'primType' to draw.
///
virtual void drawIndexedPrimitive( GFXPrimitiveType primType,
U32 startVertex,
U32 minIndex,
U32 numVerts,
U32 startIndex,
U32 primitiveCount ) = 0;
void drawPrimitive( const GFXPrimitive &prim );
void drawPrimitive( U32 primitiveIndex );
void drawPrimitives();
/// @}
//-----------------------------------------------------------------------------
/// Allocate a fence. The API specific implementation of GFXDevice is responsible
/// to make sure that the proper type is used. GFXGeneralFence should work in
/// all cases.
virtual GFXFence *createFence() = 0;
/// Returns a hardware occlusion query object or NULL
/// if this device does not support them.
virtual GFXOcclusionQuery* createOcclusionQuery() { return NULL; }
/// @name Texture State Settings
/// NONE of these should be overridden by API implementations
/// because of the state caching stuff.
/// @{
///
void setTexture(U32 stage, GFXTextureObject *texture);
void setCubeTexture( U32 stage, GFXCubemap *cubemap );
void setCubeArrayTexture( U32 stage, GFXCubemapArray *cubemapArray);
void setTextureArray( U32 stage, GFXTextureArray *textureArray);
inline GFXTextureObject* getCurrentTexture( U32 stage ) { return mCurrentTexture[stage]; }
/// @}
/// @name State Block Interface
/// @{
/// Creates a state block object based on the desc passed in. This object
/// represents an immutable state.
virtual GFXStateBlockRef createStateBlock( const GFXStateBlockDesc &desc );
/// Sets the current stateblock (actually activated in ::updateStates)
virtual void setStateBlock( GFXStateBlock *block );
GFXStateBlock* getStateBlock() { return mNewStateBlock; }
/// This sets a stateblock directly from the description
/// structure. Its acceptable to use this for debug rendering
/// and other low frequency rendering tasks.
virtual void setStateBlockByDesc( const GFXStateBlockDesc &desc );
/// @}
/// @name General state interface
/// @{
/// Sets the dirty Render/Texture/Sampler states from the caching system
void updateStates(bool forceSetAll = false);
void clearTextureStateImmediate(U32 stage);
/// Returns the forced global wireframe state.
static bool getWireframe() { return smWireframe; }
/// Returns true if the occlusion query is disabled.
static bool getDisableOcclusionQuery() { return smDisableOcclusionQuery; }
/// @}
//-----------------------------------------------------------------------------
/// @name Matrix interface
/// @{
/// Sets the top of the world matrix stack
/// @param newWorld New world matrix to set
void setWorldMatrix( const MatrixF &newWorld );
/// Gets the matrix on the top of the world matrix stack
inline const MatrixF &getWorldMatrix() const { return mWorldMatrix[mWorldStackSize]; }
/// Pushes the world matrix stack and copies the current top
/// matrix to the new top of the stack
void pushWorldMatrix();
/// Pops the world matrix stack
void popWorldMatrix();
/// Sets the projection matrix
/// @param newProj New projection matrix to set
void setProjectionMatrix( const MatrixF &newProj );
/// Gets the projection matrix
inline const MatrixF &getProjectionMatrix() const { return mProjectionMatrix; }
/// Sets the view matrix
/// @param newView New view matrix to set
void setViewMatrix( const MatrixF &newView );
/// Gets the view matrix
inline const MatrixF &getViewMatrix() const { return mViewMatrix; }
/// Multiplies the matrix at the top of the world matrix stack by a matrix
/// and replaces the top of the matrix stack with the result
/// @param mat Matrix to multiply
void multWorld( const MatrixF &mat );
/// Set texture matrix for a sampler
void setTextureMatrix( const U32 stage, const MatrixF &texMat );
/// Set an area of the target to render to.
void setViewport( const RectI &rect );
/// Get the current area of the target we will render to.
const RectI &getViewport() const { return mViewport; }
virtual void setClipRect( const RectI &rect ) = 0;
virtual const RectI &getClipRect() const = 0;
/// Set the projection frustum.
///
/// @see MathUtils::makeFrustum()
virtual void setFrustum( F32 left, F32 right,
F32 bottom, F32 top,
F32 nearPlane, F32 farPlane,
bool bRotate = true);
///
virtual void setFrustum( const Frustum& frust,
bool bRotate = true );
/// Get the projection frustum.
void getFrustum( F32 *left,
F32 *right,
F32 *bottom,
F32 *top,
F32 *nearPlane,
F32 *farPlane,
bool *isOrtho ) const;
/// Get the projection frustum.
const Frustum& getFrustum() const { return mFrustum; }
/// This will construct and apply an orthographic projection matrix with the provided parameters
/// @param doRotate If set to true, the resulting matrix will be rotated PI/2 around the X axis
// for support in tsShapeInstance. You probably want to leave this as 'false'.
void setOrtho(F32 left, F32 right, F32 bottom, F32 top, F32 nearPlane, F32 farPlane, bool doRotate = false);
/// Return true if the current frustum uses orthographic projection rather than perspective projection.
bool isFrustumOrtho() const { return mFrustum.isOrtho(); }
/// @}
/// Returns the scale for converting world space
/// units to screen space units... aka pixels.
///
/// This is the true scale which is best used for GUI
/// drawing. For doing lod calculations you should be
/// using the functions in SceneState which is adjusted
/// for special cases like shadows and reflections.
///
/// @see SceneState::getWorldToScreenScale()
/// @see SceneState::projectRadius()
///
Point2F getWorldToScreenScale() const;
public:
enum GenericShaderType
{
GSColor = 0,
GSTexture,
GSModColorTexture,
GSAddColorTexture,
GSTargetRestore,
GS_COUNT
};
/// This is a helper function to set a default shader for rendering GUI elements
/// on systems which do not support fixed-function operations as well as for
/// things which need just generic position/texture/color shaders
///
/// @param type Type of generic shader, add your own if you need
virtual void setupGenericShaders( GenericShaderType type = GSColor ) {};
/// Get the fill convention for this device
virtual F32 getFillConventionOffset() const = 0;
virtual U32 getMaxDynamicVerts() = 0;
virtual U32 getMaxDynamicIndices() = 0;
virtual void doParanoidStateCheck(){};
/// Get access to this device's drawing utility class.
GFXDrawUtil *getDrawUtil();
#ifndef TORQUE_SHIPPING
/// This is a method designed for debugging. It will allow you to dump the states
/// in the render manager out to a file so that it can be diffed and examined.
void dumpStates( const char *fileName ) const;
#else
void dumpStates( const char *fileName ) const {};
#endif
protected:
GFXDrawUtil *mDrawer;
};
//-----------------------------------------------------------------------------
// Matrix interface
inline void GFXDevice::setWorldMatrix( const MatrixF &newWorld )
{
mStateDirty = true;
mWorldMatrix[mWorldStackSize] = newWorld;
}
inline void GFXDevice::pushWorldMatrix()
{
mStateDirty = true;
mWorldStackSize++;
AssertFatal( mWorldStackSize < GFX_WORLD_STACK_MAX, "GFX: Exceeded world matrix stack size" );
mWorldMatrix[mWorldStackSize] = mWorldMatrix[mWorldStackSize - 1];
}
inline void GFXDevice::popWorldMatrix()
{
mStateDirty = true;
mWorldStackSize--;
AssertFatal( mWorldStackSize >= 0, "GFX: Negative WorldStackSize!" );
}
inline void GFXDevice::multWorld( const MatrixF &mat )
{
mStateDirty = true;
mWorldMatrix[mWorldStackSize].mul(mat);
}
inline void GFXDevice::setProjectionMatrix( const MatrixF &newProj )
{
mStateDirty = true;
mProjectionMatrix = newProj;
}
inline void GFXDevice::setViewMatrix( const MatrixF &newView )
{
mStateDirty = true;
mViewMatrix = newView;
}
//-----------------------------------------------------------------------------
// Buffer management
inline void GFXDevice::setVertexBuffer( GFXVertexBuffer *buffer, U32 stream, U32 frequency )
{
AssertFatal( stream < VERTEX_STREAM_COUNT, "GFXDevice::setVertexBuffer - Bad stream index!" );
if ( buffer && stream == 0 )
setVertexFormat( &buffer->mVertexFormat );
if ( buffer != mCurrentVertexBuffer[stream] )
{
mCurrentVertexBuffer[stream] = buffer;
mVertexBufferDirty[stream] = true;
mStateDirty = true;
}
if ( mVertexBufferFrequency[stream] != frequency )
{
mVertexBufferFrequency[stream] = frequency;
mVertexBufferFrequencyDirty[stream] = true;
mStateDirty = true;
}
}
inline void GFXDevice::setVertexFormat( const GFXVertexFormat *vertexFormat )
{
if ( vertexFormat->getDecl() == mCurrVertexDecl )
return;
mCurrVertexDecl = vertexFormat->getDecl();
mVertexDeclDirty = true;
mStateDirty = true;
}
#if defined(TORQUE_DEBUG) && defined(TORQUE_DEBUG_GFX)
#define GFXAssertFatal(x, error) AssertFatal(x, error)
#else
#define GFXAssertFatal(x, error)
#endif
#endif // _GFXDEVICE_H_