moved gl3 code here; added files i forgot last time
This commit is contained in:
parent
9623bdbf11
commit
e3fa1fcc7f
2
Makefile
2
Makefile
@ -28,6 +28,6 @@ $(BUILDDIR)/%.d: $(SRCDIR)/%.cpp
|
|||||||
|
|
||||||
clean:
|
clean:
|
||||||
echo $(SRC)
|
echo $(SRC)
|
||||||
rm -f $(BUILDDIR)/*.[od]
|
rm -rf $(BUILDDIR)/*
|
||||||
|
|
||||||
-include $(DEP)
|
-include $(DEP)
|
||||||
|
2
rw.h
2
rw.h
@ -15,3 +15,5 @@
|
|||||||
#include "src/d3d/rwd3d8.h"
|
#include "src/d3d/rwd3d8.h"
|
||||||
#include "src/d3d/rwd3d9.h"
|
#include "src/d3d/rwd3d9.h"
|
||||||
#include "src/gl/rwwdgl.h"
|
#include "src/gl/rwwdgl.h"
|
||||||
|
#include "src/gl/rwgl3.h"
|
||||||
|
#include "src/gl/rwgl3shader.h"
|
||||||
|
613
src/d3d/d3d.cpp
Normal file
613
src/d3d/d3d.cpp
Normal file
@ -0,0 +1,613 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "../rwbase.h"
|
||||||
|
#include "../rwplg.h"
|
||||||
|
#include "../rwpipeline.h"
|
||||||
|
#include "../rwobjects.h"
|
||||||
|
#include "../rwengine.h"
|
||||||
|
#include "rwd3d.h"
|
||||||
|
|
||||||
|
namespace rw {
|
||||||
|
namespace d3d {
|
||||||
|
|
||||||
|
bool32 isP8supported = 1;
|
||||||
|
|
||||||
|
#ifdef RW_D3D9
|
||||||
|
IDirect3DDevice9 *device = nil;
|
||||||
|
#else
|
||||||
|
#define MAKEFOURCC(ch0, ch1, ch2, ch3) \
|
||||||
|
((uint32)(uint8)(ch0) | ((uint32)(uint8)(ch1) << 8) | \
|
||||||
|
((uint32)(uint8)(ch2) << 16) | ((uint32)(uint8)(ch3) << 24 ))
|
||||||
|
enum {
|
||||||
|
D3DFMT_UNKNOWN = 0,
|
||||||
|
|
||||||
|
D3DFMT_R8G8B8 = 20,
|
||||||
|
D3DFMT_A8R8G8B8 = 21,
|
||||||
|
D3DFMT_X8R8G8B8 = 22,
|
||||||
|
D3DFMT_R5G6B5 = 23,
|
||||||
|
D3DFMT_X1R5G5B5 = 24,
|
||||||
|
D3DFMT_A1R5G5B5 = 25,
|
||||||
|
D3DFMT_A4R4G4B4 = 26,
|
||||||
|
D3DFMT_R3G3B2 = 27,
|
||||||
|
D3DFMT_A8 = 28,
|
||||||
|
D3DFMT_A8R3G3B2 = 29,
|
||||||
|
D3DFMT_X4R4G4B4 = 30,
|
||||||
|
D3DFMT_A2B10G10R10 = 31,
|
||||||
|
D3DFMT_A8B8G8R8 = 32,
|
||||||
|
D3DFMT_X8B8G8R8 = 33,
|
||||||
|
D3DFMT_G16R16 = 34,
|
||||||
|
D3DFMT_A2R10G10B10 = 35,
|
||||||
|
D3DFMT_A16B16G16R16 = 36,
|
||||||
|
|
||||||
|
D3DFMT_A8P8 = 40,
|
||||||
|
D3DFMT_P8 = 41,
|
||||||
|
|
||||||
|
D3DFMT_L8 = 50,
|
||||||
|
D3DFMT_A8L8 = 51,
|
||||||
|
D3DFMT_A4L4 = 52,
|
||||||
|
|
||||||
|
D3DFMT_V8U8 = 60,
|
||||||
|
D3DFMT_L6V5U5 = 61,
|
||||||
|
D3DFMT_X8L8V8U8 = 62,
|
||||||
|
D3DFMT_Q8W8V8U8 = 63,
|
||||||
|
D3DFMT_V16U16 = 64,
|
||||||
|
D3DFMT_A2W10V10U10 = 67,
|
||||||
|
|
||||||
|
D3DFMT_UYVY = MAKEFOURCC('U', 'Y', 'V', 'Y'),
|
||||||
|
D3DFMT_R8G8_B8G8 = MAKEFOURCC('R', 'G', 'B', 'G'),
|
||||||
|
D3DFMT_YUY2 = MAKEFOURCC('Y', 'U', 'Y', '2'),
|
||||||
|
D3DFMT_G8R8_G8B8 = MAKEFOURCC('G', 'R', 'G', 'B'),
|
||||||
|
D3DFMT_DXT1 = MAKEFOURCC('D', 'X', 'T', '1'),
|
||||||
|
D3DFMT_DXT2 = MAKEFOURCC('D', 'X', 'T', '2'),
|
||||||
|
D3DFMT_DXT3 = MAKEFOURCC('D', 'X', 'T', '3'),
|
||||||
|
D3DFMT_DXT4 = MAKEFOURCC('D', 'X', 'T', '4'),
|
||||||
|
D3DFMT_DXT5 = MAKEFOURCC('D', 'X', 'T', '5'),
|
||||||
|
|
||||||
|
D3DFMT_D16_LOCKABLE = 70,
|
||||||
|
D3DFMT_D32 = 71,
|
||||||
|
D3DFMT_D15S1 = 73,
|
||||||
|
D3DFMT_D24S8 = 75,
|
||||||
|
D3DFMT_D24X8 = 77,
|
||||||
|
D3DFMT_D24X4S4 = 79,
|
||||||
|
D3DFMT_D16 = 80,
|
||||||
|
|
||||||
|
D3DFMT_D32F_LOCKABLE = 82,
|
||||||
|
D3DFMT_D24FS8 = 83,
|
||||||
|
|
||||||
|
// d3d9ex only
|
||||||
|
/* Z-Stencil formats valid for CPU access */
|
||||||
|
D3DFMT_D32_LOCKABLE = 84,
|
||||||
|
D3DFMT_S8_LOCKABLE = 85,
|
||||||
|
|
||||||
|
D3DFMT_L16 = 81,
|
||||||
|
|
||||||
|
D3DFMT_VERTEXDATA =100,
|
||||||
|
D3DFMT_INDEX16 =101,
|
||||||
|
D3DFMT_INDEX32 =102,
|
||||||
|
|
||||||
|
D3DFMT_Q16W16V16U16 =110,
|
||||||
|
|
||||||
|
D3DFMT_MULTI2_ARGB8 = MAKEFOURCC('M','E','T','1'),
|
||||||
|
|
||||||
|
// Floating point surface formats
|
||||||
|
|
||||||
|
// s10e5 formats (16-bits per channel)
|
||||||
|
D3DFMT_R16F = 111,
|
||||||
|
D3DFMT_G16R16F = 112,
|
||||||
|
D3DFMT_A16B16G16R16F = 113,
|
||||||
|
|
||||||
|
// IEEE s23e8 formats (32-bits per channel)
|
||||||
|
D3DFMT_R32F = 114,
|
||||||
|
D3DFMT_G32R32F = 115,
|
||||||
|
D3DFMT_A32B32G32R32F = 116,
|
||||||
|
|
||||||
|
D3DFMT_CxV8U8 = 117,
|
||||||
|
|
||||||
|
// d3d9ex only
|
||||||
|
// Monochrome 1 bit per pixel format
|
||||||
|
D3DFMT_A1 = 118,
|
||||||
|
// 2.8 biased fixed point
|
||||||
|
D3DFMT_A2B10G10R10_XR_BIAS = 119,
|
||||||
|
// Binary format indicating that the data has no inherent type
|
||||||
|
D3DFMT_BINARYBUFFER = 199,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// stolen from d3d8to9
|
||||||
|
static uint32
|
||||||
|
calculateTextureSize(uint32 width, uint32 height, uint32 depth, uint32 format)
|
||||||
|
{
|
||||||
|
#define D3DFMT_W11V11U10 65
|
||||||
|
switch(format){
|
||||||
|
default:
|
||||||
|
case D3DFMT_UNKNOWN:
|
||||||
|
return 0;
|
||||||
|
case D3DFMT_R3G3B2:
|
||||||
|
case D3DFMT_A8:
|
||||||
|
case D3DFMT_P8:
|
||||||
|
case D3DFMT_L8:
|
||||||
|
case D3DFMT_A4L4:
|
||||||
|
return width * height * depth;
|
||||||
|
case D3DFMT_R5G6B5:
|
||||||
|
case D3DFMT_X1R5G5B5:
|
||||||
|
case D3DFMT_A1R5G5B5:
|
||||||
|
case D3DFMT_A4R4G4B4:
|
||||||
|
case D3DFMT_A8R3G3B2:
|
||||||
|
case D3DFMT_X4R4G4B4:
|
||||||
|
case D3DFMT_A8P8:
|
||||||
|
case D3DFMT_A8L8:
|
||||||
|
case D3DFMT_V8U8:
|
||||||
|
case D3DFMT_L6V5U5:
|
||||||
|
case D3DFMT_D16_LOCKABLE:
|
||||||
|
case D3DFMT_D15S1:
|
||||||
|
case D3DFMT_D16:
|
||||||
|
case D3DFMT_UYVY:
|
||||||
|
case D3DFMT_YUY2:
|
||||||
|
return width * 2 * height * depth;
|
||||||
|
case D3DFMT_R8G8B8:
|
||||||
|
return width * 3 * height * depth;
|
||||||
|
case D3DFMT_A8R8G8B8:
|
||||||
|
case D3DFMT_X8R8G8B8:
|
||||||
|
case D3DFMT_A2B10G10R10:
|
||||||
|
case D3DFMT_A8B8G8R8:
|
||||||
|
case D3DFMT_X8B8G8R8:
|
||||||
|
case D3DFMT_G16R16:
|
||||||
|
case D3DFMT_X8L8V8U8:
|
||||||
|
case D3DFMT_Q8W8V8U8:
|
||||||
|
case D3DFMT_V16U16:
|
||||||
|
case D3DFMT_W11V11U10:
|
||||||
|
case D3DFMT_A2W10V10U10:
|
||||||
|
case D3DFMT_D32:
|
||||||
|
case D3DFMT_D24S8:
|
||||||
|
case D3DFMT_D24X8:
|
||||||
|
case D3DFMT_D24X4S4:
|
||||||
|
return width * 4 * height * depth;
|
||||||
|
case D3DFMT_DXT1:
|
||||||
|
assert(depth <= 1);
|
||||||
|
return ((width + 3) >> 2) * ((height + 3) >> 2) * 8;
|
||||||
|
case D3DFMT_DXT2:
|
||||||
|
case D3DFMT_DXT3:
|
||||||
|
case D3DFMT_DXT4:
|
||||||
|
case D3DFMT_DXT5:
|
||||||
|
assert(depth <= 1);
|
||||||
|
return ((width + 3) >> 2) * ((height + 3) >> 2) * 16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int vertFormatMap[] = {
|
||||||
|
-1, VERT_FLOAT2, VERT_FLOAT3, -1, VERT_ARGB
|
||||||
|
};
|
||||||
|
|
||||||
|
void*
|
||||||
|
createIndexBuffer(uint32 length)
|
||||||
|
{
|
||||||
|
#ifdef RW_D3D9
|
||||||
|
IDirect3DIndexBuffer9 *ibuf;
|
||||||
|
device->CreateIndexBuffer(length, D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED, &ibuf, 0);
|
||||||
|
return ibuf;
|
||||||
|
#else
|
||||||
|
return new uint8[length];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16*
|
||||||
|
lockIndices(void *indexBuffer, uint32 offset, uint32 size, uint32 flags)
|
||||||
|
{
|
||||||
|
if(indexBuffer == nil)
|
||||||
|
return nil;
|
||||||
|
#ifdef RW_D3D9
|
||||||
|
uint16 *indices;
|
||||||
|
IDirect3DIndexBuffer9 *ibuf = (IDirect3DIndexBuffer9*)indexBuffer;
|
||||||
|
ibuf->Lock(offset, size, (void**)&indices, flags);
|
||||||
|
return indices;
|
||||||
|
#else
|
||||||
|
(void)offset;
|
||||||
|
(void)size;
|
||||||
|
(void)flags;
|
||||||
|
return (uint16*)indexBuffer;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
unlockIndices(void *indexBuffer)
|
||||||
|
{
|
||||||
|
if(indexBuffer == nil)
|
||||||
|
return;
|
||||||
|
#ifdef RW_D3D9
|
||||||
|
IDirect3DIndexBuffer9 *ibuf = (IDirect3DIndexBuffer9*)indexBuffer;
|
||||||
|
ibuf->Unlock();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
createVertexBuffer(uint32 length, uint32 fvf, int32 pool)
|
||||||
|
{
|
||||||
|
#ifdef RW_D3D9
|
||||||
|
IDirect3DVertexBuffer9 *vbuf;
|
||||||
|
device->CreateVertexBuffer(length, D3DUSAGE_WRITEONLY, fvf, (D3DPOOL)pool, &vbuf, 0);
|
||||||
|
return vbuf;
|
||||||
|
#else
|
||||||
|
(void)fvf;
|
||||||
|
(void)pool;
|
||||||
|
return new uint8[length];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8*
|
||||||
|
lockVertices(void *vertexBuffer, uint32 offset, uint32 size, uint32 flags)
|
||||||
|
{
|
||||||
|
if(vertexBuffer == nil)
|
||||||
|
return nil;
|
||||||
|
#ifdef RW_D3D9
|
||||||
|
uint8 *verts;
|
||||||
|
IDirect3DVertexBuffer9 *vertbuf = (IDirect3DVertexBuffer9*)vertexBuffer;
|
||||||
|
vertbuf->Lock(offset, size, (void**)&verts, flags);
|
||||||
|
return verts;
|
||||||
|
#else
|
||||||
|
(void)offset;
|
||||||
|
(void)size;
|
||||||
|
(void)flags;
|
||||||
|
return (uint8*)vertexBuffer;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
unlockVertices(void *vertexBuffer)
|
||||||
|
{
|
||||||
|
if(vertexBuffer == nil)
|
||||||
|
return;
|
||||||
|
#ifdef RW_D3D9
|
||||||
|
IDirect3DVertexBuffer9 *vertbuf = (IDirect3DVertexBuffer9*)vertexBuffer;
|
||||||
|
vertbuf->Unlock();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
createTexture(int32 width, int32 height, int32 numlevels, uint32 format)
|
||||||
|
{
|
||||||
|
#ifdef RW_D3D9
|
||||||
|
IDirect3DTexture9 *tex;
|
||||||
|
device->CreateTexture(width, height, numlevels, 0,
|
||||||
|
(D3DFORMAT)format, D3DPOOL_MANAGED, &tex, nil);
|
||||||
|
return tex;
|
||||||
|
#else
|
||||||
|
int32 w = width;
|
||||||
|
int32 h = height;
|
||||||
|
int32 size = 0;
|
||||||
|
for(int32 i = 0; i < numlevels; i++){
|
||||||
|
size += calculateTextureSize(w, h, 1, format);
|
||||||
|
w /= 2;
|
||||||
|
if(w == 0) w = 1;
|
||||||
|
h /= 2;
|
||||||
|
if(h == 0) h = 1;
|
||||||
|
}
|
||||||
|
uint8 *data = new uint8[sizeof(RasterLevels)+sizeof(RasterLevels::Level)*(numlevels-1)+size];
|
||||||
|
RasterLevels *levels = (RasterLevels*)data;
|
||||||
|
data += sizeof(RasterLevels)+sizeof(RasterLevels::Level)*(numlevels-1);
|
||||||
|
levels->numlevels = numlevels;
|
||||||
|
levels->format = format;
|
||||||
|
w = width;
|
||||||
|
h = height;
|
||||||
|
for(int32 i = 0; i < numlevels; i++){
|
||||||
|
levels->levels[i].width = w;
|
||||||
|
levels->levels[i].height = h;
|
||||||
|
levels->levels[i].data = data;
|
||||||
|
levels->levels[i].size = calculateTextureSize(w, h, 1, format);
|
||||||
|
data += levels->levels[i].size;
|
||||||
|
w /= 2;
|
||||||
|
if(w == 0) w = 1;
|
||||||
|
h /= 2;
|
||||||
|
if(h == 0) h = 1;
|
||||||
|
}
|
||||||
|
return levels;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8*
|
||||||
|
lockTexture(void *texture, int32 level)
|
||||||
|
{
|
||||||
|
#ifdef RW_D3D9
|
||||||
|
IDirect3DTexture9 *tex = (IDirect3DTexture9*)texture;
|
||||||
|
D3DLOCKED_RECT lr;
|
||||||
|
tex->LockRect(level, &lr, 0, 0);
|
||||||
|
return (uint8*)lr.pBits;
|
||||||
|
#else
|
||||||
|
RasterLevels *levels = (RasterLevels*)texture;
|
||||||
|
return levels->levels[level].data;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
unlockTexture(void *texture, int32 level)
|
||||||
|
{
|
||||||
|
(void)texture;
|
||||||
|
(void)level;
|
||||||
|
#ifdef RW_D3D9
|
||||||
|
IDirect3DTexture9 *tex = (IDirect3DTexture9*)texture;
|
||||||
|
tex->UnlockRect(level);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
deleteObject(void *object)
|
||||||
|
{
|
||||||
|
if(object == nil)
|
||||||
|
return;
|
||||||
|
#ifdef RW_D3D9
|
||||||
|
IUnknown *unk = (IUnknown*)object;
|
||||||
|
unk->Release();
|
||||||
|
#else
|
||||||
|
delete[] (uint*)object;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Native Raster
|
||||||
|
|
||||||
|
int32 nativeRasterOffset;
|
||||||
|
|
||||||
|
static void
|
||||||
|
rasterCreate(Raster *raster)
|
||||||
|
{
|
||||||
|
D3dRaster *natras = PLUGINOFFSET(D3dRaster, raster, nativeRasterOffset);
|
||||||
|
static uint32 formatMap[] = {
|
||||||
|
0,
|
||||||
|
D3DFMT_A1R5G5B5,
|
||||||
|
D3DFMT_R5G6B5,
|
||||||
|
D3DFMT_A4R4G4B4,
|
||||||
|
D3DFMT_L8,
|
||||||
|
D3DFMT_A8R8G8B8,
|
||||||
|
D3DFMT_X8R8G8B8,
|
||||||
|
0, 0, 0,
|
||||||
|
D3DFMT_X1R5G5B5,
|
||||||
|
0, 0, 0, 0, 0
|
||||||
|
};
|
||||||
|
static bool32 alphaMap[] = {
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0, 0, 0,
|
||||||
|
0,
|
||||||
|
0, 0, 0, 0, 0
|
||||||
|
};
|
||||||
|
if(raster->flags & 0x80)
|
||||||
|
return;
|
||||||
|
uint32 format;
|
||||||
|
if(raster->format & (Raster::PAL4 | Raster::PAL8)){
|
||||||
|
format = D3DFMT_P8;
|
||||||
|
natras->palette = new uint8[4*256];
|
||||||
|
}else
|
||||||
|
format = formatMap[(raster->format >> 8) & 0xF];
|
||||||
|
natras->format = 0;
|
||||||
|
natras->hasAlpha = alphaMap[(raster->format >> 8) & 0xF];
|
||||||
|
int32 levels = Raster::calculateNumLevels(raster->width, raster->height);
|
||||||
|
natras->texture = createTexture(raster->width, raster->height,
|
||||||
|
raster->format & Raster::MIPMAP ? levels : 1,
|
||||||
|
format);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8*
|
||||||
|
rasterLock(Raster *raster, int32 level)
|
||||||
|
{
|
||||||
|
D3dRaster *natras = PLUGINOFFSET(D3dRaster, raster, nativeRasterOffset);
|
||||||
|
return lockTexture(natras->texture, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rasterUnlock(Raster *raster, int32 level)
|
||||||
|
{
|
||||||
|
D3dRaster *natras = PLUGINOFFSET(D3dRaster, raster, nativeRasterOffset);
|
||||||
|
unlockTexture(natras->texture, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32
|
||||||
|
rasterNumLevels(Raster *raster)
|
||||||
|
{
|
||||||
|
D3dRaster *natras = PLUGINOFFSET(D3dRaster, raster, nativeRasterOffset);
|
||||||
|
#ifdef RW_D3D9
|
||||||
|
IDirect3DTexture9 *tex = (IDirect3DTexture9*)natras->texture;
|
||||||
|
return tex->GetLevelCount();
|
||||||
|
#else
|
||||||
|
RasterLevels *levels = (RasterLevels*)natras->texture;
|
||||||
|
return levels->numlevels;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rasterFromImage(Raster *raster, Image *image)
|
||||||
|
{
|
||||||
|
int32 format;
|
||||||
|
D3dRaster *natras = PLUGINOFFSET(D3dRaster, raster, nativeRasterOffset);
|
||||||
|
switch(image->depth){
|
||||||
|
case 32:
|
||||||
|
format = image->hasAlpha() ? Raster::C8888 : Raster::C888;
|
||||||
|
break;
|
||||||
|
case 24:
|
||||||
|
format = Raster::C888;
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
format = Raster::C1555;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
format = Raster::PAL8 | Raster::C8888;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
format = Raster::PAL4 | Raster::C8888;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
format |= 4;
|
||||||
|
|
||||||
|
raster->type = format & 0x7;
|
||||||
|
raster->flags = format & 0xF8;
|
||||||
|
raster->format = format & 0xFF00;
|
||||||
|
rasterCreate(raster);
|
||||||
|
|
||||||
|
uint8 *in, *out;
|
||||||
|
int pallength = 0;
|
||||||
|
if(raster->format & Raster::PAL4)
|
||||||
|
pallength = 16;
|
||||||
|
else if(raster->format & Raster::PAL8)
|
||||||
|
pallength = 256;
|
||||||
|
if(pallength){
|
||||||
|
in = image->palette;
|
||||||
|
out = (uint8*)natras->palette;
|
||||||
|
for(int32 i = 0; i < pallength; i++){
|
||||||
|
out[0] = in[2];
|
||||||
|
out[1] = in[1];
|
||||||
|
out[2] = in[0];
|
||||||
|
out[3] = in[3];
|
||||||
|
in += 4;
|
||||||
|
out += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 inc = image->depth/8;
|
||||||
|
in = image->pixels;
|
||||||
|
out = raster->lock(0);
|
||||||
|
if(pallength)
|
||||||
|
memcpy(out, in, raster->width*raster->height);
|
||||||
|
else
|
||||||
|
// TODO: stride
|
||||||
|
for(int32 y = 0; y < image->height; y++)
|
||||||
|
for(int32 x = 0; x < image->width; x++)
|
||||||
|
switch(raster->format & 0xF00){
|
||||||
|
case Raster::C8888:
|
||||||
|
out[0] = in[2];
|
||||||
|
out[1] = in[1];
|
||||||
|
out[2] = in[0];
|
||||||
|
out[3] = in[3];
|
||||||
|
in += inc;
|
||||||
|
out += 4;
|
||||||
|
break;
|
||||||
|
case Raster::C888:
|
||||||
|
out[0] = in[2];
|
||||||
|
out[1] = in[1];
|
||||||
|
out[2] = in[0];
|
||||||
|
out[3] = 0xFF;
|
||||||
|
in += inc;
|
||||||
|
out += 4;
|
||||||
|
break;
|
||||||
|
case Raster::C1555:
|
||||||
|
out[0] = in[0];
|
||||||
|
out[1] = in[1];
|
||||||
|
in += 2;
|
||||||
|
out += 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
raster->unlock(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32
|
||||||
|
getLevelSize(Raster *raster, int32 level)
|
||||||
|
{
|
||||||
|
D3dRaster *ras = PLUGINOFFSET(D3dRaster, raster, nativeRasterOffset);
|
||||||
|
#ifdef RW_D3D9
|
||||||
|
IDirect3DTexture9 *tex = (IDirect3DTexture9*)ras->texture;
|
||||||
|
D3DSURFACE_DESC desc;
|
||||||
|
tex->GetLevelDesc(level, &desc);
|
||||||
|
return calculateTextureSize(desc.Width, desc.Height, 1, desc.Format);
|
||||||
|
#else
|
||||||
|
RasterLevels *levels = (RasterLevels*)ras->texture;
|
||||||
|
return levels->levels[level].size;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
allocateDXT(Raster *raster, int32 dxt, int32 numLevels, bool32 hasAlpha)
|
||||||
|
{
|
||||||
|
static uint32 dxtMap[] = {
|
||||||
|
0x31545844, // DXT1
|
||||||
|
0x32545844, // DXT2
|
||||||
|
0x33545844, // DXT3
|
||||||
|
0x34545844, // DXT4
|
||||||
|
0x35545844, // DXT5
|
||||||
|
};
|
||||||
|
D3dRaster *ras = PLUGINOFFSET(D3dRaster, raster, nativeRasterOffset);
|
||||||
|
ras->format = dxtMap[dxt-1];
|
||||||
|
ras->hasAlpha = hasAlpha;
|
||||||
|
ras->texture = createTexture(raster->width, raster->height,
|
||||||
|
raster->format & Raster::MIPMAP ? numLevels : 1,
|
||||||
|
ras->format);
|
||||||
|
raster->flags &= ~0x80;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
setPalette(Raster *raster, void *palette, int32 size)
|
||||||
|
{
|
||||||
|
D3dRaster *ras = PLUGINOFFSET(D3dRaster, raster, nativeRasterOffset);
|
||||||
|
memcpy(ras->palette, palette, 4*size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
setTexels(Raster *raster, void *texels, int32 level)
|
||||||
|
{
|
||||||
|
uint8 *dst = raster->lock(level);
|
||||||
|
memcpy(dst, texels, getLevelSize(raster, level));
|
||||||
|
raster->unlock(level);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void*
|
||||||
|
createNativeRaster(void *object, int32 offset, int32)
|
||||||
|
{
|
||||||
|
D3dRaster *raster = PLUGINOFFSET(D3dRaster, object, offset);
|
||||||
|
raster->texture = nil;
|
||||||
|
raster->palette = nil;
|
||||||
|
raster->format = 0;
|
||||||
|
raster->hasAlpha = 0;
|
||||||
|
raster->customFormat = 0;
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void*
|
||||||
|
destroyNativeRaster(void *object, int32 offset, int32)
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
(void)offset;
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void*
|
||||||
|
copyNativeRaster(void *dst, void *, int32 offset, int32)
|
||||||
|
{
|
||||||
|
D3dRaster *raster = PLUGINOFFSET(D3dRaster, dst, offset);
|
||||||
|
raster->texture = nil;
|
||||||
|
raster->palette = nil;
|
||||||
|
raster->format = 0;
|
||||||
|
raster->hasAlpha = 0;
|
||||||
|
raster->customFormat = 0;
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
registerNativeRaster(void)
|
||||||
|
{
|
||||||
|
nativeRasterOffset = Raster::registerPlugin(sizeof(D3dRaster),
|
||||||
|
0x12340000 | PLATFORM_D3D9,
|
||||||
|
createNativeRaster,
|
||||||
|
destroyNativeRaster,
|
||||||
|
copyNativeRaster);
|
||||||
|
driver[PLATFORM_D3D8].rasterNativeOffset = nativeRasterOffset;
|
||||||
|
driver[PLATFORM_D3D8].rasterCreate = rasterCreate;
|
||||||
|
driver[PLATFORM_D3D8].rasterLock = rasterLock;
|
||||||
|
driver[PLATFORM_D3D8].rasterUnlock = rasterUnlock;
|
||||||
|
driver[PLATFORM_D3D8].rasterNumLevels = rasterNumLevels;
|
||||||
|
driver[PLATFORM_D3D8].rasterFromImage = rasterFromImage;
|
||||||
|
|
||||||
|
driver[PLATFORM_D3D9].rasterNativeOffset = nativeRasterOffset;
|
||||||
|
driver[PLATFORM_D3D9].rasterCreate = rasterCreate;
|
||||||
|
driver[PLATFORM_D3D9].rasterLock = rasterLock;
|
||||||
|
driver[PLATFORM_D3D9].rasterUnlock = rasterUnlock;
|
||||||
|
driver[PLATFORM_D3D9].rasterNumLevels = rasterNumLevels;
|
||||||
|
driver[PLATFORM_D3D9].rasterFromImage = rasterFromImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
630
src/d3d/d3d8.cpp
Normal file
630
src/d3d/d3d8.cpp
Normal file
@ -0,0 +1,630 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "../rwbase.h"
|
||||||
|
#include "../rwerror.h"
|
||||||
|
#include "../rwplg.h"
|
||||||
|
#include "../rwpipeline.h"
|
||||||
|
#include "../rwobjects.h"
|
||||||
|
#include "../rwengine.h"
|
||||||
|
#include "rwd3d.h"
|
||||||
|
#include "rwd3d8.h"
|
||||||
|
|
||||||
|
#define PLUGIN_ID 2
|
||||||
|
|
||||||
|
namespace rw {
|
||||||
|
namespace d3d8 {
|
||||||
|
using namespace d3d;
|
||||||
|
|
||||||
|
void
|
||||||
|
initializePlatform(void)
|
||||||
|
{
|
||||||
|
driver[PLATFORM_D3D8].defaultPipeline = makeDefaultPipeline();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32
|
||||||
|
makeFVFDeclaration(uint32 flags, int32 numTex)
|
||||||
|
{
|
||||||
|
uint32 fvf = 0x2;
|
||||||
|
if(flags & Geometry::NORMALS)
|
||||||
|
fvf |= 0x10;
|
||||||
|
if(flags & Geometry::PRELIT)
|
||||||
|
fvf |= 0x40;
|
||||||
|
fvf |= numTex << 8;
|
||||||
|
return fvf;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32
|
||||||
|
getStride(uint32 flags, int32 numTex)
|
||||||
|
{
|
||||||
|
int32 stride = 12;
|
||||||
|
if(flags & Geometry::NORMALS)
|
||||||
|
stride += 12;;
|
||||||
|
if(flags & Geometry::PRELIT)
|
||||||
|
stride += 4;
|
||||||
|
stride += numTex*8;
|
||||||
|
return stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
destroyNativeData(void *object, int32, int32)
|
||||||
|
{
|
||||||
|
Geometry *geometry = (Geometry*)object;
|
||||||
|
if(geometry->instData == nil ||
|
||||||
|
geometry->instData->platform != PLATFORM_D3D8)
|
||||||
|
return object;
|
||||||
|
InstanceDataHeader *header =
|
||||||
|
(InstanceDataHeader*)geometry->instData;
|
||||||
|
geometry->instData = nil;
|
||||||
|
InstanceData *inst = header->inst;
|
||||||
|
for(uint32 i = 0; i < header->numMeshes; i++){
|
||||||
|
deleteObject(inst->indexBuffer);
|
||||||
|
deleteObject(inst->vertexBuffer);
|
||||||
|
inst++;
|
||||||
|
}
|
||||||
|
delete[] header->inst;
|
||||||
|
delete header;
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream*
|
||||||
|
readNativeData(Stream *stream, int32, void *object, int32, int32)
|
||||||
|
{
|
||||||
|
Geometry *geometry = (Geometry*)object;
|
||||||
|
uint32 platform;
|
||||||
|
if(!findChunk(stream, ID_STRUCT, nil, nil)){
|
||||||
|
RWERROR((ERR_CHUNK, "STRUCT"))
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
platform = stream->readU32();
|
||||||
|
if(platform != PLATFORM_D3D8){
|
||||||
|
RWERROR((ERR_PLATFORM, platform));
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
InstanceDataHeader *header = new InstanceDataHeader;
|
||||||
|
geometry->instData = header;
|
||||||
|
header->platform = PLATFORM_D3D8;
|
||||||
|
|
||||||
|
int32 size = stream->readI32();
|
||||||
|
uint8 *data = new uint8[size];
|
||||||
|
stream->read(data, size);
|
||||||
|
uint8 *p = data;
|
||||||
|
header->serialNumber = *(uint16*)p; p += 2;
|
||||||
|
header->numMeshes = *(uint16*)p; p += 2;
|
||||||
|
header->inst = new InstanceData[header->numMeshes];
|
||||||
|
|
||||||
|
InstanceData *inst = header->inst;
|
||||||
|
for(uint32 i = 0; i < header->numMeshes; i++){
|
||||||
|
inst->minVert = *(uint32*)p; p += 4;
|
||||||
|
inst->stride = *(uint32*)p; p += 4;
|
||||||
|
inst->numVertices = *(uint32*)p; p += 4;
|
||||||
|
inst->numIndices = *(uint32*)p; p += 4;
|
||||||
|
uint32 matid = *(uint32*)p; p += 4;
|
||||||
|
inst->material = geometry->materialList[matid];
|
||||||
|
inst->vertexShader = *(uint32*)p; p += 4;
|
||||||
|
inst->primType = *(uint32*)p; p += 4;
|
||||||
|
inst->indexBuffer = nil; p += 4;
|
||||||
|
inst->vertexBuffer = nil; p += 4;
|
||||||
|
inst->baseIndex = 0; p += 4;
|
||||||
|
inst->vertexAlpha = *p++;
|
||||||
|
inst->managed = 0; p++;
|
||||||
|
inst->remapped = 0; p++; // TODO: really unused? and what's that anyway?
|
||||||
|
inst++;
|
||||||
|
}
|
||||||
|
delete[] data;
|
||||||
|
|
||||||
|
inst = header->inst;
|
||||||
|
for(uint32 i = 0; i < header->numMeshes; i++){
|
||||||
|
inst->indexBuffer = createIndexBuffer(inst->numIndices*2);
|
||||||
|
uint16 *indices = lockIndices(inst->indexBuffer, 0, 0, 0);
|
||||||
|
stream->read(indices, 2*inst->numIndices);
|
||||||
|
unlockIndices(inst->indexBuffer);
|
||||||
|
|
||||||
|
inst->managed = 1;
|
||||||
|
inst->vertexBuffer = createVertexBuffer(inst->stride*inst->numVertices, 0, D3DPOOL_MANAGED);
|
||||||
|
uint8 *verts = lockVertices(inst->vertexBuffer, 0, 0, D3DLOCK_NOSYSLOCK);
|
||||||
|
stream->read(verts, inst->stride*inst->numVertices);
|
||||||
|
unlockVertices(inst->vertexBuffer);
|
||||||
|
|
||||||
|
inst++;
|
||||||
|
}
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream*
|
||||||
|
writeNativeData(Stream *stream, int32 len, void *object, int32, int32)
|
||||||
|
{
|
||||||
|
Geometry *geometry = (Geometry*)object;
|
||||||
|
writeChunkHeader(stream, ID_STRUCT, len-12);
|
||||||
|
if(geometry->instData == nil ||
|
||||||
|
geometry->instData->platform != PLATFORM_D3D8)
|
||||||
|
return stream;
|
||||||
|
stream->writeU32(PLATFORM_D3D8);
|
||||||
|
InstanceDataHeader *header = (InstanceDataHeader*)geometry->instData;
|
||||||
|
|
||||||
|
int32 size = 4 + geometry->meshHeader->numMeshes*0x2C;
|
||||||
|
uint8 *data = new uint8[size];
|
||||||
|
stream->writeI32(size);
|
||||||
|
uint8 *p = data;
|
||||||
|
*(uint16*)p = header->serialNumber; p += 2;
|
||||||
|
*(uint16*)p = header->numMeshes; p += 2;
|
||||||
|
|
||||||
|
InstanceData *inst = header->inst;
|
||||||
|
for(uint32 i = 0; i < header->numMeshes; i++){
|
||||||
|
*(uint32*)p = inst->minVert; p += 4;
|
||||||
|
*(uint32*)p = inst->stride; p += 4;
|
||||||
|
*(uint32*)p = inst->numVertices; p += 4;
|
||||||
|
*(uint32*)p = inst->numIndices; p += 4;
|
||||||
|
int32 matid = findPointer(inst->material, (void**)geometry->materialList, geometry->numMaterials);
|
||||||
|
*(int32*)p = matid; p += 4;
|
||||||
|
*(uint32*)p = inst->vertexShader; p += 4;
|
||||||
|
*(uint32*)p = inst->primType; p += 4;
|
||||||
|
*(uint32*)p = 0; p += 4; // index buffer
|
||||||
|
*(uint32*)p = 0; p += 4; // vertex buffer
|
||||||
|
*(uint32*)p = inst->baseIndex; p += 4;
|
||||||
|
*p++ = inst->vertexAlpha;
|
||||||
|
*p++ = inst->managed;
|
||||||
|
*p++ = inst->remapped;
|
||||||
|
inst++;
|
||||||
|
}
|
||||||
|
stream->write(data, size);
|
||||||
|
delete[] data;
|
||||||
|
|
||||||
|
inst = header->inst;
|
||||||
|
for(uint32 i = 0; i < header->numMeshes; i++){
|
||||||
|
uint16 *indices = lockIndices(inst->indexBuffer, 0, 0, 0);
|
||||||
|
stream->write(indices, 2*inst->numIndices);
|
||||||
|
unlockIndices(inst->indexBuffer);
|
||||||
|
|
||||||
|
uint8 *verts = lockVertices(inst->vertexBuffer, 0, 0, D3DLOCK_NOSYSLOCK);
|
||||||
|
stream->write(verts, inst->stride*inst->numVertices);
|
||||||
|
unlockVertices(inst->vertexBuffer);
|
||||||
|
inst++;
|
||||||
|
}
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32
|
||||||
|
getSizeNativeData(void *object, int32, int32)
|
||||||
|
{
|
||||||
|
Geometry *geometry = (Geometry*)object;
|
||||||
|
if(geometry->instData == nil ||
|
||||||
|
geometry->instData->platform != PLATFORM_D3D8)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
InstanceDataHeader *header = (InstanceDataHeader*)geometry->instData;
|
||||||
|
InstanceData *inst = header->inst;
|
||||||
|
int32 size = 12 + 4 + 4 + 4 + header->numMeshes*0x2C;
|
||||||
|
for(int32 i = 0; i < header->numMeshes; i++){
|
||||||
|
size += inst->numIndices*2 + inst->numVertices*inst->stride;
|
||||||
|
inst++;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
registerNativeDataPlugin(void)
|
||||||
|
{
|
||||||
|
Geometry::registerPlugin(0, ID_NATIVEDATA,
|
||||||
|
nil, destroyNativeData, nil);
|
||||||
|
Geometry::registerPluginStream(ID_NATIVEDATA,
|
||||||
|
readNativeData,
|
||||||
|
writeNativeData,
|
||||||
|
getSizeNativeData);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
instance(rw::ObjPipeline *rwpipe, Atomic *atomic)
|
||||||
|
{
|
||||||
|
ObjPipeline *pipe = (ObjPipeline*)rwpipe;
|
||||||
|
Geometry *geo = atomic->geometry;
|
||||||
|
if(geo->geoflags & Geometry::NATIVE)
|
||||||
|
return;
|
||||||
|
geo->geoflags |= Geometry::NATIVE;
|
||||||
|
InstanceDataHeader *header = new InstanceDataHeader;
|
||||||
|
MeshHeader *meshh = geo->meshHeader;
|
||||||
|
geo->instData = header;
|
||||||
|
header->platform = PLATFORM_D3D8;
|
||||||
|
|
||||||
|
header->serialNumber = 0;
|
||||||
|
header->numMeshes = meshh->numMeshes;
|
||||||
|
header->inst = new InstanceData[header->numMeshes];
|
||||||
|
|
||||||
|
InstanceData *inst = header->inst;
|
||||||
|
Mesh *mesh = meshh->mesh;
|
||||||
|
for(uint32 i = 0; i < header->numMeshes; i++){
|
||||||
|
findMinVertAndNumVertices(mesh->indices, mesh->numIndices,
|
||||||
|
&inst->minVert, &inst->numVertices);
|
||||||
|
inst->numIndices = mesh->numIndices;
|
||||||
|
inst->material = mesh->material;
|
||||||
|
inst->vertexShader = 0;
|
||||||
|
inst->primType = meshh->flags == 1 ? D3DPT_TRIANGLESTRIP : D3DPT_TRIANGLELIST;
|
||||||
|
inst->vertexBuffer = nil;
|
||||||
|
inst->baseIndex = 0; // (maybe) not used by us
|
||||||
|
inst->vertexAlpha = 0;
|
||||||
|
inst->managed = 0;
|
||||||
|
inst->remapped = 0;
|
||||||
|
|
||||||
|
inst->indexBuffer = createIndexBuffer(inst->numIndices*2);
|
||||||
|
uint16 *indices = lockIndices(inst->indexBuffer, 0, 0, 0);
|
||||||
|
if(inst->minVert == 0)
|
||||||
|
memcpy(indices, mesh->indices, inst->numIndices*2);
|
||||||
|
else
|
||||||
|
for(int32 j = 0; j < inst->numIndices; j++)
|
||||||
|
indices[j] = mesh->indices[j] - inst->minVert;
|
||||||
|
unlockIndices(inst->indexBuffer);
|
||||||
|
|
||||||
|
pipe->instanceCB(geo, inst);
|
||||||
|
mesh++;
|
||||||
|
inst++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
uninstance(rw::ObjPipeline *rwpipe, Atomic *atomic)
|
||||||
|
{
|
||||||
|
ObjPipeline *pipe = (ObjPipeline*)rwpipe;
|
||||||
|
Geometry *geo = atomic->geometry;
|
||||||
|
if((geo->geoflags & Geometry::NATIVE) == 0)
|
||||||
|
return;
|
||||||
|
assert(geo->instData != nil);
|
||||||
|
assert(geo->instData->platform == PLATFORM_D3D8);
|
||||||
|
geo->geoflags &= ~Geometry::NATIVE;
|
||||||
|
geo->allocateData();
|
||||||
|
geo->meshHeader->allocateIndices();
|
||||||
|
|
||||||
|
InstanceDataHeader *header = (InstanceDataHeader*)geo->instData;
|
||||||
|
InstanceData *inst = header->inst;
|
||||||
|
Mesh *mesh = geo->meshHeader->mesh;
|
||||||
|
for(uint32 i = 0; i < header->numMeshes; i++){
|
||||||
|
uint16 *indices = lockIndices(inst->indexBuffer, 0, 0, 0);
|
||||||
|
if(inst->minVert == 0)
|
||||||
|
memcpy(mesh->indices, indices, inst->numIndices*2);
|
||||||
|
else
|
||||||
|
for(int32 j = 0; j < inst->numIndices; j++)
|
||||||
|
mesh->indices[j] = indices[j] + inst->minVert;
|
||||||
|
unlockIndices(inst->indexBuffer);
|
||||||
|
|
||||||
|
pipe->uninstanceCB(geo, inst);
|
||||||
|
mesh++;
|
||||||
|
inst++;
|
||||||
|
}
|
||||||
|
geo->generateTriangles();
|
||||||
|
destroyNativeData(geo, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
render(rw::ObjPipeline *rwpipe, Atomic *atomic)
|
||||||
|
{
|
||||||
|
ObjPipeline *pipe = (ObjPipeline*)rwpipe;
|
||||||
|
Geometry *geo = atomic->geometry;
|
||||||
|
if((geo->geoflags & Geometry::NATIVE) == 0)
|
||||||
|
pipe->instance(atomic);
|
||||||
|
assert(geo->instData != nil);
|
||||||
|
assert(geo->instData->platform == PLATFORM_D3D8);
|
||||||
|
if(pipe->renderCB)
|
||||||
|
pipe->renderCB(atomic, (InstanceDataHeader*)geo->instData);
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjPipeline::ObjPipeline(uint32 platform)
|
||||||
|
: rw::ObjPipeline(platform)
|
||||||
|
{
|
||||||
|
this->impl.instance = d3d8::instance;
|
||||||
|
this->impl.uninstance = d3d8::uninstance;
|
||||||
|
this->impl.render = d3d8::render;
|
||||||
|
this->instanceCB = nil;
|
||||||
|
this->uninstanceCB = nil;
|
||||||
|
this->renderCB = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
defaultInstanceCB(Geometry *geo, InstanceData *inst)
|
||||||
|
{
|
||||||
|
inst->vertexShader = makeFVFDeclaration(geo->geoflags, geo->numTexCoordSets);
|
||||||
|
inst->stride = getStride(geo->geoflags, geo->numTexCoordSets);
|
||||||
|
|
||||||
|
inst->vertexBuffer = createVertexBuffer(inst->numVertices*inst->stride,
|
||||||
|
inst->vertexShader, D3DPOOL_MANAGED);
|
||||||
|
inst->managed = 1;
|
||||||
|
|
||||||
|
uint8 *dst = lockVertices(inst->vertexBuffer, 0, 0, D3DLOCK_NOSYSLOCK);
|
||||||
|
instV3d(VERT_FLOAT3, dst,
|
||||||
|
&geo->morphTargets[0].vertices[3*inst->minVert],
|
||||||
|
inst->numVertices, inst->stride);
|
||||||
|
dst += 12;
|
||||||
|
|
||||||
|
if(geo->geoflags & Geometry::NORMALS){
|
||||||
|
instV3d(VERT_FLOAT3, dst,
|
||||||
|
&geo->morphTargets[0].normals[3*inst->minVert],
|
||||||
|
inst->numVertices, inst->stride);
|
||||||
|
dst += 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
inst->vertexAlpha = 0;
|
||||||
|
if(geo->geoflags & Geometry::PRELIT){
|
||||||
|
inst->vertexAlpha = instColor(VERT_ARGB, dst, &geo->colors[4*inst->minVert],
|
||||||
|
inst->numVertices, inst->stride);
|
||||||
|
dst += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int32 i = 0; i < geo->numTexCoordSets; i++){
|
||||||
|
instV2d(VERT_FLOAT2, dst, &geo->texCoords[i][2*inst->minVert],
|
||||||
|
inst->numVertices, inst->stride);
|
||||||
|
dst += 8;
|
||||||
|
}
|
||||||
|
unlockVertices(inst->vertexBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
defaultUninstanceCB(Geometry *geo, InstanceData *inst)
|
||||||
|
{
|
||||||
|
uint8 *src = lockVertices(inst->vertexBuffer, 0, 0, D3DLOCK_NOSYSLOCK);
|
||||||
|
uninstV3d(VERT_FLOAT3,
|
||||||
|
&geo->morphTargets[0].vertices[3*inst->minVert],
|
||||||
|
src, inst->numVertices, inst->stride);
|
||||||
|
src += 12;
|
||||||
|
|
||||||
|
if(geo->geoflags & Geometry::NORMALS){
|
||||||
|
uninstV3d(VERT_FLOAT3,
|
||||||
|
&geo->morphTargets[0].normals[3*inst->minVert],
|
||||||
|
src, inst->numVertices, inst->stride);
|
||||||
|
src += 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
inst->vertexAlpha = 0;
|
||||||
|
if(geo->geoflags & Geometry::PRELIT){
|
||||||
|
uninstColor(VERT_ARGB, &geo->colors[4*inst->minVert], src,
|
||||||
|
inst->numVertices, inst->stride);
|
||||||
|
src += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int32 i = 0; i < geo->numTexCoordSets; i++){
|
||||||
|
uninstV2d(VERT_FLOAT2, &geo->texCoords[i][2*inst->minVert], src,
|
||||||
|
inst->numVertices, inst->stride);
|
||||||
|
src += 8;
|
||||||
|
}
|
||||||
|
unlockVertices(inst->vertexBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjPipeline*
|
||||||
|
makeDefaultPipeline(void)
|
||||||
|
{
|
||||||
|
ObjPipeline *pipe = new ObjPipeline(PLATFORM_D3D8);
|
||||||
|
pipe->instanceCB = defaultInstanceCB;
|
||||||
|
pipe->uninstanceCB = defaultUninstanceCB;
|
||||||
|
pipe->renderCB = defaultRenderCB;
|
||||||
|
return pipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjPipeline*
|
||||||
|
makeSkinPipeline(void)
|
||||||
|
{
|
||||||
|
ObjPipeline *pipe = new ObjPipeline(PLATFORM_D3D8);
|
||||||
|
pipe->instanceCB = defaultInstanceCB;
|
||||||
|
pipe->uninstanceCB = defaultUninstanceCB;
|
||||||
|
pipe->renderCB = defaultRenderCB;
|
||||||
|
pipe->pluginID = ID_SKIN;
|
||||||
|
pipe->pluginData = 1;
|
||||||
|
return pipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjPipeline*
|
||||||
|
makeMatFXPipeline(void)
|
||||||
|
{
|
||||||
|
ObjPipeline *pipe = new ObjPipeline(PLATFORM_D3D8);
|
||||||
|
pipe->instanceCB = defaultInstanceCB;
|
||||||
|
pipe->uninstanceCB = defaultUninstanceCB;
|
||||||
|
pipe->renderCB = defaultRenderCB;
|
||||||
|
pipe->pluginID = ID_MATFX;
|
||||||
|
pipe->pluginData = 0;
|
||||||
|
return pipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Native Texture and Raster
|
||||||
|
|
||||||
|
// only handles 4 and 8 bit textures right now
|
||||||
|
Raster*
|
||||||
|
readAsImage(Stream *stream, int32 width, int32 height, int32 depth, int32 format, int32 numLevels)
|
||||||
|
{
|
||||||
|
uint8 palette[256*4];
|
||||||
|
uint8 *data;
|
||||||
|
|
||||||
|
Image *img = Image::create(width, height, 32);
|
||||||
|
img->allocate();
|
||||||
|
|
||||||
|
if(format & Raster::PAL4)
|
||||||
|
stream->read(palette, 4*32);
|
||||||
|
else if(format & Raster::PAL8)
|
||||||
|
stream->read(palette, 4*256);
|
||||||
|
|
||||||
|
// Only read one mipmap
|
||||||
|
for(int32 i = 0; i < numLevels; i++){
|
||||||
|
uint32 size = stream->readU32();
|
||||||
|
if(i == 0){
|
||||||
|
data = new uint8[size];
|
||||||
|
stream->read(data, size);
|
||||||
|
}else
|
||||||
|
stream->seek(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(format & (Raster::PAL4 | Raster::PAL8)){
|
||||||
|
uint8 *idx = data;
|
||||||
|
uint8 *pixels = img->pixels;
|
||||||
|
for(int y = 0; y < img->height; y++){
|
||||||
|
uint8 *line = pixels;
|
||||||
|
for(int x = 0; x < img->width; x++){
|
||||||
|
line[0] = palette[*idx*4+0];
|
||||||
|
line[1] = palette[*idx*4+1];
|
||||||
|
line[2] = palette[*idx*4+2];
|
||||||
|
line[3] = palette[*idx*4+3];
|
||||||
|
line += 4;
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
pixels += img->stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] data;
|
||||||
|
Raster *ras = Raster::createFromImage(img);
|
||||||
|
img->destroy();
|
||||||
|
return ras;
|
||||||
|
}
|
||||||
|
|
||||||
|
Texture*
|
||||||
|
readNativeTexture(Stream *stream)
|
||||||
|
{
|
||||||
|
uint32 platform;
|
||||||
|
if(!findChunk(stream, ID_STRUCT, nil, nil)){
|
||||||
|
RWERROR((ERR_CHUNK, "STRUCT"))
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
platform = stream->readU32();
|
||||||
|
if(platform != PLATFORM_D3D8){
|
||||||
|
RWERROR((ERR_PLATFORM, platform));
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
Texture *tex = Texture::create(nil);
|
||||||
|
if(tex == nil)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
// Texture
|
||||||
|
tex->filterAddressing = stream->readU32();
|
||||||
|
stream->read(tex->name, 32);
|
||||||
|
stream->read(tex->mask, 32);
|
||||||
|
|
||||||
|
// Raster
|
||||||
|
uint32 format = stream->readU32();
|
||||||
|
bool32 hasAlpha = stream->readI32();
|
||||||
|
int32 width = stream->readU16();
|
||||||
|
int32 height = stream->readU16();
|
||||||
|
int32 depth = stream->readU8();
|
||||||
|
int32 numLevels = stream->readU8();
|
||||||
|
int32 type = stream->readU8();
|
||||||
|
int32 compression = stream->readU8();
|
||||||
|
|
||||||
|
int32 pallength = 0;
|
||||||
|
if(format & Raster::PAL4 || format & Raster::PAL8){
|
||||||
|
pallength = format & Raster::PAL4 ? 32 : 256;
|
||||||
|
if(!d3d::isP8supported){
|
||||||
|
tex->raster = readAsImage(stream, width, height, depth, format|type, numLevels);
|
||||||
|
tex->streamReadPlugins(stream);
|
||||||
|
return tex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Raster *raster;
|
||||||
|
D3dRaster *ras;
|
||||||
|
if(compression){
|
||||||
|
raster = Raster::create(width, height, depth, format | type | 0x80, PLATFORM_D3D8);
|
||||||
|
ras = PLUGINOFFSET(D3dRaster, raster, nativeRasterOffset);
|
||||||
|
allocateDXT(raster, compression, numLevels, hasAlpha);
|
||||||
|
ras->customFormat = 1;
|
||||||
|
}else{
|
||||||
|
raster = Raster::create(width, height, depth, format | type, PLATFORM_D3D8);
|
||||||
|
ras = PLUGINOFFSET(D3dRaster, raster, nativeRasterOffset);
|
||||||
|
}
|
||||||
|
tex->raster = raster;
|
||||||
|
|
||||||
|
// TODO: check if format supported and convert if necessary
|
||||||
|
|
||||||
|
if(pallength != 0)
|
||||||
|
stream->read(ras->palette, 4*pallength);
|
||||||
|
|
||||||
|
uint32 size;
|
||||||
|
uint8 *data;
|
||||||
|
for(int32 i = 0; i < numLevels; i++){
|
||||||
|
size = stream->readU32();
|
||||||
|
if(i < raster->getNumLevels()){
|
||||||
|
data = raster->lock(i);
|
||||||
|
stream->read(data, size);
|
||||||
|
raster->unlock(i);
|
||||||
|
}else
|
||||||
|
stream->seek(size);
|
||||||
|
}
|
||||||
|
tex->streamReadPlugins(stream);
|
||||||
|
return tex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
writeNativeTexture(Texture *tex, Stream *stream)
|
||||||
|
{
|
||||||
|
int32 chunksize = getSizeNativeTexture(tex);
|
||||||
|
int32 plgsize = tex->streamGetPluginSize();
|
||||||
|
writeChunkHeader(stream, ID_TEXTURENATIVE, chunksize);
|
||||||
|
writeChunkHeader(stream, ID_STRUCT, chunksize-24-plgsize);
|
||||||
|
stream->writeU32(PLATFORM_D3D8);
|
||||||
|
|
||||||
|
// Texture
|
||||||
|
stream->writeU32(tex->filterAddressing);
|
||||||
|
stream->write(tex->name, 32);
|
||||||
|
stream->write(tex->mask, 32);
|
||||||
|
|
||||||
|
// Raster
|
||||||
|
Raster *raster = tex->raster;
|
||||||
|
D3dRaster *ras = PLUGINOFFSET(D3dRaster, raster, nativeRasterOffset);
|
||||||
|
int32 numLevels = raster->getNumLevels();
|
||||||
|
stream->writeI32(raster->format);
|
||||||
|
stream->writeI32(ras->hasAlpha);
|
||||||
|
stream->writeU16(raster->width);
|
||||||
|
stream->writeU16(raster->height);
|
||||||
|
stream->writeU8(raster->depth);
|
||||||
|
stream->writeU8(numLevels);
|
||||||
|
stream->writeU8(raster->type);
|
||||||
|
int32 compression = 0;
|
||||||
|
if(ras->format)
|
||||||
|
switch(ras->format){
|
||||||
|
case 0x31545844: // DXT1
|
||||||
|
compression = 1;
|
||||||
|
break;
|
||||||
|
case 0x32545844: // DXT2
|
||||||
|
compression = 2;
|
||||||
|
break;
|
||||||
|
case 0x33545844: // DXT3
|
||||||
|
compression = 3;
|
||||||
|
break;
|
||||||
|
case 0x34545844: // DXT4
|
||||||
|
compression = 4;
|
||||||
|
break;
|
||||||
|
case 0x35545844: // DXT5
|
||||||
|
compression = 5;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
stream->writeU8(compression);
|
||||||
|
|
||||||
|
if(raster->format & Raster::PAL4)
|
||||||
|
stream->write(ras->palette, 4*32);
|
||||||
|
else if(raster->format & Raster::PAL8)
|
||||||
|
stream->write(ras->palette, 4*256);
|
||||||
|
|
||||||
|
uint32 size;
|
||||||
|
uint8 *data;
|
||||||
|
for(int32 i = 0; i < numLevels; i++){
|
||||||
|
size = getLevelSize(raster, i);
|
||||||
|
stream->writeU32(size);
|
||||||
|
data = raster->lock(i);
|
||||||
|
stream->write(data, size);
|
||||||
|
raster->unlock(i);
|
||||||
|
}
|
||||||
|
tex->streamWritePlugins(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32
|
||||||
|
getSizeNativeTexture(Texture *tex)
|
||||||
|
{
|
||||||
|
uint32 size = 12 + 72 + 16;
|
||||||
|
int32 levels = tex->raster->getNumLevels();
|
||||||
|
if(tex->raster->format & Raster::PAL4)
|
||||||
|
size += 4*32;
|
||||||
|
else if(tex->raster->format & Raster::PAL8)
|
||||||
|
size += 4*256;
|
||||||
|
for(int32 i = 0; i < levels; i++)
|
||||||
|
size += 4 + getLevelSize(tex->raster, i);
|
||||||
|
size += 12 + tex->streamGetPluginSize();
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
51
src/d3d/d3d8render.cpp
Normal file
51
src/d3d/d3d8render.cpp
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "../rwbase.h"
|
||||||
|
#include "../rwplg.h"
|
||||||
|
#include "../rwpipeline.h"
|
||||||
|
#include "../rwobjects.h"
|
||||||
|
#include "rwd3d.h"
|
||||||
|
#include "rwd3d8.h"
|
||||||
|
|
||||||
|
namespace rw {
|
||||||
|
namespace d3d8 {
|
||||||
|
using namespace d3d;
|
||||||
|
|
||||||
|
#ifndef RW_D3D9
|
||||||
|
void defaultRenderCB(Atomic*, InstanceDataHeader*) {}
|
||||||
|
#else
|
||||||
|
|
||||||
|
void
|
||||||
|
defaultRenderCB(Atomic *atomic, InstanceDataHeader *header)
|
||||||
|
{
|
||||||
|
Geometry *geo = atomic->geometry;
|
||||||
|
Frame *f = atomic->getFrame();
|
||||||
|
device->SetTransform(D3DTS_WORLD, (D3DMATRIX*)f->getLTM());
|
||||||
|
|
||||||
|
InstanceData *inst = header->inst;
|
||||||
|
for(uint32 i = 0; i < header->numMeshes; i++){
|
||||||
|
d3d::setTexture(0, inst->material->texture);
|
||||||
|
d3d::setMaterial(inst->material);
|
||||||
|
d3d::setRenderState(D3DRS_AMBIENT, D3DCOLOR_ARGB(0xFF, 0x40, 0x40, 0x40));
|
||||||
|
d3d::setRenderState(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL);
|
||||||
|
d3d::setRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL);
|
||||||
|
if(geo->geoflags & Geometry::PRELIT)
|
||||||
|
d3d::setRenderState(D3DRS_EMISSIVEMATERIALSOURCE, D3DMCS_COLOR1);
|
||||||
|
|
||||||
|
device->SetFVF(inst->vertexShader);
|
||||||
|
device->SetStreamSource(0, (IDirect3DVertexBuffer9*)inst->vertexBuffer, 0, inst->stride);
|
||||||
|
device->SetIndices((IDirect3DIndexBuffer9*)inst->indexBuffer);
|
||||||
|
uint32 numPrim = inst->primType == D3DPT_TRIANGLESTRIP ? inst->numIndices-2 : inst->numIndices/3;
|
||||||
|
d3d::flushCache();
|
||||||
|
device->DrawIndexedPrimitive((D3DPRIMITIVETYPE)inst->primType, inst->baseIndex,
|
||||||
|
0, inst->numVertices, 0, numPrim);
|
||||||
|
inst++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
727
src/d3d/d3d9.cpp
Normal file
727
src/d3d/d3d9.cpp
Normal file
@ -0,0 +1,727 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "../rwbase.h"
|
||||||
|
#include "../rwerror.h"
|
||||||
|
#include "../rwplg.h"
|
||||||
|
#include "../rwpipeline.h"
|
||||||
|
#include "../rwobjects.h"
|
||||||
|
#include "../rwengine.h"
|
||||||
|
#include "rwd3d.h"
|
||||||
|
#include "rwd3d9.h"
|
||||||
|
|
||||||
|
#define PLUGIN_ID 2
|
||||||
|
|
||||||
|
namespace rw {
|
||||||
|
namespace d3d9 {
|
||||||
|
using namespace d3d;
|
||||||
|
|
||||||
|
// TODO: move to header, but not as #define
|
||||||
|
#ifndef RW_D3D9
|
||||||
|
#define D3DDECL_END() {0xFF,0,D3DDECLTYPE_UNUSED,0,0,0}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define NUMDECLELT 12
|
||||||
|
|
||||||
|
void
|
||||||
|
initializePlatform(void)
|
||||||
|
{
|
||||||
|
driver[PLATFORM_D3D9].defaultPipeline = makeDefaultPipeline();
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
createVertexDeclaration(VertexElement *elements)
|
||||||
|
{
|
||||||
|
#ifdef RW_D3D9
|
||||||
|
IDirect3DVertexDeclaration9 *decl = 0;
|
||||||
|
device->CreateVertexDeclaration((D3DVERTEXELEMENT9*)elements, &decl);
|
||||||
|
return decl;
|
||||||
|
#else
|
||||||
|
int n = 0;
|
||||||
|
VertexElement *e = (VertexElement*)elements;
|
||||||
|
while(e[n++].stream != 0xFF)
|
||||||
|
;
|
||||||
|
e = (VertexElement*)new uint8[n*sizeof(VertexElement)];
|
||||||
|
memcpy(e, elements, n*sizeof(VertexElement));
|
||||||
|
return e;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32
|
||||||
|
getDeclaration(void *declaration, VertexElement *elements)
|
||||||
|
{
|
||||||
|
#ifdef RW_D3D9
|
||||||
|
IDirect3DVertexDeclaration9 *decl = (IDirect3DVertexDeclaration9*)declaration;
|
||||||
|
UINT numElt;
|
||||||
|
decl->GetDeclaration((D3DVERTEXELEMENT9*)elements, &numElt);
|
||||||
|
return numElt;
|
||||||
|
#else
|
||||||
|
int n = 0;
|
||||||
|
VertexElement *e = (VertexElement*)declaration;
|
||||||
|
while(e[n++].stream != 0xFF)
|
||||||
|
;
|
||||||
|
if(elements)
|
||||||
|
memcpy(elements, declaration, n*sizeof(VertexElement));
|
||||||
|
return n;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void*
|
||||||
|
destroyNativeData(void *object, int32, int32)
|
||||||
|
{
|
||||||
|
Geometry *geometry = (Geometry*)object;
|
||||||
|
if(geometry->instData == nil ||
|
||||||
|
geometry->instData->platform != PLATFORM_D3D9)
|
||||||
|
return object;
|
||||||
|
InstanceDataHeader *header =
|
||||||
|
(InstanceDataHeader*)geometry->instData;
|
||||||
|
geometry->instData = nil;
|
||||||
|
deleteObject(header->vertexDeclaration);
|
||||||
|
deleteObject(header->indexBuffer);
|
||||||
|
deleteObject(header->vertexStream[0].vertexBuffer);
|
||||||
|
deleteObject(header->vertexStream[1].vertexBuffer);
|
||||||
|
delete[] header->inst;
|
||||||
|
delete header;
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream*
|
||||||
|
readNativeData(Stream *stream, int32, void *object, int32, int32)
|
||||||
|
{
|
||||||
|
Geometry *geometry = (Geometry*)object;
|
||||||
|
uint32 platform;
|
||||||
|
if(!findChunk(stream, ID_STRUCT, nil, nil)){
|
||||||
|
RWERROR((ERR_CHUNK, "STRUCT"))
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
platform = stream->readU32();
|
||||||
|
if(platform != PLATFORM_D3D9){
|
||||||
|
RWERROR((ERR_PLATFORM, platform));
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
InstanceDataHeader *header = new InstanceDataHeader;
|
||||||
|
geometry->instData = header;
|
||||||
|
header->platform = PLATFORM_D3D9;
|
||||||
|
|
||||||
|
int32 size = stream->readI32();
|
||||||
|
uint8 *data = new uint8[size];
|
||||||
|
stream->read(data, size);
|
||||||
|
uint8 *p = data;
|
||||||
|
header->serialNumber = *(uint32*)p; p += 4;
|
||||||
|
header->numMeshes = *(uint32*)p; p += 4;
|
||||||
|
header->indexBuffer = nil; p += 4;
|
||||||
|
header->primType = *(uint32*)p; p += 4;
|
||||||
|
p += 16*2; // skip vertex streams, they're repeated with the vertex buffers
|
||||||
|
header->useOffsets = *(bool32*)p; p += 4;
|
||||||
|
header->vertexDeclaration = nil; p += 4;
|
||||||
|
header->totalNumIndex = *(uint32*)p; p += 4;
|
||||||
|
header->totalNumVertex = *(uint32*)p; p += 4;
|
||||||
|
header->inst = new InstanceData[header->numMeshes];
|
||||||
|
|
||||||
|
InstanceData *inst = header->inst;
|
||||||
|
for(uint32 i = 0; i < header->numMeshes; i++){
|
||||||
|
inst->numIndex = *(uint32*)p; p += 4;
|
||||||
|
inst->minVert = *(uint32*)p; p += 4;
|
||||||
|
uint32 matid = *(uint32*)p; p += 4;
|
||||||
|
inst->material = geometry->materialList[matid];
|
||||||
|
inst->vertexAlpha = *(bool32*)p; p += 4;
|
||||||
|
inst->vertexShader = nil; p += 4;
|
||||||
|
inst->baseIndex = 0; p += 4;
|
||||||
|
inst->numVertices = *(uint32*)p; p += 4;
|
||||||
|
inst->startIndex = *(uint32*)p; p += 4;
|
||||||
|
inst->numPrimitives = *(uint32*)p; p += 4;
|
||||||
|
inst++;
|
||||||
|
}
|
||||||
|
|
||||||
|
VertexElement elements[NUMDECLELT];
|
||||||
|
uint32 numDeclarations = stream->readU32();
|
||||||
|
stream->read(elements, numDeclarations*8);
|
||||||
|
header->vertexDeclaration = createVertexDeclaration(elements);
|
||||||
|
|
||||||
|
header->indexBuffer = createIndexBuffer(header->totalNumIndex*2);
|
||||||
|
uint16 *indices = lockIndices(header->indexBuffer, 0, 0, 0);
|
||||||
|
stream->read(indices, 2*header->totalNumIndex);
|
||||||
|
unlockIndices(header->indexBuffer);
|
||||||
|
|
||||||
|
VertexStream *s;
|
||||||
|
p = data;
|
||||||
|
for(int i = 0; i < 2; i++){
|
||||||
|
stream->read(p, 16);
|
||||||
|
s = &header->vertexStream[i];
|
||||||
|
s->vertexBuffer = (void*)*(uint32*)p; p += 4;
|
||||||
|
s->offset = 0; p += 4;
|
||||||
|
s->stride = *(uint32*)p; p += 4;
|
||||||
|
s->geometryFlags = *(uint16*)p; p += 2;
|
||||||
|
s->managed = *p++;
|
||||||
|
s->dynamicLock = *p++;
|
||||||
|
|
||||||
|
if(s->vertexBuffer == nil)
|
||||||
|
continue;
|
||||||
|
// TODO: unset managed flag when using morph targets.
|
||||||
|
// also uses different buffer type and locks differently
|
||||||
|
s->vertexBuffer = createVertexBuffer(s->stride*header->totalNumVertex, 0, D3DPOOL_MANAGED);
|
||||||
|
uint8 *verts = lockVertices(s->vertexBuffer, 0, 0, D3DLOCK_NOSYSLOCK);
|
||||||
|
stream->read(verts, s->stride*header->totalNumVertex);
|
||||||
|
unlockVertices(s->vertexBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: somehow depends on number of streams used (baseIndex = minVert when more than one)
|
||||||
|
inst = header->inst;
|
||||||
|
for(uint32 i = 0; i < header->numMeshes; i++){
|
||||||
|
inst->baseIndex = inst->minVert + header->vertexStream[0].offset / header->vertexStream[0].stride;
|
||||||
|
inst++;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] data;
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream*
|
||||||
|
writeNativeData(Stream *stream, int32 len, void *object, int32, int32)
|
||||||
|
{
|
||||||
|
Geometry *geometry = (Geometry*)object;
|
||||||
|
writeChunkHeader(stream, ID_STRUCT, len-12);
|
||||||
|
if(geometry->instData == nil ||
|
||||||
|
geometry->instData->platform != PLATFORM_D3D9)
|
||||||
|
return stream;
|
||||||
|
stream->writeU32(PLATFORM_D3D9);
|
||||||
|
InstanceDataHeader *header = (InstanceDataHeader*)geometry->instData;
|
||||||
|
int32 size = 64 + geometry->meshHeader->numMeshes*36;
|
||||||
|
uint8 *data = new uint8[size];
|
||||||
|
stream->writeI32(size);
|
||||||
|
|
||||||
|
uint8 *p = data;
|
||||||
|
*(uint32*)p = header->serialNumber; p += 4;
|
||||||
|
*(uint32*)p = header->numMeshes; p += 4;
|
||||||
|
p += 4; // skip index buffer
|
||||||
|
*(uint32*)p = header->primType; p += 4;
|
||||||
|
p += 16*2; // skip vertex streams, they're repeated with the vertex buffers
|
||||||
|
*(bool32*)p = header->useOffsets; p += 4;
|
||||||
|
p += 4; // skip vertex declaration
|
||||||
|
*(uint32*)p = header->totalNumIndex; p += 4;
|
||||||
|
*(uint32*)p = header->totalNumVertex; p += 4;
|
||||||
|
|
||||||
|
InstanceData *inst = header->inst;
|
||||||
|
for(uint32 i = 0; i < header->numMeshes; i++){
|
||||||
|
*(uint32*)p = inst->numIndex; p += 4;
|
||||||
|
*(uint32*)p = inst->minVert; p += 4;
|
||||||
|
int32 matid = findPointer(inst->material, (void**)geometry->materialList, geometry->numMaterials);
|
||||||
|
*(int32*)p = matid; p += 4;
|
||||||
|
*(bool32*)p = inst->vertexAlpha; p += 4;
|
||||||
|
*(uint32*)p = 0; p += 4; // vertex shader
|
||||||
|
*(uint32*)p = inst->baseIndex; p += 4; // not used but meh...
|
||||||
|
*(uint32*)p = inst->numVertices; p += 4;
|
||||||
|
*(uint32*)p = inst->startIndex; p += 4;
|
||||||
|
*(uint32*)p = inst->numPrimitives; p += 4;
|
||||||
|
inst++;
|
||||||
|
}
|
||||||
|
stream->write(data, size);
|
||||||
|
|
||||||
|
VertexElement elements[NUMDECLELT];
|
||||||
|
uint32 numElt = getDeclaration(header->vertexDeclaration, elements);
|
||||||
|
stream->writeU32(numElt);
|
||||||
|
stream->write(elements, 8*numElt);
|
||||||
|
|
||||||
|
uint16 *indices = lockIndices(header->indexBuffer, 0, 0, 0);
|
||||||
|
stream->write(indices, 2*header->totalNumIndex);
|
||||||
|
unlockIndices(header->indexBuffer);
|
||||||
|
|
||||||
|
VertexStream *s;
|
||||||
|
for(int i = 0; i < 2; i++){
|
||||||
|
s = &header->vertexStream[i];
|
||||||
|
p = data;
|
||||||
|
*(uint32*)p = s->vertexBuffer ? 0xbadeaffe : 0; p += 4;
|
||||||
|
*(uint32*)p = s->offset; p += 4;
|
||||||
|
*(uint32*)p = s->stride; p += 4;
|
||||||
|
*(uint16*)p = s->geometryFlags; p += 2;
|
||||||
|
*p++ = s->managed;
|
||||||
|
*p++ = s->dynamicLock;
|
||||||
|
stream->write(data, 16);
|
||||||
|
|
||||||
|
if(s->vertexBuffer == nil)
|
||||||
|
continue;
|
||||||
|
uint8 *verts = lockVertices(s->vertexBuffer, 0, 0, D3DLOCK_NOSYSLOCK);
|
||||||
|
stream->write(verts, s->stride*header->totalNumVertex);
|
||||||
|
unlockVertices(s->vertexBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] data;
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32
|
||||||
|
getSizeNativeData(void *object, int32, int32)
|
||||||
|
{
|
||||||
|
Geometry *geometry = (Geometry*)object;
|
||||||
|
if(geometry->instData == nil ||
|
||||||
|
geometry->instData->platform != PLATFORM_D3D9)
|
||||||
|
return 0;
|
||||||
|
InstanceDataHeader *header = (InstanceDataHeader*)geometry->instData;
|
||||||
|
int32 size = 12 + 4 + 4 + 64 + header->numMeshes*36;
|
||||||
|
uint32 numElt = getDeclaration(header->vertexDeclaration, nil);
|
||||||
|
size += 4 + numElt*8;
|
||||||
|
size += 2*header->totalNumIndex;
|
||||||
|
size += 0x10 + header->vertexStream[0].stride*header->totalNumVertex;
|
||||||
|
size += 0x10 + header->vertexStream[1].stride*header->totalNumVertex;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
registerNativeDataPlugin(void)
|
||||||
|
{
|
||||||
|
Geometry::registerPlugin(0, ID_NATIVEDATA,
|
||||||
|
nil, destroyNativeData, nil);
|
||||||
|
Geometry::registerPluginStream(ID_NATIVEDATA,
|
||||||
|
readNativeData,
|
||||||
|
writeNativeData,
|
||||||
|
getSizeNativeData);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
instance(rw::ObjPipeline *rwpipe, Atomic *atomic)
|
||||||
|
{
|
||||||
|
ObjPipeline *pipe = (ObjPipeline*)rwpipe;
|
||||||
|
Geometry *geo = atomic->geometry;
|
||||||
|
if(geo->geoflags & Geometry::NATIVE)
|
||||||
|
return;
|
||||||
|
geo->geoflags |= Geometry::NATIVE;
|
||||||
|
InstanceDataHeader *header = new InstanceDataHeader;
|
||||||
|
MeshHeader *meshh = geo->meshHeader;
|
||||||
|
geo->instData = header;
|
||||||
|
header->platform = PLATFORM_D3D9;
|
||||||
|
|
||||||
|
header->serialNumber = 0;
|
||||||
|
header->numMeshes = meshh->numMeshes;
|
||||||
|
header->primType = meshh->flags == 1 ? D3DPT_TRIANGLESTRIP : D3DPT_TRIANGLELIST;
|
||||||
|
header->useOffsets = 0;
|
||||||
|
header->totalNumVertex = geo->numVertices;
|
||||||
|
header->totalNumIndex = meshh->totalIndices;
|
||||||
|
header->inst = new InstanceData[header->numMeshes];
|
||||||
|
|
||||||
|
header->indexBuffer = createIndexBuffer(header->totalNumIndex*2);
|
||||||
|
|
||||||
|
uint16 *indices = lockIndices(header->indexBuffer, 0, 0, 0);
|
||||||
|
InstanceData *inst = header->inst;
|
||||||
|
Mesh *mesh = meshh->mesh;
|
||||||
|
uint32 startindex = 0;
|
||||||
|
for(uint32 i = 0; i < header->numMeshes; i++){
|
||||||
|
findMinVertAndNumVertices(mesh->indices, mesh->numIndices,
|
||||||
|
&inst->minVert, (int32*)&inst->numVertices);
|
||||||
|
inst->numIndex = mesh->numIndices;
|
||||||
|
inst->material = mesh->material;
|
||||||
|
inst->vertexAlpha = 0;
|
||||||
|
inst->vertexShader = nil;
|
||||||
|
inst->baseIndex = inst->minVert;
|
||||||
|
inst->startIndex = startindex;
|
||||||
|
inst->numPrimitives = header->primType == D3DPT_TRIANGLESTRIP ? inst->numIndex-2 : inst->numIndex/3;
|
||||||
|
if(inst->minVert == 0)
|
||||||
|
memcpy(&indices[inst->startIndex], mesh->indices, inst->numIndex*2);
|
||||||
|
else
|
||||||
|
for(uint32 j = 0; j < inst->numIndex; j++)
|
||||||
|
indices[inst->startIndex+j] = mesh->indices[j] - inst->minVert;
|
||||||
|
startindex += inst->numIndex;
|
||||||
|
mesh++;
|
||||||
|
inst++;
|
||||||
|
}
|
||||||
|
unlockIndices(header->indexBuffer);
|
||||||
|
|
||||||
|
memset(&header->vertexStream, 0, 2*sizeof(VertexStream));
|
||||||
|
|
||||||
|
pipe->instanceCB(geo, header);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
uninstance(rw::ObjPipeline *rwpipe, Atomic *atomic)
|
||||||
|
{
|
||||||
|
ObjPipeline *pipe = (ObjPipeline*)rwpipe;
|
||||||
|
Geometry *geo = atomic->geometry;
|
||||||
|
if((geo->geoflags & Geometry::NATIVE) == 0)
|
||||||
|
return;
|
||||||
|
assert(geo->instData != nil);
|
||||||
|
assert(geo->instData->platform == PLATFORM_D3D9);
|
||||||
|
geo->geoflags &= ~Geometry::NATIVE;
|
||||||
|
geo->allocateData();
|
||||||
|
geo->meshHeader->allocateIndices();
|
||||||
|
|
||||||
|
InstanceDataHeader *header = (InstanceDataHeader*)geo->instData;
|
||||||
|
uint16 *indices = lockIndices(header->indexBuffer, 0, 0, 0);
|
||||||
|
InstanceData *inst = header->inst;
|
||||||
|
Mesh *mesh = geo->meshHeader->mesh;
|
||||||
|
for(uint32 i = 0; i < header->numMeshes; i++){
|
||||||
|
if(inst->minVert == 0)
|
||||||
|
memcpy(mesh->indices, &indices[inst->startIndex], inst->numIndex*2);
|
||||||
|
else
|
||||||
|
for(uint32 j = 0; j < inst->numIndex; j++)
|
||||||
|
mesh->indices[j] = indices[inst->startIndex+j] + inst->minVert;
|
||||||
|
mesh++;
|
||||||
|
inst++;
|
||||||
|
}
|
||||||
|
unlockIndices(header->indexBuffer);
|
||||||
|
|
||||||
|
pipe->uninstanceCB(geo, header);
|
||||||
|
geo->generateTriangles();
|
||||||
|
destroyNativeData(geo, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
render(rw::ObjPipeline *rwpipe, Atomic *atomic)
|
||||||
|
{
|
||||||
|
ObjPipeline *pipe = (ObjPipeline*)rwpipe;
|
||||||
|
Geometry *geo = atomic->geometry;
|
||||||
|
if((geo->geoflags & Geometry::NATIVE) == 0)
|
||||||
|
pipe->instance(atomic);
|
||||||
|
assert(geo->instData != nil);
|
||||||
|
assert(geo->instData->platform == PLATFORM_D3D9);
|
||||||
|
if(pipe->renderCB)
|
||||||
|
pipe->renderCB(atomic, (InstanceDataHeader*)geo->instData);
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjPipeline::ObjPipeline(uint32 platform)
|
||||||
|
: rw::ObjPipeline(platform)
|
||||||
|
{
|
||||||
|
this->impl.instance = d3d9::instance;
|
||||||
|
this->impl.uninstance = d3d9::uninstance;
|
||||||
|
this->impl.render = d3d9::render;
|
||||||
|
this->instanceCB = nil;
|
||||||
|
this->uninstanceCB = nil;
|
||||||
|
this->renderCB = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
defaultInstanceCB(Geometry *geo, InstanceDataHeader *header)
|
||||||
|
{
|
||||||
|
VertexElement dcl[NUMDECLELT];
|
||||||
|
|
||||||
|
VertexStream *s = &header->vertexStream[0];
|
||||||
|
s->offset = 0;
|
||||||
|
s->managed = 1;
|
||||||
|
s->geometryFlags = 0;
|
||||||
|
s->dynamicLock = 0;
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
dcl[i].stream = 0;
|
||||||
|
dcl[i].offset = 0;
|
||||||
|
dcl[i].type = D3DDECLTYPE_FLOAT3;
|
||||||
|
dcl[i].method = D3DDECLMETHOD_DEFAULT;
|
||||||
|
dcl[i].usage = D3DDECLUSAGE_POSITION;
|
||||||
|
dcl[i].usageIndex = 0;
|
||||||
|
i++;
|
||||||
|
uint16 stride = 12;
|
||||||
|
s->geometryFlags |= 0x2;
|
||||||
|
|
||||||
|
bool isPrelit = (geo->geoflags & Geometry::PRELIT) != 0;
|
||||||
|
if(isPrelit){
|
||||||
|
dcl[i].stream = 0;
|
||||||
|
dcl[i].offset = stride;
|
||||||
|
dcl[i].type = D3DDECLTYPE_D3DCOLOR;
|
||||||
|
dcl[i].method = D3DDECLMETHOD_DEFAULT;
|
||||||
|
dcl[i].usage = D3DDECLUSAGE_COLOR;
|
||||||
|
dcl[i].usageIndex = 0;
|
||||||
|
i++;
|
||||||
|
s->geometryFlags |= 0x8;
|
||||||
|
stride += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int32 n = 0; n < geo->numTexCoordSets; n++){
|
||||||
|
dcl[i].stream = 0;
|
||||||
|
dcl[i].offset = stride;
|
||||||
|
dcl[i].type = D3DDECLTYPE_FLOAT2;
|
||||||
|
dcl[i].method = D3DDECLMETHOD_DEFAULT;
|
||||||
|
dcl[i].usage = D3DDECLUSAGE_TEXCOORD;
|
||||||
|
dcl[i].usageIndex = (uint8)n;
|
||||||
|
i++;
|
||||||
|
s->geometryFlags |= 0x10 << n;
|
||||||
|
stride += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasNormals = (geo->geoflags & Geometry::NORMALS) != 0;
|
||||||
|
if(hasNormals){
|
||||||
|
dcl[i].stream = 0;
|
||||||
|
dcl[i].offset = stride;
|
||||||
|
dcl[i].type = D3DDECLTYPE_FLOAT3;
|
||||||
|
dcl[i].method = D3DDECLMETHOD_DEFAULT;
|
||||||
|
dcl[i].usage = D3DDECLUSAGE_NORMAL;
|
||||||
|
dcl[i].usageIndex = 0;
|
||||||
|
i++;
|
||||||
|
s->geometryFlags |= 0x4;
|
||||||
|
stride += 12;
|
||||||
|
}
|
||||||
|
dcl[i] = D3DDECL_END();
|
||||||
|
header->vertexStream[0].stride = stride;
|
||||||
|
|
||||||
|
header->vertexDeclaration = createVertexDeclaration((VertexElement*)dcl);
|
||||||
|
|
||||||
|
s->vertexBuffer = createVertexBuffer(header->totalNumVertex*s->stride, 0, D3DPOOL_MANAGED);
|
||||||
|
|
||||||
|
// TODO: support both vertex buffers
|
||||||
|
uint8 *verts = lockVertices(s->vertexBuffer, 0, 0, D3DLOCK_NOSYSLOCK);
|
||||||
|
for(i = 0; dcl[i].usage != D3DDECLUSAGE_POSITION || dcl[i].usageIndex != 0; i++)
|
||||||
|
;
|
||||||
|
instV3d(vertFormatMap[dcl[i].type], verts + dcl[i].offset,
|
||||||
|
geo->morphTargets[0].vertices,
|
||||||
|
header->totalNumVertex,
|
||||||
|
header->vertexStream[dcl[i].stream].stride);
|
||||||
|
|
||||||
|
if(isPrelit){
|
||||||
|
for(i = 0; dcl[i].usage != D3DDECLUSAGE_COLOR || dcl[i].usageIndex != 0; i++)
|
||||||
|
;
|
||||||
|
// TODO: vertex alpha (instance per mesh)
|
||||||
|
instColor(vertFormatMap[dcl[i].type], verts + dcl[i].offset,
|
||||||
|
geo->colors,
|
||||||
|
header->totalNumVertex,
|
||||||
|
header->vertexStream[dcl[i].stream].stride);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int32 n = 0; n < geo->numTexCoordSets; n++){
|
||||||
|
for(i = 0; dcl[i].usage != D3DDECLUSAGE_TEXCOORD || dcl[i].usageIndex != n; i++)
|
||||||
|
;
|
||||||
|
instV2d(vertFormatMap[dcl[i].type], verts + dcl[i].offset,
|
||||||
|
geo->texCoords[n],
|
||||||
|
header->totalNumVertex,
|
||||||
|
header->vertexStream[dcl[i].stream].stride);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(hasNormals){
|
||||||
|
for(i = 0; dcl[i].usage != D3DDECLUSAGE_NORMAL || dcl[i].usageIndex != 0; i++)
|
||||||
|
;
|
||||||
|
instV3d(vertFormatMap[dcl[i].type], verts + dcl[i].offset,
|
||||||
|
geo->morphTargets[0].normals,
|
||||||
|
header->totalNumVertex,
|
||||||
|
header->vertexStream[dcl[i].stream].stride);
|
||||||
|
}
|
||||||
|
unlockVertices(s->vertexBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
defaultUninstanceCB(Geometry *geo, InstanceDataHeader *header)
|
||||||
|
{
|
||||||
|
VertexElement dcl[NUMDECLELT];
|
||||||
|
|
||||||
|
uint8 *verts[2];
|
||||||
|
verts[0] = lockVertices(header->vertexStream[0].vertexBuffer, 0, 0, D3DLOCK_NOSYSLOCK);
|
||||||
|
verts[1] = lockVertices(header->vertexStream[1].vertexBuffer, 0, 0, D3DLOCK_NOSYSLOCK);
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for(i = 0; dcl[i].usage != D3DDECLUSAGE_POSITION || dcl[i].usageIndex != 0; i++)
|
||||||
|
;
|
||||||
|
uninstV3d(vertFormatMap[dcl[i].type],
|
||||||
|
geo->morphTargets[0].vertices,
|
||||||
|
verts[dcl[i].stream] + dcl[i].offset,
|
||||||
|
header->totalNumVertex,
|
||||||
|
header->vertexStream[dcl[i].stream].stride);
|
||||||
|
|
||||||
|
if(geo->geoflags & Geometry::PRELIT){
|
||||||
|
for(i = 0; dcl[i].usage != D3DDECLUSAGE_COLOR || dcl[i].usageIndex != 0; i++)
|
||||||
|
;
|
||||||
|
uninstColor(vertFormatMap[dcl[i].type],
|
||||||
|
geo->colors,
|
||||||
|
verts[dcl[i].stream] + dcl[i].offset,
|
||||||
|
header->totalNumVertex,
|
||||||
|
header->vertexStream[dcl[i].stream].stride);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int32 n = 0; n < geo->numTexCoordSets; n++){
|
||||||
|
for(i = 0; dcl[i].usage != D3DDECLUSAGE_TEXCOORD || dcl[i].usageIndex != n; i++)
|
||||||
|
;
|
||||||
|
uninstV2d(vertFormatMap[dcl[i].type],
|
||||||
|
geo->texCoords[n],
|
||||||
|
verts[dcl[i].stream] + dcl[i].offset,
|
||||||
|
header->totalNumVertex,
|
||||||
|
header->vertexStream[dcl[i].stream].stride);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(geo->geoflags & Geometry::NORMALS){
|
||||||
|
for(i = 0; dcl[i].usage != D3DDECLUSAGE_NORMAL || dcl[i].usageIndex != 0; i++)
|
||||||
|
;
|
||||||
|
uninstV3d(vertFormatMap[dcl[i].type],
|
||||||
|
geo->morphTargets[0].normals,
|
||||||
|
verts[dcl[i].stream] + dcl[i].offset,
|
||||||
|
header->totalNumVertex,
|
||||||
|
header->vertexStream[dcl[i].stream].stride);
|
||||||
|
}
|
||||||
|
|
||||||
|
unlockVertices(verts[0]);
|
||||||
|
unlockVertices(verts[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjPipeline*
|
||||||
|
makeDefaultPipeline(void)
|
||||||
|
{
|
||||||
|
ObjPipeline *pipe = new ObjPipeline(PLATFORM_D3D9);
|
||||||
|
pipe->instanceCB = defaultInstanceCB;
|
||||||
|
pipe->uninstanceCB = defaultUninstanceCB;
|
||||||
|
pipe->renderCB = defaultRenderCB;
|
||||||
|
return pipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjPipeline*
|
||||||
|
makeSkinPipeline(void)
|
||||||
|
{
|
||||||
|
ObjPipeline *pipe = new ObjPipeline(PLATFORM_D3D9);
|
||||||
|
pipe->instanceCB = defaultInstanceCB;
|
||||||
|
pipe->uninstanceCB = defaultUninstanceCB;
|
||||||
|
pipe->renderCB = defaultRenderCB;
|
||||||
|
pipe->pluginID = ID_SKIN;
|
||||||
|
pipe->pluginData = 1;
|
||||||
|
return pipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjPipeline*
|
||||||
|
makeMatFXPipeline(void)
|
||||||
|
{
|
||||||
|
ObjPipeline *pipe = new ObjPipeline(PLATFORM_D3D9);
|
||||||
|
pipe->instanceCB = defaultInstanceCB;
|
||||||
|
pipe->uninstanceCB = defaultUninstanceCB;
|
||||||
|
pipe->renderCB = defaultRenderCB;
|
||||||
|
pipe->pluginID = ID_MATFX;
|
||||||
|
pipe->pluginData = 0;
|
||||||
|
return pipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Native Texture and Raster
|
||||||
|
|
||||||
|
Texture*
|
||||||
|
readNativeTexture(Stream *stream)
|
||||||
|
{
|
||||||
|
uint32 platform;
|
||||||
|
if(!findChunk(stream, ID_STRUCT, nil, nil)){
|
||||||
|
RWERROR((ERR_CHUNK, "STRUCT"))
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
platform = stream->readU32();
|
||||||
|
if(platform != PLATFORM_D3D9){
|
||||||
|
RWERROR((ERR_PLATFORM, platform));
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
Texture *tex = Texture::create(nil);
|
||||||
|
if(tex == nil)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
// Texture
|
||||||
|
tex->filterAddressing = stream->readU32();
|
||||||
|
stream->read(tex->name, 32);
|
||||||
|
stream->read(tex->mask, 32);
|
||||||
|
|
||||||
|
// Raster
|
||||||
|
int32 format = stream->readI32();
|
||||||
|
int32 d3dformat = stream->readI32();
|
||||||
|
int32 width = stream->readU16();
|
||||||
|
int32 height = stream->readU16();
|
||||||
|
int32 depth = stream->readU8();
|
||||||
|
int32 numLevels = stream->readU8();
|
||||||
|
int32 type = stream->readU8();
|
||||||
|
int32 flags = stream->readU8();
|
||||||
|
|
||||||
|
Raster *raster;
|
||||||
|
D3dRaster *ras;
|
||||||
|
|
||||||
|
assert((flags & 2) == 0);
|
||||||
|
if(flags & 8){
|
||||||
|
raster = Raster::create(width, height, depth, format | type | 0x80, PLATFORM_D3D9);
|
||||||
|
ras = PLUGINOFFSET(D3dRaster, raster, nativeRasterOffset);
|
||||||
|
ras->format = d3dformat;
|
||||||
|
ras->hasAlpha = flags & 1;
|
||||||
|
ras->texture = createTexture(raster->width, raster->height,
|
||||||
|
raster->format & Raster::MIPMAP ? numLevels : 1,
|
||||||
|
ras->format);
|
||||||
|
raster->flags &= ~0x80;
|
||||||
|
ras->customFormat = 1;
|
||||||
|
}else{
|
||||||
|
raster = Raster::create(width, height, depth, format | type, PLATFORM_D3D9);
|
||||||
|
ras = PLUGINOFFSET(D3dRaster, raster, nativeRasterOffset);
|
||||||
|
}
|
||||||
|
tex->raster = raster;
|
||||||
|
|
||||||
|
// TODO: check if format supported and convert if necessary
|
||||||
|
|
||||||
|
if(raster->format & Raster::PAL4)
|
||||||
|
stream->read(ras->palette, 4*32);
|
||||||
|
else if(raster->format & Raster::PAL8)
|
||||||
|
stream->read(ras->palette, 4*256);
|
||||||
|
|
||||||
|
uint32 size;
|
||||||
|
uint8 *data;
|
||||||
|
for(int32 i = 0; i < numLevels; i++){
|
||||||
|
size = stream->readU32();
|
||||||
|
if(i < raster->getNumLevels()){
|
||||||
|
data = raster->lock(i);
|
||||||
|
stream->read(data, size);
|
||||||
|
raster->unlock(i);
|
||||||
|
}else
|
||||||
|
stream->seek(size);
|
||||||
|
}
|
||||||
|
tex->streamReadPlugins(stream);
|
||||||
|
return tex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
writeNativeTexture(Texture *tex, Stream *stream)
|
||||||
|
{
|
||||||
|
int32 chunksize = getSizeNativeTexture(tex);
|
||||||
|
int32 plgsize = tex->streamGetPluginSize();
|
||||||
|
writeChunkHeader(stream, ID_TEXTURENATIVE, chunksize);
|
||||||
|
writeChunkHeader(stream, ID_STRUCT, chunksize-24-plgsize);
|
||||||
|
stream->writeU32(PLATFORM_D3D9);
|
||||||
|
|
||||||
|
// Texture
|
||||||
|
stream->writeU32(tex->filterAddressing);
|
||||||
|
stream->write(tex->name, 32);
|
||||||
|
stream->write(tex->mask, 32);
|
||||||
|
|
||||||
|
// Raster
|
||||||
|
Raster *raster = tex->raster;
|
||||||
|
D3dRaster *ras = PLUGINOFFSET(D3dRaster, raster, nativeRasterOffset);
|
||||||
|
int32 numLevels = raster->getNumLevels();
|
||||||
|
stream->writeI32(raster->format);
|
||||||
|
stream->writeU32(ras->format);
|
||||||
|
stream->writeU16(raster->width);
|
||||||
|
stream->writeU16(raster->height);
|
||||||
|
stream->writeU8(raster->depth);
|
||||||
|
stream->writeU8(numLevels);
|
||||||
|
stream->writeU8(raster->type);
|
||||||
|
uint8 flags = 0;
|
||||||
|
if(ras->hasAlpha)
|
||||||
|
flags |= 1;
|
||||||
|
// 2 - cube map
|
||||||
|
// 4 - something about mipmaps...
|
||||||
|
if(ras->customFormat)
|
||||||
|
flags |= 8;
|
||||||
|
stream->writeU8(flags);
|
||||||
|
|
||||||
|
if(raster->format & Raster::PAL4)
|
||||||
|
stream->write(ras->palette, 4*32);
|
||||||
|
else if(raster->format & Raster::PAL8)
|
||||||
|
stream->write(ras->palette, 4*256);
|
||||||
|
|
||||||
|
uint32 size;
|
||||||
|
uint8 *data;
|
||||||
|
for(int32 i = 0; i < numLevels; i++){
|
||||||
|
size = getLevelSize(raster, i);
|
||||||
|
stream->writeU32(size);
|
||||||
|
data = raster->lock(i);
|
||||||
|
stream->write(data, size);
|
||||||
|
raster->unlock(i);
|
||||||
|
}
|
||||||
|
tex->streamWritePlugins(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32
|
||||||
|
getSizeNativeTexture(Texture *tex)
|
||||||
|
{
|
||||||
|
uint32 size = 12 + 72 + 16;
|
||||||
|
int32 levels = tex->raster->getNumLevels();
|
||||||
|
if(tex->raster->format & Raster::PAL4)
|
||||||
|
size += 4*32;
|
||||||
|
else if(tex->raster->format & Raster::PAL8)
|
||||||
|
size += 4*256;
|
||||||
|
for(int32 i = 0; i < levels; i++)
|
||||||
|
size += 4 + getLevelSize(tex->raster, i);
|
||||||
|
size += 12 + tex->streamGetPluginSize();
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
52
src/d3d/d3d9render.cpp
Normal file
52
src/d3d/d3d9render.cpp
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "../rwbase.h"
|
||||||
|
#include "../rwplg.h"
|
||||||
|
#include "../rwpipeline.h"
|
||||||
|
#include "../rwobjects.h"
|
||||||
|
#include "rwd3d.h"
|
||||||
|
#include "rwd3d9.h"
|
||||||
|
|
||||||
|
namespace rw {
|
||||||
|
namespace d3d9 {
|
||||||
|
using namespace d3d;
|
||||||
|
|
||||||
|
#ifndef RW_D3D9
|
||||||
|
void defaultRenderCB(Atomic*, InstanceDataHeader*) {}
|
||||||
|
#else
|
||||||
|
|
||||||
|
void
|
||||||
|
defaultRenderCB(Atomic *atomic, InstanceDataHeader *header)
|
||||||
|
{
|
||||||
|
Geometry *geo = atomic->geometry;
|
||||||
|
Frame *f = atomic->getFrame();
|
||||||
|
device->SetTransform(D3DTS_WORLD, (D3DMATRIX*)f->getLTM());
|
||||||
|
|
||||||
|
device->SetStreamSource(0, (IDirect3DVertexBuffer9*)header->vertexStream[0].vertexBuffer,
|
||||||
|
0, header->vertexStream[0].stride);
|
||||||
|
device->SetIndices((IDirect3DIndexBuffer9*)header->indexBuffer);
|
||||||
|
device->SetVertexDeclaration((IDirect3DVertexDeclaration9*)header->vertexDeclaration);
|
||||||
|
|
||||||
|
InstanceData *inst = header->inst;
|
||||||
|
for(uint32 i = 0; i < header->numMeshes; i++){
|
||||||
|
d3d::setTexture(0, inst->material->texture);
|
||||||
|
d3d::setMaterial(inst->material);
|
||||||
|
d3d::setRenderState(D3DRS_AMBIENT, D3DCOLOR_ARGB(0xFF, 0x40, 0x40, 0x40));
|
||||||
|
d3d::setRenderState(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL);
|
||||||
|
d3d::setRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL);
|
||||||
|
if(geo->geoflags & Geometry::PRELIT)
|
||||||
|
d3d::setRenderState(D3DRS_EMISSIVEMATERIALSOURCE, D3DMCS_COLOR1);
|
||||||
|
d3d::flushCache();
|
||||||
|
device->DrawIndexedPrimitive((D3DPRIMITIVETYPE)header->primType, inst->baseIndex,
|
||||||
|
0, inst->numVertices,
|
||||||
|
inst->startIndex, inst->numPrimitives);
|
||||||
|
inst++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
182
src/d3d/d3ddriver.cpp
Normal file
182
src/d3d/d3ddriver.cpp
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "../rwbase.h"
|
||||||
|
#include "../rwplg.h"
|
||||||
|
#include "../rwpipeline.h"
|
||||||
|
#include "../rwobjects.h"
|
||||||
|
#include "rwd3d.h"
|
||||||
|
|
||||||
|
namespace rw {
|
||||||
|
namespace d3d {
|
||||||
|
|
||||||
|
#ifdef RW_D3D9
|
||||||
|
|
||||||
|
#define MAXNUMSTATES D3DRS_BLENDOPALPHA
|
||||||
|
#define MAXNUMSTAGES 8
|
||||||
|
#define MAXNUMTEXSTATES D3DTSS_CONSTANT
|
||||||
|
#define MAXNUMSAMPLERSTATES D3DSAMP_DMAPOFFSET
|
||||||
|
|
||||||
|
static int32 numDirtyStates;
|
||||||
|
static uint32 dirtyStates[MAXNUMSTATES];
|
||||||
|
static struct {
|
||||||
|
uint32 value;
|
||||||
|
bool32 dirty;
|
||||||
|
} stateCache[MAXNUMSTATES];
|
||||||
|
static uint32 d3dStates[MAXNUMSTATES];
|
||||||
|
|
||||||
|
static int32 numDirtyTextureStageStates;
|
||||||
|
static struct {
|
||||||
|
uint32 stage;
|
||||||
|
uint32 type;
|
||||||
|
} dirtyTextureStageStates[MAXNUMTEXSTATES*MAXNUMSTAGES];
|
||||||
|
static struct {
|
||||||
|
uint32 value;
|
||||||
|
bool32 dirty;
|
||||||
|
} textureStageStateCache[MAXNUMSTATES][MAXNUMSTAGES];
|
||||||
|
static uint32 d3dTextureStageStates[MAXNUMSTATES][MAXNUMSTAGES];
|
||||||
|
|
||||||
|
static uint32 d3dSamplerStates[MAXNUMSAMPLERSTATES][MAXNUMSTAGES];
|
||||||
|
|
||||||
|
static Raster *d3dRaster[MAXNUMSTAGES];
|
||||||
|
|
||||||
|
static D3DMATERIAL9 d3dmaterial;
|
||||||
|
|
||||||
|
void
|
||||||
|
setRenderState(uint32 state, uint32 value)
|
||||||
|
{
|
||||||
|
if(stateCache[state].value != value){
|
||||||
|
stateCache[state].value = value;
|
||||||
|
if(!stateCache[state].dirty){
|
||||||
|
stateCache[state].dirty = 1;
|
||||||
|
dirtyStates[numDirtyStates++] = state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
setTextureStageState(uint32 stage, uint32 type, uint32 value)
|
||||||
|
{
|
||||||
|
if(textureStageStateCache[type][stage].value != value){
|
||||||
|
textureStageStateCache[type][stage].value = value;
|
||||||
|
if(!textureStageStateCache[type][stage].dirty){
|
||||||
|
textureStageStateCache[type][stage].dirty = 1;
|
||||||
|
dirtyTextureStageStates[numDirtyTextureStageStates].stage = stage;
|
||||||
|
dirtyTextureStageStates[numDirtyTextureStageStates].type = type;
|
||||||
|
numDirtyTextureStageStates++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
flushCache(void)
|
||||||
|
{
|
||||||
|
uint32 s, t;
|
||||||
|
uint32 v;
|
||||||
|
for(int32 i = 0; i < numDirtyStates; i++){
|
||||||
|
s = dirtyStates[i];
|
||||||
|
v = stateCache[s].value;
|
||||||
|
stateCache[s].dirty = 0;
|
||||||
|
if(d3dStates[s] != v){
|
||||||
|
device->SetRenderState((D3DRENDERSTATETYPE)s, v);
|
||||||
|
d3dStates[s] = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
numDirtyStates = 0;
|
||||||
|
for(int32 i = 0; i < numDirtyTextureStageStates; i++){
|
||||||
|
s = dirtyTextureStageStates[i].stage;
|
||||||
|
t = dirtyTextureStageStates[i].type;
|
||||||
|
v = textureStageStateCache[t][s].value;
|
||||||
|
textureStageStateCache[t][s].dirty = 0;
|
||||||
|
if(d3dTextureStageStates[t][s] != v){
|
||||||
|
device->SetTextureStageState(s, (D3DTEXTURESTAGESTATETYPE)t, v);
|
||||||
|
d3dTextureStageStates[t][s] = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
numDirtyTextureStageStates = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
setSamplerState(uint32 stage, uint32 type, uint32 value)
|
||||||
|
{
|
||||||
|
if(d3dSamplerStates[type][stage] != value){
|
||||||
|
device->SetSamplerState(stage, (D3DSAMPLERSTATETYPE)type, value);
|
||||||
|
d3dSamplerStates[type][stage] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
setRasterStage(uint32 stage, Raster *raster)
|
||||||
|
{
|
||||||
|
D3dRaster *d3draster = nil;
|
||||||
|
if(raster != d3dRaster[stage]){
|
||||||
|
d3dRaster[stage] = raster;
|
||||||
|
if(raster){
|
||||||
|
d3draster = PLUGINOFFSET(D3dRaster, raster, nativeRasterOffset);
|
||||||
|
device->SetTexture(stage, (IDirect3DTexture9*)d3draster->texture);
|
||||||
|
}else
|
||||||
|
device->SetTexture(stage, nil);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
setTexture(uint32 stage, Texture *tex)
|
||||||
|
{
|
||||||
|
static DWORD filternomip[] = {
|
||||||
|
0, D3DTEXF_POINT, D3DTEXF_LINEAR,
|
||||||
|
D3DTEXF_POINT, D3DTEXF_LINEAR,
|
||||||
|
D3DTEXF_POINT, D3DTEXF_LINEAR
|
||||||
|
};
|
||||||
|
static DWORD wrap[] = {
|
||||||
|
0, D3DTADDRESS_WRAP, D3DTADDRESS_MIRROR,
|
||||||
|
D3DTADDRESS_CLAMP, D3DTADDRESS_BORDER
|
||||||
|
};
|
||||||
|
if(tex == nil){
|
||||||
|
setRasterStage(stage, nil);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(tex->raster){
|
||||||
|
setSamplerState(stage, D3DSAMP_MAGFILTER, filternomip[tex->filterAddressing & 0xFF]);
|
||||||
|
setSamplerState(stage, D3DSAMP_MINFILTER, filternomip[tex->filterAddressing & 0xFF]);
|
||||||
|
setSamplerState(stage, D3DSAMP_ADDRESSU, wrap[(tex->filterAddressing >> 8) & 0xF]);
|
||||||
|
setSamplerState(stage, D3DSAMP_ADDRESSV, wrap[(tex->filterAddressing >> 12) & 0xF]);
|
||||||
|
}
|
||||||
|
setRasterStage(stage, tex->raster);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
setMaterial(Material *mat)
|
||||||
|
{
|
||||||
|
D3DMATERIAL9 mat9;
|
||||||
|
D3DCOLORVALUE black = { 0, 0, 0, 0 };
|
||||||
|
float ambmult = mat->surfaceProps.ambient/255.0f;
|
||||||
|
float diffmult = mat->surfaceProps.diffuse/255.0f;
|
||||||
|
mat9.Ambient.r = mat->color.red*ambmult;
|
||||||
|
mat9.Ambient.g = mat->color.green*ambmult;
|
||||||
|
mat9.Ambient.b = mat->color.blue*ambmult;
|
||||||
|
mat9.Ambient.a = mat->color.alpha*ambmult;
|
||||||
|
mat9.Diffuse.r = mat->color.red*diffmult;
|
||||||
|
mat9.Diffuse.g = mat->color.green*diffmult;
|
||||||
|
mat9.Diffuse.b = mat->color.blue*diffmult;
|
||||||
|
mat9.Diffuse.a = mat->color.alpha*diffmult;
|
||||||
|
mat9.Power = 0.0f;
|
||||||
|
mat9.Emissive = black;
|
||||||
|
mat9.Specular = black;
|
||||||
|
if(d3dmaterial.Diffuse.r != mat9.Diffuse.r ||
|
||||||
|
d3dmaterial.Diffuse.g != mat9.Diffuse.g ||
|
||||||
|
d3dmaterial.Diffuse.b != mat9.Diffuse.b ||
|
||||||
|
d3dmaterial.Diffuse.a != mat9.Diffuse.a ||
|
||||||
|
d3dmaterial.Ambient.r != mat9.Ambient.r ||
|
||||||
|
d3dmaterial.Ambient.g != mat9.Ambient.g ||
|
||||||
|
d3dmaterial.Ambient.b != mat9.Ambient.b ||
|
||||||
|
d3dmaterial.Ambient.a != mat9.Ambient.a){
|
||||||
|
device->SetMaterial(&mat9);
|
||||||
|
d3dmaterial = mat9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
105
src/d3d/rwd3d.h
Normal file
105
src/d3d/rwd3d.h
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
#ifdef RW_D3D9
|
||||||
|
#include <d3d9.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace rw {
|
||||||
|
namespace d3d {
|
||||||
|
|
||||||
|
extern bool32 isP8supported;
|
||||||
|
|
||||||
|
#ifdef RW_D3D9
|
||||||
|
extern IDirect3DDevice9 *device;
|
||||||
|
#else
|
||||||
|
enum {
|
||||||
|
D3DLOCK_NOSYSLOCK = 0, // ignored
|
||||||
|
D3DPOOL_MANAGED = 0, // ignored
|
||||||
|
D3DPT_TRIANGLELIST = 4,
|
||||||
|
D3DPT_TRIANGLESTRIP = 5,
|
||||||
|
|
||||||
|
|
||||||
|
D3DDECLTYPE_FLOAT1 = 0, // 1D float expanded to (value, 0., 0., 1.)
|
||||||
|
D3DDECLTYPE_FLOAT2 = 1, // 2D float expanded to (value, value, 0., 1.)
|
||||||
|
D3DDECLTYPE_FLOAT3 = 2, // 3D float expanded to (value, value, value, 1.)
|
||||||
|
D3DDECLTYPE_FLOAT4 = 3, // 4D float
|
||||||
|
D3DDECLTYPE_D3DCOLOR = 4, // 4D packed unsigned bytes mapped to 0. to 1. range
|
||||||
|
// Input is in D3DCOLOR format (ARGB) expanded to (R, G, B, A)
|
||||||
|
D3DDECLTYPE_UBYTE4 = 5, // 4D unsigned byte
|
||||||
|
D3DDECLTYPE_SHORT2 = 6, // 2D signed short expanded to (value, value, 0., 1.)
|
||||||
|
D3DDECLTYPE_SHORT4 = 7, // 4D signed short
|
||||||
|
|
||||||
|
D3DDECLTYPE_UBYTE4N = 8, // Each of 4 bytes is normalized by dividing to 255.0
|
||||||
|
D3DDECLTYPE_SHORT2N = 9, // 2D signed short normalized (v[0]/32767.0,v[1]/32767.0,0,1)
|
||||||
|
D3DDECLTYPE_SHORT4N = 10, // 4D signed short normalized (v[0]/32767.0,v[1]/32767.0,v[2]/32767.0,v[3]/32767.0)
|
||||||
|
D3DDECLTYPE_USHORT2N = 11, // 2D unsigned short normalized (v[0]/65535.0,v[1]/65535.0,0,1)
|
||||||
|
D3DDECLTYPE_USHORT4N = 12, // 4D unsigned short normalized (v[0]/65535.0,v[1]/65535.0,v[2]/65535.0,v[3]/65535.0)
|
||||||
|
D3DDECLTYPE_UDEC3 = 13, // 3D unsigned 10 10 10 format expanded to (value, value, value, 1)
|
||||||
|
D3DDECLTYPE_DEC3N = 14, // 3D signed 10 10 10 format normalized and expanded to (v[0]/511.0, v[1]/511.0, v[2]/511.0, 1)
|
||||||
|
D3DDECLTYPE_FLOAT16_2 = 15, // Two 16-bit floating point values, expanded to (value, value, 0, 1)
|
||||||
|
D3DDECLTYPE_FLOAT16_4 = 16, // Four 16-bit floating point values
|
||||||
|
D3DDECLTYPE_UNUSED = 17, // When the type field in a decl is unused.
|
||||||
|
|
||||||
|
|
||||||
|
D3DDECLMETHOD_DEFAULT = 0,
|
||||||
|
|
||||||
|
|
||||||
|
D3DDECLUSAGE_POSITION = 0,
|
||||||
|
D3DDECLUSAGE_BLENDWEIGHT, // 1
|
||||||
|
D3DDECLUSAGE_BLENDINDICES, // 2
|
||||||
|
D3DDECLUSAGE_NORMAL, // 3
|
||||||
|
D3DDECLUSAGE_PSIZE, // 4
|
||||||
|
D3DDECLUSAGE_TEXCOORD, // 5
|
||||||
|
D3DDECLUSAGE_TANGENT, // 6
|
||||||
|
D3DDECLUSAGE_BINORMAL, // 7
|
||||||
|
D3DDECLUSAGE_TESSFACTOR, // 8
|
||||||
|
D3DDECLUSAGE_POSITIONT, // 9
|
||||||
|
D3DDECLUSAGE_COLOR, // 10
|
||||||
|
D3DDECLUSAGE_FOG, // 11
|
||||||
|
D3DDECLUSAGE_DEPTH, // 12
|
||||||
|
D3DDECLUSAGE_SAMPLE, // 13
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern int vertFormatMap[];
|
||||||
|
|
||||||
|
void *createIndexBuffer(uint32 length);
|
||||||
|
uint16 *lockIndices(void *indexBuffer, uint32 offset, uint32 size, uint32 flags);
|
||||||
|
void unlockIndices(void *indexBuffer);
|
||||||
|
void *createVertexBuffer(uint32 length, uint32 fvf, int32 pool);
|
||||||
|
uint8 *lockVertices(void *vertexBuffer, uint32 offset, uint32 size, uint32 flags);
|
||||||
|
void unlockVertices(void *vertexBuffer);
|
||||||
|
void *createTexture(int32 width, int32 height, int32 levels, uint32 format);
|
||||||
|
uint8 *lockTexture(void *texture, int32 level);
|
||||||
|
void unlockTexture(void *texture, int32 level);
|
||||||
|
void deleteObject(void *object);
|
||||||
|
|
||||||
|
// Native Texture and Raster
|
||||||
|
|
||||||
|
struct D3dRaster
|
||||||
|
{
|
||||||
|
void *texture;
|
||||||
|
void *palette;
|
||||||
|
uint32 format;
|
||||||
|
bool32 hasAlpha;
|
||||||
|
bool32 customFormat;
|
||||||
|
};
|
||||||
|
|
||||||
|
int32 getLevelSize(Raster *raster, int32 level);
|
||||||
|
void allocateDXT(Raster *raster, int32 dxt, int32 numLevels, bool32 hasAlpha);
|
||||||
|
void setPalette(Raster *raster, void *palette, int32 size);
|
||||||
|
void setTexels(Raster *raster, void *texels, int32 level);
|
||||||
|
|
||||||
|
extern int32 nativeRasterOffset;
|
||||||
|
void registerNativeRaster(void);
|
||||||
|
|
||||||
|
// Rendering
|
||||||
|
|
||||||
|
void setRenderState(uint32 state, uint32 value);
|
||||||
|
void setTextureStageState(uint32 stage, uint32 type, uint32 value);
|
||||||
|
void flushCache(void);
|
||||||
|
void setSamplerState(uint32 stage, uint32 type, uint32 value);
|
||||||
|
|
||||||
|
void setTexture(uint32 stage, Texture *tex);
|
||||||
|
void setMaterial(Material *mat);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
67
src/d3d/rwd3d8.h
Normal file
67
src/d3d/rwd3d8.h
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
namespace rw {
|
||||||
|
namespace d3d8 {
|
||||||
|
|
||||||
|
void initializePlatform(void);
|
||||||
|
|
||||||
|
struct InstanceData
|
||||||
|
{
|
||||||
|
uint32 minVert;
|
||||||
|
int32 stride;
|
||||||
|
int32 numVertices;
|
||||||
|
int32 numIndices;
|
||||||
|
Material *material;
|
||||||
|
uint32 vertexShader;
|
||||||
|
uint32 primType;
|
||||||
|
void *indexBuffer;
|
||||||
|
void *vertexBuffer;
|
||||||
|
uint32 baseIndex;
|
||||||
|
uint8 vertexAlpha;
|
||||||
|
uint8 managed;
|
||||||
|
uint8 remapped;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct InstanceDataHeader : rw::InstanceDataHeader
|
||||||
|
{
|
||||||
|
uint16 serialNumber;
|
||||||
|
uint16 numMeshes;
|
||||||
|
|
||||||
|
InstanceData *inst;
|
||||||
|
};
|
||||||
|
|
||||||
|
uint32 makeFVFDeclaration(uint32 flags, int32 numTex);
|
||||||
|
int32 getStride(uint32 flags, int32 numTex);
|
||||||
|
|
||||||
|
void *destroyNativeData(void *object, int32, int32);
|
||||||
|
Stream *readNativeData(Stream *stream, int32 len, void *object, int32, int32);
|
||||||
|
Stream *writeNativeData(Stream *stream, int32 len, void *object, int32, int32);
|
||||||
|
int32 getSizeNativeData(void *object, int32, int32);
|
||||||
|
void registerNativeDataPlugin(void);
|
||||||
|
|
||||||
|
class ObjPipeline : public rw::ObjPipeline
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void (*instanceCB)(Geometry *geo, InstanceData *header);
|
||||||
|
void (*uninstanceCB)(Geometry *geo, InstanceData *header);
|
||||||
|
void (*renderCB)(Atomic *atomic, InstanceDataHeader *header);
|
||||||
|
|
||||||
|
ObjPipeline(uint32 platform);
|
||||||
|
};
|
||||||
|
|
||||||
|
void defaultInstanceCB(Geometry *geo, InstanceDataHeader *header);
|
||||||
|
void defaultUninstanceCB(Geometry *geo, InstanceDataHeader *header);
|
||||||
|
void defaultRenderCB(Atomic *atomic, InstanceDataHeader *header);
|
||||||
|
|
||||||
|
ObjPipeline *makeDefaultPipeline(void);
|
||||||
|
|
||||||
|
ObjPipeline *makeSkinPipeline(void);
|
||||||
|
|
||||||
|
ObjPipeline *makeMatFXPipeline(void);
|
||||||
|
|
||||||
|
// Native Texture and Raster
|
||||||
|
|
||||||
|
Texture *readNativeTexture(Stream *stream);
|
||||||
|
void writeNativeTexture(Texture *tex, Stream *stream);
|
||||||
|
uint32 getSizeNativeTexture(Texture *tex);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
90
src/d3d/rwd3d9.h
Normal file
90
src/d3d/rwd3d9.h
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
namespace rw {
|
||||||
|
namespace d3d9 {
|
||||||
|
|
||||||
|
void initializePlatform(void);
|
||||||
|
|
||||||
|
struct VertexElement
|
||||||
|
{
|
||||||
|
uint16 stream;
|
||||||
|
uint16 offset;
|
||||||
|
uint8 type;
|
||||||
|
uint8 method;
|
||||||
|
uint8 usage;
|
||||||
|
uint8 usageIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VertexStream
|
||||||
|
{
|
||||||
|
void *vertexBuffer;
|
||||||
|
uint32 offset;
|
||||||
|
uint32 stride;
|
||||||
|
uint16 geometryFlags;
|
||||||
|
uint8 managed;
|
||||||
|
uint8 dynamicLock;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct InstanceData
|
||||||
|
{
|
||||||
|
uint32 numIndex;
|
||||||
|
uint32 minVert;
|
||||||
|
Material *material;
|
||||||
|
bool32 vertexAlpha;
|
||||||
|
void *vertexShader;
|
||||||
|
uint32 baseIndex;
|
||||||
|
uint32 numVertices;
|
||||||
|
uint32 startIndex;
|
||||||
|
uint32 numPrimitives;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct InstanceDataHeader : rw::InstanceDataHeader
|
||||||
|
{
|
||||||
|
uint32 serialNumber;
|
||||||
|
uint32 numMeshes;
|
||||||
|
void *indexBuffer;
|
||||||
|
uint32 primType;
|
||||||
|
VertexStream vertexStream[2];
|
||||||
|
bool32 useOffsets;
|
||||||
|
void *vertexDeclaration;
|
||||||
|
uint32 totalNumIndex;
|
||||||
|
uint32 totalNumVertex;
|
||||||
|
|
||||||
|
InstanceData *inst;
|
||||||
|
};
|
||||||
|
|
||||||
|
void *createVertexDeclaration(VertexElement *elements);
|
||||||
|
uint32 getDeclaration(void *declaration, VertexElement *elements);
|
||||||
|
|
||||||
|
void *destroyNativeData(void *object, int32, int32);
|
||||||
|
Stream *readNativeData(Stream *stream, int32 len, void *object, int32, int32);
|
||||||
|
Stream *writeNativeData(Stream *stream, int32 len, void *object, int32, int32);
|
||||||
|
int32 getSizeNativeData(void *object, int32, int32);
|
||||||
|
void registerNativeDataPlugin(void);
|
||||||
|
|
||||||
|
class ObjPipeline : public rw::ObjPipeline
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void (*instanceCB)(Geometry *geo, InstanceDataHeader *header);
|
||||||
|
void (*uninstanceCB)(Geometry *geo, InstanceDataHeader *header);
|
||||||
|
void (*renderCB)(Atomic *atomic, InstanceDataHeader *header);
|
||||||
|
|
||||||
|
ObjPipeline(uint32 platform);
|
||||||
|
};
|
||||||
|
|
||||||
|
void defaultInstanceCB(Geometry *geo, InstanceDataHeader *header);
|
||||||
|
void defaultUninstanceCB(Geometry *geo, InstanceDataHeader *header);
|
||||||
|
void defaultRenderCB(Atomic *atomic, InstanceDataHeader *header);
|
||||||
|
|
||||||
|
ObjPipeline *makeDefaultPipeline(void);
|
||||||
|
|
||||||
|
ObjPipeline *makeSkinPipeline(void);
|
||||||
|
|
||||||
|
ObjPipeline *makeMatFXPipeline(void);
|
||||||
|
|
||||||
|
// Native Texture and Raster
|
||||||
|
|
||||||
|
Texture *readNativeTexture(Stream *stream);
|
||||||
|
void writeNativeTexture(Texture *tex, Stream *stream);
|
||||||
|
uint32 getSizeNativeTexture(Texture *tex);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
181
src/d3d/rwxbox.h
Normal file
181
src/d3d/rwxbox.h
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
namespace rw {
|
||||||
|
namespace xbox {
|
||||||
|
|
||||||
|
void initializePlatform(void);
|
||||||
|
|
||||||
|
struct InstanceData
|
||||||
|
{
|
||||||
|
uint32 minVert;
|
||||||
|
int32 numVertices;
|
||||||
|
int32 numIndices;
|
||||||
|
void *indexBuffer;
|
||||||
|
Material *material;
|
||||||
|
uint32 vertexShader;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct InstanceDataHeader : rw::InstanceDataHeader
|
||||||
|
{
|
||||||
|
int32 size;
|
||||||
|
uint16 serialNumber;
|
||||||
|
uint16 numMeshes;
|
||||||
|
uint32 primType;
|
||||||
|
int32 numVertices;
|
||||||
|
int32 stride;
|
||||||
|
void *vertexBuffer;
|
||||||
|
bool32 vertexAlpha;
|
||||||
|
InstanceData *begin;
|
||||||
|
InstanceData *end;
|
||||||
|
|
||||||
|
uint8 *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
void *destroyNativeData(void *object, int32, int32);
|
||||||
|
Stream *readNativeData(Stream *stream, int32 len, void *object, int32, int32);
|
||||||
|
Stream *writeNativeData(Stream *stream, int32 len, void *object, int32, int32);
|
||||||
|
int32 getSizeNativeData(void *object, int32, int32);
|
||||||
|
void registerNativeDataPlugin(void);
|
||||||
|
|
||||||
|
class ObjPipeline : public rw::ObjPipeline
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void (*instanceCB)(Geometry *geo, InstanceDataHeader *header);
|
||||||
|
void (*uninstanceCB)(Geometry *geo, InstanceDataHeader *header);
|
||||||
|
|
||||||
|
ObjPipeline(uint32 platform);
|
||||||
|
};
|
||||||
|
|
||||||
|
ObjPipeline *makeDefaultPipeline(void);
|
||||||
|
|
||||||
|
// Skin plugin
|
||||||
|
|
||||||
|
Stream *readNativeSkin(Stream *stream, int32, void *object, int32 offset);
|
||||||
|
Stream *writeNativeSkin(Stream *stream, int32 len, void *object, int32 offset);
|
||||||
|
int32 getSizeNativeSkin(void *object, int32 offset);
|
||||||
|
|
||||||
|
ObjPipeline *makeSkinPipeline(void);
|
||||||
|
|
||||||
|
ObjPipeline *makeMatFXPipeline(void);
|
||||||
|
|
||||||
|
// Vertex Format plugin
|
||||||
|
|
||||||
|
extern uint32 vertexFormatSizes[6];
|
||||||
|
|
||||||
|
uint32 *getVertexFmt(Geometry *g);
|
||||||
|
uint32 makeVertexFmt(int32 flags, uint32 numTexSets);
|
||||||
|
uint32 getVertexFmtStride(uint32 fmt);
|
||||||
|
|
||||||
|
void registerVertexFormatPlugin(void);
|
||||||
|
|
||||||
|
// Native Texture and Raster
|
||||||
|
|
||||||
|
struct XboxRaster
|
||||||
|
{
|
||||||
|
void *texture;
|
||||||
|
void *palette;
|
||||||
|
uint32 format;
|
||||||
|
bool32 hasAlpha;
|
||||||
|
bool32 unknownFlag;
|
||||||
|
};
|
||||||
|
|
||||||
|
int32 getLevelSize(Raster *raster, int32 level);
|
||||||
|
|
||||||
|
extern int32 nativeRasterOffset;
|
||||||
|
void registerNativeRaster(void);
|
||||||
|
|
||||||
|
Texture *readNativeTexture(Stream *stream);
|
||||||
|
void writeNativeTexture(Texture *tex, Stream *stream);
|
||||||
|
uint32 getSizeNativeTexture(Texture *tex);
|
||||||
|
|
||||||
|
enum {
|
||||||
|
D3DFMT_UNKNOWN = 0xFFFFFFFF,
|
||||||
|
|
||||||
|
/* Swizzled formats */
|
||||||
|
|
||||||
|
D3DFMT_A8R8G8B8 = 0x00000006,
|
||||||
|
D3DFMT_X8R8G8B8 = 0x00000007,
|
||||||
|
D3DFMT_R5G6B5 = 0x00000005,
|
||||||
|
D3DFMT_R6G5B5 = 0x00000027,
|
||||||
|
D3DFMT_X1R5G5B5 = 0x00000003,
|
||||||
|
D3DFMT_A1R5G5B5 = 0x00000002,
|
||||||
|
D3DFMT_A4R4G4B4 = 0x00000004,
|
||||||
|
D3DFMT_A8 = 0x00000019,
|
||||||
|
D3DFMT_A8B8G8R8 = 0x0000003A,
|
||||||
|
D3DFMT_B8G8R8A8 = 0x0000003B,
|
||||||
|
D3DFMT_R4G4B4A4 = 0x00000039,
|
||||||
|
D3DFMT_R5G5B5A1 = 0x00000038,
|
||||||
|
D3DFMT_R8G8B8A8 = 0x0000003C,
|
||||||
|
D3DFMT_R8B8 = 0x00000029,
|
||||||
|
D3DFMT_G8B8 = 0x00000028,
|
||||||
|
|
||||||
|
D3DFMT_P8 = 0x0000000B,
|
||||||
|
|
||||||
|
D3DFMT_L8 = 0x00000000,
|
||||||
|
D3DFMT_A8L8 = 0x0000001A,
|
||||||
|
D3DFMT_AL8 = 0x00000001,
|
||||||
|
D3DFMT_L16 = 0x00000032,
|
||||||
|
|
||||||
|
D3DFMT_V8U8 = 0x00000028,
|
||||||
|
D3DFMT_L6V5U5 = 0x00000027,
|
||||||
|
D3DFMT_X8L8V8U8 = 0x00000007,
|
||||||
|
D3DFMT_Q8W8V8U8 = 0x0000003A,
|
||||||
|
D3DFMT_V16U16 = 0x00000033,
|
||||||
|
|
||||||
|
D3DFMT_D16_LOCKABLE = 0x0000002C,
|
||||||
|
D3DFMT_D16 = 0x0000002C,
|
||||||
|
D3DFMT_D24S8 = 0x0000002A,
|
||||||
|
D3DFMT_F16 = 0x0000002D,
|
||||||
|
D3DFMT_F24S8 = 0x0000002B,
|
||||||
|
|
||||||
|
/* YUV formats */
|
||||||
|
|
||||||
|
D3DFMT_YUY2 = 0x00000024,
|
||||||
|
D3DFMT_UYVY = 0x00000025,
|
||||||
|
|
||||||
|
/* Compressed formats */
|
||||||
|
|
||||||
|
D3DFMT_DXT1 = 0x0000000C,
|
||||||
|
D3DFMT_DXT2 = 0x0000000E,
|
||||||
|
D3DFMT_DXT3 = 0x0000000E,
|
||||||
|
D3DFMT_DXT4 = 0x0000000F,
|
||||||
|
D3DFMT_DXT5 = 0x0000000F,
|
||||||
|
|
||||||
|
/* Linear formats */
|
||||||
|
|
||||||
|
D3DFMT_LIN_A1R5G5B5 = 0x00000010,
|
||||||
|
D3DFMT_LIN_A4R4G4B4 = 0x0000001D,
|
||||||
|
D3DFMT_LIN_A8 = 0x0000001F,
|
||||||
|
D3DFMT_LIN_A8B8G8R8 = 0x0000003F,
|
||||||
|
D3DFMT_LIN_A8R8G8B8 = 0x00000012,
|
||||||
|
D3DFMT_LIN_B8G8R8A8 = 0x00000040,
|
||||||
|
D3DFMT_LIN_G8B8 = 0x00000017,
|
||||||
|
D3DFMT_LIN_R4G4B4A4 = 0x0000003E,
|
||||||
|
D3DFMT_LIN_R5G5B5A1 = 0x0000003D,
|
||||||
|
D3DFMT_LIN_R5G6B5 = 0x00000011,
|
||||||
|
D3DFMT_LIN_R6G5B5 = 0x00000037,
|
||||||
|
D3DFMT_LIN_R8B8 = 0x00000016,
|
||||||
|
D3DFMT_LIN_R8G8B8A8 = 0x00000041,
|
||||||
|
D3DFMT_LIN_X1R5G5B5 = 0x0000001C,
|
||||||
|
D3DFMT_LIN_X8R8G8B8 = 0x0000001E,
|
||||||
|
|
||||||
|
D3DFMT_LIN_A8L8 = 0x00000020,
|
||||||
|
D3DFMT_LIN_AL8 = 0x0000001B,
|
||||||
|
D3DFMT_LIN_L16 = 0x00000035,
|
||||||
|
D3DFMT_LIN_L8 = 0x00000013,
|
||||||
|
|
||||||
|
D3DFMT_LIN_V16U16 = 0x00000036,
|
||||||
|
D3DFMT_LIN_V8U8 = 0x00000017,
|
||||||
|
D3DFMT_LIN_L6V5U5 = 0x00000037,
|
||||||
|
D3DFMT_LIN_X8L8V8U8 = 0x0000001E,
|
||||||
|
D3DFMT_LIN_Q8W8V8U8 = 0x00000012,
|
||||||
|
|
||||||
|
D3DFMT_LIN_D24S8 = 0x0000002E,
|
||||||
|
D3DFMT_LIN_F24S8 = 0x0000002F,
|
||||||
|
D3DFMT_LIN_D16 = 0x00000030,
|
||||||
|
D3DFMT_LIN_F16 = 0x00000031,
|
||||||
|
|
||||||
|
D3DFMT_VERTEXDATA = 100,
|
||||||
|
D3DFMT_INDEX16 = 101,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
1050
src/d3d/xbox.cpp
Normal file
1050
src/d3d/xbox.cpp
Normal file
File diff suppressed because it is too large
Load Diff
276
src/gl/gl3pipe.cpp
Normal file
276
src/gl/gl3pipe.cpp
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "../rwbase.h"
|
||||||
|
#include "../rwerror.h"
|
||||||
|
#include "../rwplg.h"
|
||||||
|
#include "../rwpipeline.h"
|
||||||
|
#include "../rwobjects.h"
|
||||||
|
#include "../rwengine.h"
|
||||||
|
#include "../rwplugins.h"
|
||||||
|
#ifdef RW_OPENGL
|
||||||
|
#include <GL/glew.h>
|
||||||
|
#endif
|
||||||
|
#include "rwgl3.h"
|
||||||
|
#include "rwgl3shader.h"
|
||||||
|
|
||||||
|
namespace rw {
|
||||||
|
namespace gl3 {
|
||||||
|
|
||||||
|
// TODO: make some of these things platform-independent
|
||||||
|
|
||||||
|
void
|
||||||
|
initializePlatform(void)
|
||||||
|
{
|
||||||
|
#ifdef RW_OPENGL
|
||||||
|
driver[PLATFORM_GL3].defaultPipeline = makeDefaultPipeline();
|
||||||
|
matFXGlobals.pipelines[PLATFORM_GL3] = makeMatFXPipeline();
|
||||||
|
skinGlobals.pipelines[PLATFORM_GL3] = makeSkinPipeline();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
initializeRender();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef RW_OPENGL
|
||||||
|
|
||||||
|
static void
|
||||||
|
instance(rw::ObjPipeline *rwpipe, Atomic *atomic)
|
||||||
|
{
|
||||||
|
ObjPipeline *pipe = (ObjPipeline*)rwpipe;
|
||||||
|
Geometry *geo = atomic->geometry;
|
||||||
|
if(geo->geoflags & Geometry::NATIVE)
|
||||||
|
return;
|
||||||
|
geo->geoflags |= Geometry::NATIVE;
|
||||||
|
InstanceDataHeader *header = new InstanceDataHeader;
|
||||||
|
MeshHeader *meshh = geo->meshHeader;
|
||||||
|
geo->instData = header;
|
||||||
|
header->platform = PLATFORM_GL3;
|
||||||
|
|
||||||
|
header->serialNumber = 0;
|
||||||
|
header->numMeshes = meshh->numMeshes;
|
||||||
|
header->primType = meshh->flags == 1 ? GL_TRIANGLE_STRIP : GL_TRIANGLES;
|
||||||
|
header->totalNumVertex = geo->numVertices;
|
||||||
|
header->totalNumIndex = meshh->totalIndices;
|
||||||
|
header->inst = new InstanceData[header->numMeshes];
|
||||||
|
|
||||||
|
header->indexBuffer = new uint16[header->totalNumIndex];
|
||||||
|
InstanceData *inst = header->inst;
|
||||||
|
Mesh *mesh = meshh->mesh;
|
||||||
|
uint32 offset = 0;
|
||||||
|
for(uint32 i = 0; i < header->numMeshes; i++){
|
||||||
|
findMinVertAndNumVertices(mesh->indices, mesh->numIndices,
|
||||||
|
&inst->minVert, nil);
|
||||||
|
inst->numIndex = mesh->numIndices;
|
||||||
|
inst->material = mesh->material;
|
||||||
|
inst->vertexAlpha = 0;
|
||||||
|
inst->program = 0;
|
||||||
|
inst->offset = offset;
|
||||||
|
memcpy((uint8*)header->indexBuffer + inst->offset,
|
||||||
|
mesh->indices, inst->numIndex*2);
|
||||||
|
offset += inst->numIndex*2;
|
||||||
|
mesh++;
|
||||||
|
inst++;
|
||||||
|
}
|
||||||
|
|
||||||
|
header->vertexBuffer = nil;
|
||||||
|
header->numAttribs = 0;
|
||||||
|
header->attribDesc = nil;
|
||||||
|
header->ibo = 0;
|
||||||
|
header->vbo = 0;
|
||||||
|
|
||||||
|
glGenBuffers(1, &header->ibo);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, header->ibo);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, header->totalNumIndex*2,
|
||||||
|
header->indexBuffer, GL_STATIC_DRAW);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
|
||||||
|
pipe->instanceCB(geo, header);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
uninstance(rw::ObjPipeline *rwpipe, Atomic *atomic)
|
||||||
|
{
|
||||||
|
assert(0 && "can't uninstance");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
render(rw::ObjPipeline *rwpipe, Atomic *atomic)
|
||||||
|
{
|
||||||
|
ObjPipeline *pipe = (ObjPipeline*)rwpipe;
|
||||||
|
Geometry *geo = atomic->geometry;
|
||||||
|
if((geo->geoflags & Geometry::NATIVE) == 0)
|
||||||
|
pipe->instance(atomic);
|
||||||
|
assert(geo->instData != nil);
|
||||||
|
assert(geo->instData->platform == PLATFORM_GL3);
|
||||||
|
if(pipe->renderCB)
|
||||||
|
pipe->renderCB(atomic, (InstanceDataHeader*)geo->instData);
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjPipeline::ObjPipeline(uint32 platform)
|
||||||
|
: rw::ObjPipeline(platform)
|
||||||
|
{
|
||||||
|
this->impl.instance = gl3::instance;
|
||||||
|
this->impl.uninstance = gl3::uninstance;
|
||||||
|
this->impl.render = gl3::render;
|
||||||
|
this->instanceCB = nil;
|
||||||
|
this->uninstanceCB = nil;
|
||||||
|
this->renderCB = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
defaultInstanceCB(Geometry *geo, InstanceDataHeader *header)
|
||||||
|
{
|
||||||
|
AttribDesc attribs[12], *a;
|
||||||
|
uint32 stride;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Create attribute descriptions
|
||||||
|
//
|
||||||
|
a = attribs;
|
||||||
|
stride = 0;
|
||||||
|
|
||||||
|
// Positions
|
||||||
|
a->index = ATTRIB_POS;
|
||||||
|
a->size = 3;
|
||||||
|
a->type = GL_FLOAT;
|
||||||
|
a->normalized = GL_FALSE;
|
||||||
|
a->offset = stride;
|
||||||
|
stride += 12;
|
||||||
|
a++;
|
||||||
|
|
||||||
|
// Normals
|
||||||
|
// TODO: compress
|
||||||
|
bool hasNormals = !!(geo->geoflags & Geometry::NORMALS);
|
||||||
|
if(hasNormals){
|
||||||
|
a->index = ATTRIB_NORMAL;
|
||||||
|
a->size = 3;
|
||||||
|
a->type = GL_FLOAT;
|
||||||
|
a->normalized = GL_FALSE;
|
||||||
|
a->offset = stride;
|
||||||
|
stride += 12;
|
||||||
|
a++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prelighting
|
||||||
|
bool isPrelit = !!(geo->geoflags & Geometry::PRELIT);
|
||||||
|
if(isPrelit){
|
||||||
|
a->index = ATTRIB_COLOR;
|
||||||
|
a->size = 4;
|
||||||
|
a->type = GL_UNSIGNED_BYTE;
|
||||||
|
a->normalized = GL_TRUE;
|
||||||
|
a->offset = stride;
|
||||||
|
stride += 4;
|
||||||
|
a++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Texture coordinates
|
||||||
|
for(int32 n = 0; n < geo->numTexCoordSets; n++){
|
||||||
|
a->index = ATTRIB_TEXCOORDS0+n;
|
||||||
|
a->size = 2;
|
||||||
|
a->type = GL_FLOAT;
|
||||||
|
a->normalized = GL_FALSE;
|
||||||
|
a->offset = stride;
|
||||||
|
stride += 8;
|
||||||
|
a++;
|
||||||
|
}
|
||||||
|
|
||||||
|
header->numAttribs = a - attribs;
|
||||||
|
for(a = attribs; a != &attribs[header->numAttribs]; a++)
|
||||||
|
a->stride = stride;
|
||||||
|
header->attribDesc = new AttribDesc[header->numAttribs];
|
||||||
|
memcpy(header->attribDesc, attribs,
|
||||||
|
header->numAttribs*sizeof(AttribDesc));
|
||||||
|
|
||||||
|
//
|
||||||
|
// Allocate and fill vertex buffer
|
||||||
|
//
|
||||||
|
uint8 *verts = new uint8[header->totalNumVertex*stride];
|
||||||
|
header->vertexBuffer = verts;
|
||||||
|
|
||||||
|
// Positions
|
||||||
|
for(a = attribs; a->index != ATTRIB_POS; a++)
|
||||||
|
;
|
||||||
|
instV3d(VERT_FLOAT3, verts + a->offset,
|
||||||
|
geo->morphTargets[0].vertices,
|
||||||
|
header->totalNumVertex, a->stride);
|
||||||
|
|
||||||
|
// Normals
|
||||||
|
if(hasNormals){
|
||||||
|
for(a = attribs; a->index != ATTRIB_NORMAL; a++)
|
||||||
|
;
|
||||||
|
instV3d(VERT_FLOAT3, verts + a->offset,
|
||||||
|
geo->morphTargets[0].normals,
|
||||||
|
header->totalNumVertex, a->stride);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prelighting
|
||||||
|
if(isPrelit){
|
||||||
|
for(a = attribs; a->index != ATTRIB_COLOR; a++)
|
||||||
|
;
|
||||||
|
instColor(VERT_RGBA, verts + a->offset,
|
||||||
|
geo->colors,
|
||||||
|
header->totalNumVertex, a->stride);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Texture coordinates
|
||||||
|
for(int32 n = 0; n < geo->numTexCoordSets; n++){
|
||||||
|
for(a = attribs; a->index != ATTRIB_TEXCOORDS0+n; a++)
|
||||||
|
;
|
||||||
|
instV2d(VERT_FLOAT2, verts + a->offset,
|
||||||
|
geo->texCoords[n],
|
||||||
|
header->totalNumVertex, a->stride);
|
||||||
|
}
|
||||||
|
|
||||||
|
glGenBuffers(1, &header->vbo);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, header->vbo);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, header->totalNumVertex*stride,
|
||||||
|
header->vertexBuffer, GL_STATIC_DRAW);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
defaultUninstanceCB(Geometry *geo, InstanceDataHeader *header)
|
||||||
|
{
|
||||||
|
assert(0 && "can't uninstance");
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjPipeline*
|
||||||
|
makeDefaultPipeline(void)
|
||||||
|
{
|
||||||
|
ObjPipeline *pipe = new ObjPipeline(PLATFORM_GL3);
|
||||||
|
pipe->instanceCB = defaultInstanceCB;
|
||||||
|
pipe->uninstanceCB = defaultUninstanceCB;
|
||||||
|
pipe->renderCB = defaultRenderCB;
|
||||||
|
return pipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjPipeline*
|
||||||
|
makeSkinPipeline(void)
|
||||||
|
{
|
||||||
|
ObjPipeline *pipe = new ObjPipeline(PLATFORM_GL3);
|
||||||
|
pipe->instanceCB = defaultInstanceCB;
|
||||||
|
pipe->uninstanceCB = defaultUninstanceCB;
|
||||||
|
pipe->renderCB = defaultRenderCB;
|
||||||
|
pipe->pluginID = ID_SKIN;
|
||||||
|
pipe->pluginData = 1;
|
||||||
|
return pipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjPipeline*
|
||||||
|
makeMatFXPipeline(void)
|
||||||
|
{
|
||||||
|
ObjPipeline *pipe = new ObjPipeline(PLATFORM_GL3);
|
||||||
|
pipe->instanceCB = defaultInstanceCB;
|
||||||
|
pipe->uninstanceCB = defaultUninstanceCB;
|
||||||
|
pipe->renderCB = defaultRenderCB;
|
||||||
|
pipe->pluginID = ID_MATFX;
|
||||||
|
pipe->pluginData = 0;
|
||||||
|
return pipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
132
src/gl/gl3raster.cpp
Normal file
132
src/gl/gl3raster.cpp
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "../rwbase.h"
|
||||||
|
#include "../rwerror.h"
|
||||||
|
#include "../rwplg.h"
|
||||||
|
#include "../rwpipeline.h"
|
||||||
|
#include "../rwobjects.h"
|
||||||
|
#include "../rwengine.h"
|
||||||
|
#include "../rwplugins.h"
|
||||||
|
#ifdef RW_OPENGL
|
||||||
|
#include <GL/glew.h>
|
||||||
|
#endif
|
||||||
|
#include "rwgl3.h"
|
||||||
|
#include "rwgl3shader.h"
|
||||||
|
|
||||||
|
namespace rw {
|
||||||
|
namespace gl3 {
|
||||||
|
|
||||||
|
int32 nativeRasterOffset;
|
||||||
|
|
||||||
|
static void
|
||||||
|
rasterCreate(Raster *raster)
|
||||||
|
{
|
||||||
|
Gl3Raster *natras = PLUGINOFFSET(Gl3Raster, raster, nativeRasterOffset);
|
||||||
|
if(raster->flags & Raster::DONTALLOCATE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
assert(raster->depth == 32);
|
||||||
|
|
||||||
|
#ifdef RW_OPENGL
|
||||||
|
glGenTextures(1, &natras->texid);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, natras->texid);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, raster->width, raster->height,
|
||||||
|
0, GL_RGBA, GL_UNSIGNED_BYTE, nil);
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8*
|
||||||
|
rasterLock(Raster*, int32 level)
|
||||||
|
{
|
||||||
|
printf("locking\n");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rasterUnlock(Raster*, int32)
|
||||||
|
{
|
||||||
|
printf("unlocking\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32
|
||||||
|
rasterNumLevels(Raster*)
|
||||||
|
{
|
||||||
|
printf("numlevels\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rasterFromImage(Raster *raster, Image *image)
|
||||||
|
{
|
||||||
|
int32 format;
|
||||||
|
Gl3Raster *natras = PLUGINOFFSET(Gl3Raster, raster, nativeRasterOffset);
|
||||||
|
|
||||||
|
format = Raster::C8888;
|
||||||
|
format |= 4;
|
||||||
|
|
||||||
|
raster->type = format & 0x7;
|
||||||
|
raster->flags = format & 0xF8;
|
||||||
|
raster->format = format & 0xFF00;
|
||||||
|
rasterCreate(raster);
|
||||||
|
|
||||||
|
assert(image->depth == 32);
|
||||||
|
|
||||||
|
natras->hasAlpha = image->hasAlpha();
|
||||||
|
|
||||||
|
#ifdef RW_OPENGL
|
||||||
|
glBindTexture(GL_TEXTURE_2D, natras->texid);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, raster->width, raster->height,
|
||||||
|
0, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void*
|
||||||
|
createNativeRaster(void *object, int32 offset, int32)
|
||||||
|
{
|
||||||
|
Gl3Raster *ras = PLUGINOFFSET(Gl3Raster, object, offset);
|
||||||
|
ras->texid = 0;
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void*
|
||||||
|
destroyNativeRaster(void *object, int32, int32)
|
||||||
|
{
|
||||||
|
//Gl3Raster *ras = PLUGINOFFSET(Gl3Raster, object, offset);
|
||||||
|
// TODO
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void*
|
||||||
|
copyNativeRaster(void *dst, void *, int32 offset, int32)
|
||||||
|
{
|
||||||
|
Gl3Raster *d = PLUGINOFFSET(Gl3Raster, dst, offset);
|
||||||
|
d->texid = 0;
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
registerNativeRaster(void)
|
||||||
|
{
|
||||||
|
nativeRasterOffset = Raster::registerPlugin(sizeof(Gl3Raster),
|
||||||
|
0x12340000 | PLATFORM_GL3,
|
||||||
|
createNativeRaster,
|
||||||
|
destroyNativeRaster,
|
||||||
|
copyNativeRaster);
|
||||||
|
driver[PLATFORM_GL3].rasterNativeOffset = nativeRasterOffset;
|
||||||
|
driver[PLATFORM_GL3].rasterCreate = rasterCreate;
|
||||||
|
driver[PLATFORM_GL3].rasterLock = rasterLock;
|
||||||
|
driver[PLATFORM_GL3].rasterUnlock = rasterUnlock;
|
||||||
|
driver[PLATFORM_GL3].rasterNumLevels = rasterNumLevels;
|
||||||
|
driver[PLATFORM_GL3].rasterFromImage = rasterFromImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
359
src/gl/gl3render.cpp
Normal file
359
src/gl/gl3render.cpp
Normal file
@ -0,0 +1,359 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "../rwbase.h"
|
||||||
|
#include "../rwerror.h"
|
||||||
|
#include "../rwplg.h"
|
||||||
|
#include "../rwpipeline.h"
|
||||||
|
#include "../rwobjects.h"
|
||||||
|
#include "../rwengine.h"
|
||||||
|
#include "../rwplugins.h"
|
||||||
|
#ifdef RW_OPENGL
|
||||||
|
#include <GL/glew.h>
|
||||||
|
#include "rwgl3.h"
|
||||||
|
#include "rwgl3shader.h"
|
||||||
|
|
||||||
|
namespace rw {
|
||||||
|
namespace gl3 {
|
||||||
|
|
||||||
|
struct UniformScene
|
||||||
|
{
|
||||||
|
float32 proj[16];
|
||||||
|
float32 view[16];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UniformLight
|
||||||
|
{
|
||||||
|
V3d position;
|
||||||
|
float32 w;
|
||||||
|
V3d direction;
|
||||||
|
int32 pad1;
|
||||||
|
RGBAf color;
|
||||||
|
float32 radius;
|
||||||
|
float32 minusCosAngle;
|
||||||
|
int32 pad2[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MAX_LIGHTS 8
|
||||||
|
|
||||||
|
struct UniformObject
|
||||||
|
{
|
||||||
|
Matrix world;
|
||||||
|
RGBAf ambLight;
|
||||||
|
int32 numLights;
|
||||||
|
int32 pad[3];
|
||||||
|
UniformLight lights[MAX_LIGHTS];
|
||||||
|
};
|
||||||
|
|
||||||
|
GLuint vao;
|
||||||
|
GLuint ubo_scene, ubo_object;
|
||||||
|
GLuint whitetex;
|
||||||
|
UniformScene uniformScene;
|
||||||
|
UniformObject uniformObject;
|
||||||
|
|
||||||
|
void
|
||||||
|
beginUpdate(Camera *cam)
|
||||||
|
{
|
||||||
|
float view[16], proj[16];
|
||||||
|
// View Matrix
|
||||||
|
Matrix inv;
|
||||||
|
Matrix::invert(&inv, cam->getFrame()->getLTM());
|
||||||
|
// Since we're looking into positive Z,
|
||||||
|
// flip X to ge a left handed view space.
|
||||||
|
view[0] = -inv.right.x;
|
||||||
|
view[1] = inv.right.y;
|
||||||
|
view[2] = inv.right.z;
|
||||||
|
view[3] = 0.0f;
|
||||||
|
view[4] = -inv.up.x;
|
||||||
|
view[5] = inv.up.y;
|
||||||
|
view[6] = inv.up.z;
|
||||||
|
view[7] = 0.0f;
|
||||||
|
view[8] = -inv.at.x;
|
||||||
|
view[9] = inv.at.y;
|
||||||
|
view[10] = inv.at.z;
|
||||||
|
view[11] = 0.0f;
|
||||||
|
view[12] = -inv.pos.x;
|
||||||
|
view[13] = inv.pos.y;
|
||||||
|
view[14] = inv.pos.z;
|
||||||
|
view[15] = 1.0f;
|
||||||
|
setViewMatrix(view);
|
||||||
|
|
||||||
|
// Projection Matrix
|
||||||
|
float32 invwx = 1.0f/cam->viewWindow.x;
|
||||||
|
float32 invwy = 1.0f/cam->viewWindow.y;
|
||||||
|
float32 invz = 1.0f/(cam->farPlane-cam->nearPlane);
|
||||||
|
|
||||||
|
proj[0] = invwx;
|
||||||
|
proj[1] = 0.0f;
|
||||||
|
proj[2] = 0.0f;
|
||||||
|
proj[3] = 0.0f;
|
||||||
|
|
||||||
|
proj[4] = 0.0f;
|
||||||
|
proj[5] = invwy;
|
||||||
|
proj[6] = 0.0f;
|
||||||
|
proj[7] = 0.0f;
|
||||||
|
|
||||||
|
if(cam->projection == Camera::PERSPECTIVE){
|
||||||
|
proj[8] = cam->viewOffset.x*invwx;
|
||||||
|
proj[9] = cam->viewOffset.y*invwy;
|
||||||
|
proj[10] = (cam->farPlane+cam->nearPlane)*invz;
|
||||||
|
proj[11] = 1.0f;
|
||||||
|
|
||||||
|
proj[12] = 0.0f;
|
||||||
|
proj[13] = 0.0f;
|
||||||
|
proj[14] = -2.0f*cam->nearPlane*cam->farPlane*invz;
|
||||||
|
proj[15] = 0.0f;
|
||||||
|
}else{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
setProjectionMatrix(proj);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
initializeRender(void)
|
||||||
|
{
|
||||||
|
driver[PLATFORM_GL3].beginUpdate = beginUpdate;
|
||||||
|
|
||||||
|
glClearColor(0.25, 0.25, 0.25, 1.0);
|
||||||
|
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
glDepthFunc(GL_LESS);
|
||||||
|
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
glGenVertexArrays(1, &vao);
|
||||||
|
glBindVertexArray(vao);
|
||||||
|
|
||||||
|
registerBlock("Scene");
|
||||||
|
registerBlock("Object");
|
||||||
|
registerUniform("u_matColor");
|
||||||
|
registerUniform("u_surfaceProps");
|
||||||
|
|
||||||
|
glGenBuffers(1, &ubo_scene);
|
||||||
|
glBindBuffer(GL_UNIFORM_BUFFER, ubo_scene);
|
||||||
|
glBindBufferBase(GL_UNIFORM_BUFFER, gl3::findBlock("Scene"), ubo_scene);
|
||||||
|
glBufferData(GL_UNIFORM_BUFFER, sizeof(UniformScene), &uniformScene,
|
||||||
|
GL_DYNAMIC_DRAW);
|
||||||
|
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||||
|
|
||||||
|
|
||||||
|
glGenBuffers(1, &ubo_object);
|
||||||
|
glBindBuffer(GL_UNIFORM_BUFFER, ubo_object);
|
||||||
|
glBindBufferBase(GL_UNIFORM_BUFFER, gl3::findBlock("Object"), ubo_object);
|
||||||
|
glBufferData(GL_UNIFORM_BUFFER, sizeof(UniformObject), &uniformObject,
|
||||||
|
GL_DYNAMIC_DRAW);
|
||||||
|
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||||
|
|
||||||
|
|
||||||
|
byte whitepixel[4] = {0xFF, 0xFF, 0xFF, 0xFF};
|
||||||
|
glGenTextures(1, &whitetex);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, whitetex);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1,
|
||||||
|
0, GL_RGBA, GL_UNSIGNED_BYTE, &whitepixel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
setAttribPointers(InstanceDataHeader *header)
|
||||||
|
{
|
||||||
|
AttribDesc *a;
|
||||||
|
for(a = header->attribDesc;
|
||||||
|
a != &header->attribDesc[header->numAttribs];
|
||||||
|
a++){
|
||||||
|
glEnableVertexAttribArray(a->index);
|
||||||
|
glVertexAttribPointer(a->index, a->size, a->type, a->normalized,
|
||||||
|
a->stride, (void*)(uint64)a->offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool32 sceneDirty = 1;
|
||||||
|
static bool32 objectDirty = 1;
|
||||||
|
|
||||||
|
void
|
||||||
|
setWorldMatrix(Matrix *mat)
|
||||||
|
{
|
||||||
|
uniformObject.world = *mat;
|
||||||
|
objectDirty = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
setAmbientLight(RGBAf *amb)
|
||||||
|
{
|
||||||
|
uniformObject.ambLight = *amb;
|
||||||
|
objectDirty = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
setNumLights(int32 n)
|
||||||
|
{
|
||||||
|
uniformObject.numLights = n;
|
||||||
|
objectDirty = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
setLight(int32 n, Light *light)
|
||||||
|
{
|
||||||
|
UniformLight *l;
|
||||||
|
Frame *f;
|
||||||
|
Matrix *m;
|
||||||
|
|
||||||
|
l = &uniformObject.lights[n];
|
||||||
|
f = light->getFrame();
|
||||||
|
if(f){
|
||||||
|
m = f->getLTM();
|
||||||
|
l->position = m->pos;
|
||||||
|
l->direction = m->at;
|
||||||
|
}
|
||||||
|
// light has position
|
||||||
|
l->w = light->getType() >= Light::POINT ? 1.0f : 0.0;
|
||||||
|
l->color = light->color;
|
||||||
|
l->radius = light->radius;
|
||||||
|
l->minusCosAngle = light->minusCosAngle;
|
||||||
|
objectDirty = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
setProjectionMatrix(float32 *mat)
|
||||||
|
{
|
||||||
|
memcpy(&uniformScene.proj, mat, 64);
|
||||||
|
sceneDirty = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
setViewMatrix(float32 *mat)
|
||||||
|
{
|
||||||
|
memcpy(&uniformScene.view, mat, 64);
|
||||||
|
sceneDirty = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool32 vertexAlpha;
|
||||||
|
static bool32 textureAlpha;
|
||||||
|
|
||||||
|
void
|
||||||
|
setTexture(int32 n, Texture *tex)
|
||||||
|
{
|
||||||
|
bool32 alpha;
|
||||||
|
glActiveTexture(GL_TEXTURE0+n);
|
||||||
|
if(tex == nil){
|
||||||
|
glBindTexture(GL_TEXTURE_2D, whitetex);
|
||||||
|
alpha = 0;
|
||||||
|
}else{
|
||||||
|
Gl3Raster *natras = PLUGINOFFSET(Gl3Raster, tex->raster,
|
||||||
|
nativeRasterOffset);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, natras->texid);
|
||||||
|
alpha = natras->hasAlpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(textureAlpha == alpha)
|
||||||
|
return;
|
||||||
|
if(alpha)
|
||||||
|
/*printf("enable\n"),*/ glEnable(GL_BLEND);
|
||||||
|
else if(!vertexAlpha)
|
||||||
|
/*printf("disable\n"),*/ glDisable(GL_BLEND);
|
||||||
|
textureAlpha = alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
setVertexAlpha(bool32 alpha)
|
||||||
|
{
|
||||||
|
if(vertexAlpha == alpha)
|
||||||
|
return;
|
||||||
|
if(alpha)
|
||||||
|
/*printf("enable\n"),*/ glEnable(GL_BLEND);
|
||||||
|
else if(!textureAlpha)
|
||||||
|
/*printf("disable\n"),*/ glDisable(GL_BLEND);
|
||||||
|
vertexAlpha = alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
flushCache(void)
|
||||||
|
{
|
||||||
|
if(objectDirty){
|
||||||
|
glBindBuffer(GL_UNIFORM_BUFFER, ubo_object);
|
||||||
|
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(UniformObject),
|
||||||
|
&uniformObject);
|
||||||
|
objectDirty = 0;
|
||||||
|
}
|
||||||
|
if(sceneDirty){
|
||||||
|
glBindBuffer(GL_UNIFORM_BUFFER, ubo_scene);
|
||||||
|
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(UniformScene),
|
||||||
|
&uniformScene);
|
||||||
|
sceneDirty = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lightingCB(void)
|
||||||
|
{
|
||||||
|
World *world;
|
||||||
|
RGBAf ambLight = (RGBAf){0.0, 0.0, 0.0, 1.0};
|
||||||
|
int n = 0;
|
||||||
|
|
||||||
|
world = (World*)engine.currentWorld;
|
||||||
|
// only unpositioned lights right now
|
||||||
|
FORLIST(lnk, world->directionalLights){
|
||||||
|
Light *l = Light::fromWorld(lnk);
|
||||||
|
if(l->getType() == Light::DIRECTIONAL){
|
||||||
|
if(n >= MAX_LIGHTS)
|
||||||
|
continue;
|
||||||
|
setLight(n++, l);
|
||||||
|
}else if(l->getType() == Light::AMBIENT){
|
||||||
|
ambLight.red += l->color.red;
|
||||||
|
ambLight.green += l->color.green;
|
||||||
|
ambLight.blue += l->color.blue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setNumLights(n);
|
||||||
|
setAmbientLight(&ambLight);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
defaultRenderCB(Atomic *atomic, InstanceDataHeader *header)
|
||||||
|
{
|
||||||
|
setWorldMatrix(atomic->getFrame()->getLTM());
|
||||||
|
lightingCB();
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, header->vbo);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, header->ibo);
|
||||||
|
setAttribPointers(header);
|
||||||
|
|
||||||
|
Material *m;
|
||||||
|
RGBAf col;
|
||||||
|
GLfloat surfProps[4];
|
||||||
|
int id;
|
||||||
|
InstanceData *inst = header->inst;
|
||||||
|
int32 n = header->numMeshes;
|
||||||
|
|
||||||
|
while(n--){
|
||||||
|
m = inst->material;
|
||||||
|
|
||||||
|
#define U(s) currentShader->uniformLocations[findUniform(s)]
|
||||||
|
|
||||||
|
convColor(&col, &m->color);
|
||||||
|
glUniform4fv(U("u_matColor"), 1, (GLfloat*)&col);
|
||||||
|
|
||||||
|
surfProps[0] = m->surfaceProps.ambient;
|
||||||
|
surfProps[1] = m->surfaceProps.specular;
|
||||||
|
surfProps[2] = m->surfaceProps.diffuse;
|
||||||
|
surfProps[3] = 0.0f;
|
||||||
|
glUniform4fv(U("u_surfaceProps"), 1, surfProps);
|
||||||
|
|
||||||
|
setTexture(0, m->texture);
|
||||||
|
|
||||||
|
setVertexAlpha(inst->vertexAlpha || m->color.alpha != 0xFF);
|
||||||
|
|
||||||
|
flushCache();
|
||||||
|
glDrawElements(header->primType, inst->numIndex,
|
||||||
|
GL_UNSIGNED_SHORT, (void*)(uintptr)inst->offset);
|
||||||
|
inst++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
193
src/gl/gl3shader.cpp
Normal file
193
src/gl/gl3shader.cpp
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "../rwbase.h"
|
||||||
|
#include "../rwerror.h"
|
||||||
|
#include "../rwplg.h"
|
||||||
|
#include "../rwpipeline.h"
|
||||||
|
#include "../rwobjects.h"
|
||||||
|
#include "../rwengine.h"
|
||||||
|
#include "../rwplugins.h"
|
||||||
|
#ifdef RW_OPENGL
|
||||||
|
#include <GL/glew.h>
|
||||||
|
#include "rwgl3.h"
|
||||||
|
#include "rwgl3shader.h"
|
||||||
|
|
||||||
|
namespace rw {
|
||||||
|
namespace gl3 {
|
||||||
|
|
||||||
|
UniformRegistry uniformRegistry;
|
||||||
|
|
||||||
|
int
|
||||||
|
registerUniform(const char *name)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
i = findUniform(name);
|
||||||
|
if(i >= 0) return i;
|
||||||
|
uniformRegistry.uniformNames[uniformRegistry.numUniforms] = strdup(name);
|
||||||
|
return uniformRegistry.numUniforms++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
findUniform(const char *name)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < uniformRegistry.numUniforms; i++)
|
||||||
|
if(strcmp(name, uniformRegistry.uniformNames[i]) == 0)
|
||||||
|
return i;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
registerBlock(const char *name)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
i = findBlock(name);
|
||||||
|
if(i >= 0) return i;
|
||||||
|
uniformRegistry.blockNames[uniformRegistry.numBlocks] = strdup(name);
|
||||||
|
return uniformRegistry.numBlocks++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
findBlock(const char *name)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < uniformRegistry.numBlocks; i++)
|
||||||
|
if(strcmp(name, uniformRegistry.blockNames[i]) == 0)
|
||||||
|
return i;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Shader *currentShader;
|
||||||
|
|
||||||
|
// TODO: maybe make this public somewhere?
|
||||||
|
static char*
|
||||||
|
loadfile(const char *path)
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
char *buf;
|
||||||
|
long len;
|
||||||
|
|
||||||
|
if(f = fopen(path, "rb"), f == nil){
|
||||||
|
fprintf(stderr, "Couldn't open file %s\n", path);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
len = ftell(f);
|
||||||
|
buf = (char*)malloc(len+1);
|
||||||
|
rewind(f);
|
||||||
|
fread(buf, 1, len, f);
|
||||||
|
buf[len] = '\0';
|
||||||
|
fclose(f);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
compileshader(GLenum type, const char *src, GLuint *shader)
|
||||||
|
{
|
||||||
|
GLint shdr, success;
|
||||||
|
GLint len;
|
||||||
|
char *log;
|
||||||
|
|
||||||
|
shdr = glCreateShader(type);
|
||||||
|
glShaderSource(shdr, 1, &src, nil);
|
||||||
|
glCompileShader(shdr);
|
||||||
|
glGetShaderiv(shdr, GL_COMPILE_STATUS, &success);
|
||||||
|
if(!success){
|
||||||
|
fprintf(stderr, "Error in %s shader\n",
|
||||||
|
type == GL_VERTEX_SHADER ? "vertex" : "fragment");
|
||||||
|
glGetShaderiv(shdr, GL_INFO_LOG_LENGTH, &len);
|
||||||
|
log = (char*)malloc(len);
|
||||||
|
glGetShaderInfoLog(shdr, len, nil, log);
|
||||||
|
fprintf(stderr, "%s\n", log);
|
||||||
|
free(log);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
*shader = shdr;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
linkprogram(GLint vs, GLint fs, GLuint *program)
|
||||||
|
{
|
||||||
|
GLint prog, success;
|
||||||
|
GLint len;
|
||||||
|
char *log;
|
||||||
|
|
||||||
|
prog = glCreateProgram();
|
||||||
|
|
||||||
|
glAttachShader(prog, vs);
|
||||||
|
glAttachShader(prog, fs);
|
||||||
|
glLinkProgram(prog);
|
||||||
|
glGetProgramiv(prog, GL_LINK_STATUS, &success);
|
||||||
|
if(!success){
|
||||||
|
fprintf(stderr, "Error in program\n");
|
||||||
|
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &len);
|
||||||
|
log = (char*)malloc(len);
|
||||||
|
glGetProgramInfoLog(prog, len, nil, log);
|
||||||
|
fprintf(stderr, "%s\n", log);
|
||||||
|
free(log);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
*program = prog;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Shader*
|
||||||
|
Shader::fromFiles(const char *vspath, const char *fspath)
|
||||||
|
{
|
||||||
|
GLuint vs, fs, program;
|
||||||
|
int i;
|
||||||
|
char *src;
|
||||||
|
int fail;
|
||||||
|
|
||||||
|
src = loadfile(vspath);
|
||||||
|
fail = compileshader(GL_VERTEX_SHADER, src, &vs);
|
||||||
|
free(src);
|
||||||
|
if(fail)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
src = loadfile(fspath);
|
||||||
|
fail = compileshader(GL_FRAGMENT_SHADER, src, &fs);
|
||||||
|
free(src);
|
||||||
|
if(fail)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
fail = linkprogram(vs, fs, &program);
|
||||||
|
if(fail)
|
||||||
|
return nil;
|
||||||
|
glDeleteProgram(vs);
|
||||||
|
glDeleteProgram(fs);
|
||||||
|
|
||||||
|
Shader *sh = new Shader;
|
||||||
|
|
||||||
|
// set uniform block binding
|
||||||
|
for(i = 0; i < uniformRegistry.numBlocks; i++){
|
||||||
|
int idx = glGetUniformBlockIndex(program,
|
||||||
|
uniformRegistry.blockNames[i]);
|
||||||
|
if(idx >= 0)
|
||||||
|
glUniformBlockBinding(program, idx, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// query uniform locations
|
||||||
|
sh->program = program;
|
||||||
|
sh->uniformLocations = new GLint[uniformRegistry.numUniforms];
|
||||||
|
for(i = 0; i < uniformRegistry.numUniforms; i++)
|
||||||
|
sh->uniformLocations[i] = glGetUniformLocation(program,
|
||||||
|
uniformRegistry.uniformNames[i]);
|
||||||
|
|
||||||
|
return sh;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Shader::use(void)
|
||||||
|
{
|
||||||
|
glUseProgram(this->program);
|
||||||
|
currentShader = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
108
src/gl/rwgl3.h
Normal file
108
src/gl/rwgl3.h
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
namespace rw {
|
||||||
|
namespace gl3 {
|
||||||
|
|
||||||
|
void initializePlatform(void);
|
||||||
|
void initializeRender(void);
|
||||||
|
|
||||||
|
// arguments to glVertexAttribPointer basically
|
||||||
|
struct AttribDesc
|
||||||
|
{
|
||||||
|
uint32 index;
|
||||||
|
int32 type;
|
||||||
|
bool32 normalized;
|
||||||
|
int32 size;
|
||||||
|
uint32 stride;
|
||||||
|
uint32 offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum AttribIndices
|
||||||
|
{
|
||||||
|
ATTRIB_POS = 0,
|
||||||
|
ATTRIB_NORMAL,
|
||||||
|
ATTRIB_COLOR,
|
||||||
|
ATTRIB_TEXCOORDS0,
|
||||||
|
ATTRIB_TEXCOORDS1,
|
||||||
|
ATTRIB_TEXCOORDS2,
|
||||||
|
ATTRIB_TEXCOORDS3,
|
||||||
|
ATTRIB_TEXCOORDS4,
|
||||||
|
ATTRIB_TEXCOORDS5,
|
||||||
|
ATTRIB_TEXCOORDS6,
|
||||||
|
ATTRIB_TEXCOORDS7,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct InstanceData
|
||||||
|
{
|
||||||
|
uint32 numIndex;
|
||||||
|
uint32 minVert; // not used for rendering
|
||||||
|
Material *material;
|
||||||
|
bool32 vertexAlpha;
|
||||||
|
uint32 program;
|
||||||
|
uint32 offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct InstanceDataHeader : rw::InstanceDataHeader
|
||||||
|
{
|
||||||
|
uint32 serialNumber; // not really needed right now
|
||||||
|
uint32 numMeshes;
|
||||||
|
uint16 *indexBuffer;
|
||||||
|
uint32 primType;
|
||||||
|
uint8 *vertexBuffer;
|
||||||
|
int32 numAttribs;
|
||||||
|
AttribDesc *attribDesc;
|
||||||
|
uint32 totalNumIndex;
|
||||||
|
uint32 totalNumVertex;
|
||||||
|
|
||||||
|
uint32 ibo;
|
||||||
|
uint32 vbo; // or 2?
|
||||||
|
|
||||||
|
InstanceData *inst;
|
||||||
|
};
|
||||||
|
|
||||||
|
void setAttribPointers(InstanceDataHeader *header);
|
||||||
|
|
||||||
|
// per Scene
|
||||||
|
void setProjectionMatrix(float32*);
|
||||||
|
void setViewMatrix(float32*);
|
||||||
|
|
||||||
|
// per Object
|
||||||
|
void setWorldMatrix(Matrix*);
|
||||||
|
void setAmbientLight(RGBAf*);
|
||||||
|
void setNumLights(int32 n);
|
||||||
|
void setLight(int32 n, Light*);
|
||||||
|
|
||||||
|
// per Mesh
|
||||||
|
void setTexture(int32 n, Texture *tex);
|
||||||
|
void setVertexAlpha(bool32 enable);
|
||||||
|
|
||||||
|
class ObjPipeline : public rw::ObjPipeline
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void (*instanceCB)(Geometry *geo, InstanceDataHeader *header);
|
||||||
|
void (*uninstanceCB)(Geometry *geo, InstanceDataHeader *header);
|
||||||
|
void (*renderCB)(Atomic *atomic, InstanceDataHeader *header);
|
||||||
|
|
||||||
|
ObjPipeline(uint32 platform);
|
||||||
|
};
|
||||||
|
|
||||||
|
void defaultInstanceCB(Geometry *geo, InstanceDataHeader *header);
|
||||||
|
void defaultUninstanceCB(Geometry *geo, InstanceDataHeader *header);
|
||||||
|
void defaultRenderCB(Atomic *atomic, InstanceDataHeader *header);
|
||||||
|
|
||||||
|
ObjPipeline *makeDefaultPipeline(void);
|
||||||
|
ObjPipeline *makeSkinPipeline(void);
|
||||||
|
ObjPipeline *makeMatFXPipeline(void);
|
||||||
|
|
||||||
|
// Native Texture and Raster
|
||||||
|
|
||||||
|
extern int32 nativeRasterOffset;
|
||||||
|
|
||||||
|
struct Gl3Raster
|
||||||
|
{
|
||||||
|
uint32 texid;
|
||||||
|
bool32 hasAlpha;
|
||||||
|
};
|
||||||
|
|
||||||
|
void registerNativeRaster(void);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
44
src/gl/rwgl3shader.h
Normal file
44
src/gl/rwgl3shader.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#ifdef RW_OPENGL
|
||||||
|
|
||||||
|
namespace rw {
|
||||||
|
namespace gl3 {
|
||||||
|
|
||||||
|
// TODO: make this dynamic
|
||||||
|
enum {
|
||||||
|
MAX_UNIFORMS = 20,
|
||||||
|
MAX_BLOCKS = 20
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UniformRegistry
|
||||||
|
{
|
||||||
|
int numUniforms;
|
||||||
|
char *uniformNames[MAX_UNIFORMS];
|
||||||
|
|
||||||
|
int numBlocks;
|
||||||
|
char *blockNames[MAX_BLOCKS];
|
||||||
|
};
|
||||||
|
|
||||||
|
int registerUniform(const char *name);
|
||||||
|
int findUniform(const char *name);
|
||||||
|
int registerBlock(const char *name);
|
||||||
|
int findBlock(const char *name);
|
||||||
|
|
||||||
|
extern UniformRegistry uniformRegistry;
|
||||||
|
|
||||||
|
class Shader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GLuint program;
|
||||||
|
// same number of elements as UniformRegistry::numUniforms
|
||||||
|
GLint *uniformLocations;
|
||||||
|
|
||||||
|
static Shader *fromFiles(const char *vs, const char *fs);
|
||||||
|
void use(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern Shader *currentShader;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
83
src/gl/rwwdgl.h
Normal file
83
src/gl/rwwdgl.h
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
|
||||||
|
namespace rw {
|
||||||
|
namespace wdgl {
|
||||||
|
|
||||||
|
// NOTE: This is not really RW OpenGL! It's specific to WarDrum's GTA ports
|
||||||
|
|
||||||
|
void initializePlatform(void);
|
||||||
|
|
||||||
|
struct AttribDesc
|
||||||
|
{
|
||||||
|
// arguments to glVertexAttribPointer (should use OpenGL types here)
|
||||||
|
// Vertex = 0, TexCoord, Normal, Color, Weight, Bone Index, Extra Color
|
||||||
|
uint32 index;
|
||||||
|
// float = 0, byte, ubyte, short, ushort
|
||||||
|
int32 type;
|
||||||
|
bool32 normalized;
|
||||||
|
int32 size;
|
||||||
|
uint32 stride;
|
||||||
|
uint32 offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct InstanceDataHeader : rw::InstanceDataHeader
|
||||||
|
{
|
||||||
|
int32 numAttribs;
|
||||||
|
AttribDesc *attribs;
|
||||||
|
uint32 dataSize;
|
||||||
|
uint8 *data;
|
||||||
|
|
||||||
|
// needed for rendering
|
||||||
|
uint32 vbo;
|
||||||
|
uint32 ibo;
|
||||||
|
};
|
||||||
|
|
||||||
|
// only RW_OPENGL
|
||||||
|
void uploadGeo(Geometry *geo);
|
||||||
|
void setAttribPointers(InstanceDataHeader *inst);
|
||||||
|
|
||||||
|
void packattrib(uint8 *dst, float32 *src, AttribDesc *a, float32 scale);
|
||||||
|
void unpackattrib(float *dst, uint8 *src, AttribDesc *a, float32 scale);
|
||||||
|
|
||||||
|
void *destroyNativeData(void *object, int32, int32);
|
||||||
|
Stream *readNativeData(Stream *stream, int32 len, void *object, int32, int32);
|
||||||
|
Stream *writeNativeData(Stream *stream, int32 len, void *object, int32, int32);
|
||||||
|
int32 getSizeNativeData(void *object, int32, int32);
|
||||||
|
void registerNativeDataPlugin(void);
|
||||||
|
|
||||||
|
void printPipeinfo(Atomic *a);
|
||||||
|
|
||||||
|
class ObjPipeline : public rw::ObjPipeline
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
uint32 numCustomAttribs;
|
||||||
|
uint32 (*instanceCB)(Geometry *g, int32 i, uint32 offset);
|
||||||
|
void (*uninstanceCB)(Geometry *g);
|
||||||
|
|
||||||
|
ObjPipeline(uint32 platform);
|
||||||
|
};
|
||||||
|
|
||||||
|
ObjPipeline *makeDefaultPipeline(void);
|
||||||
|
|
||||||
|
// Skin plugin
|
||||||
|
|
||||||
|
Stream *readNativeSkin(Stream *stream, int32, void *object, int32 offset);
|
||||||
|
Stream *writeNativeSkin(Stream *stream, int32 len, void *object, int32 offset);
|
||||||
|
int32 getSizeNativeSkin(void *object, int32 offset);
|
||||||
|
|
||||||
|
ObjPipeline *makeSkinPipeline(void);
|
||||||
|
|
||||||
|
ObjPipeline *makeMatFXPipeline(void);
|
||||||
|
|
||||||
|
// Raster
|
||||||
|
|
||||||
|
struct Texture : rw::Texture
|
||||||
|
{
|
||||||
|
void upload(void);
|
||||||
|
void bind(int n);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern int32 nativeRasterOffset;
|
||||||
|
void registerNativeRaster(void);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
793
src/gl/wdgl.cpp
Normal file
793
src/gl/wdgl.cpp
Normal file
@ -0,0 +1,793 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "../rwbase.h"
|
||||||
|
#include "../rwerror.h"
|
||||||
|
#include "../rwplg.h"
|
||||||
|
#include "../rwpipeline.h"
|
||||||
|
#include "../rwobjects.h"
|
||||||
|
#include "../rwengine.h"
|
||||||
|
#include "../rwplugins.h"
|
||||||
|
#include "rwwdgl.h"
|
||||||
|
|
||||||
|
#ifdef RW_OPENGL
|
||||||
|
#include <GL/glew.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PLUGIN_ID 2
|
||||||
|
|
||||||
|
namespace rw {
|
||||||
|
namespace wdgl {
|
||||||
|
|
||||||
|
void
|
||||||
|
initializePlatform(void)
|
||||||
|
{
|
||||||
|
driver[PLATFORM_WDGL].defaultPipeline = makeDefaultPipeline();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// VC
|
||||||
|
// 8733 0 0 0 3
|
||||||
|
// 45 1 0 0 2
|
||||||
|
// 8657 1 3 0 2
|
||||||
|
// 4610 2 1 1 3
|
||||||
|
// 4185 3 2 1 4
|
||||||
|
// 256 4 2 1 4
|
||||||
|
// 201 4 4 1 4
|
||||||
|
// 457 5 2 0 4
|
||||||
|
|
||||||
|
// SA
|
||||||
|
// 20303 0 0 0 3 vertices: 3 floats
|
||||||
|
// 53 1 0 0 2 texCoords: 2 floats
|
||||||
|
// 20043 1 3 0 2 texCoords: 2 shorts
|
||||||
|
// 6954 2 1 1 3 normal: 3 bytes normalized
|
||||||
|
// 13527 3 2 1 4 color: 4 ubytes normalized
|
||||||
|
// 196 4 2 1 4 weight: 4 ubytes normalized
|
||||||
|
// 225 4 4 1 4 weight: 4 ushorts normalized
|
||||||
|
// 421 5 2 0 4 indices: 4 ubytes
|
||||||
|
// 12887 6 2 1 4 extracolor:4 ubytes normalized
|
||||||
|
|
||||||
|
/*
|
||||||
|
static void
|
||||||
|
printAttribInfo(AttribDesc *attribs, int n)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < n; i++)
|
||||||
|
printf("%x %x %x %x\n",
|
||||||
|
attribs[i].index,
|
||||||
|
attribs[i].type,
|
||||||
|
attribs[i].normalized,
|
||||||
|
attribs[i].size);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef RW_OPENGL
|
||||||
|
void
|
||||||
|
uploadGeo(Geometry *geo)
|
||||||
|
{
|
||||||
|
InstanceDataHeader *inst = (InstanceDataHeader*)geo->instData;
|
||||||
|
MeshHeader *meshHeader = geo->meshHeader;
|
||||||
|
|
||||||
|
glGenBuffers(1, &inst->vbo);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, inst->vbo);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, inst->dataSize,
|
||||||
|
inst->data, GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
glGenBuffers(1, &inst->ibo);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, inst->ibo);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, meshHeader->totalIndices*2,
|
||||||
|
0, GL_STATIC_DRAW);
|
||||||
|
GLintptr offset = 0;
|
||||||
|
for(uint32 i = 0; i < meshHeader->numMeshes; i++){
|
||||||
|
Mesh *mesh = &meshHeader->mesh[i];
|
||||||
|
glBufferSubData(GL_ARRAY_BUFFER, offset, mesh->numIndices*2,
|
||||||
|
mesh->indices);
|
||||||
|
offset += mesh->numIndices*2;
|
||||||
|
}
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
setAttribPointers(InstanceDataHeader *inst)
|
||||||
|
{
|
||||||
|
static GLenum attribType[] = {
|
||||||
|
GL_FLOAT,
|
||||||
|
GL_BYTE, GL_UNSIGNED_BYTE,
|
||||||
|
GL_SHORT, GL_UNSIGNED_SHORT
|
||||||
|
};
|
||||||
|
for(int32 i = 0; i < inst->numAttribs; i++){
|
||||||
|
AttribDesc *a = &inst->attribs[i];
|
||||||
|
glEnableVertexAttribArray(a->index);
|
||||||
|
glVertexAttribPointer(a->index, a->size, attribType[a->type],
|
||||||
|
a->normalized, a->stride,
|
||||||
|
(void*)(uint64)a->offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
packattrib(uint8 *dst, float32 *src, AttribDesc *a, float32 scale=1.0f)
|
||||||
|
{
|
||||||
|
int8 *i8dst;
|
||||||
|
uint16 *u16dst;
|
||||||
|
int16 *i16dst;
|
||||||
|
|
||||||
|
switch(a->type){
|
||||||
|
case 0: // float
|
||||||
|
memcpy(dst, src, a->size*4);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// TODO: maybe have loop inside if?
|
||||||
|
case 1: // byte
|
||||||
|
i8dst = (int8*)dst;
|
||||||
|
for(int i = 0; i < a->size; i++){
|
||||||
|
if(!a->normalized)
|
||||||
|
i8dst[i] = src[i]*scale;
|
||||||
|
else
|
||||||
|
i8dst[i] = src[i]*127.0f;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: // ubyte
|
||||||
|
for(int i = 0; i < a->size; i++){
|
||||||
|
if(!a->normalized)
|
||||||
|
dst[i] = src[i]*scale;
|
||||||
|
else
|
||||||
|
dst[i] = src[i]*255.0f;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3: // short
|
||||||
|
i16dst = (int16*)dst;
|
||||||
|
for(int i = 0; i < a->size; i++){
|
||||||
|
if(!a->normalized)
|
||||||
|
i16dst[i] = src[i]*scale;
|
||||||
|
else
|
||||||
|
i16dst[i] = src[i]*32767.0f;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4: // ushort
|
||||||
|
u16dst = (uint16*)dst;
|
||||||
|
for(int i = 0; i < a->size; i++){
|
||||||
|
if(!a->normalized)
|
||||||
|
u16dst[i] = src[i]*scale;
|
||||||
|
else
|
||||||
|
u16dst[i] = src[i]*65535.0f;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
unpackattrib(float *dst, uint8 *src, AttribDesc *a, float32 scale=1.0f)
|
||||||
|
{
|
||||||
|
int8 *i8src;
|
||||||
|
uint16 *u16src;
|
||||||
|
int16 *i16src;
|
||||||
|
|
||||||
|
switch(a->type){
|
||||||
|
case 0: // float
|
||||||
|
memcpy(dst, src, a->size*4);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// TODO: maybe have loop inside if?
|
||||||
|
case 1: // byte
|
||||||
|
i8src = (int8*)src;
|
||||||
|
for(int i = 0; i < a->size; i++){
|
||||||
|
if(!a->normalized)
|
||||||
|
dst[i] = i8src[i]/scale;
|
||||||
|
else
|
||||||
|
dst[i] = i8src[i]/127.0f;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: // ubyte
|
||||||
|
for(int i = 0; i < a->size; i++){
|
||||||
|
if(!a->normalized)
|
||||||
|
dst[i] = src[i]/scale;
|
||||||
|
else
|
||||||
|
dst[i] = src[i]/255.0f;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3: // short
|
||||||
|
i16src = (int16*)src;
|
||||||
|
for(int i = 0; i < a->size; i++){
|
||||||
|
if(!a->normalized)
|
||||||
|
dst[i] = i16src[i]/scale;
|
||||||
|
else
|
||||||
|
dst[i] = i16src[i]/32767.0f;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4: // ushort
|
||||||
|
u16src = (uint16*)src;
|
||||||
|
for(int i = 0; i < a->size; i++){
|
||||||
|
if(!a->normalized)
|
||||||
|
dst[i] = u16src[i]/scale;
|
||||||
|
else
|
||||||
|
dst[i] = u16src[i]/65435.0f;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
destroyNativeData(void *object, int32, int32)
|
||||||
|
{
|
||||||
|
Geometry *geometry = (Geometry*)object;
|
||||||
|
if(geometry->instData == nil ||
|
||||||
|
geometry->instData->platform != PLATFORM_WDGL)
|
||||||
|
return object;
|
||||||
|
InstanceDataHeader *header =
|
||||||
|
(InstanceDataHeader*)geometry->instData;
|
||||||
|
geometry->instData = nil;
|
||||||
|
// TODO: delete ibo and vbo
|
||||||
|
delete[] header->attribs;
|
||||||
|
delete[] header->data;
|
||||||
|
delete header;
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream*
|
||||||
|
readNativeData(Stream *stream, int32, void *object, int32, int32)
|
||||||
|
{
|
||||||
|
Geometry *geometry = (Geometry*)object;
|
||||||
|
InstanceDataHeader *header = new InstanceDataHeader;
|
||||||
|
geometry->instData = header;
|
||||||
|
header->platform = PLATFORM_WDGL;
|
||||||
|
header->vbo = 0;
|
||||||
|
header->ibo = 0;
|
||||||
|
header->numAttribs = stream->readU32();
|
||||||
|
header->attribs = new AttribDesc[header->numAttribs];
|
||||||
|
stream->read(header->attribs,
|
||||||
|
header->numAttribs*sizeof(AttribDesc));
|
||||||
|
header->dataSize = header->attribs[0].stride*geometry->numVertices;
|
||||||
|
header->data = new uint8[header->dataSize];
|
||||||
|
stream->read(header->data, header->dataSize);
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream*
|
||||||
|
writeNativeData(Stream *stream, int32, void *object, int32, int32)
|
||||||
|
{
|
||||||
|
Geometry *geometry = (Geometry*)object;
|
||||||
|
if(geometry->instData == nil ||
|
||||||
|
geometry->instData->platform != PLATFORM_WDGL)
|
||||||
|
return stream;
|
||||||
|
InstanceDataHeader *header = (InstanceDataHeader*)geometry->instData;
|
||||||
|
stream->writeU32(header->numAttribs);
|
||||||
|
stream->write(header->attribs, header->numAttribs*sizeof(AttribDesc));
|
||||||
|
stream->write(header->data, header->dataSize);
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32
|
||||||
|
getSizeNativeData(void *object, int32, int32)
|
||||||
|
{
|
||||||
|
Geometry *geometry = (Geometry*)object;
|
||||||
|
if(geometry->instData == nil ||
|
||||||
|
geometry->instData->platform != PLATFORM_WDGL)
|
||||||
|
return 0;
|
||||||
|
InstanceDataHeader *header = (InstanceDataHeader*)geometry->instData;
|
||||||
|
return 4 + header->numAttribs*sizeof(AttribDesc) + header->dataSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
registerNativeDataPlugin(void)
|
||||||
|
{
|
||||||
|
Geometry::registerPlugin(0, ID_NATIVEDATA,
|
||||||
|
nil, destroyNativeData, nil);
|
||||||
|
Geometry::registerPluginStream(ID_NATIVEDATA,
|
||||||
|
readNativeData,
|
||||||
|
writeNativeData,
|
||||||
|
getSizeNativeData);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
printPipeinfo(Atomic *a)
|
||||||
|
{
|
||||||
|
Geometry *g = a->geometry;
|
||||||
|
if(g->instData == nil || g->instData->platform != PLATFORM_WDGL)
|
||||||
|
return;
|
||||||
|
int32 plgid = 0;
|
||||||
|
if(a->pipeline)
|
||||||
|
plgid = a->pipeline->pluginID;
|
||||||
|
printf("%s %x: ", debugFile, plgid);
|
||||||
|
InstanceDataHeader *h = (InstanceDataHeader*)g->instData;
|
||||||
|
for(int i = 0; i < h->numAttribs; i++)
|
||||||
|
printf("%x(%x) ", h->attribs[i].index, h->attribs[i].type);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
instance(rw::ObjPipeline *rwpipe, Atomic *atomic)
|
||||||
|
{
|
||||||
|
ObjPipeline *pipe = (ObjPipeline*)rwpipe;
|
||||||
|
Geometry *geo = atomic->geometry;
|
||||||
|
if(geo->geoflags & Geometry::NATIVE)
|
||||||
|
return;
|
||||||
|
InstanceDataHeader *header = new InstanceDataHeader;
|
||||||
|
geo->instData = header;
|
||||||
|
header->platform = PLATFORM_WDGL;
|
||||||
|
header->vbo = 0;
|
||||||
|
header->ibo = 0;
|
||||||
|
header->numAttribs =
|
||||||
|
pipe->numCustomAttribs + 1 + (geo->numTexCoordSets > 0);
|
||||||
|
if(geo->geoflags & Geometry::PRELIT)
|
||||||
|
header->numAttribs++;
|
||||||
|
if(geo->geoflags & Geometry::NORMALS)
|
||||||
|
header->numAttribs++;
|
||||||
|
int32 offset = 0;
|
||||||
|
header->attribs = new AttribDesc[header->numAttribs];
|
||||||
|
|
||||||
|
AttribDesc *a = header->attribs;
|
||||||
|
// Vertices
|
||||||
|
a->index = 0;
|
||||||
|
a->type = 0;
|
||||||
|
a->normalized = 0;
|
||||||
|
a->size = 3;
|
||||||
|
a->offset = offset;
|
||||||
|
offset += 12;
|
||||||
|
a++;
|
||||||
|
int32 firstCustom = 1;
|
||||||
|
|
||||||
|
// texCoords, only one set here
|
||||||
|
if(geo->numTexCoordSets){
|
||||||
|
a->index = 1;
|
||||||
|
a->type = 3;
|
||||||
|
a->normalized = 0;
|
||||||
|
a->size = 2;
|
||||||
|
a->offset = offset;
|
||||||
|
offset += 4;
|
||||||
|
a++;
|
||||||
|
firstCustom++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(geo->geoflags & Geometry::NORMALS){
|
||||||
|
a->index = 2;
|
||||||
|
a->type = 1;
|
||||||
|
a->normalized = 1;
|
||||||
|
a->size = 3;
|
||||||
|
a->offset = offset;
|
||||||
|
offset += 4;
|
||||||
|
a++;
|
||||||
|
firstCustom++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(geo->geoflags & Geometry::PRELIT){
|
||||||
|
a->index = 3;
|
||||||
|
a->type = 2;
|
||||||
|
a->normalized = 1;
|
||||||
|
a->size = 4;
|
||||||
|
a->offset = offset;
|
||||||
|
offset += 4;
|
||||||
|
a++;
|
||||||
|
firstCustom++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pipe->instanceCB)
|
||||||
|
offset += pipe->instanceCB(geo, firstCustom, offset);
|
||||||
|
else{
|
||||||
|
header->dataSize = offset*geo->numVertices;
|
||||||
|
header->data = new uint8[header->dataSize];
|
||||||
|
}
|
||||||
|
|
||||||
|
a = header->attribs;
|
||||||
|
for(int32 i = 0; i < header->numAttribs; i++)
|
||||||
|
a[i].stride = offset;
|
||||||
|
|
||||||
|
uint8 *p = header->data + a->offset;
|
||||||
|
float32 *vert = geo->morphTargets->vertices;
|
||||||
|
for(int32 i = 0; i < geo->numVertices; i++){
|
||||||
|
packattrib(p, vert, a);
|
||||||
|
vert += 3;
|
||||||
|
p += a->stride;
|
||||||
|
}
|
||||||
|
a++;
|
||||||
|
|
||||||
|
if(geo->numTexCoordSets){
|
||||||
|
p = header->data + a->offset;
|
||||||
|
float32 *texcoord = geo->texCoords[0];
|
||||||
|
for(int32 i = 0; i < geo->numVertices; i++){
|
||||||
|
packattrib(p, texcoord, a, 512.0f);
|
||||||
|
texcoord += 2;
|
||||||
|
p += a->stride;
|
||||||
|
}
|
||||||
|
a++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(geo->geoflags & Geometry::NORMALS){
|
||||||
|
p = header->data + a->offset;
|
||||||
|
float32 *norm = geo->morphTargets->normals;
|
||||||
|
for(int32 i = 0; i < geo->numVertices; i++){
|
||||||
|
packattrib(p, norm, a);
|
||||||
|
norm += 3;
|
||||||
|
p += a->stride;
|
||||||
|
}
|
||||||
|
a++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(geo->geoflags & Geometry::PRELIT){
|
||||||
|
// TODO: this seems too complicated
|
||||||
|
p = header->data + a->offset;
|
||||||
|
uint8 *color = geo->colors;
|
||||||
|
float32 f[4];
|
||||||
|
for(int32 i = 0; i < geo->numVertices; i++){
|
||||||
|
f[0] = color[0]/255.0f;
|
||||||
|
f[1] = color[1]/255.0f;
|
||||||
|
f[2] = color[2]/255.0f;
|
||||||
|
f[3] = color[3]/255.0f;
|
||||||
|
packattrib(p, f, a);
|
||||||
|
color += 4;
|
||||||
|
p += a->stride;
|
||||||
|
}
|
||||||
|
a++;
|
||||||
|
}
|
||||||
|
geo->geoflags |= Geometry::NATIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
uninstance(rw::ObjPipeline *rwpipe, Atomic *atomic)
|
||||||
|
{
|
||||||
|
ObjPipeline *pipe = (ObjPipeline*)rwpipe;
|
||||||
|
Geometry *geo = atomic->geometry;
|
||||||
|
if((geo->geoflags & Geometry::NATIVE) == 0)
|
||||||
|
return;
|
||||||
|
assert(geo->instData != nil);
|
||||||
|
assert(geo->instData->platform == PLATFORM_WDGL);
|
||||||
|
geo->geoflags &= ~Geometry::NATIVE;
|
||||||
|
geo->allocateData();
|
||||||
|
|
||||||
|
uint8 *p;
|
||||||
|
float32 *texcoord = geo->texCoords[0];
|
||||||
|
uint8 *color = geo->colors;
|
||||||
|
float32 *vert = geo->morphTargets->vertices;
|
||||||
|
float32 *norm = geo->morphTargets->normals;
|
||||||
|
float32 f[4];
|
||||||
|
|
||||||
|
InstanceDataHeader *header = (InstanceDataHeader*)geo->instData;
|
||||||
|
for(int i = 0; i < header->numAttribs; i++){
|
||||||
|
AttribDesc *a = &header->attribs[i];
|
||||||
|
p = header->data + a->offset;
|
||||||
|
|
||||||
|
switch(a->index){
|
||||||
|
case 0: // Vertices
|
||||||
|
for(int32 i = 0; i < geo->numVertices; i++){
|
||||||
|
unpackattrib(vert, p, a);
|
||||||
|
vert += 3;
|
||||||
|
p += a->stride;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1: // texCoords
|
||||||
|
for(int32 i = 0; i < geo->numVertices; i++){
|
||||||
|
unpackattrib(texcoord, p, a, 512.0f);
|
||||||
|
texcoord += 2;
|
||||||
|
p += a->stride;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: // normals
|
||||||
|
for(int32 i = 0; i < geo->numVertices; i++){
|
||||||
|
unpackattrib(norm, p, a);
|
||||||
|
norm += 3;
|
||||||
|
p += a->stride;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3: // colors
|
||||||
|
for(int32 i = 0; i < geo->numVertices; i++){
|
||||||
|
// TODO: this seems too complicated
|
||||||
|
unpackattrib(f, p, a);
|
||||||
|
color[0] = f[0]*255.0f;
|
||||||
|
color[1] = f[1]*255.0f;
|
||||||
|
color[2] = f[2]*255.0f;
|
||||||
|
color[3] = f[3]*255.0f;
|
||||||
|
color += 4;
|
||||||
|
p += a->stride;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pipe->uninstanceCB)
|
||||||
|
pipe->uninstanceCB(geo);
|
||||||
|
|
||||||
|
geo->generateTriangles();
|
||||||
|
|
||||||
|
destroyNativeData(geo, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjPipeline::ObjPipeline(uint32 platform)
|
||||||
|
: rw::ObjPipeline(platform)
|
||||||
|
{
|
||||||
|
this->numCustomAttribs = 0;
|
||||||
|
this->impl.instance = wdgl::instance;
|
||||||
|
this->impl.uninstance = wdgl::uninstance;
|
||||||
|
this->instanceCB = nil;
|
||||||
|
this->uninstanceCB = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjPipeline*
|
||||||
|
makeDefaultPipeline(void)
|
||||||
|
{
|
||||||
|
ObjPipeline *pipe = new ObjPipeline(PLATFORM_WDGL);
|
||||||
|
return pipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skin
|
||||||
|
|
||||||
|
Stream*
|
||||||
|
readNativeSkin(Stream *stream, int32, void *object, int32 offset)
|
||||||
|
{
|
||||||
|
Geometry *geometry = (Geometry*)object;
|
||||||
|
uint32 platform;
|
||||||
|
if(!findChunk(stream, ID_STRUCT, nil, nil)){
|
||||||
|
RWERROR((ERR_CHUNK, "STRUCT"));
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
platform = stream->readU32();
|
||||||
|
if(platform != PLATFORM_GL){
|
||||||
|
RWERROR((ERR_PLATFORM, platform));
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
Skin *skin = new Skin;
|
||||||
|
*PLUGINOFFSET(Skin*, geometry, offset) = skin;
|
||||||
|
|
||||||
|
int32 numBones = stream->readI32();
|
||||||
|
skin->init(numBones, 0, 0);
|
||||||
|
stream->read(skin->inverseMatrices, skin->numBones*64);
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream*
|
||||||
|
writeNativeSkin(Stream *stream, int32 len, void *object, int32 offset)
|
||||||
|
{
|
||||||
|
writeChunkHeader(stream, ID_STRUCT, len-12);
|
||||||
|
stream->writeU32(PLATFORM_WDGL);
|
||||||
|
Skin *skin = *PLUGINOFFSET(Skin*, object, offset);
|
||||||
|
stream->writeI32(skin->numBones);
|
||||||
|
stream->write(skin->inverseMatrices, skin->numBones*64);
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32
|
||||||
|
getSizeNativeSkin(void *object, int32 offset)
|
||||||
|
{
|
||||||
|
Skin *skin = *PLUGINOFFSET(Skin*, object, offset);
|
||||||
|
if(skin == nil)
|
||||||
|
return -1;
|
||||||
|
int32 size = 12 + 4 + 4 + skin->numBones*64;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32
|
||||||
|
skinInstanceCB(Geometry *g, int32 i, uint32 offset)
|
||||||
|
{
|
||||||
|
InstanceDataHeader *header = (InstanceDataHeader*)g->instData;
|
||||||
|
AttribDesc *a = &header->attribs[i];
|
||||||
|
// weights
|
||||||
|
a->index = 4;
|
||||||
|
a->type = 2; /* but also short o_O */
|
||||||
|
a->normalized = 1;
|
||||||
|
a->size = 4;
|
||||||
|
a->offset = offset;
|
||||||
|
offset += 4;
|
||||||
|
a++;
|
||||||
|
|
||||||
|
// indices
|
||||||
|
a->index = 5;
|
||||||
|
a->type = 2;
|
||||||
|
a->normalized = 0;
|
||||||
|
a->size = 4;
|
||||||
|
a->offset = offset;
|
||||||
|
offset += 4;
|
||||||
|
|
||||||
|
header->dataSize = offset*g->numVertices;
|
||||||
|
header->data = new uint8[header->dataSize];
|
||||||
|
|
||||||
|
Skin *skin = *PLUGINOFFSET(Skin*, g, skinGlobals.offset);
|
||||||
|
if(skin == nil)
|
||||||
|
return 8;
|
||||||
|
|
||||||
|
a = &header->attribs[i];
|
||||||
|
uint8 *wgt = header->data + a[0].offset;
|
||||||
|
uint8 *idx = header->data + a[1].offset;
|
||||||
|
uint8 *indices = skin->indices;
|
||||||
|
float32 *weights = skin->weights;
|
||||||
|
for(int32 i = 0; i < g->numVertices; i++){
|
||||||
|
packattrib(wgt, weights, a);
|
||||||
|
weights += 4;
|
||||||
|
wgt += offset;
|
||||||
|
idx[0] = *indices++;
|
||||||
|
idx[1] = *indices++;
|
||||||
|
idx[2] = *indices++;
|
||||||
|
idx[3] = *indices++;
|
||||||
|
idx += offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
skinUninstanceCB(Geometry *geo)
|
||||||
|
{
|
||||||
|
InstanceDataHeader *header = (InstanceDataHeader*)geo->instData;
|
||||||
|
|
||||||
|
Skin *skin = *PLUGINOFFSET(Skin*, geo, skinGlobals.offset);
|
||||||
|
if(skin == nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint8 *data = skin->data;
|
||||||
|
float *invMats = skin->inverseMatrices;
|
||||||
|
skin->init(skin->numBones, skin->numBones, geo->numVertices);
|
||||||
|
memcpy(skin->inverseMatrices, invMats, skin->numBones*64);
|
||||||
|
delete[] data;
|
||||||
|
|
||||||
|
uint8 *p;
|
||||||
|
float *weights = skin->weights;
|
||||||
|
uint8 *indices = skin->indices;
|
||||||
|
for(int i = 0; i < header->numAttribs; i++){
|
||||||
|
AttribDesc *a = &header->attribs[i];
|
||||||
|
p = header->data + a->offset;
|
||||||
|
|
||||||
|
switch(a->index){
|
||||||
|
case 4: // weights
|
||||||
|
for(int32 i = 0; i < geo->numVertices; i++){
|
||||||
|
unpackattrib(weights, p, a);
|
||||||
|
weights += 4;
|
||||||
|
p += a->stride;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5: // indices
|
||||||
|
for(int32 i = 0; i < geo->numVertices; i++){
|
||||||
|
*indices++ = p[0];
|
||||||
|
*indices++ = p[1];
|
||||||
|
*indices++ = p[2];
|
||||||
|
*indices++ = p[3];
|
||||||
|
p += a->stride;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
skin->findNumWeights(geo->numVertices);
|
||||||
|
skin->findUsedBones(geo->numVertices);
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjPipeline*
|
||||||
|
makeSkinPipeline(void)
|
||||||
|
{
|
||||||
|
ObjPipeline *pipe = new ObjPipeline(PLATFORM_WDGL);
|
||||||
|
pipe->pluginID = ID_SKIN;
|
||||||
|
pipe->pluginData = 1;
|
||||||
|
pipe->numCustomAttribs = 2;
|
||||||
|
pipe->instanceCB = skinInstanceCB;
|
||||||
|
pipe->uninstanceCB = skinUninstanceCB;
|
||||||
|
return pipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjPipeline*
|
||||||
|
makeMatFXPipeline(void)
|
||||||
|
{
|
||||||
|
ObjPipeline *pipe = new ObjPipeline(PLATFORM_WDGL);
|
||||||
|
pipe->pluginID = ID_MATFX;
|
||||||
|
pipe->pluginData = 0;
|
||||||
|
return pipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Raster
|
||||||
|
|
||||||
|
int32 nativeRasterOffset;
|
||||||
|
|
||||||
|
#ifdef RW_OPENGL
|
||||||
|
struct GlRaster {
|
||||||
|
GLuint id;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void*
|
||||||
|
createNativeRaster(void *object, int32 offset, int32)
|
||||||
|
{
|
||||||
|
GlRaster *raster = PLUGINOFFSET(GlRaster, object, offset);
|
||||||
|
raster->id = 0;
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void*
|
||||||
|
destroyNativeRaster(void *object, int32 offset, int32)
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void*
|
||||||
|
copyNativeRaster(void *dst, void *, int32 offset, int32)
|
||||||
|
{
|
||||||
|
GlRaster *raster = PLUGINOFFSET(GlRaster, dst, offset);
|
||||||
|
raster->id = 0;
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
registerNativeRaster(void)
|
||||||
|
{
|
||||||
|
nativeRasterOffset = Raster::registerPlugin(sizeof(GlRaster),
|
||||||
|
0x12340000 | PLATFORM_WDGL,
|
||||||
|
createNativeRaster,
|
||||||
|
destroyNativeRaster,
|
||||||
|
copyNativeRaster);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Texture::upload(void)
|
||||||
|
{
|
||||||
|
GLuint id;
|
||||||
|
glGenTextures(1, &id);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, id);
|
||||||
|
Raster *r = this->raster;
|
||||||
|
if(r->palette){
|
||||||
|
printf("can't upload paletted raster\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GLenum filter[] = {
|
||||||
|
0, GL_NEAREST, GL_LINEAR,
|
||||||
|
GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_NEAREST,
|
||||||
|
GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_LINEAR
|
||||||
|
};
|
||||||
|
static GLenum filternomip[] = {
|
||||||
|
0, GL_NEAREST, GL_LINEAR,
|
||||||
|
GL_NEAREST, GL_LINEAR,
|
||||||
|
GL_NEAREST, GL_LINEAR
|
||||||
|
};
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
||||||
|
filternomip[this->filterAddressing & 0xFF]);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
|
||||||
|
filternomip[this->filterAddressing & 0xFF]);
|
||||||
|
|
||||||
|
static GLenum wrap[] = {
|
||||||
|
0, GL_REPEAT, GL_MIRRORED_REPEAT,
|
||||||
|
GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER
|
||||||
|
};
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
|
||||||
|
wrap[(this->filterAddressing >> 8) & 0xF]);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
|
||||||
|
wrap[(this->filterAddressing >> 12) & 0xF]);
|
||||||
|
|
||||||
|
switch(r->format & 0xF00){
|
||||||
|
case Raster::C8888:
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, 4, r->width, r->height,
|
||||||
|
0, GL_RGBA, GL_UNSIGNED_BYTE, r->texels);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("unsupported raster format: %x\n", r->format);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
GlRaster *glr = PLUGINOFFSET(GlRaster, r, nativeRasterOffset);
|
||||||
|
glr->id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Texture::bind(int n)
|
||||||
|
{
|
||||||
|
Raster *r = this->raster;
|
||||||
|
GlRaster *glr = PLUGINOFFSET(GlRaster, r, nativeRasterOffset);
|
||||||
|
glActiveTexture(GL_TEXTURE0+n);
|
||||||
|
if(r){
|
||||||
|
if(glr->id == 0)
|
||||||
|
this->upload();
|
||||||
|
glBindTexture(GL_TEXTURE_2D, glr->id);
|
||||||
|
}else
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
0
src/image.cpp
Executable file → Normal file
0
src/image.cpp
Executable file → Normal file
187
src/ps2/pds.cpp
Normal file
187
src/ps2/pds.cpp
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "../rwbase.h"
|
||||||
|
#include "../rwplg.h"
|
||||||
|
#include "../rwpipeline.h"
|
||||||
|
#include "../rwobjects.h"
|
||||||
|
#include "../rwplugins.h"
|
||||||
|
#include "rwps2.h"
|
||||||
|
#include "rwps2plg.h"
|
||||||
|
|
||||||
|
namespace rw {
|
||||||
|
namespace ps2 {
|
||||||
|
|
||||||
|
struct PdsGlobals
|
||||||
|
{
|
||||||
|
Pipeline **pipes;
|
||||||
|
int32 maxPipes;
|
||||||
|
int32 numPipes;
|
||||||
|
};
|
||||||
|
static PdsGlobals pdsGlobals;
|
||||||
|
|
||||||
|
Pipeline*
|
||||||
|
getPDSPipe(uint32 data)
|
||||||
|
{
|
||||||
|
for(int32 i = 0; i < pdsGlobals.numPipes; i++)
|
||||||
|
if(pdsGlobals.pipes[i]->pluginData == data)
|
||||||
|
return pdsGlobals.pipes[i];
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
registerPDSPipe(Pipeline *pipe)
|
||||||
|
{
|
||||||
|
assert(pdsGlobals.numPipes < pdsGlobals.maxPipes);
|
||||||
|
pdsGlobals.pipes[pdsGlobals.numPipes++] = pipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
atomicPDSRights(void *object, int32, int32, uint32 data)
|
||||||
|
{
|
||||||
|
Atomic *a = (Atomic*)object;
|
||||||
|
a->pipeline = (ObjPipeline*)getPDSPipe(data);
|
||||||
|
// printf("atm pds: %x %x %x\n", data, a->pipeline->pluginID, a->pipeline->pluginData);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
materialPDSRights(void *object, int32, int32, uint32 data)
|
||||||
|
{
|
||||||
|
Material *m = (Material*)object;
|
||||||
|
m->pipeline = (ObjPipeline*)getPDSPipe(data);
|
||||||
|
// printf("mat pds: %x %x %x\n", data, m->pipeline->pluginID, m->pipeline->pluginData);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
registerPDSPlugin(int32 n)
|
||||||
|
{
|
||||||
|
pdsGlobals.maxPipes = n;
|
||||||
|
pdsGlobals.numPipes = 0;
|
||||||
|
pdsGlobals.pipes = new Pipeline*[n];
|
||||||
|
Atomic::registerPlugin(0, ID_PDS, nil, nil, nil);
|
||||||
|
Atomic::setStreamRightsCallback(ID_PDS, atomicPDSRights);
|
||||||
|
|
||||||
|
Material::registerPlugin(0, ID_PDS, nil, nil, nil);
|
||||||
|
Material::setStreamRightsCallback(ID_PDS, materialPDSRights);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
registerPluginPDSPipes(void)
|
||||||
|
{
|
||||||
|
// rwPDS_G3_Skin_GrpMatPipeID
|
||||||
|
MatPipeline *pipe = new MatPipeline(PLATFORM_PS2);
|
||||||
|
pipe->pluginID = ID_PDS;
|
||||||
|
pipe->pluginData = 0x11001;
|
||||||
|
pipe->attribs[AT_XYZ] = &attribXYZ;
|
||||||
|
pipe->attribs[AT_UV] = &attribUV;
|
||||||
|
pipe->attribs[AT_RGBA] = &attribRGBA;
|
||||||
|
pipe->attribs[AT_NORMAL] = &attribNormal;
|
||||||
|
pipe->attribs[AT_NORMAL+1] = &attribWeights;
|
||||||
|
uint32 vertCount = MatPipeline::getVertCount(VU_Lights-0x100, 5, 3, 2);
|
||||||
|
pipe->setTriBufferSizes(5, vertCount);
|
||||||
|
pipe->vifOffset = pipe->inputStride*vertCount;
|
||||||
|
pipe->instanceCB = skinInstanceCB;
|
||||||
|
pipe->uninstanceCB = genericUninstanceCB;
|
||||||
|
pipe->preUninstCB = skinPreCB;
|
||||||
|
pipe->postUninstCB = skinPostCB;
|
||||||
|
registerPDSPipe(pipe);
|
||||||
|
|
||||||
|
// rwPDS_G3_Skin_GrpAtmPipeID
|
||||||
|
ObjPipeline *opipe = new ObjPipeline(PLATFORM_PS2);
|
||||||
|
opipe->pluginID = ID_PDS;
|
||||||
|
opipe->pluginData = 0x11002;
|
||||||
|
opipe->groupPipeline = pipe;
|
||||||
|
registerPDSPipe(opipe);
|
||||||
|
|
||||||
|
// rwPDS_G3_MatfxUV1_GrpMatPipeID
|
||||||
|
pipe = new MatPipeline(PLATFORM_PS2);
|
||||||
|
pipe->pluginID = ID_PDS;
|
||||||
|
pipe->pluginData = 0x1100b;
|
||||||
|
pipe->attribs[AT_XYZ] = &attribXYZ;
|
||||||
|
pipe->attribs[AT_UV] = &attribUV;
|
||||||
|
pipe->attribs[AT_RGBA] = &attribRGBA;
|
||||||
|
pipe->attribs[AT_NORMAL] = &attribNormal;
|
||||||
|
vertCount = MatPipeline::getVertCount(0x3C5, 4, 3, 3);
|
||||||
|
pipe->setTriBufferSizes(4, vertCount);
|
||||||
|
pipe->vifOffset = pipe->inputStride*vertCount;
|
||||||
|
pipe->uninstanceCB = genericUninstanceCB;
|
||||||
|
registerPDSPipe(pipe);
|
||||||
|
|
||||||
|
// rwPDS_G3_MatfxUV1_GrpAtmPipeID
|
||||||
|
opipe = new ObjPipeline(PLATFORM_PS2);
|
||||||
|
opipe->pluginID = ID_PDS;
|
||||||
|
opipe->pluginData = 0x1100d;
|
||||||
|
opipe->groupPipeline = pipe;
|
||||||
|
registerPDSPipe(opipe);
|
||||||
|
|
||||||
|
// rwPDS_G3_MatfxUV2_GrpMatPipeID
|
||||||
|
pipe = new MatPipeline(PLATFORM_PS2);
|
||||||
|
pipe->pluginID = ID_PDS;
|
||||||
|
pipe->pluginData = 0x1100c;
|
||||||
|
pipe->attribs[AT_XYZ] = &attribXYZ;
|
||||||
|
pipe->attribs[AT_UV] = &attribUV2;
|
||||||
|
pipe->attribs[AT_RGBA] = &attribRGBA;
|
||||||
|
pipe->attribs[AT_NORMAL] = &attribNormal;
|
||||||
|
vertCount = MatPipeline::getVertCount(0x3C5, 4, 3, 3);
|
||||||
|
pipe->setTriBufferSizes(4, vertCount);
|
||||||
|
pipe->vifOffset = pipe->inputStride*vertCount;
|
||||||
|
pipe->uninstanceCB = genericUninstanceCB;
|
||||||
|
registerPDSPipe(pipe);
|
||||||
|
|
||||||
|
// rwPDS_G3_MatfxUV2_GrpAtmPipeID
|
||||||
|
opipe = new ObjPipeline(PLATFORM_PS2);
|
||||||
|
opipe->pluginID = ID_PDS;
|
||||||
|
opipe->pluginData = 0x1100e;
|
||||||
|
opipe->groupPipeline = pipe;
|
||||||
|
registerPDSPipe(opipe);
|
||||||
|
|
||||||
|
// RW World plugin
|
||||||
|
|
||||||
|
// rwPDS_G3x_Generic_AtmPipeID
|
||||||
|
opipe = new ObjPipeline(PLATFORM_PS2);
|
||||||
|
opipe->pluginID = ID_PDS;
|
||||||
|
opipe->pluginData = 0x50001;
|
||||||
|
registerPDSPipe(opipe);
|
||||||
|
|
||||||
|
// rwPDS_G3x_Skin_AtmPipeID
|
||||||
|
opipe = new ObjPipeline(PLATFORM_PS2);
|
||||||
|
opipe->pluginID = ID_PDS;
|
||||||
|
opipe->pluginData = 0x5000b;
|
||||||
|
registerPDSPipe(opipe);
|
||||||
|
|
||||||
|
// rwPDS_G3xd_A4D_MatPipeID
|
||||||
|
pipe = new MatPipeline(PLATFORM_PS2);
|
||||||
|
pipe->pluginID = ID_PDS;
|
||||||
|
pipe->pluginData = 0x5002f;
|
||||||
|
pipe->attribs[0] = &attribXYZW;
|
||||||
|
pipe->attribs[1] = &attribUV;
|
||||||
|
pipe->attribs[2] = &attribNormal;
|
||||||
|
vertCount = 0x50;
|
||||||
|
pipe->setTriBufferSizes(3, vertCount);
|
||||||
|
pipe->vifOffset = pipe->inputStride*vertCount;
|
||||||
|
pipe->uninstanceCB = genericUninstanceCB;
|
||||||
|
pipe->preUninstCB = genericPreCB;
|
||||||
|
registerPDSPipe(pipe);
|
||||||
|
|
||||||
|
// rwPDS_G3xd_A4DSkin_MatPipeID
|
||||||
|
pipe = new MatPipeline(PLATFORM_PS2);
|
||||||
|
pipe->pluginID = ID_PDS;
|
||||||
|
pipe->pluginData = 0x5003e;
|
||||||
|
pipe->attribs[0] = &attribXYZW;
|
||||||
|
pipe->attribs[1] = &attribUV;
|
||||||
|
pipe->attribs[2] = &attribNormal;
|
||||||
|
pipe->attribs[3] = &attribWeights;
|
||||||
|
vertCount = 0x30;
|
||||||
|
pipe->setTriBufferSizes(4, vertCount);
|
||||||
|
pipe->vifOffset = pipe->inputStride*vertCount;
|
||||||
|
pipe->instanceCB = skinInstanceCB;
|
||||||
|
pipe->uninstanceCB = genericUninstanceCB;
|
||||||
|
pipe->preUninstCB = genericPreCB;
|
||||||
|
pipe->postUninstCB = skinPostCB;
|
||||||
|
registerPDSPipe(pipe);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
1627
src/ps2/ps2.cpp
Normal file
1627
src/ps2/ps2.cpp
Normal file
File diff suppressed because it is too large
Load Diff
674
src/ps2/ps2raster.cpp
Normal file
674
src/ps2/ps2raster.cpp
Normal file
@ -0,0 +1,674 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "../rwbase.h"
|
||||||
|
#include "../rwerror.h"
|
||||||
|
#include "../rwplg.h"
|
||||||
|
#include "../rwpipeline.h"
|
||||||
|
#include "../rwobjects.h"
|
||||||
|
#include "../rwengine.h"
|
||||||
|
#include "rwps2.h"
|
||||||
|
|
||||||
|
#define PLUGIN_ID 0
|
||||||
|
|
||||||
|
#define max(a, b) ((a) > (b) ? (a) : (b))
|
||||||
|
|
||||||
|
namespace rw {
|
||||||
|
namespace ps2 {
|
||||||
|
|
||||||
|
int32 nativeRasterOffset;
|
||||||
|
|
||||||
|
#define MAXLEVEL(r) ((r)->tex1[1]>>18 & 0x3F)
|
||||||
|
#define SETMAXLEVEL(r, l) ((r)->tex1[1] = (r)->tex1[1]&~0xFF0000 | l<<18)
|
||||||
|
#define SETKL(r, val) ((r)->tex1[1] = (r)->tex1[1]&~0xFFFF | (uint16)(val))
|
||||||
|
static bool32 noNewStyleRasters;
|
||||||
|
|
||||||
|
// i don't really understand this, stolen from RW
|
||||||
|
static void
|
||||||
|
ps2MinSize(int32 psm, int32 flags, int32 *minw, int32 *minh)
|
||||||
|
{
|
||||||
|
*minh = 1;
|
||||||
|
switch(psm){
|
||||||
|
case 0x00:
|
||||||
|
case 0x30:
|
||||||
|
*minw = 2; // 32 bit
|
||||||
|
break;
|
||||||
|
case 0x02:
|
||||||
|
case 0x0A:
|
||||||
|
case 0x32:
|
||||||
|
case 0x3A:
|
||||||
|
*minw = 4; // 16 bit
|
||||||
|
break;
|
||||||
|
case 0x01:
|
||||||
|
case 0x13:
|
||||||
|
case 0x14:
|
||||||
|
case 0x1B:
|
||||||
|
case 0x24:
|
||||||
|
case 0x2C:
|
||||||
|
case 0x31:
|
||||||
|
*minw = 8; // everything else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(flags & 0x2 && psm == 0x13){ // PSMT8
|
||||||
|
*minw = 16;
|
||||||
|
*minh = 4;
|
||||||
|
}
|
||||||
|
if(flags & 0x4 && psm == 0x14){ // PSMT4
|
||||||
|
*minw = 32;
|
||||||
|
*minh = 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dword
|
||||||
|
{
|
||||||
|
uint32 lo;
|
||||||
|
uint32 hi;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ALIGN64(x) ((x) + 0x3F & ~0x3F)
|
||||||
|
|
||||||
|
static void
|
||||||
|
rasterCreate(Raster *raster)
|
||||||
|
{
|
||||||
|
uint64 bufferWidth[7], bufferBase[7];
|
||||||
|
int32 pageWidth, pageHeight;
|
||||||
|
Ps2Raster *ras = PLUGINOFFSET(Ps2Raster, raster, nativeRasterOffset);
|
||||||
|
|
||||||
|
//printf("%x %x %x %x\n", raster->format, raster->flags, raster->type, noNewStyleRasters);
|
||||||
|
assert(raster->type == 4); // Texture
|
||||||
|
switch(raster->depth){
|
||||||
|
case 4:
|
||||||
|
pageWidth = 128;
|
||||||
|
pageHeight = 128;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
pageWidth = 128;
|
||||||
|
pageHeight = 64;
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
pageWidth = 64;
|
||||||
|
pageHeight = 64;
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
pageWidth = 64;
|
||||||
|
pageHeight = 32;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(0 && "unsupported depth");
|
||||||
|
}
|
||||||
|
int32 logw = 0, logh = 0;
|
||||||
|
int32 s;
|
||||||
|
for(s = 1; s < raster->width; s *= 2)
|
||||||
|
logw++;
|
||||||
|
for(s = 1; s < raster->height; s *= 2)
|
||||||
|
logh++;
|
||||||
|
SETKL(ras, 0xFC0);
|
||||||
|
//printf("%d %d %d %d\n", raster->width, logw, raster->height, logh);
|
||||||
|
ras->tex0[0] |= (raster->width < pageWidth ? pageWidth : raster->width)/64 << 14;
|
||||||
|
ras->tex0[0] |= logw << 26;
|
||||||
|
ras->tex0[0] |= logh << 30;
|
||||||
|
ras->tex0[1] |= logh >> 2;
|
||||||
|
|
||||||
|
int32 paletteWidth, paletteHeight, paletteDepth;
|
||||||
|
int32 palettePagewidth, palettePageheight;
|
||||||
|
if(raster->format & (Raster::PAL4 | Raster::PAL8))
|
||||||
|
switch(raster->format & 0xF00){
|
||||||
|
case Raster::C1555:
|
||||||
|
ras->tex0[1] |= 0xA << 19; // PSMCT16S
|
||||||
|
paletteDepth = 2;
|
||||||
|
palettePagewidth = palettePageheight = 64;
|
||||||
|
break;
|
||||||
|
case Raster::C8888:
|
||||||
|
// PSMCT32
|
||||||
|
paletteDepth = 4;
|
||||||
|
palettePagewidth = 64;
|
||||||
|
palettePageheight = 32;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(0 && "unsupported palette format\n");
|
||||||
|
}
|
||||||
|
if(raster->format & Raster::PAL4){
|
||||||
|
ras->tex0[0] |= 0x14 << 20; // PSMT4
|
||||||
|
ras->tex0[1] |= 1<<29 | 1<<2; // CLD 1, TCC RGBA
|
||||||
|
paletteWidth = 8;
|
||||||
|
paletteHeight = 2;
|
||||||
|
}else if(raster->format & Raster::PAL8){
|
||||||
|
ras->tex0[0] |= 0x13 << 20; // PSMT8
|
||||||
|
ras->tex0[1] |= 1<<29 | 1<<2; // CLD 1, TCC RGBA
|
||||||
|
paletteWidth = paletteHeight = 16;
|
||||||
|
}else{
|
||||||
|
paletteWidth = 0;
|
||||||
|
paletteHeight = 0;
|
||||||
|
paletteDepth = 0;
|
||||||
|
palettePagewidth = 0;
|
||||||
|
palettePageheight = 0;
|
||||||
|
switch(raster->format & 0xF00){
|
||||||
|
case Raster::C1555:
|
||||||
|
ras->tex0[0] |= 0xA << 20; // PSMCT16S
|
||||||
|
ras->tex0[1] |= 1 << 2; // TCC RGBA
|
||||||
|
break;
|
||||||
|
case Raster::C8888:
|
||||||
|
// PSMCT32
|
||||||
|
ras->tex0[1] |= 1 << 2; // TCC RGBA
|
||||||
|
break;
|
||||||
|
case Raster::C888:
|
||||||
|
ras->tex0[0] |= 1 << 20; // PSMCT24
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(0 && "unsupported raster format\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < 7; i++){
|
||||||
|
bufferWidth[i] = 1;
|
||||||
|
bufferBase[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 mipw, miph;
|
||||||
|
int32 n;
|
||||||
|
int32 nPagW, nPagH;
|
||||||
|
int32 w = raster->width;
|
||||||
|
int32 h = raster->height;
|
||||||
|
int32 d = raster->depth;
|
||||||
|
raster->stride = w*d/8;
|
||||||
|
|
||||||
|
if(raster->format & Raster::MIPMAP){
|
||||||
|
static uint32 blockOffset32_24_8[8] = { 0, 2, 2, 8, 8, 10, 10, 32 };
|
||||||
|
static uint32 blockOffset16_4[8] = { 0, 1, 4, 5, 16, 17, 20, 21 };
|
||||||
|
static uint32 blockOffset16S[8] = { 0, 1, 8, 9, 4, 5, 12, 13 };
|
||||||
|
uint64 lastBufferWidth;
|
||||||
|
mipw = w;
|
||||||
|
miph = h;
|
||||||
|
lastBufferWidth = max(pageWidth, w)/64;
|
||||||
|
ras->texelSize = 0;
|
||||||
|
int32 gsoffset = 0;
|
||||||
|
int32 gsaddress = 0;
|
||||||
|
for(n = 0; n < 7; n++){
|
||||||
|
if(w >= 8 && h >= 8 && (mipw < 8 || miph < 8))
|
||||||
|
break;
|
||||||
|
ras->texelSize += ALIGN64(mipw*miph*d/8);
|
||||||
|
bufferWidth[n] = max(pageWidth, mipw)/64;
|
||||||
|
|
||||||
|
if(bufferWidth[n] != lastBufferWidth){
|
||||||
|
nPagW = ((w >> n-1) + pageWidth-1)/pageWidth;
|
||||||
|
nPagH = ((h >> n-1) + pageHeight-1)/pageHeight;
|
||||||
|
gsaddress = (gsoffset + nPagW*nPagH*0x800) & ~0x7FF;
|
||||||
|
}
|
||||||
|
lastBufferWidth = bufferWidth[n];
|
||||||
|
gsaddress = ALIGN64(gsaddress);
|
||||||
|
uint32 b = gsaddress/256 & 7;
|
||||||
|
switch(ras->tex0[0]>>20 & 0x3F){
|
||||||
|
case 0: case 1: case 0x13:
|
||||||
|
b = blockOffset32_24_8[b];
|
||||||
|
break;
|
||||||
|
case 2: case 0x14:
|
||||||
|
b = blockOffset16_4[b];
|
||||||
|
break;
|
||||||
|
case 0xA:
|
||||||
|
b = blockOffset16S[b];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// can't happen
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bufferBase[n] = b + (gsaddress>>11 << 5);
|
||||||
|
int32 stride = bufferWidth[n]/64*d/8;
|
||||||
|
gsaddress = ALIGN64(miph*stride/4 + gsoffset);
|
||||||
|
|
||||||
|
mipw /= 2;
|
||||||
|
miph /= 2;
|
||||||
|
}
|
||||||
|
assert(0);
|
||||||
|
}else{
|
||||||
|
ras->texelSize = raster->stride*raster->height+0xF & ~0xF;
|
||||||
|
ras->paletteSize = paletteWidth*paletteHeight*paletteDepth;
|
||||||
|
ras->miptbp1[0] |= 1<<14; // TBW1
|
||||||
|
ras->miptbp1[1] |= 1<<2 | 1<<22; // TBW2,3
|
||||||
|
ras->miptbp2[0] |= 1<<14; // TBW4
|
||||||
|
ras->miptbp2[1] |= 1<<2 | 1<<22; // TBW5,6
|
||||||
|
SETMAXLEVEL(ras, 0);
|
||||||
|
nPagW = (raster->width + pageWidth-1)/pageWidth;
|
||||||
|
nPagH = (raster->height + pageHeight-1)/pageHeight;
|
||||||
|
bufferBase[0] = 0;
|
||||||
|
bufferWidth[0] = nPagW * (pageWidth >> 6);
|
||||||
|
ras->gsSize = (nPagW*nPagH*0x800)&~0x7FF;
|
||||||
|
if(ras->paletteSize){
|
||||||
|
// BITBLTBUF DBP
|
||||||
|
if(pageWidth*nPagW > raster->width ||
|
||||||
|
pageHeight*nPagH > raster->height)
|
||||||
|
ras->tex1[0] = (ras->gsSize >> 6) - 4;
|
||||||
|
else
|
||||||
|
ras->tex1[0] = ras->gsSize >> 6;
|
||||||
|
nPagW = (paletteWidth + palettePagewidth-1)/palettePagewidth;
|
||||||
|
nPagH = (paletteHeight + palettePageheight-1)/palettePageheight;
|
||||||
|
ras->gsSize += (nPagW*nPagH*0x800)&~0x7FF;
|
||||||
|
}else
|
||||||
|
ras->tex1[0] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// allocate data and fill with GIF packets
|
||||||
|
ras->texelSize = ras->texelSize+0xF & ~0xF;
|
||||||
|
int32 numLevels = MAXLEVEL(ras)+1;
|
||||||
|
if(noNewStyleRasters ||
|
||||||
|
(raster->width*raster->height*raster->depth & ~0x7F) >= 0x3FFF80){
|
||||||
|
assert(0);
|
||||||
|
}else{
|
||||||
|
ras->flags |= 1; // include GIF packets
|
||||||
|
int32 psm = ras->tex0[0]>>20 & 0x3F;
|
||||||
|
//int32 cpsm = ras->tex0[1]>>19 & 0x3F;
|
||||||
|
if(psm == 0x13){ // PSMT8
|
||||||
|
ras->flags |= 2;
|
||||||
|
// TODO: stuff
|
||||||
|
}
|
||||||
|
if(psm == 0x14){ // PSMT4
|
||||||
|
// swizzle flag probably depends on version :/
|
||||||
|
if(rw::version > 0x31000)
|
||||||
|
ras->flags |= 4;
|
||||||
|
// TODO: stuff
|
||||||
|
}
|
||||||
|
ras->texelSize = 0x50*numLevels; // GIF packets
|
||||||
|
int32 minW, minH;
|
||||||
|
ps2MinSize(psm, ras->flags, &minW, &minH);
|
||||||
|
w = raster->width;
|
||||||
|
h = raster->height;
|
||||||
|
n = numLevels;
|
||||||
|
while(n--){
|
||||||
|
mipw = w < minW ? minW : w;
|
||||||
|
miph = h < minH ? minH : h;
|
||||||
|
ras->texelSize += mipw*miph*raster->depth/8+0xF & ~0xF;
|
||||||
|
w /= 2;
|
||||||
|
h /= 2;
|
||||||
|
}
|
||||||
|
if(ras->paletteSize){
|
||||||
|
if(rw::version > 0x31000 && paletteHeight == 2)
|
||||||
|
paletteHeight = 3;
|
||||||
|
ras->paletteSize = 0x50 +
|
||||||
|
paletteDepth*paletteWidth*paletteHeight;
|
||||||
|
}
|
||||||
|
// TODO: allocate space for more DMA packets
|
||||||
|
ras->dataSize = ras->paletteSize+ras->texelSize;
|
||||||
|
uint8 *data = new uint8[ras->dataSize];
|
||||||
|
assert(data);
|
||||||
|
ras->data = data;
|
||||||
|
raster->texels = data + 0x50;
|
||||||
|
if(ras->paletteSize)
|
||||||
|
raster->palette = data + ras->texelSize + 0x50;
|
||||||
|
uint32 *p = (uint32*)data;
|
||||||
|
w = raster->width;
|
||||||
|
h = raster->height;
|
||||||
|
for(n = 0; n < numLevels; n++){
|
||||||
|
mipw = w < minW ? minW : w;
|
||||||
|
miph = h < minH ? minH : h;
|
||||||
|
|
||||||
|
// GIF tag
|
||||||
|
*p++ = 3; // NLOOP = 3
|
||||||
|
*p++ = 0x10000000; // NREG = 1
|
||||||
|
*p++ = 0xE; // A+D
|
||||||
|
*p++ = 0;
|
||||||
|
|
||||||
|
// TRXPOS
|
||||||
|
*p++ = 0; // TODO
|
||||||
|
*p++ = 0; // TODO
|
||||||
|
*p++ = 0x51;
|
||||||
|
*p++ = 0;
|
||||||
|
|
||||||
|
// TRXREG
|
||||||
|
if(ras->flags & 2 && psm == 0x13 ||
|
||||||
|
ras->flags & 4 && psm == 0x14){
|
||||||
|
*p++ = mipw/2;
|
||||||
|
*p++ = miph/2;
|
||||||
|
}else{
|
||||||
|
*p++ = mipw;
|
||||||
|
*p++ = miph;
|
||||||
|
}
|
||||||
|
*p++ = 0x52;
|
||||||
|
*p++ = 0;
|
||||||
|
|
||||||
|
// TRXDIR
|
||||||
|
*p++ = 0; // host -> local
|
||||||
|
*p++ = 0;
|
||||||
|
*p++ = 0x53;
|
||||||
|
*p++ = 0;
|
||||||
|
|
||||||
|
// GIF tag
|
||||||
|
uint32 sz = mipw*miph*raster->depth/8 + 0xF >> 4;
|
||||||
|
*p++ = sz;
|
||||||
|
*p++ = 0x08000000; // IMAGE
|
||||||
|
*p++ = 0;
|
||||||
|
*p++ = 0;
|
||||||
|
|
||||||
|
p += sz*4;
|
||||||
|
w /= 2;
|
||||||
|
h /= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ras->paletteSize){
|
||||||
|
p = (uint32*)(raster->palette - 0x50);
|
||||||
|
// GIF tag
|
||||||
|
*p++ = 3; // NLOOP = 3
|
||||||
|
*p++ = 0x10000000; // NREG = 1
|
||||||
|
*p++ = 0xE; // A+D
|
||||||
|
*p++ = 0;
|
||||||
|
|
||||||
|
// TRXPOS
|
||||||
|
*p++ = 0; // TODO
|
||||||
|
*p++ = 0; // TODO
|
||||||
|
*p++ = 0x51;
|
||||||
|
*p++ = 0;
|
||||||
|
|
||||||
|
// TRXREG
|
||||||
|
*p++ = paletteWidth;
|
||||||
|
*p++ = paletteHeight;
|
||||||
|
*p++ = 0x52;
|
||||||
|
*p++ = 0;
|
||||||
|
|
||||||
|
// TRXDIR
|
||||||
|
*p++ = 0; // host -> local
|
||||||
|
*p++ = 0;
|
||||||
|
*p++ = 0x53;
|
||||||
|
*p++ = 0;
|
||||||
|
|
||||||
|
// GIF tag
|
||||||
|
uint32 sz = ras->paletteSize - 0x50 + 0xF >> 4;
|
||||||
|
*p++ = sz;
|
||||||
|
*p++ = 0x08000000; // IMAGE
|
||||||
|
*p++ = 0;
|
||||||
|
*p++ = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8*
|
||||||
|
rasterLock(Raster *raster, int32 level)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
(void)raster;
|
||||||
|
(void)level;
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rasterUnlock(Raster *raster, int32 level)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
(void)raster;
|
||||||
|
(void)level;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32
|
||||||
|
rasterNumLevels(Raster *raster)
|
||||||
|
{
|
||||||
|
Ps2Raster *ras = PLUGINOFFSET(Ps2Raster, raster, nativeRasterOffset);
|
||||||
|
if(raster->texels == nil) return 0;
|
||||||
|
if(raster->format & Raster::MIPMAP)
|
||||||
|
return MAXLEVEL(ras)+1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void*
|
||||||
|
createNativeRaster(void *object, int32 offset, int32)
|
||||||
|
{
|
||||||
|
Ps2Raster *raster = PLUGINOFFSET(Ps2Raster, object, offset);
|
||||||
|
raster->tex0[0] = 0;
|
||||||
|
raster->tex0[1] = 0;
|
||||||
|
raster->tex1[0] = 0;
|
||||||
|
raster->tex1[1] = 0;
|
||||||
|
raster->miptbp1[0] = 0;
|
||||||
|
raster->miptbp1[1] = 0;
|
||||||
|
raster->miptbp2[0] = 0;
|
||||||
|
raster->miptbp2[1] = 0;
|
||||||
|
raster->texelSize = 0;
|
||||||
|
raster->paletteSize = 0;
|
||||||
|
raster->gsSize = 0;
|
||||||
|
raster->flags = 0;
|
||||||
|
SETKL(raster, 0xFC0);
|
||||||
|
|
||||||
|
raster->dataSize = 0;
|
||||||
|
raster->data = nil;
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void*
|
||||||
|
destroyNativeRaster(void *object, int32 offset, int32)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
(void)offset;
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void*
|
||||||
|
copyNativeRaster(void *dst, void *src, int32 offset, int32)
|
||||||
|
{
|
||||||
|
Ps2Raster *dstraster = PLUGINOFFSET(Ps2Raster, dst, offset);
|
||||||
|
Ps2Raster *srcraster = PLUGINOFFSET(Ps2Raster, src, offset);
|
||||||
|
*dstraster = *srcraster;
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Stream*
|
||||||
|
readMipmap(Stream *stream, int32, void *object, int32 offset, int32)
|
||||||
|
{
|
||||||
|
uint16 val = stream->readI32();
|
||||||
|
Texture *tex = (Texture*)object;
|
||||||
|
if(tex->raster == nil)
|
||||||
|
return stream;
|
||||||
|
Ps2Raster *raster = PLUGINOFFSET(Ps2Raster, tex->raster, offset);
|
||||||
|
SETKL(raster, val);
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Stream*
|
||||||
|
writeMipmap(Stream *stream, int32, void *object, int32 offset, int32)
|
||||||
|
{
|
||||||
|
Texture *tex = (Texture*)object;
|
||||||
|
if(tex->raster)
|
||||||
|
return nil;
|
||||||
|
Ps2Raster *raster = PLUGINOFFSET(Ps2Raster, tex->raster, offset);
|
||||||
|
stream->writeI32(raster->tex1[1]&0xFFFF);
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32
|
||||||
|
getSizeMipmap(void*, int32, int32)
|
||||||
|
{
|
||||||
|
return rw::platform == PLATFORM_PS2 ? 4 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
registerNativeRaster(void)
|
||||||
|
{
|
||||||
|
nativeRasterOffset = Raster::registerPlugin(sizeof(Ps2Raster),
|
||||||
|
0x12340000 | PLATFORM_PS2,
|
||||||
|
createNativeRaster,
|
||||||
|
destroyNativeRaster,
|
||||||
|
copyNativeRaster);
|
||||||
|
driver[PLATFORM_PS2].rasterNativeOffset = nativeRasterOffset;
|
||||||
|
driver[PLATFORM_PS2].rasterCreate = rasterCreate;
|
||||||
|
driver[PLATFORM_PS2].rasterLock = rasterLock;
|
||||||
|
driver[PLATFORM_PS2].rasterUnlock = rasterUnlock;
|
||||||
|
driver[PLATFORM_PS2].rasterNumLevels = rasterNumLevels;
|
||||||
|
|
||||||
|
Texture::registerPlugin(0, ID_SKYMIPMAP, nil, nil, nil);
|
||||||
|
Texture::registerPluginStream(ID_SKYMIPMAP, readMipmap, writeMipmap, getSizeMipmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct StreamRasterExt
|
||||||
|
{
|
||||||
|
int32 width;
|
||||||
|
int32 height;
|
||||||
|
int32 depth;
|
||||||
|
uint16 rasterFormat;
|
||||||
|
int16 type;
|
||||||
|
uint32 tex0[2];
|
||||||
|
uint32 tex1[2];
|
||||||
|
uint32 miptbp1[2];
|
||||||
|
uint32 miptbp2[2];
|
||||||
|
uint32 texelSize;
|
||||||
|
uint32 paletteSize;
|
||||||
|
uint32 gsSize;
|
||||||
|
uint32 mipmapVal;
|
||||||
|
};
|
||||||
|
|
||||||
|
Texture*
|
||||||
|
readNativeTexture(Stream *stream)
|
||||||
|
{
|
||||||
|
uint32 length, oldversion, version;
|
||||||
|
uint32 fourcc;
|
||||||
|
Raster *raster;
|
||||||
|
Ps2Raster *natras;
|
||||||
|
if(!findChunk(stream, ID_STRUCT, nil, nil)){
|
||||||
|
RWERROR((ERR_CHUNK, "STRUCT"));
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
fourcc = stream->readU32();
|
||||||
|
if(fourcc != FOURCC_PS2){
|
||||||
|
RWERROR((ERR_PLATFORM, fourcc));
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
Texture *tex = Texture::create(nil);
|
||||||
|
if(tex == nil)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
// Texture
|
||||||
|
tex->filterAddressing = stream->readU32();
|
||||||
|
if(!findChunk(stream, ID_STRING, &length, nil)){
|
||||||
|
RWERROR((ERR_CHUNK, "STRING"));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
stream->read(tex->name, length);
|
||||||
|
if(!findChunk(stream, ID_STRING, &length, nil)){
|
||||||
|
RWERROR((ERR_CHUNK, "STRING"));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
stream->read(tex->mask, length);
|
||||||
|
|
||||||
|
// Raster
|
||||||
|
StreamRasterExt streamExt;
|
||||||
|
oldversion = rw::version;
|
||||||
|
if(!findChunk(stream, ID_STRUCT, nil, nil)){
|
||||||
|
RWERROR((ERR_CHUNK, "STRUCT"));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if(!findChunk(stream, ID_STRUCT, nil, &version)){
|
||||||
|
RWERROR((ERR_CHUNK, "STRUCT"));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
stream->read(&streamExt, 0x40);
|
||||||
|
noNewStyleRasters = streamExt.type < 2;
|
||||||
|
rw::version = version;
|
||||||
|
raster = Raster::create(streamExt.width, streamExt.height,
|
||||||
|
streamExt.depth, streamExt.rasterFormat,
|
||||||
|
PLATFORM_PS2);
|
||||||
|
noNewStyleRasters = 0;
|
||||||
|
rw::version = oldversion;
|
||||||
|
tex->raster = raster;
|
||||||
|
natras = PLUGINOFFSET(Ps2Raster, raster, nativeRasterOffset);
|
||||||
|
//printf("%08X%08X %08X%08X %08X%08X %08X%08X\n",
|
||||||
|
// ras->tex0[1], ras->tex0[0], ras->tex1[1], ras->tex1[0],
|
||||||
|
// ras->miptbp1[0], ras->miptbp1[1], ras->miptbp2[0], ras->miptbp2[1]);
|
||||||
|
natras->tex0[0] = streamExt.tex0[0];
|
||||||
|
natras->tex0[1] = streamExt.tex0[1];
|
||||||
|
natras->tex1[0] = streamExt.tex1[0];
|
||||||
|
natras->tex1[1] = natras->tex1[1]&~0xFF0000 |
|
||||||
|
streamExt.tex1[1]<<16 & 0xFF0000;
|
||||||
|
natras->miptbp1[0] = streamExt.miptbp1[0];
|
||||||
|
natras->miptbp1[1] = streamExt.miptbp1[1];
|
||||||
|
natras->miptbp2[0] = streamExt.miptbp2[0];
|
||||||
|
natras->miptbp2[1] = streamExt.miptbp2[1];
|
||||||
|
natras->texelSize = streamExt.texelSize;
|
||||||
|
natras->paletteSize = streamExt.paletteSize;
|
||||||
|
natras->gsSize = streamExt.gsSize;
|
||||||
|
SETKL(natras, streamExt.mipmapVal);
|
||||||
|
//printf("%08X%08X %08X%08X %08X%08X %08X%08X\n",
|
||||||
|
// ras->tex0[1], ras->tex0[0], ras->tex1[1], ras->tex1[0],
|
||||||
|
// ras->miptbp1[0], ras->miptbp1[1], ras->miptbp2[0], ras->miptbp2[1]);
|
||||||
|
|
||||||
|
if(!findChunk(stream, ID_STRING, &length, nil)){
|
||||||
|
RWERROR((ERR_CHUNK, "STRING"));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if(streamExt.type < 2){
|
||||||
|
stream->read(raster->texels, length);
|
||||||
|
}else{
|
||||||
|
stream->read(raster->texels-0x50, natras->texelSize);
|
||||||
|
stream->read(raster->palette-0x50, natras->paletteSize);
|
||||||
|
}
|
||||||
|
if(tex->streamReadPlugins(stream))
|
||||||
|
return tex;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
tex->destroy();
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
writeNativeTexture(Texture *tex, Stream *stream)
|
||||||
|
{
|
||||||
|
Raster *raster = tex->raster;
|
||||||
|
Ps2Raster *ras = PLUGINOFFSET(Ps2Raster, raster, nativeRasterOffset);
|
||||||
|
int32 chunksize = getSizeNativeTexture(tex);
|
||||||
|
writeChunkHeader(stream, ID_TEXTURENATIVE, chunksize);
|
||||||
|
writeChunkHeader(stream, ID_STRUCT, 8);
|
||||||
|
stream->writeU32(FOURCC_PS2);
|
||||||
|
stream->writeU32(tex->filterAddressing);
|
||||||
|
int32 len = strlen(tex->name)+4 & ~3;
|
||||||
|
writeChunkHeader(stream, ID_STRING, len);
|
||||||
|
stream->write(tex->name, len);
|
||||||
|
len = strlen(tex->mask)+4 & ~3;
|
||||||
|
writeChunkHeader(stream, ID_STRING, len);
|
||||||
|
stream->write(tex->mask, len);
|
||||||
|
|
||||||
|
int32 sz = ras->texelSize + ras->paletteSize;
|
||||||
|
writeChunkHeader(stream, ID_STRUCT, 12 + 64 + 12 + sz);
|
||||||
|
writeChunkHeader(stream, ID_STRUCT, 64);
|
||||||
|
StreamRasterExt streamExt;
|
||||||
|
streamExt.width = raster->width;
|
||||||
|
streamExt.height = raster->height;
|
||||||
|
streamExt.depth = raster->depth;
|
||||||
|
streamExt.rasterFormat = raster->format | raster->type;
|
||||||
|
streamExt.type = 0;
|
||||||
|
if(ras->flags == 2 && raster->depth == 8)
|
||||||
|
streamExt.type = 1;
|
||||||
|
if(ras->flags & 1)
|
||||||
|
streamExt.type = 2;
|
||||||
|
streamExt.tex0[0] = ras->tex0[0];
|
||||||
|
streamExt.tex0[1] = ras->tex0[1];
|
||||||
|
streamExt.tex1[0] = ras->tex1[0];
|
||||||
|
streamExt.tex1[1] = ras->tex1[1]>>16 & 0xFF;
|
||||||
|
streamExt.miptbp1[0] = ras->miptbp1[0];
|
||||||
|
streamExt.miptbp1[1] = ras->miptbp1[1];
|
||||||
|
streamExt.miptbp2[0] = ras->miptbp2[0];
|
||||||
|
streamExt.miptbp2[1] = ras->miptbp2[1];
|
||||||
|
streamExt.texelSize = ras->texelSize;
|
||||||
|
streamExt.paletteSize = ras->paletteSize;
|
||||||
|
streamExt.gsSize = ras->gsSize;
|
||||||
|
streamExt.mipmapVal = ras->tex1[1]&0xFFFF;
|
||||||
|
stream->write(&streamExt, 64);
|
||||||
|
|
||||||
|
writeChunkHeader(stream, ID_STRUCT, sz);
|
||||||
|
if(streamExt.type < 2){
|
||||||
|
stream->write(raster->texels, sz);
|
||||||
|
}else{
|
||||||
|
stream->write(raster->texels-0x50, ras->texelSize);
|
||||||
|
stream->write(raster->palette-0x50, ras->paletteSize);
|
||||||
|
}
|
||||||
|
tex->streamWritePlugins(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32
|
||||||
|
getSizeNativeTexture(Texture *tex)
|
||||||
|
{
|
||||||
|
uint32 size = 12 + 8;
|
||||||
|
size += 12 + strlen(tex->name)+4 & ~3;
|
||||||
|
size += 12 + strlen(tex->mask)+4 & ~3;
|
||||||
|
size += 12 + 12 + 64 + 12;
|
||||||
|
Ps2Raster *ras = PLUGINOFFSET(Ps2Raster, tex->raster, nativeRasterOffset);
|
||||||
|
size += ras->texelSize + ras->paletteSize;
|
||||||
|
size += 12 + tex->streamGetPluginSize();
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
204
src/ps2/rwps2.h
Normal file
204
src/ps2/rwps2.h
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
namespace rw {
|
||||||
|
namespace ps2 {
|
||||||
|
|
||||||
|
void initializePlatform(void);
|
||||||
|
|
||||||
|
struct InstanceData
|
||||||
|
{
|
||||||
|
// 0 - addresses in ref tags need fixing
|
||||||
|
// 1 - no ref tags, so no fixing
|
||||||
|
// set by the program:
|
||||||
|
// 2 - ref tags are fixed, need to unfix before stream write
|
||||||
|
uint32 arePointersFixed;
|
||||||
|
uint32 dataSize;
|
||||||
|
uint8 *data;
|
||||||
|
Material *material;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct InstanceDataHeader : rw::InstanceDataHeader
|
||||||
|
{
|
||||||
|
uint32 numMeshes;
|
||||||
|
InstanceData *instanceMeshes;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
VU_Lights = 0x3d0
|
||||||
|
};
|
||||||
|
|
||||||
|
enum PS2Attribs {
|
||||||
|
AT_V2_32 = 0x64000000,
|
||||||
|
AT_V2_16 = 0x65000000,
|
||||||
|
AT_V2_8 = 0x66000000,
|
||||||
|
AT_V3_32 = 0x68000000,
|
||||||
|
AT_V3_16 = 0x69000000,
|
||||||
|
AT_V3_8 = 0x6A000000,
|
||||||
|
AT_V4_32 = 0x6C000000,
|
||||||
|
AT_V4_16 = 0x6D000000,
|
||||||
|
AT_V4_8 = 0x6E000000,
|
||||||
|
AT_UNSGN = 0x00004000,
|
||||||
|
|
||||||
|
AT_RW = 0x6
|
||||||
|
};
|
||||||
|
|
||||||
|
// Not really types as in RW but offsets
|
||||||
|
enum PS2AttibTypes {
|
||||||
|
AT_XYZ = 0,
|
||||||
|
AT_UV = 1,
|
||||||
|
AT_RGBA = 2,
|
||||||
|
AT_NORMAL = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
void *destroyNativeData(void *object, int32, int32);
|
||||||
|
Stream *readNativeData(Stream *stream, int32 len, void *object, int32, int32);
|
||||||
|
Stream *writeNativeData(Stream *stream, int32 len, void *object, int32, int32);
|
||||||
|
int32 getSizeNativeData(void *object, int32, int32);
|
||||||
|
void registerNativeDataPlugin(void);
|
||||||
|
|
||||||
|
void printDMA(InstanceData *inst);
|
||||||
|
void sizedebug(InstanceData *inst);
|
||||||
|
|
||||||
|
// only RW_PS2
|
||||||
|
void fixDmaOffsets(InstanceData *inst);
|
||||||
|
void unfixDmaOffsets(InstanceData *inst);
|
||||||
|
//
|
||||||
|
|
||||||
|
struct PipeAttribute
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
uint32 attrib;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern PipeAttribute attribXYZ;
|
||||||
|
extern PipeAttribute attribXYZW;
|
||||||
|
extern PipeAttribute attribUV;
|
||||||
|
extern PipeAttribute attribUV2;
|
||||||
|
extern PipeAttribute attribRGBA;
|
||||||
|
extern PipeAttribute attribNormal;
|
||||||
|
extern PipeAttribute attribWeights;
|
||||||
|
|
||||||
|
class MatPipeline : public rw::Pipeline
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
uint32 vifOffset;
|
||||||
|
uint32 inputStride;
|
||||||
|
uint32 triStripCount, triListCount;
|
||||||
|
PipeAttribute *attribs[10];
|
||||||
|
void (*instanceCB)(MatPipeline*, Geometry*, Mesh*, uint8**);
|
||||||
|
void (*uninstanceCB)(MatPipeline*, Geometry*, uint32*, Mesh*, uint8**);
|
||||||
|
void (*preUninstCB)(MatPipeline*, Geometry*);
|
||||||
|
void (*postUninstCB)(MatPipeline*, Geometry*);
|
||||||
|
// RW has more:
|
||||||
|
// instanceTestCB()
|
||||||
|
// resEntryAllocCB()
|
||||||
|
// bridgeCB()
|
||||||
|
// postMeshCB()
|
||||||
|
// vu1code
|
||||||
|
// primtype
|
||||||
|
|
||||||
|
static uint32 getVertCount(uint32 top, uint32 inAttribs,
|
||||||
|
uint32 outAttribs, uint32 outBufs) {
|
||||||
|
return (top-outBufs)/(inAttribs*2+outAttribs*outBufs);
|
||||||
|
}
|
||||||
|
|
||||||
|
MatPipeline(uint32 platform);
|
||||||
|
void dump(void);
|
||||||
|
void setTriBufferSizes(uint32 inputStride, uint32 stripCount);
|
||||||
|
void instance(Geometry *g, InstanceData *inst, Mesh *m);
|
||||||
|
uint8 *collectData(Geometry *g, InstanceData *inst, Mesh *m, uint8 *data[]);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ObjPipeline : public rw::ObjPipeline
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MatPipeline *groupPipeline;
|
||||||
|
// RW has more:
|
||||||
|
// setupCB()
|
||||||
|
// finalizeCB()
|
||||||
|
// lightOffset
|
||||||
|
// lightSize
|
||||||
|
|
||||||
|
ObjPipeline(uint32 platform);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Vertex {
|
||||||
|
float32 p[3];
|
||||||
|
float32 t[2];
|
||||||
|
float32 t1[2];
|
||||||
|
uint8 c[4];
|
||||||
|
float32 n[3];
|
||||||
|
// skin
|
||||||
|
float32 w[4];
|
||||||
|
uint8 i[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
void insertVertex(Geometry *geo, int32 i, uint32 mask, Vertex *v);
|
||||||
|
|
||||||
|
extern ObjPipeline *defaultObjPipe;
|
||||||
|
extern MatPipeline *defaultMatPipe;
|
||||||
|
|
||||||
|
void genericUninstanceCB(MatPipeline *pipe, Geometry *geo, uint32 flags[], Mesh *mesh, uint8 *data[]);
|
||||||
|
void genericPreCB(MatPipeline *pipe, Geometry *geo); // skin and ADC
|
||||||
|
//void defaultUninstanceCB(MatPipeline *pipe, Geometry *geo, uint32 flags[], Mesh *mesh, uint8 *data[]);
|
||||||
|
void skinInstanceCB(MatPipeline *, Geometry *g, Mesh *m, uint8 **data);
|
||||||
|
//void skinUninstanceCB(MatPipeline*, Geometry *geo, uint32 flags[], Mesh *mesh, uint8 *data[]);
|
||||||
|
|
||||||
|
ObjPipeline *makeDefaultPipeline(void);
|
||||||
|
void dumpPipeline(rw::Pipeline *pipe);
|
||||||
|
|
||||||
|
// ADC plugin
|
||||||
|
|
||||||
|
// Each element in adcBits corresponds to an index in Mesh->indices,
|
||||||
|
// this assumes the Mesh indices are ADC formatted.
|
||||||
|
// ADCData->numBits != Mesh->numIndices. ADCData->numBits is probably
|
||||||
|
// equal to Mesh->numIndices before the Mesh gets ADC formatted.
|
||||||
|
//
|
||||||
|
// Can't convert between ADC-formatted and non-ADC-formatted yet :(
|
||||||
|
|
||||||
|
struct ADCData
|
||||||
|
{
|
||||||
|
bool32 adcFormatted;
|
||||||
|
int8 *adcBits;
|
||||||
|
int32 numBits;
|
||||||
|
};
|
||||||
|
extern int32 adcOffset;
|
||||||
|
void registerADCPlugin(void);
|
||||||
|
|
||||||
|
int8 *getADCbits(Geometry *geo);
|
||||||
|
int8 *getADCbitsForMesh(Geometry *geo, Mesh *mesh);
|
||||||
|
void convertADC(Geometry *g);
|
||||||
|
void unconvertADC(Geometry *geo);
|
||||||
|
void allocateADC(Geometry *geo);
|
||||||
|
|
||||||
|
// PDS plugin
|
||||||
|
|
||||||
|
Pipeline *getPDSPipe(uint32 data);
|
||||||
|
void registerPDSPipe(Pipeline *pipe);
|
||||||
|
void registerPDSPlugin(int32 n);
|
||||||
|
void registerPluginPDSPipes(void);
|
||||||
|
|
||||||
|
// Native Texture and Raster
|
||||||
|
|
||||||
|
struct Ps2Raster
|
||||||
|
{
|
||||||
|
uint32 tex0[2];
|
||||||
|
uint32 tex1[2];
|
||||||
|
uint32 miptbp1[2];
|
||||||
|
uint32 miptbp2[2];
|
||||||
|
uint32 texelSize;
|
||||||
|
uint32 paletteSize;
|
||||||
|
uint32 gsSize;
|
||||||
|
int8 flags;
|
||||||
|
|
||||||
|
uint8 *data; //tmp
|
||||||
|
uint32 dataSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern int32 nativeRasterOffset;
|
||||||
|
void registerNativeRaster(void);
|
||||||
|
|
||||||
|
Texture *readNativeTexture(Stream *stream);
|
||||||
|
void writeNativeTexture(Texture *tex, Stream *stream);
|
||||||
|
uint32 getSizeNativeTexture(Texture *tex);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
22
src/ps2/rwps2plg.h
Normal file
22
src/ps2/rwps2plg.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
namespace rw {
|
||||||
|
namespace ps2 {
|
||||||
|
|
||||||
|
ObjPipeline *makeSkinPipeline(void);
|
||||||
|
ObjPipeline *makeMatFXPipeline(void);
|
||||||
|
|
||||||
|
// Skin plugin
|
||||||
|
|
||||||
|
void insertVertexSkin(Geometry *geo, int32 i, uint32 mask, Vertex *v);
|
||||||
|
int32 findVertexSkin(Geometry *g, uint32 flags[], uint32 mask, Vertex *v);
|
||||||
|
|
||||||
|
Stream *readNativeSkin(Stream *stream, int32, void *object, int32 offset);
|
||||||
|
Stream *writeNativeSkin(Stream *stream, int32 len, void *object, int32 offset);
|
||||||
|
int32 getSizeNativeSkin(void *object, int32 offset);
|
||||||
|
|
||||||
|
void instanceSkinData(Geometry *g, Mesh *m, Skin *skin, uint32 *data);
|
||||||
|
|
||||||
|
void skinPreCB(MatPipeline*, Geometry*);
|
||||||
|
void skinPostCB(MatPipeline*, Geometry*);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -26,8 +26,10 @@ int32 version = 0x36003;
|
|||||||
int32 build = 0xFFFF;
|
int32 build = 0xFFFF;
|
||||||
#ifdef RW_PS2
|
#ifdef RW_PS2
|
||||||
int32 platform = PLATFORM_PS2;
|
int32 platform = PLATFORM_PS2;
|
||||||
#elif RW_OPENGL
|
#elif RW_WDGL
|
||||||
int32 platform = PLATFORM_WDGL;
|
int32 platform = PLATFORM_WDGL;
|
||||||
|
#elif RW_GL3
|
||||||
|
int32 platform = PLATFORM_GL3;
|
||||||
#elif RW_D3D9
|
#elif RW_D3D9
|
||||||
int32 platform = PLATFORM_D3D9;
|
int32 platform = PLATFORM_D3D9;
|
||||||
#else
|
#else
|
||||||
|
@ -3,6 +3,14 @@
|
|||||||
#endif
|
#endif
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
#ifdef RW_GL3
|
||||||
|
#define RW_OPENGL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef RW_WDGL
|
||||||
|
#define RW_OPENGL
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace rw {
|
namespace rw {
|
||||||
|
|
||||||
#ifdef RW_PS2
|
#ifdef RW_PS2
|
||||||
|
Loading…
Reference in New Issue
Block a user