re3/src/extras/screendroplets.cpp

818 lines
22 KiB
C++
Raw Normal View History

2020-11-19 18:07:32 +00:00
#define WITH_D3D
#include "common.h"
#ifdef SCREEN_DROPLETS
#ifndef LIBRW
#error "Need librw for SCREEN_DROPLETS"
#endif
#include "General.h"
2020-12-26 14:19:19 +00:00
#include "main.h"
2020-11-19 18:07:32 +00:00
#include "RwHelper.h"
#include "Timer.h"
#include "Camera.h"
2020-12-28 20:58:21 +00:00
#include "World.h"
2020-11-19 18:07:32 +00:00
#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);
}
2020-11-19 18:07:32 +00:00
void
ScreenDroplets::InitDraw(void)
{
ms_maskTex = CreateDropMask(64);
2020-11-19 18:07:32 +00:00
ms_screenTex = RwTextureCreate(nil);
RwTextureSetFilterMode(ms_screenTex, rwFILTERLINEAR);
openim2d_uv2();
#ifdef RW_D3D9
2021-01-19 10:38:51 +00:00
#include "shaders/obj/screenDroplet_PS.inc"
2020-11-19 18:07:32 +00:00
screenDroplet_PS = rw::d3d::createPixelShader(screenDroplet_PS_cso);
#endif
#ifdef RW_GL3
using namespace rw::gl3;
{
2021-01-19 10:38:51 +00:00
#include "shaders/obj/im2d_UV2_vert.inc"
#include "shaders/obj/screenDroplet_frag.inc"
2020-11-19 18:07:32 +00:00
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;
2021-01-01 22:33:29 +00:00
if(dist.MagnitudeSqr() < 50.0f){ // 20 originally
2020-11-19 18:07:32 +00:00
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);
2020-11-19 18:07:32 +00:00
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;
2020-12-28 20:58:21 +00:00
bool isLookingInDirection = FindPlayerVehicle() && mode == CCam::MODE_1STPERSON &&
(CPad::GetPad(0)->GetLookBehindForCar() || CPad::GetPad(0)->GetLookLeft() || CPad::GetPad(0)->GetLookRight());
2020-11-19 18:07:32 +00:00
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