#include #include #include #include #include "rwbase.h" #include "rwerror.h" #include "rwplg.h" #include "rwpipeline.h" #include "rwobjects.h" #include "rwengine.h" #include "ps2/rwps2.h" #include "d3d/rwxbox.h" #include "d3d/rwd3d.h" #include "d3d/rwd3d8.h" #include "d3d/rwd3d9.h" #include "gl/rwgl3.h" #include "gl/rwwdgl.h" #define PLUGIN_ID 0 // on windows //#ifdef DEBUG //#include //#define free(p) _free_dbg(p, _NORMAL_BLOCK); //#define malloc(sz) _malloc_dbg(sz, _NORMAL_BLOCK, __FILE__, __LINE__) //#define realloc(p, sz) _realloc_dbg(p, sz, _NORMAL_BLOCK, __FILE__, __LINE__) //#endif namespace rw { Engine *engine; PluginList Engine::s_plglist(sizeof(Engine)); Engine::State Engine::state = Dead; MemoryFunctions Engine::memfuncs; PluginList Driver::s_plglist[NUM_PLATFORMS]; const char *allocLocation; void *malloc_h(size_t sz, uint32 hint) { if(sz == 0) return nil; return malloc(sz); } void *realloc_h(void *p, size_t sz, uint32 hint) { return realloc(p, sz); } struct MemoryBlock { size_t sz; uint32 hint; void *origPtr; const char *codeline; LLLink inAllocList; }; LinkList allocations; size_t totalMemoryAllocated; // We align managed memory blocks on a 16 byte boundary #define ALIGN16(x) ((x) + 0xF & ~0xF) void* malloc_managed(size_t sz, uint32 hint) { void *origPtr; uint8 *data; MemoryBlock *mem; if(sz == 0) return nil; origPtr = malloc(sz + sizeof(MemoryBlock) + 15); if(origPtr == nil) return nil; totalMemoryAllocated += sz; data = (uint8*)origPtr; data += sizeof(MemoryBlock); data = (uint8*)ALIGN16((uintptr)data); mem = (MemoryBlock*)(data-sizeof(MemoryBlock)); mem->sz = sz; mem->hint = hint; mem->origPtr = origPtr; mem->codeline = allocLocation; allocations.add(&mem->inAllocList); return data; } void* realloc_managed(void *p, size_t sz, uint32 hint) { void *origPtr; MemoryBlock *mem; uint32 offset; if(p == nil) return malloc_managed(sz, hint); mem = (MemoryBlock*)((uint8*)p-sizeof(MemoryBlock)); offset = (uint8*)p - (uint8*)mem->origPtr; mem->inAllocList.remove(); origPtr = realloc(mem->origPtr, sz + sizeof(MemoryBlock) + 15); if(origPtr == nil){ allocations.add(&mem->inAllocList); return nil; } p = (uint8*)origPtr + offset; mem = (MemoryBlock*)((uint8*)p-sizeof(MemoryBlock)); totalMemoryAllocated -= mem->sz; mem->sz = sz; mem->hint = hint; mem->origPtr = origPtr; mem->codeline = allocLocation; allocations.add(&mem->inAllocList); totalMemoryAllocated += mem->sz; return p; } void free_managed(void *p) { MemoryBlock *mem; if(p == nil) return; mem = (MemoryBlock*)((uint8*)p-sizeof(MemoryBlock)); mem->inAllocList.remove(); totalMemoryAllocated -= mem->sz; free(mem->origPtr); } void printleaks(void) { FORLIST(lnk, allocations){ MemoryBlock *mem = LLLinkGetData(lnk, MemoryBlock, inAllocList); printf("sz %d hint %X\n %s\n", mem->sz, mem->hint, mem->codeline); } } // TODO: make the debug out configurable void *mustmalloc_h(size_t sz, uint32 hint) { void *ret; ret = Engine::memfuncs.rwmalloc(sz, hint); if(ret || sz == 0) return ret; fprintf(stderr, "Error: out of memory\n"); exit(1); return nil; } void *mustrealloc_h(void *p, size_t sz, uint32 hint) { void *ret; ret = Engine::memfuncs.rwrealloc(p, sz, hint); if(ret || sz == 0) return ret; fprintf(stderr, "Error: out of memory\n"); exit(1); return nil; } MemoryFunctions defaultMemfuncs = { malloc_h, realloc_h, free, nil, nil }; MemoryFunctions managedMemfuncs = { malloc_managed, realloc_managed, free_managed, nil, nil }; // This function mainly registers engine plugins bool32 Engine::init(MemoryFunctions *memfuncs) { if(engine || Engine::state != Dead){ RWERROR((ERR_ENGINEINIT)); return 0; } totalMemoryAllocated = 0; allocations.init(); if(memfuncs) Engine::memfuncs = *memfuncs; else Engine::memfuncs = defaultMemfuncs; if(Engine::memfuncs.rwmustmalloc == nil) Engine::memfuncs.rwmustmalloc = mustmalloc_h; if(Engine::memfuncs.rwmustrealloc == nil) Engine::memfuncs.rwmustrealloc = mustrealloc_h; PluginList::open(); for(uint i = 0; i < NUM_PLATFORMS; i++) new (&Driver::s_plglist[i]) PluginList(sizeof(Driver)); // core plugin attach here Frame::registerModule(); Image::registerModule(); Raster::registerModule(); Texture::registerModule(); // TODO: reset all allocation counts here. or maybe do that in modules? Frame::numAllocated = 0; Image::numAllocated = 0; Raster::numAllocated = 0; Texture::numAllocated = 0; TexDictionary::numAllocated = 0; Geometry::numAllocated = 0; Material::numAllocated = 0; Atomic::numAllocated = 0; Light::numAllocated = 0; Camera::numAllocated = 0; Clump::numAllocated = 0; World::numAllocated = 0; // driver plugin attach ps2::registerPlatformPlugins(); xbox::registerPlatformPlugins(); d3d8::registerPlatformPlugins(); d3d9::registerPlatformPlugins(); wdgl::registerPlatformPlugins(); gl3::registerPlatformPlugins(); Engine::state = Initialized; return 1; } // This is where RW allocates the engine and e.g. opens d3d bool32 Engine::open(EngineOpenParams *p) { if(engine || Engine::state != Initialized){ RWERROR((ERR_ENGINEOPEN)); return 0; } // Allocate engine engine = (Engine*)rwNew(Engine::s_plglist.size, MEMDUR_GLOBAL); engine->currentCamera = nil; engine->currentWorld = nil; // Initialize device // Device and possibly OS specific! #ifdef RW_PS2 engine->device = ps2::renderdevice; #elif RW_GL3 engine->device = gl3::renderdevice; #elif RW_D3D9 engine->device = d3d::renderdevice; #else engine->device = null::renderdevice; #endif engine->device.system(DEVICEOPEN, (void*)p, 0); engine->dummyDefaultPipeline = ObjPipeline::create(); for(uint i = 0; i < NUM_PLATFORMS; i++){ rw::engine->driver[i] = (Driver*)rwNew(Driver::s_plglist[i].size, MEMDUR_GLOBAL); engine->driver[i]->defaultPipeline = engine->dummyDefaultPipeline; engine->driver[i]->rasterCreate = null::rasterCreate; engine->driver[i]->rasterLock = null::rasterLock; engine->driver[i]->rasterUnlock = null::rasterUnlock; engine->driver[i]->rasterLockPalette = null::rasterLockPalette; engine->driver[i]->rasterUnlockPalette = null::rasterUnlockPalette; engine->driver[i]->rasterNumLevels = null::rasterNumLevels; engine->driver[i]->imageFindRasterFormat = null::imageFindRasterFormat; engine->driver[i]->rasterFromImage = null::rasterFromImage; engine->driver[i]->rasterToImage = null::rasterToImage; } Engine::state = Opened; return 1; } // This is where RW creates the actual rendering device // and calls the engine plugin ctors bool32 Engine::start(void) { if(engine == nil || Engine::state != Opened){ RWERROR((ERR_ENGINESTART)); return 0; } engine->device.system(DEVICEINIT, nil, 0); Engine::s_plglist.construct(engine); for(uint i = 0; i < NUM_PLATFORMS; i++) Driver::s_plglist[i].construct(rw::engine->driver[i]); engine->device.system(DEVICEFINALIZE, nil, 0); // Register some image formats. Or should we leave that to the user? Image::registerFileFormat("tga", readTGA, writeTGA); Image::registerFileFormat("bmp", readBMP, writeBMP); Image::registerFileFormat("png", readPNG, writePNG); Engine::state = Started; return 1; } void Engine::term(void) { if(engine || Engine::state != Initialized){ RWERROR((ERR_GENERAL)); return; } PluginList::close(); // This has to be reset because it won't be opened again otherwise // TODO: maybe reset more stuff here? d3d::nativeRasterOffset = 0; Engine::state = Dead; } void Engine::close(void) { if(engine == nil || Engine::state != Opened){ RWERROR((ERR_GENERAL)); return; } engine->device.system(DEVICECLOSE, nil, 0); for(uint i = 0; i < NUM_PLATFORMS; i++) rwFree(rw::engine->driver[i]); engine->dummyDefaultPipeline->destroy(); rwFree(engine); engine = nil; Engine::state = Initialized; } void Engine::stop(void) { if(engine == nil || Engine::state != Started){ RWERROR((ERR_GENERAL)); return; } for(uint i = 0; i < NUM_PLATFORMS; i++) Driver::s_plglist[i].destruct(rw::engine->driver[i]); Engine::s_plglist.destruct(engine); engine->device.system(DEVICETERM, nil, 0); Engine::state = Opened; } int32 Engine::getNumSubSystems(void) { return engine->device.system(DEVICEGETNUMSUBSYSTEMS, nil, 0); } int32 Engine::getCurrentSubSystem(void) { return engine->device.system(DEVICEGETCURRENTSUBSYSTEM, nil, 0); } bool32 Engine::setSubSystem(int32 subsys) { return engine->device.system(DEVICESETSUBSYSTEM, nil, subsys); } SubSystemInfo* Engine::getSubSystemInfo(SubSystemInfo *info, int32 subsys) { if(engine->device.system(DEVICEGETSUBSSYSTEMINFO, info, subsys)) return info; return nil; } int32 Engine::getNumVideoModes(void) { return engine->device.system(DEVICEGETNUMVIDEOMODES, nil, 0); } int32 Engine::getCurrentVideoMode(void) { return engine->device.system(DEVICEGETCURRENTVIDEOMODE, nil, 0); } bool32 Engine::setVideoMode(int32 mode) { return engine->device.system(DEVICESETVIDEOMODE, nil, mode); } VideoMode* Engine::getVideoModeInfo(VideoMode *info, int32 mode) { if(engine->device.system(DEVICEGETVIDEOMODEINFO, info, mode)) return info; return nil; } namespace null { void beginUpdate(Camera*) { } void endUpdate(Camera*) { } void clearCamera(Camera*,RGBA*,uint32) { } void showRaster(Raster*,uint32) { } void setRenderState(int32, void*) { } void *getRenderState(int32) { return 0; } bool32 rasterRenderFast(Raster *raster, int32 x, int32 y) { return 0; } void im2DRenderLine(void*, int32, int32, int32) { } void im2DRenderTriangle(void*, int32, int32, int32, int32) { } void im2DRenderPrimitive(PrimitiveType, void*, int32) { } void im2DRenderIndexedPrimitive(PrimitiveType, void*, int32, void*, int32) { } void im3DTransform(void *vertices, int32 numVertices, Matrix *world, uint32 flags) { } void im3DRenderPrimitive(PrimitiveType primType) { } void im3DRenderIndexedPrimitive(PrimitiveType primType, void *indices, int32 numIndices) { } void im3DEnd(void) { } Raster* rasterCreate(Raster*) { assert(0 && "rasterCreate not implemented"); return nil; } uint8* rasterLock(Raster*, int32, int32) { assert(0 && "lockRaster not implemented"); return nil; } void rasterUnlock(Raster*, int32) { assert(0 && "unlockRaster not implemented"); } uint8* rasterLockPalette(Raster*, int32) { assert(0 && "rasterLockPalette not implemented"); return nil; } void rasterUnlockPalette(Raster*) { assert(0 && "rasterUnlockPalette not implemented"); } int32 rasterNumLevels(Raster*) { assert(0 && "rasterNumLevels not implemented"); return 0; } bool32 imageFindRasterFormat(Image *img, int32 type, int32 *width, int32 *height, int32 *depth, int32 *format) { assert(0 && "imageFindRasterFormat not implemented"); return 0; } bool32 rasterFromImage(Raster*, Image*) { assert(0 && "rasterFromImage not implemented"); return 0; } Image* rasterToImage(Raster*) { assert(0 && "rasterToImage not implemented"); return nil; } int deviceSystem(DeviceReq req, void *arg0, int32 n) { switch(req){ case DEVICEGETNUMSUBSYSTEMS: return 0; case DEVICEGETCURRENTSUBSYSTEM: return 0; case DEVICEGETSUBSSYSTEMINFO: return 0; } return 1; } Device renderdevice = { 0.0f, 1.0f, null::beginUpdate, null::endUpdate, null::clearCamera, null::showRaster, null::rasterRenderFast, null::setRenderState, null::getRenderState, null::im2DRenderLine, null::im2DRenderTriangle, null::im2DRenderPrimitive, null::im2DRenderIndexedPrimitive, null::im3DTransform, null::im3DRenderPrimitive, null::im3DRenderIndexedPrimitive, null::im3DEnd, null::deviceSystem }; } }