#include "renderer_d3d9.h" GeometryInterfaceD3D9::GeometryInterfaceD3D9(int flags,unsigned int numtextures): vertptr(0), verts(NULL), is_valid(true), flags(flags), numtextures(numtextures) { if (!(flags&RAVEN_GEOMETRY_FLAG_VERTICES)) { is_valid=false; return; } vertsize=sizeof(float)*3; fvf=D3DFVF_XYZ; if (flags&RAVEN_GEOMETRY_FLAG_NORMALS) { norm_offset=vertsize; vertsize+=sizeof(float)*3; fvf|=D3DFVF_NORMAL; } if (flags&RAVEN_GEOMETRY_FLAG_COLORS) { color_offset=vertsize; vertsize+=sizeof(DWORD); fvf|=D3DFVF_DIFFUSE; } if (flags&RAVEN_GEOMETRY_FLAG_TEXCOORDS) { tex_offset=vertsize; vertsize+=sizeof(float)*2*numtextures; fvf|=numtextures<SetFVF(fvf); if (primtype) // d3d support, render it all! { dev->DrawPrimitiveUP((D3DPRIMITIVETYPE)primtype,prim_count(numverts,geomtype),verts,vertsize); return true; } else // no d3d support, get creative (less efficient but serves for portability) { switch (geomtype) { case RAVEN_GEOMETRY_LINE_LOOP: AdvancePtr(); numverts=vertptr+1; memcpy(verts+vertptr*vertsize,verts,vertsize); return dev->DrawPrimitiveUP(D3DPT_LINESTRIP,prim_count(numverts,RAVEN_GEOMETRY_LINE_STRIP),verts,vertsize)==D3D_OK; case RAVEN_GEOMETRY_QUADS: for (register unsigned int i=0; iDrawPrimitiveUP(D3DPT_TRIANGLEFAN,2,verts+i*vertsize,vertsize)!=D3D_OK) return false; } return true; default: return false; } } } #define VECTOR2D3DCOLORVALUE(v) (*(D3DCOLORVALUE *)((float *)v)) void RendererD3D9::UpdateD3DState() { D3DVIEWPORT9 d3dvp= { (DWORD)viewport.left, (DWORD)viewport.top, (DWORD)(viewport.right-viewport.left), (DWORD)(viewport.bottom-viewport.top), 0.0f,1.0f }; d3dcore->dev->SetViewport(&d3dvp); d3dcore->dev->SetRenderState(D3DRS_ZENABLE,!(stateflags&RAVEN_STATE_NODEPTH)); d3dcore->dev->SetRenderState(D3DRS_FILLMODE,(stateflags&RAVEN_STATE_WIREFRAME)?D3DFILL_WIREFRAME:D3DFILL_SOLID); switch (blend) { case RAVEN_BLEND_MASK_LOW: d3dcore->dev->SetRenderState(D3DRS_ALPHABLENDENABLE,FALSE); d3dcore->dev->SetRenderState(D3DRS_ALPHATESTENABLE,TRUE); d3dcore->dev->SetRenderState(D3DRS_ALPHAREF,D3DCOLOR_COLORVALUE(0,0,0,blendmask)); d3dcore->dev->SetRenderState(D3DRS_ALPHAFUNC,D3DCMP_GREATEREQUAL); break; case RAVEN_BLEND_MASK_HI: d3dcore->dev->SetRenderState(D3DRS_ALPHABLENDENABLE,FALSE); d3dcore->dev->SetRenderState(D3DRS_ALPHATESTENABLE,TRUE); d3dcore->dev->SetRenderState(D3DRS_ALPHAREF,D3DCOLOR_COLORVALUE(0,0,0,blendmask)); d3dcore->dev->SetRenderState(D3DRS_ALPHAFUNC,D3DCMP_LESSEQUAL); break; case RAVEN_BLEND_ALPHA: d3dcore->dev->SetRenderState(D3DRS_ALPHABLENDENABLE,TRUE); d3dcore->dev->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA); d3dcore->dev->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA); d3dcore->dev->SetRenderState(D3DRS_ALPHATESTENABLE,FALSE); break; case RAVEN_BLEND_ADD: d3dcore->dev->SetRenderState(D3DRS_ALPHABLENDENABLE,TRUE); d3dcore->dev->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_ONE); d3dcore->dev->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_ONE); d3dcore->dev->SetRenderState(D3DRS_ALPHATESTENABLE,FALSE); break; case RAVEN_BLEND_MULT: d3dcore->dev->SetRenderState(D3DRS_ALPHABLENDENABLE,TRUE); d3dcore->dev->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_DESTCOLOR); d3dcore->dev->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_ZERO); d3dcore->dev->SetRenderState(D3DRS_ALPHATESTENABLE,FALSE); break; case RAVEN_BLEND_LIGHT: d3dcore->dev->SetRenderState(D3DRS_ALPHABLENDENABLE,TRUE); d3dcore->dev->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA); d3dcore->dev->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_ONE); d3dcore->dev->SetRenderState(D3DRS_ALPHATESTENABLE,FALSE); break; default: d3dcore->dev->SetRenderState(D3DRS_ALPHABLENDENABLE,FALSE); d3dcore->dev->SetRenderState(D3DRS_ALPHATESTENABLE,FALSE); break; } if (stateflags&RAVEN_STATE_MATERIAL) { if (stateflags&RAVEN_STATE_LIGHT) { d3dcore->dev->SetRenderState(D3DRS_LIGHTING,TRUE); d3dcore->dev->SetRenderState(D3DRS_SPECULARENABLE,TRUE); d3dcore->dev->SetMaterial(&d3dmaterial); // compute ambience Vector4 ambience(1.0f); register unsigned int numlights=min(RAVEN_MAXIMUM_LIGHTS,caps.MaxActiveLights); for (register unsigned int i=0; iGetComponent(RAVEN_OPTICS_AMBIENT_COMPONENT,thisamb); ambience*=thisamb; } d3dcore->dev->SetRenderState(D3DRS_AMBIENT,D3DCOLOR_COLORVALUE(ambience.x,ambience.y,ambience.z,ambience.w)); if (stateflags&RAVEN_STATE_TEXTURE) { Texture *tex=material.Tex(); if (tex) tex->Bind(0); } if (material.UsingVertexColor()) { // this is the equivalent of glColorMaterial, only you must be more specific d3dcore->dev->SetRenderState(D3DRS_COLORVERTEX,TRUE); d3dcore->dev->SetRenderState(D3DRS_AMBIENTMATERIALSOURCE,D3DMCS_COLOR1); d3dcore->dev->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE,D3DMCS_COLOR1); d3dcore->dev->SetRenderState(D3DRS_SPECULARMATERIALSOURCE,D3DMCS_MATERIAL); d3dcore->dev->SetRenderState(D3DRS_EMISSIVEMATERIALSOURCE,D3DMCS_MATERIAL); } else d3dcore->dev->SetRenderState(D3DRS_COLORVERTEX,FALSE); } else { d3dcore->dev->SetRenderState(D3DRS_COLORVERTEX,TRUE); d3dcore->dev->SetRenderState(D3DRS_LIGHTING,FALSE); d3dcore->dev->SetRenderState(D3DRS_SPECULARENABLE,FALSE); if (stateflags&RAVEN_STATE_TEXTURE) { Texture *tex=material.Tex(); if (tex) tex->Bind(0); } } } switch (cullmode) { case RAVEN_CULL_NONE: d3dcore->dev->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE); break; case RAVEN_CULL_FRONT: d3dcore->dev->SetRenderState(D3DRS_CULLMODE,D3DCULL_CCW); break; case RAVEN_CULL_BACK: d3dcore->dev->SetRenderState(D3DRS_CULLMODE,D3DCULL_CW); break; } } RendererD3D9::RendererD3D9(Core *core): Renderer(core), geom_d3di(NULL) { d3dcore=dynamic_cast(core); if (!d3dcore) cerr<<"Core is not correct type!"<dev->GetDeviceCaps(&caps); d3dcore->dev->GetDepthStencilSurface(&defaultdepthstencilsurface); UpdateD3DState(); } RendererD3D9::~RendererD3D9() {} void RendererD3D9::TargetViewport(const Viewport &vp) { viewport=vp; UpdateD3DState(); } Viewport RendererD3D9::TargetViewport() { return viewport; } void RendererD3D9::PushProjection() { proj_stack[++proj_stack_ptr]=proj_stack[proj_stack_ptr-1]; d3dcore->dev->SetTransform(D3DTS_PROJECTION,reinterpret_cast((float *)(const float *)transpose(proj_stack[proj_stack_ptr]))); } void RendererD3D9::LoadProjection(const Matrix4x4 &mat) { proj_stack[proj_stack_ptr]=mat; d3dcore->dev->SetTransform(D3DTS_PROJECTION,reinterpret_cast((float *)(const float *)transpose(proj_stack[proj_stack_ptr]))); } void RendererD3D9::LoadProjection(const Projection &proj) { Matrix4x4 mat; Projection _proj(proj); _proj.ToMatrix(mat); proj_stack[proj_stack_ptr]=mat; d3dcore->dev->SetTransform(D3DTS_PROJECTION,reinterpret_cast((float *)(const float *)transpose(proj_stack[proj_stack_ptr]))); } void RendererD3D9::MultProjection(Matrix4x4 &mat) { proj_stack[proj_stack_ptr]=proj_stack[proj_stack_ptr]*mat; d3dcore->dev->SetTransform(D3DTS_PROJECTION,reinterpret_cast((float *)(const float *)transpose(proj_stack[proj_stack_ptr]))); } void RendererD3D9::PopProjection() { proj_stack_ptr--; d3dcore->dev->SetTransform(D3DTS_PROJECTION,reinterpret_cast((float *)(const float *)transpose(proj_stack[proj_stack_ptr]))); } Matrix4x4 RendererD3D9::GetProjection() { return proj_stack[proj_stack_ptr]; } Frustum RendererD3D9::GetProjectionFrustum() { Frustum frustum; frustum.LoadFrustum(proj_stack[proj_stack_ptr]); return frustum; } unsigned int RendererD3D9::GetProjectionStackDepth() { return proj_stack_ptr; } void RendererD3D9::PushModelView() { mdvw_stack[++mdvw_stack_ptr]=mdvw_stack[mdvw_stack_ptr-1]; d3dcore->dev->SetTransform(D3DTS_WORLD,reinterpret_cast((float *)(const float *)transpose(mdvw_stack[mdvw_stack_ptr]))); } void RendererD3D9::LoadModelView(const Matrix4x4 &mat) { mdvw_stack[mdvw_stack_ptr]=mat; d3dcore->dev->SetTransform(D3DTS_WORLD,reinterpret_cast((float *)(const float *)transpose(mdvw_stack[mdvw_stack_ptr]))); } void RendererD3D9::MultModelView(const Matrix4x4 &mat) { mdvw_stack[mdvw_stack_ptr]=mdvw_stack[mdvw_stack_ptr]*mat; d3dcore->dev->SetTransform(D3DTS_WORLD,reinterpret_cast((float *)(const float *)transpose(mdvw_stack[mdvw_stack_ptr]))); } void RendererD3D9::PopModelView() { mdvw_stack_ptr--; d3dcore->dev->SetTransform(D3DTS_WORLD,reinterpret_cast((float *)(const float *)transpose(mdvw_stack[mdvw_stack_ptr]))); } Matrix4x4 RendererD3D9::GetModelView() { return mdvw_stack[mdvw_stack_ptr]; } unsigned int RendererD3D9::GetModelViewStackDepth() { return mdvw_stack_ptr; } bool RendererD3D9::BeginScene(bool clearcolor,bool cleardepth,Vector4 color) { if (clearcolor||cleardepth) { d3dcore->dev->Clear(0,NULL, (clearcolor?D3DCLEAR_TARGET:0)| (cleardepth?D3DCLEAR_ZBUFFER:0), D3DCOLOR_COLORVALUE(color.x,color.y,color.z,1.0f),1.0f,0); } d3dcore->dev->BeginScene(); return true; } bool RendererD3D9::EndScene(bool flip) { d3dcore->dev->EndScene(); if (flip) return d3dcore->Update(); else return true; } void RendererD3D9::SetCullMode(CullMode mode) { cullmode=mode; UpdateD3DState(); } void RendererD3D9::State(int state,bool on) { if (on) stateflags|=state; else stateflags&=~state; UpdateD3DState(); } #define RVECTOR2D3DVECTOR(v) (*(D3DVECTOR *)((float *)v)) bool RendererD3D9::EnableLight(int slot,Light *light) { if (min(RAVEN_MAXIMUM_LIGHTS,(int)caps.MaxActiveLights)GetComponent(RAVEN_OPTICS_AMBIENT_COMPONENT,ambient); active_lights[slot]->GetComponent(RAVEN_OPTICS_DIFFUSE_COMPONENT,diffuse); active_lights[slot]->GetComponent(RAVEN_OPTICS_SPECULAR_COMPONENT,specular); if (active_lights[slot]->GetType()==RAVEN_LIGHT_DIRECTIONAL) { d3dlight.Type=D3DLIGHT_DIRECTIONAL; d3dlight.Direction=RVECTOR2D3DVECTOR(-active_lights[slot]->Direction()); } else { d3dlight.Type=D3DLIGHT_POINT; d3dlight.Position=RVECTOR2D3DVECTOR(active_lights[slot]->Position()); } d3dlight.Attenuation1=active_lights[slot]->Attenuation(); d3dlight.Ambient=VECTOR2D3DCOLORVALUE(ambient); d3dlight.Diffuse=VECTOR2D3DCOLORVALUE(diffuse); d3dlight.Specular=VECTOR2D3DCOLORVALUE(specular); d3dcore->dev->LightEnable(slot,TRUE); d3dcore->dev->SetLight(slot,&d3dlight); return true; } bool RendererD3D9::DisableLight(int slot) { if (active_lights[slot]==NULL) return false; d3dcore->dev->LightEnable(slot,FALSE); active_lights[slot]=NULL; return true; } void RendererD3D9::Blend(BlendMode mode,float mask) { blend=mode; blendmask=mask; UpdateD3DState(); } void RendererD3D9::BlendMask(float mask) { blendmask=mask; UpdateD3DState(); } void RendererD3D9::Material(const RenderMaterial &material) { this->material=material; Vector4 ambient,specular; Vector3 diffuse; this->material.GetComponent(RAVEN_OPTICS_AMBIENT_COMPONENT,ambient); this->material.GetComponent(RAVEN_OPTICS_DIFFUSE_COMPONENT,diffuse); this->material.GetComponent(RAVEN_OPTICS_SPECULAR_COMPONENT,specular); memset(&d3dmaterial,0,sizeof(D3DMATERIAL9)); d3dmaterial.Ambient=VECTOR2D3DCOLORVALUE(ambient); d3dmaterial.Diffuse=VECTOR2D3DCOLORVALUE(Vector4(diffuse,this->material.Alpha())); d3dmaterial.Specular=VECTOR2D3DCOLORVALUE(specular); d3dmaterial.Power=this->material.Shininess(); UpdateD3DState(); } VertexBuffer *RendererD3D9::CreateVertexBuffer(int attribs) { if (stateflags&RAVEN_STATE_USE_HW_VERTEX_MEMORY) return new VertexBufferD3D9(d3dcore->dev,attribs); else return new VertexBuffer(attribs); } bool RendererD3D9::RenderVertexBuffer(VertexBuffer *buf,GeometryType geomtype) { if (dynamic_cast(buf)) return buf->Render(geomtype); else if (buf->IsSoftBuffer()) { unsigned int numtextures; unsigned int *indices; Vector3 *verts; Vector3 *norms; Vector4 *colors; Vector2 *texcoords; int attribs=buf->GetBufAttribs(); if (!(attribs&RAVEN_GEOMETRY_FLAG_VERTICES)) return false; buf->Get(RAVEN_GEOMETRY_FLAG_INDICES,0,(void **)&indices); buf->Get(RAVEN_GEOMETRY_FLAG_VERTICES,0,(void **)&verts); buf->Get(RAVEN_GEOMETRY_FLAG_NORMALS,0,(void **)&norms); buf->Get(RAVEN_GEOMETRY_FLAG_COLORS,0,(void **)&colors); if ((numtextures=buf->NumTextures())==1) buf->Get(RAVEN_GEOMETRY_FLAG_TEXCOORDS,0,(void **)&texcoords); if (attribs&RAVEN_GEOMETRY_FLAG_INDICES) { unsigned int numindices=buf->NumIndices(); if (!BeginGeometry(attribs,numtextures,geomtype)) return false; for (register unsigned int i=0; iNumVerts(); if (!BeginGeometry(attribs,numtextures,geomtype)) return false; for (register unsigned int i=0; iIsValid()) { delete geom_d3di; geom_d3di=NULL; return false; } d3dgeomtype=geomtype; return true; } void RendererD3D9::GeometryVertex(const Vector3 &vert) { if (!geom_d3di) return; geom_d3di->SetVertex(vert); geom_d3di->AdvancePtr(); } void RendererD3D9::GeometryNormal(const Vector3 &norm) { if (!geom_d3di) return; geom_d3di->SetNormal(norm); } void RendererD3D9::GeometryColor(const Vector4 &color) { if (!geom_d3di) return; geom_d3di->SetColor(color); } void RendererD3D9::GeometryTexCoord(const Vector2 &texcoord,int idx) { if (!geom_d3di) return; geom_d3di->SetTexCoords(texcoord,idx); } bool RendererD3D9::EndGeometry() { bool result=true; if (!geom_d3di) return false; if (!geom_d3di->RenderPrimitives(d3dgeomtype,d3dcore->dev)) result=false; delete geom_d3di; geom_d3di=NULL; return result; } RenderTarget *RendererD3D9::CreateRenderTargetColorTexture(SamplerState samp,int po2lev,bool floatformat) { RenderTargetD3D9 *rt=new RenderTargetD3D9(d3dcore->dev,samp,po2lev,floatformat); if (!rt->IsValid()) { delete rt; return NULL; } else return rt; } bool RendererD3D9::BindRenderTarget(RenderTarget *target) { if (!target) return false; if (target->IsMainFrameBuffer()) { LPDIRECT3DSURFACE9 backbuf; d3dcore->dev->GetBackBuffer(0,0,D3DBACKBUFFER_TYPE_MONO,&backbuf); d3dcore->dev->SetRenderTarget(0,backbuf); d3dcore->dev->SetDepthStencilSurface(defaultdepthstencilsurface); curr_target=target; } else { bool result=target->BindTarget(); if (!result) return result; else { curr_target=target; return result; } } return true; } Texture *RendererD3D9::CreateTexture(Pixelmap *image,SamplerState samp,unsigned int flags) { TextureD3D9 *tex=new TextureD3D9(d3dcore->dev,image,samp,flags); if (!tex->IsValid()) { delete tex; return NULL; } return tex; } FontBase *RendererD3D9::LoadFont(const char *file,int pt) { TrueTypeFont *ttf=new TrueTypeFont(file,pt); if (!ttf->IsValid()) { delete ttf; return NULL; } FontD3D9 *d3dfont=new FontD3D9(d3dcore->dev,ttf); delete ttf; if (!d3dfont->IsValid()) { delete d3dfont; return NULL; } return d3dfont; } bool RendererD3D9::RenderText(FontBase *font,int x,int y,const char *text) { if (!font) return false; font->Render(x,y,text); return true; }