summaryrefslogtreecommitdiffstats
path: root/src/extras/screendroplets.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/extras/screendroplets.cpp')
-rw-r--r--src/extras/screendroplets.cpp791
1 files changed, 791 insertions, 0 deletions
diff --git a/src/extras/screendroplets.cpp b/src/extras/screendroplets.cpp
new file mode 100644
index 00000000..2d34cdcb
--- /dev/null
+++ b/src/extras/screendroplets.cpp
@@ -0,0 +1,791 @@
+#define WITH_D3D
+#include "common.h"
+
+#ifdef SCREEN_DROPLETS
+
+#ifndef LIBRW
+#error "Need librw for SCREEN_DROPLETS"
+#endif
+
+#include "General.h"
+#include "Main.h"
+#include "RwHelper.h"
+#include "Main.h"
+#include "Timer.h"
+#include "Camera.h"
+#include "ZoneCull.h"
+#include "Weather.h"
+#include "ParticleObject.h"
+ #include "Pad.h"
+#include "RenderBuffer.h"
+#include "custompipes.h"
+#include "postfx.h"
+#include "screendroplets.h"
+
+// for 640
+#define MAXSIZE 15
+#define MINSIZE 4
+
+int ScreenDroplets::ms_initialised;
+RwTexture *ScreenDroplets::ms_maskTex;
+RwTexture *ScreenDroplets::ms_screenTex;
+
+bool ScreenDroplets::ms_enabled = true;
+bool ScreenDroplets::ms_movingEnabled = true;
+
+ScreenDroplets::ScreenDrop ScreenDroplets::ms_drops[ScreenDroplets::MAXDROPS];
+int ScreenDroplets::ms_numDrops;
+ScreenDroplets::ScreenDropMoving ScreenDroplets::ms_dropsMoving[ScreenDroplets::MAXDROPSMOVING];
+int ScreenDroplets::ms_numDropsMoving;
+
+CVector ScreenDroplets::ms_prevCamUp;
+CVector ScreenDroplets::ms_prevCamPos;
+CVector ScreenDroplets::ms_camMoveDelta;
+float ScreenDroplets::ms_camMoveDist;
+CVector ScreenDroplets::ms_screenMoveDelta;
+float ScreenDroplets::ms_screenMoveDist;
+float ScreenDroplets::ms_camUpAngle;
+
+int ScreenDroplets::ms_splashDuration;
+CParticleObject *ScreenDroplets::ms_splashObject;
+
+struct Im2DVertexUV2 : rw::RWDEVICE::Im2DVertex
+{
+ rw::float32 u2, v2;
+};
+
+#ifdef RW_D3D9
+static void *screenDroplet_PS;
+#endif
+#ifdef RW_GL3
+static rw::gl3::Shader *screenDroplet;
+#endif
+
+// platform specific
+static void openim2d_uv2(void);
+static void closeim2d_uv2(void);
+static void RenderIndexedPrimitive_UV2(RwPrimitiveType primType, Im2DVertexUV2 *vertices, RwInt32 numVertices, RwImVertexIndex *indices, RwInt32 numIndices);
+
+static Im2DVertexUV2 VertexBuffer[TEMPBUFFERVERTSIZE];
+
+void
+ScreenDroplets::Initialise(void)
+{
+ Clear();
+ ms_splashDuration = -1;
+ ms_splashObject = nil;
+}
+
+void
+ScreenDroplets::InitDraw(void)
+{
+ if(CustomPipes::neoTxd)
+ ms_maskTex = CustomPipes::neoTxd->find("dropmask");
+
+ ms_screenTex = RwTextureCreate(nil);
+ RwTextureSetFilterMode(ms_screenTex, rwFILTERLINEAR);
+
+ openim2d_uv2();
+#ifdef RW_D3D9
+#include "shaders/screenDroplet_PS.inc"
+ screenDroplet_PS = rw::d3d::createPixelShader(screenDroplet_PS_cso);
+#endif
+#ifdef RW_GL3
+ using namespace rw::gl3;
+ {
+#include "shaders/im2d_UV2_gl.inc"
+#include "shaders/screenDroplet_fs_gl.inc"
+ const char *vs[] = { shaderDecl, header_vert_src, im2d_UV2_vert_src, nil };
+ const char *fs[] = { shaderDecl, header_frag_src, screenDroplet_frag_src, nil };
+ screenDroplet = Shader::create(vs, fs);
+ assert(screenDroplet);
+ }
+#endif
+
+ ms_initialised = 1;
+}
+
+void
+ScreenDroplets::Shutdown(void)
+{
+ if(ms_maskTex){
+ RwTextureDestroy(ms_maskTex);
+ ms_maskTex = nil;
+ }
+ if(ms_screenTex){
+ RwTextureSetRaster(ms_screenTex, nil);
+ RwTextureDestroy(ms_screenTex);
+ ms_screenTex = nil;
+ }
+#ifdef RW_D3D9
+ if(screenDroplet_PS){
+ rw::d3d::destroyPixelShader(screenDroplet_PS);
+ screenDroplet_PS = nil;
+ }
+#endif
+#ifdef RW_GL3
+ if(screenDroplet){
+ screenDroplet->destroy();
+ screenDroplet = nil;
+ }
+#endif
+
+ closeim2d_uv2();
+}
+
+void
+ScreenDroplets::Process(void)
+{
+ ProcessCameraMovement();
+ SprayDrops();
+ ProcessMoving();
+ Fade();
+}
+
+static void
+FlushBuffer(void)
+{
+ if(TempBufferIndicesStored){
+ RenderIndexedPrimitive_UV2(rwPRIMTYPETRILIST,
+ VertexBuffer, TempBufferVerticesStored,
+ TempBufferRenderIndexList, TempBufferIndicesStored);
+ TempBufferVerticesStored = 0;
+ TempBufferIndicesStored = 0;
+ }
+}
+
+static int
+StartStoring(int numIndices, int numVertices, RwImVertexIndex **indexStart, Im2DVertexUV2 **vertexStart)
+{
+ if(TempBufferIndicesStored + numIndices >= TEMPBUFFERINDEXSIZE ||
+ TempBufferVerticesStored + numVertices >= TEMPBUFFERVERTSIZE)
+ FlushBuffer();
+ *indexStart = &TempBufferRenderIndexList[TempBufferIndicesStored];
+ *vertexStart = &VertexBuffer[TempBufferVerticesStored];
+ int vertOffset = TempBufferVerticesStored;
+ TempBufferIndicesStored += numIndices;
+ TempBufferVerticesStored += numVertices;
+ return vertOffset;
+}
+
+void
+ScreenDroplets::Render(void)
+{
+ ScreenDrop *drop;
+
+ DefinedState();
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(ms_maskTex));
+ RwRenderStateSet(rwRENDERSTATEFOGENABLE, FALSE);
+ RwRenderStateSet(rwRENDERSTATEZTESTENABLE, FALSE);
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, FALSE);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+
+ RwTextureSetRaster(ms_screenTex, CPostFX::pBackBuffer);
+#ifdef RW_D3D9
+ rw::d3d::im2dOverridePS = screenDroplet_PS;
+ rw::d3d::setTexture(1, ms_screenTex);
+#endif
+#ifdef RW_GL3
+ rw::gl3::im2dOverrideShader = screenDroplet;
+ rw::gl3::setTexture(1, ms_screenTex);
+#endif
+
+ RenderBuffer::ClearRenderBuffer();
+ for(drop = &ms_drops[0]; drop < &ms_drops[MAXDROPS]; drop++)
+ if(drop->active)
+ AddToRenderList(drop);
+ FlushBuffer();
+
+#ifdef RW_D3D9
+ rw::d3d::im2dOverridePS = nil;
+ rw::d3d::setTexture(1, nil);
+#endif
+#ifdef RW_GL3
+ rw::gl3::im2dOverrideShader = nil;
+ rw::gl3::setTexture(1, nil);
+#endif
+
+ RwRenderStateSet(rwRENDERSTATEFOGENABLE, FALSE);
+ RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, FALSE);
+}
+
+void
+ScreenDroplets::AddToRenderList(ScreenDroplets::ScreenDrop *drop)
+{
+ static float xy[] = {
+ -1.0f, -1.0f,
+ -1.0f, 1.0f,
+ 1.0f, 1.0f,
+ 1.0f, -1.0f
+ };
+ static float uv[] = {
+ 0.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 1.0f,
+ 1.0f, 0.0f
+ };
+
+ int i;
+ RwImVertexIndex *indices;
+ Im2DVertexUV2 *verts;
+ int first = StartStoring(6, 4, &indices, &verts);
+
+ float scale = 0.5f*SCREEN_SCALE_X(drop->size);
+
+ float screenz = RwIm2DGetNearScreenZ();
+ float z = RwCameraGetNearClipPlane(Scene.camera);
+ float recipz = 1.0f/z;
+
+ float magSize = SCREEN_SCALE_Y(drop->magnification*(300.0f-40.0f) + 40.0f);
+ float ul = drop->x - magSize;
+ float vt = drop->y - magSize;
+ float ur = drop->x + magSize;
+ float vb = drop->y + magSize;
+ ul = Max(ul, 0.0f)/RwRasterGetWidth(CPostFX::pBackBuffer);
+ vt = Max(vt, 0.0f)/RwRasterGetHeight(CPostFX::pBackBuffer);
+ ur = Min(ur, SCREEN_WIDTH)/RwRasterGetWidth(CPostFX::pBackBuffer);
+ vb = Min(vb, SCREEN_HEIGHT)/RwRasterGetHeight(CPostFX::pBackBuffer);
+
+ for(i = 0; i < 4; i++){
+ RwIm2DVertexSetScreenX(&verts[i], drop->x + xy[i*2]*scale);
+ RwIm2DVertexSetScreenY(&verts[i], drop->y + xy[i*2+1]*scale);
+ RwIm2DVertexSetScreenZ(&verts[i], screenz);
+ RwIm2DVertexSetCameraZ(&verts[i], z);
+ RwIm2DVertexSetRecipCameraZ(&verts[i], recipz);
+ RwIm2DVertexSetIntRGBA(&verts[i], drop->color.r, drop->color.g, drop->color.b, drop->color.a);
+ RwIm2DVertexSetU(&verts[i], uv[i*2], recipz);
+ RwIm2DVertexSetV(&verts[i], uv[i*2+1], recipz);
+
+ verts[i].u2 = i < 2 ? ul : ur;
+ verts[i].v2 = i % 3 ? vt : vb;
+ }
+ indices[0] = first + 0;
+ indices[1] = first + 1;
+ indices[2] = first + 2;
+ indices[3] = first + 2;
+ indices[4] = first + 3;
+ indices[5] = first + 0;
+}
+
+void
+ScreenDroplets::Clear(void)
+{
+ ScreenDrop *drop;
+ for(drop = &ms_drops[0]; drop < &ms_drops[MAXDROPS]; drop++)
+ drop->active = false;
+ ms_numDrops = 0;
+}
+
+ScreenDroplets::ScreenDrop*
+ScreenDroplets::NewDrop(float x, float y, float size, float lifetime, bool fades, int r, int g, int b)
+{
+ ScreenDrop *drop;
+ int i;
+
+ for(i = 0, drop = ms_drops; i < MAXDROPS; i++, drop++)
+ if(!ms_drops[i].active)
+ goto found;
+ return nil;
+found:
+ ms_numDrops++;
+ drop->x = x;
+ drop->y = y;
+ drop->size = size;
+ drop->magnification = (MAXSIZE - size + 1.0f) / (MAXSIZE - MINSIZE + 1.0f);
+ drop->fades = fades;
+ drop->active = true;
+ drop->color.r = r;
+ drop->color.g = g;
+ drop->color.b = b;
+ drop->color.a = 255;
+ drop->time = 0.0f;
+ drop->lifetime = lifetime;
+ return drop;
+}
+
+void
+ScreenDroplets::SetMoving(ScreenDroplets::ScreenDrop *drop)
+{
+ ScreenDropMoving *moving;
+ for(moving = ms_dropsMoving; moving < &ms_dropsMoving[MAXDROPSMOVING]; moving++)
+ if(moving->drop == nil)
+ goto found;
+ return;
+found:
+ ms_numDropsMoving++;
+ moving->drop = drop;
+ moving->dist = 0.0f;
+}
+
+void
+ScreenDroplets::FillScreen(int n)
+{
+ float x, y, size;
+ ScreenDrop *drop;
+
+ if(!ms_initialised)
+ return;
+ ms_numDrops = 0;
+ for(drop = &ms_drops[0]; drop < &ms_drops[MAXDROPS]; drop++){
+ drop->active = false;
+ if(drop < &ms_drops[n]){
+ x = CGeneral::GetRandomNumber() % (int)SCREEN_WIDTH;
+ y = CGeneral::GetRandomNumber() % (int)SCREEN_HEIGHT;
+ size = CGeneral::GetRandomNumberInRange(MINSIZE, MAXSIZE);
+ NewDrop(x, y, size, 2000.0f, true);
+ }
+ }
+}
+
+void
+ScreenDroplets::FillScreenMoving(float amount, bool isBlood)
+{
+ int n = (ms_screenMoveDelta.z > 5.0f ? 1.5f : 1.0f)*amount*20.0f;
+ float x, y, size;
+ ScreenDrop *drop;
+
+ while(n--)
+ if(ms_numDrops < MAXDROPS && ms_numDropsMoving < MAXDROPSMOVING){
+ x = CGeneral::GetRandomNumber() % (int)SCREEN_WIDTH;
+ y = CGeneral::GetRandomNumber() % (int)SCREEN_HEIGHT;
+ size = CGeneral::GetRandomNumberInRange(MINSIZE, MAXSIZE);
+ drop = nil;
+ if(isBlood)
+ drop = NewDrop(x, y, size, 2000.0f, true, 255, 0, 0);
+ else
+ drop = NewDrop(x, y, size, 2000.0f, true);
+ if(drop)
+ SetMoving(drop);
+ }
+}
+
+void
+ScreenDroplets::RegisterSplash(CParticleObject *pobj)
+{
+ CVector dist = pobj->GetPosition() - ms_prevCamPos;
+ if(dist.MagnitudeSqr() < 20.0f){
+ ms_splashDuration = 14;
+ ms_splashObject = pobj;
+ }
+}
+
+void
+ScreenDroplets::ProcessCameraMovement(void)
+{
+ RwMatrix *camMat = RwFrameGetMatrix(RwCameraGetFrame(Scene.camera));
+ CVector camPos = camMat->pos;
+ CVector camUp = camMat->at;
+ ms_camMoveDelta = camPos - ms_prevCamPos;
+ ms_camMoveDist = ms_camMoveDelta.Magnitude();
+
+ ms_prevCamUp = camUp;
+ ms_prevCamPos = camPos;
+
+ ms_screenMoveDelta.x = -RwV3dDotProduct(&camMat->right, (RwV3d*)&ms_camMoveDelta);
+ ms_screenMoveDelta.y = RwV3dDotProduct(&camMat->up, (RwV3d*)&ms_camMoveDelta);
+ ms_screenMoveDelta.z = RwV3dDotProduct(&camMat->at, (RwV3d*)&ms_camMoveDelta);
+ ms_screenMoveDelta *= 10.0f;
+ ms_screenMoveDist = ms_screenMoveDelta.Magnitude2D();
+
+ uint16 mode = TheCamera.Cams[TheCamera.ActiveCam].Mode;
+ bool isTopDown = mode == CCam::MODE_TOPDOWN || mode == CCam::MODE_GTACLASSIC || mode == CCam::MODE_TOP_DOWN_PED;
+ bool isLookingInDirection = CPad::GetPad(0)->GetLookBehindForCar() || CPad::GetPad(0)->GetLookLeft() || CPad::GetPad(0)->GetLookRight();
+ ms_enabled = !isTopDown && !isLookingInDirection;
+ ms_movingEnabled = !isTopDown && !isLookingInDirection;
+
+ // 0 when looking stright up, 180 when looking up or down
+ ms_camUpAngle = RADTODEG(Acos(clamp(camUp.z, -1.0f, 1.0f)));
+}
+
+void
+ScreenDroplets::SprayDrops(void)
+{
+ bool noRain = CCullZones::PlayerNoRain() || CCullZones::CamNoRain();
+ if(!noRain && CWeather::Rain > 0.0f && ms_enabled){
+ // 180 when looking stright up, 0 when looking up or down
+ float angle = 180.0f - ms_camUpAngle;
+ angle = Max(angle, 40.0f); // want at least some rain
+ FillScreenMoving((angle - 40.0f) / 150.0f * CWeather::Rain * 0.5f);
+ }
+
+ int i;
+ for(i = 0; i < MAX_AUDIOHYDRANTS; i++){
+ CAudioHydrant *hyd = CAudioHydrant::Get(i);
+ if (hyd->pParticleObject){
+ CVector dist = hyd->pParticleObject->GetPosition() - ms_prevCamPos;
+ if(dist.MagnitudeSqr() > 40.0f ||
+ DotProduct(dist, ms_prevCamUp) < 0.0f) continue;
+
+ FillScreenMoving(1.0f);
+ }
+ }
+
+ static int ndrops[] = {
+ 125, 250, 500, 1000, 1000,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ if(ms_splashDuration >= 0){
+ if(ms_numDrops < MAXDROPS) {
+ float numDropMult = 1.0f;
+ if(ms_splashObject){
+ float dist = (ms_splashObject->GetPosition() - ms_prevCamPos).Magnitude();
+ numDropMult = 1.0f - (dist - 5.0f)/15.0f;
+ if(numDropMult < 0) numDropMult = 0.0f; // fix
+ }
+ int n = ndrops[ms_splashDuration] * numDropMult;
+ while(n--)
+ if(ms_numDrops < MAXDROPS){
+ float x = CGeneral::GetRandomNumber() % (int)SCREEN_WIDTH;
+ float y = CGeneral::GetRandomNumber() % (int)SCREEN_HEIGHT;
+ float size = CGeneral::GetRandomNumberInRange(MINSIZE, MAXSIZE);
+ NewDrop(x, y, size, 10000.0f, false);
+ }
+ }
+ ms_splashDuration--;
+ }
+}
+
+void
+ScreenDroplets::NewTrace(ScreenDroplets::ScreenDropMoving *moving)
+{
+ if(ms_numDrops < MAXDROPS){
+ moving->dist = 0.0f;
+ NewDrop(moving->drop->x, moving->drop->y, MINSIZE, 500.0f, true,
+ moving->drop->color.r, moving->drop->color.g, moving->drop->color.b);
+ }
+}
+
+void
+ScreenDroplets::MoveDrop(ScreenDroplets::ScreenDropMoving *moving)
+{
+ ScreenDrop *drop = moving->drop;
+ if(!ms_movingEnabled)
+ return;
+ if(!drop->active){
+ moving->drop = nil;
+ ms_numDropsMoving--;
+ return;
+ }
+ if(ms_screenMoveDelta.z > 0.0f && ms_camMoveDist > 0.3f){
+ if(ms_screenMoveDist > 0.5f && TheCamera.Cams[TheCamera.ActiveCam].Mode != CCam::MODE_1STPERSON){
+ // movement when camera turns
+ moving->dist += ms_screenMoveDist;
+ if(moving->dist > 20.0f && drop->color.a > 100)
+ NewTrace(moving);
+
+ drop->x -= ms_screenMoveDelta.x;
+ drop->y += ms_screenMoveDelta.y;
+ }else{
+ // movement out of center
+ float d = ms_screenMoveDelta.z*0.2f;
+ float dx, dy, sum;
+ dx = drop->x - SCREEN_WIDTH*0.5f + ms_screenMoveDelta.x;
+ if(TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_1STPERSON)
+ dy = drop->y - SCREEN_HEIGHT*1.2f - ms_screenMoveDelta.y;
+ else
+ dy = drop->y - SCREEN_HEIGHT*0.5f - ms_screenMoveDelta.y;
+ sum = fabs(dx) + fabs(dy);
+ if(sum > 0.001f){
+ dx /= sum;
+ dy /= sum;
+ }
+ moving->dist += d;
+ if(moving->dist > 20.0f && drop->color.a > 100)
+ NewTrace(moving);
+ drop->x += dx * d;
+ drop->y += dy * d;
+ }
+
+ if(drop->x < 0.0f || drop->y < 0.0f ||
+ drop->x > SCREEN_WIDTH || drop->y > SCREEN_HEIGHT){
+ moving->drop = nil;
+ ms_numDropsMoving--;
+ }
+ }
+}
+
+void
+ScreenDroplets::ProcessMoving(void)
+{
+ ScreenDropMoving *moving;
+ if(!ms_movingEnabled)
+ return;
+ for(moving = ms_dropsMoving; moving < &ms_dropsMoving[MAXDROPSMOVING]; moving++)
+ if(moving->drop)
+ MoveDrop(moving);
+}
+
+void
+ScreenDroplets::Fade(void)
+{
+ ScreenDrop *drop;
+ for(drop = &ms_drops[0]; drop < &ms_drops[MAXDROPS]; drop++)
+ if(drop->active)
+ drop->Fade();
+}
+
+void
+ScreenDroplets::ScreenDrop::Fade(void)
+{
+ int delta = CTimer::GetTimeStepInMilliseconds();
+ time += delta;
+ if(time < lifetime){
+ color.a = 255 - time/lifetime*255;
+ }else if(fades){
+ ScreenDroplets::ms_numDrops--;
+ active = false;
+ }
+}
+
+
+/*
+ * Im2D with two uv coors
+ */
+
+#ifdef RW_D3D9
+// stolen from RW, not in a public header
+namespace rw {
+namespace d3d {
+void addDynamicVB(uint32 length, uint32 fvf, IDirect3DVertexBuffer9 **buf); // NB: don't share this pointer
+void removeDynamicVB(IDirect3DVertexBuffer9 **buf);
+void addDynamicIB(uint32 length, IDirect3DIndexBuffer9 **buf); // NB: don't share this pointer
+void removeDynamicIB(IDirect3DIndexBuffer9 **buf);
+}
+}
+// different than im2d
+#define NUMINDICES 1024
+#define NUMVERTICES 1024
+
+static int primTypeMap[] = {
+ D3DPT_POINTLIST, // invalid
+ D3DPT_LINELIST,
+ D3DPT_LINESTRIP,
+ D3DPT_TRIANGLELIST,
+ D3DPT_TRIANGLESTRIP,
+ D3DPT_TRIANGLEFAN,
+ D3DPT_POINTLIST, // actually not supported!
+};
+// end of stolen stuff
+
+
+static IDirect3DVertexDeclaration9 *im2ddecl_uv2;
+static IDirect3DVertexBuffer9 *im2dvertbuf_uv2;
+static IDirect3DIndexBuffer9 *im2dindbuf_uv2;
+
+void
+openim2d_uv2(void)
+{
+ using namespace rw;
+ using namespace d3d;
+ D3DVERTEXELEMENT9 elements[5] = {
+ { 0, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITIONT, 0 },
+ { 0, offsetof(Im2DVertexUV2, color), D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 },
+ { 0, offsetof(Im2DVertexUV2, u), D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
+ { 0, offsetof(Im2DVertexUV2, u2), D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1 },
+ D3DDECL_END()
+ };
+ assert(im2ddecl_uv2 == nil);
+ im2ddecl_uv2 = (IDirect3DVertexDeclaration9*)d3d9::createVertexDeclaration((d3d9::VertexElement*)elements);
+ assert(im2ddecl_uv2);
+
+ assert(im2dvertbuf_uv2 == nil);
+ im2dvertbuf_uv2 = (IDirect3DVertexBuffer9*)createVertexBuffer(NUMVERTICES*sizeof(Im2DVertexUV2), 0, true);
+ assert(im2dvertbuf_uv2);
+ addDynamicVB(NUMVERTICES*sizeof(Im2DVertexUV2), 0, &im2dvertbuf_uv2);
+
+ assert(im2dindbuf_uv2 == nil);
+ im2dindbuf_uv2 = (IDirect3DIndexBuffer9*)createIndexBuffer(NUMINDICES*sizeof(rw::uint16), true);
+ assert(im2dindbuf_uv2);
+ addDynamicIB(NUMINDICES*sizeof(rw::uint16), &im2dindbuf_uv2);
+}
+
+void
+closeim2d_uv2(void)
+{
+ using namespace rw;
+ using namespace d3d;
+
+ d3d9::destroyVertexDeclaration(im2ddecl_uv2);
+ im2ddecl_uv2 = nil;
+
+ removeDynamicVB(&im2dvertbuf_uv2);
+ destroyVertexBuffer(im2dvertbuf_uv2);
+ im2dvertbuf_uv2 = nil;
+
+ removeDynamicIB(&im2dindbuf_uv2);
+ destroyIndexBuffer(im2dindbuf_uv2);
+ im2dindbuf_uv2 = nil;
+}
+
+void
+RenderIndexedPrimitive_UV2(RwPrimitiveType primType, Im2DVertexUV2 *vertices, RwInt32 numVertices, RwImVertexIndex *indices, RwInt32 numIndices)
+{
+ using namespace rw;
+ using namespace d3d;
+
+ if(numVertices > NUMVERTICES ||
+ numIndices > NUMINDICES){
+ // TODO: error
+ return;
+ }
+ rw::uint16 *lockedindices = lockIndices(im2dindbuf_uv2, 0, numIndices*sizeof(rw::uint16), D3DLOCK_DISCARD);
+ memcpy(lockedindices, indices, numIndices*sizeof(rw::uint16));
+ unlockIndices(im2dindbuf_uv2);
+
+ rw::uint8 *lockedvertices = lockVertices(im2dvertbuf_uv2, 0, numVertices*sizeof(Im2DVertexUV2), D3DLOCK_DISCARD);
+ memcpy(lockedvertices, vertices, numVertices*sizeof(Im2DVertexUV2));
+ unlockVertices(im2dvertbuf_uv2);
+
+ setStreamSource(0, im2dvertbuf_uv2, 0, sizeof(Im2DVertexUV2));
+ setIndices(im2dindbuf_uv2);
+ setVertexDeclaration(im2ddecl_uv2);
+
+ if(im2dOverridePS)
+ setPixelShader(im2dOverridePS);
+ else if(engine->device.getRenderState(TEXTURERASTER))
+ setPixelShader(im2d_tex_PS);
+ else
+ setPixelShader(im2d_PS);
+
+ d3d::flushCache();
+
+ rw::uint32 primCount = 0;
+ switch(primType){
+ case PRIMTYPELINELIST:
+ primCount = numIndices/2;
+ break;
+ case PRIMTYPEPOLYLINE:
+ primCount = numIndices-1;
+ break;
+ case PRIMTYPETRILIST:
+ primCount = numIndices/3;
+ break;
+ case PRIMTYPETRISTRIP:
+ primCount = numIndices-2;
+ break;
+ case PRIMTYPETRIFAN:
+ primCount = numIndices-2;
+ break;
+ case PRIMTYPEPOINTLIST:
+ primCount = numIndices;
+ break;
+ }
+ d3ddevice->DrawIndexedPrimitive((D3DPRIMITIVETYPE)primTypeMap[primType], 0,
+ 0, numVertices,
+ 0, primCount);
+}
+#endif
+
+#ifdef RW_GL3
+// different than im2d
+#define NUMINDICES 1024
+#define NUMVERTICES 1024
+
+static rw::gl3::AttribDesc im2d_UV2_attribDesc[4] = {
+ { rw::gl3::ATTRIB_POS, GL_FLOAT, GL_FALSE, 4,
+ sizeof(Im2DVertexUV2), 0 },
+ { rw::gl3::ATTRIB_COLOR, GL_UNSIGNED_BYTE, GL_TRUE, 4,
+ sizeof(Im2DVertexUV2), offsetof(Im2DVertexUV2, r) },
+ { rw::gl3::ATTRIB_TEXCOORDS0, GL_FLOAT, GL_FALSE, 2,
+ sizeof(Im2DVertexUV2), offsetof(Im2DVertexUV2, u) },
+ { rw::gl3::ATTRIB_TEXCOORDS1, GL_FLOAT, GL_FALSE, 2,
+ sizeof(Im2DVertexUV2), offsetof(Im2DVertexUV2, u2) }
+};
+
+static int primTypeMap[] = {
+ GL_POINTS, // invalid
+ GL_LINES,
+ GL_LINE_STRIP,
+ GL_TRIANGLES,
+ GL_TRIANGLE_STRIP,
+ GL_TRIANGLE_FAN,
+ GL_POINTS
+};
+
+static int32 u_xform;
+
+uint32 im2D_UV2_Vbo, im2D_UV2_Ibo;
+#ifdef RW_GL_USE_VAOS
+uint32 im2D_UV2_Vao;
+#endif
+
+void
+openim2d_uv2(void)
+{
+ u_xform = rw::gl3::registerUniform("u_xform"); // this doesn't add a new one, so it's safe
+
+ glGenBuffers(1, &im2D_UV2_Ibo);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, im2D_UV2_Ibo);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, NUMINDICES*2, nil, GL_STREAM_DRAW);
+
+ glGenBuffers(1, &im2D_UV2_Vbo);
+ glBindBuffer(GL_ARRAY_BUFFER, im2D_UV2_Vbo);
+ glBufferData(GL_ARRAY_BUFFER, NUMVERTICES*sizeof(Im2DVertexUV2), nil, GL_STREAM_DRAW);
+
+#ifdef RW_GL_USE_VAOS
+ glGenVertexArrays(1, &im2D_UV2_Vao);
+ glBindVertexArray(im2D_UV2_Vao);
+ setAttribPointers(im2d_UV2_attribDesc, 4);
+#endif
+}
+
+void
+closeim2d_uv2(void)
+{
+ glDeleteBuffers(1, &im2D_UV2_Ibo);
+ glDeleteBuffers(1, &im2D_UV2_Vbo);
+#ifdef RW_GL_USE_VAOS
+ glDeleteVertexArrays(1, &im2D_UV2_Vao);
+#endif
+}
+
+void
+RenderIndexedPrimitive_UV2(RwPrimitiveType primType, Im2DVertexUV2 *vertices, RwInt32 numVertices, RwImVertexIndex *indices, RwInt32 numIndices)
+{
+ using namespace rw;
+ using namespace gl3;
+
+ GLfloat xform[4];
+ Camera *cam;
+ cam = (Camera*)engine->currentCamera;
+
+#ifdef RW_GL_USE_VAOS
+ glBindVertexArray(im2D_UV2_Vao);
+#endif
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, im2D_UV2_Ibo);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, NUMINDICES*2, nil, GL_STREAM_DRAW);
+ glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, numIndices*2, indices);
+
+ glBindBuffer(GL_ARRAY_BUFFER, im2D_UV2_Vbo);
+ glBufferData(GL_ARRAY_BUFFER, NUMVERTICES*sizeof(Im2DVertexUV2), nil, GL_STREAM_DRAW);
+ glBufferSubData(GL_ARRAY_BUFFER, 0, numVertices*sizeof(Im2DVertexUV2), vertices);
+
+ xform[0] = 2.0f/cam->frameBuffer->width;
+ xform[1] = -2.0f/cam->frameBuffer->height;
+ xform[2] = -1.0f;
+ xform[3] = 1.0f;
+
+ if(im2dOverrideShader)
+ im2dOverrideShader->use();
+ else
+ assert(0);//im2dShader->use();
+#ifndef RW_GL_USE_VAOS
+ setAttribPointers(im2d_UV2_attribDesc, 4);
+#endif
+
+ glUniform4fv(currentShader->uniformLocations[u_xform], 1, xform);
+
+ flushCache();
+ glDrawElements(primTypeMap[primType], numIndices,
+ GL_UNSIGNED_SHORT, nil);
+#ifndef RW_GL_USE_VAOS
+ disableAttribPointers(im2d_UV2_attribDesc, 4);
+#endif
+}
+#endif
+
+#endif