#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; } // Create white circle mask for rain drops static RwTexture* CreateDropMask(int32 size) { RwImage *img = RwImageCreate(size, size, 32); RwImageAllocatePixels(img); uint8 *pixels = RwImageGetPixels(img); int32 stride = RwImageGetStride(img); for(int y = 0; y < size; y++){ float yf = ((y + 0.5f)/size - 0.5f)*2.0f; for(int x = 0; x < size; x++){ float xf = ((x + 0.5f)/size - 0.5f)*2.0f; memset(&pixels[y*stride + x*4], xf*xf + yf*yf < 1.0f ? 0xFF : 0x00, 4); } } int32 width, height, depth, format; RwImageFindRasterFormat(img, rwRASTERTYPETEXTURE, &width, &height, &depth, &format); RwRaster *ras = RwRasterCreate(width, height, depth, format); RwRasterSetFromImage(ras, img); RwImageDestroy(img); return RwTextureCreate(ras); } void ScreenDroplets::InitDraw(void) { ms_maskTex = CreateDropMask(64); 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, &ms_camMoveDelta); ms_screenMoveDelta.y = RwV3dDotProduct(&camMat->up, &ms_camMoveDelta); ms_screenMoveDelta.z = RwV3dDotProduct(&camMat->at, &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