Code archives/File Utilities/Simple OOP Database engine with Threaded loading *SVN Blitz Required*
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
Tested in my own game, which it was wrote for. Now my map editor boots up instantly, and the tiles just 'stream' in one by one. In case you're wondering, it IS possible to load graphics in an external thread, you will just most likely have to use your own format. Because any DX/GL stuff most likely has to be done within the main thread. Not sure how you could call loadimage without that occuring. LoadPixMap perhaps? Also included is a oop approach to threading, the athread and amutex classes. | |||||
Type TZoneRecord Extends TDataRecord Field mZone:TMapZone Field mWorkZone:TMapZone Method New() mDataType = "Zone" End Method Function CreateZoneRecord:TZoneRecord(z:TMapZone) Local r:TZoneRecord = New TZoneRecord r.mZone = z Return r End Function Method SyncFrom() mWorkZone = New TMapZone mWorkZone.mX = mZone.mX mWorkZone.mY = mZone.mY mworkZone.mZ = mZone.mZ mworkZone.mRadius = mZone.mRadius mWorkZone.Name = mZone.name ' mworkLight.mGreen = mLight.mGreen ' mWorkLight.mBlue = mLight.mBlue ' mWorkLight.mRange = mLight.mRange End Method Method SyncTo() If mZone = Null mZone = TMapZone.CreateCircle("", 0, 0, 0, 0, Null) End If mZone.Name = mworkzone.Name mZone.mx = mworkZone.mx mZone.my = mworkZone.my mZone.mz = mworkZone.mz mZone.mRadius = mworkZone.mRadius End Method Method WriteHeader() mfile.WriteLine(mWorkZone.Name) mfile.WriteFloat(mWorkZone.mX) mfile.WriteFloat(mWorkZone.mY) mFile.WriteFloat(mWorkzone.mZ) mFile.WriteFloat(mWorkZone.mRadius) End Method Method ReadHeader() Local name:String = mfile.ReadLine() Local lx:Float = mfile.ReadFloat() Local ly:Float = mfile.ReadFloat() Local lz:Float = mfile.ReadFloat() Local lradius:Float = mfile.ReadFloat() mWorkZone = TMapZone.CreateCircle(name, lx, ly, lz, lradius, Null) End Method End Type Type TLightRecord Extends TDataRecord Field mLight:TMapLight Field mWorkLight:TMapLight Method New() mDataType = "Light" End Method Function CreateLightRecord:TLightRecord(l:TMapLight) Local r:TLightRecord = New TLightRecord r.mLight = l Return r End Function Method SyncFrom() mWorkLight = New TMapLight mWorkLight.mX = mLight.mX mWorkLight.mY = mLight.mY mworklight.mZ = mLight.mZ mworkLight.mRed = mLight.mRed mworkLight.mGreen = mLight.mGreen mWorkLight.mBlue = mLight.mBlue mWorkLight.mRange = mLight.mRange End Method Method SyncTo() If mlight = Null mLight = TMapLight.Create(0, 0, 0, 0, 0, 0, 0, Null) End If mLight.mx = mworklight.mx mlight.my = mworklight.my mlight.mz = mworklight.mz mlight.mRed = mworklight.mRed mlight.mGreen = mworklight.mGreen mLight.mBlue = mWorkLight.mBlue mLight.mRange = mWorkLight.mRange End Method Method WriteHeader() mfile.WriteFloat(mWorkLight.mX) mfile.WriteFloat(mWorkLight.mY) mFile.WriteFloat(mWorkLight.mZ) mFile.WriteFloat(mWorkLight.mRed) mFile.WriteFloat(Self.mWorkLight.mGreen) mFile.WriteFloat(Self.mWorkLight.mBlue) mFile.WriteFloat(Self.mWorkLight.mRange) End Method Method ReadHeader() Local lx:Float = mfile.ReadFloat() Local ly:Float = mfile.ReadFloat() Local lz:Float = mfile.ReadFloat() Local lr:Float = mfile.ReadFloat() Local lg:Float = mfile.ReadFloat() Local lb:Float = mfile.ReadFloat() Local lrange:Float = mfile.ReadFloat() mWorkLight = TMapLight.Create(lx, ly, lz, lr, lg, lb, lrange, Null) End Method End Type Type TMapRecord Extends TDataRecord Field mMap:TMap Field mWorkMap:TMap Method New() mDataType = "Map" End Method Function CreateMapRecord:TMapRecord(m:TMap) Local r:TMapRecord = New TMapRecord r.mMap = m Return r End Function Method SyncFrom() mWorkMap = New TMap mWorkMap.mMapWidth = mMap.mMapWidth mWorkMap.mMapHeight = mmap.mMapHeight mworkmap.mMapDepth = mmap.mMapDepth mworkmap.mTileWidth = mmap.mTileWidth mworkmap.mTileHeight = mmap.mTileHeight mworkmap.mTile = New TTile[mWorkMap.mMapWidth, mWorkMap.mMapHeight, mWorkMap.mMapDepth] mworkmap.mDrawInfo = New TDrawInfo[mworkmap.mMapWidth, mworkmap.mMapHeight] For Local x:Int = 0 Until mworkmap.mMapWidth For Local y:Int = 0 Until mworkmap.mMapHeight mworkmap.mDrawInfo[x, y] = mMap.mDrawInfo[x, y] For Local z:Int = 0 Until mworkmap.mMapDepth mWorkMAp.mTile[x, y, z] = mMap.mTile[x, y, z] Next Next Next End Method Method SyncTo() If mMap = Null mMap = New TMap End If mMap.mMapWidth = mworkMap.mMapWidth mMap.mMapHeight = mworkmap.mMapHeight mmap.mMapDepth = mworkmap.mMapDepth mmap.mTileWidth = mworkmap.mTileWidth mmap.mTileHeight = mworkmap.mTileHeight mmap.mTile = New TTile[mWorkMap.mMapWidth, mWorkMap.mMapHeight, mWorkMap.mMapDepth] mmap.mDrawInfo = New TDrawInfo[mworkmap.mMapWidth, mworkmap.mMapHeight] For Local x:Int = 0 Until mworkmap.mMapWidth For Local y:Int = 0 Until mworkmap.mMapHeight mmap.mDrawInfo[x, y] = mworkMap.mDrawInfo[x, y] For Local z:Int = 0 Until mworkmap.mMapDepth mMAp.mTile[x, y, z] = mworkMap.mTile[x, y, z] Next Next Next End Method Method WriteHeader() mfile.WriteInt(mWorkMap.mMapWidth) mfile.WriteInt(mWorkMap.mMapHeight) mFile.WriteInt(mWorkMap.mMapDepth) mFile.WriteInt(mWorkmap.mTileWidth) mFile.WriteInt(Self.mWorkMap.mTileWidth) For Local x:Int = 0 Until mworkmap.mMapWidth For Local y:Int = 0 Until mworkmap.mMapHeight For Local z:Int = 0 Until mworkmap.mMapDepth If mworkmap.mTile[x, y, z] <> Null mFile.WriteByte(1) mFile.WriteLine(mworkmap.mTile[x, y, z].dPath) mFile.WriteLine(mworkmap.mTile[x, y, z].nPath) Else mFile.WriteByte(0) EndIf Next Next Next End Method Method ReadHeader() Local mw:Int = mfile.ReadInt() Local mh:Int = mfile.ReadInt() Local md:Int = mfile.ReadInt() Local tw:Int = mfile.ReadInt() Local th:Int = mfile.ReadInt() mworkMap = TMap.Create(mw, mh, md, tw, th) Local tl:TList = CreateList() For Local x = 0 Until mw For Local y = 0 Until mh For Local z = 0 Until md Local it:Int = mfile.ReadByte() If it Local t:TTile = New TTile t.dPath = mfile.ReadLine() t.nPath = mfile.ReadLine() mworkmap.mTile[x, y, z] = t End If Next Next Next End Method End Type Type TTextureRecord Extends TDataRecord Field mTexture:Texture Method New() mDataType = "Texture" End Method Function CreateTextureRecord:TTextureRecord(tex:Texture) Local r:TTextureRecord = New TTextureRecord r.mTexture = tex If r.mTexture.Path = "" Notify "Texture has no path. Aborting." EndIf Return r End Function Method SyncFrom() mBuf = mTexture.buf mSize = mtexture.Width * mTexture.Height * mTexture.depth mbufstream = CreateRamStream(mbuf, msize, True, True) InFile = False End Method Method SyncTo() Local pa:String = mtexture.Path mTexture = Texture.FromBuf(mbuf, mtexture.Width, mtexture.Height, mtexture.depth) mtexture.Path = pa 'mTexture.buf = mBuf 'mTexture.Bind() 'mTexture.Upload() 'mTexture.Unbind() End Method Method WriteHeader() mfile.WriteInt(mTexture.Width) mFile.WriteInt(mTexture.Height) mFile.WriteInt(mTexture.depth) mFile.WriteLine(mTexture.Path) End Method Method ReadHeader() Local w:Int = mFile.ReadInt() Local H:Int = mFile.ReadInt() Local depth:Int = mFile.ReadInt() Local path:String = mfile.ReadLine() ' If mtexture = Null mTexture = Texture.Blank(w, h, depth) mtexture.Path = path ' Else ' mtexture.Width = w ' mtexture.Height = h ' mtexture.depth = depth ' EndIf End Method End Type Type TDataRecord Field InMemory:Int, InFile:Int Field Name:String Field mDataType:String Field mBuf:Byte Ptr Field mSize:Int Field mBufStream:TRamStream Field mPath:String Field mFile:TStream Method SyncFrom() Abstract Method SyncTo() Abstract Method WriteHeader() Abstract Method ReadHeader() Abstract Method CreateBuffer(size:Int) If mbuf <> Null MemFree mbuf EndIf mbuf = MemAlloc(size) mbufstream = CreateRamStream(mbuf, msize, True, True) msize = size End Method Method Open() If FileType(mPath) = 0 mFile = WriteFile(mPath) If mFile = Null Notify "Could not create file:" + mPath + " Aborting program." End If CloseFile mfile EndIf mFile = OpenFile(mPath) End Method Method Write() Open() mFile.Seek(0) SyncFrom() WriteHeader() Local ed:Byte Ptr = MemAlloc(mSize * 2) Local el:Int = mSize * 2 compress2(ed, el, mbuf, msize, 9) mFile.WriteInt(mSize) mFile.WriteInt(el) mFile.Write(ed, el) MemFree ed Close() End Method Field LoadThread:TLoadRecordThread Method IsReady:Int() If LoadThread = Null Return True EndIf Local ret:Int = False LoadThread.mMutex.Lock() ret = loadthread.mDone LoadThread.mMutex.Unlock() Return ret End Method Field mThreadDoned = False Method ThreadDone() If mThreadDoned = False mThreadDoned = True SyncTo() LoadThread = Null EndIf End Method Method Read() LoadThread = New TLoadRecordThread LoadThread.mRecord = Self LoadThread.run() Print "Started Load Thread. Item:"+name+" DataType:"+mDataType+" Size:"+mSize End Method Method Close() CloseFile mFile End Method End Type Type TLoadRecordThread Extends AThread Field mRecord:TDataRecord Field mDone:Int = False Field mMutex:AMutex Method Init() mMutex = New AMutex mDone = False End Method Method ThreadLogic:Object() Print "Loading DataRecord assets. Item:"+mRecord.name+" DataType:"+mRecord.mDataType+" Size:"+mRecord.mSize mRecord.Open() Print "Open succesfull" mRecord.mFile.Seek(0) Print "Seek succesfull" mRecord.ReadHeader() Print "Read Header OK." Local os:Int = mRecord.mfile.ReadInt() Local ds:Int = mRecord.mFile.ReadInt() Print "Read Size OK." Local cb:Byte Ptr = MemAlloc(ds) Print "Allocated Memory OK." mRecord.CreateBuffer(os) Print "Create Internal Buffer OK." mRecord.mfile.Read(cb, ds) Print "Read Record OK." uncompress(mRecord.mBuf, os, cb, ds) Print "Uncompressed data into original form OK." mRecord.mSize = os Print "Set Size OK." mRecord.close() Print "Closed Record OK." 'mRecord.SyncTo() Print "Synced Resource OK." mMutex.Lock() Print "Locked Mutex OK." mDone = True Print "Set External Variable OK." mMutex.unlock() Print "DataRecord assets loaded. Item:"+mRecord.name+" DataType:"+mRecord.mDataType+" Size:"+mRecord.mSize End Method End Type Type TDatabase Field mName:String Field mAuthor:String Field mCopyright:String Field mPath:String Field mRecords:TList = CreateList() Field mFile:TStream Field mMainPath:String Method Finished() Save() End Method Function Create:TDatabase(name:String, path:String) Local r:TDatabase = New TDatabase r.mName = name r.mAuthor = "Dreambreaker Software" r.mCopyright = "(c)Dreambreaker Software 2008" r.mPath = path Local fp:String = Path + "DATA" If FileType(fp) = 0 CreateDir(fp, True) End If Local ind:String = path + ".wdb" r.mMainPath:String = ind Select FileType(ind) Case 1 r.SyncIndex() End Select Return r End Function Method AddRecord(t:TDataRecord, name:String) t.mPath = mPath + "DATA\" + name t.InMemory = True t.InFile = False t.Name = name mRecords.addlast(t) WriteIndex() Save() End Method Method Save() For Local r:TDataRecord = EachIn mRecords If r.InFile = False r.Write() r.InFile = True End If Next End Method Method GetAllOfType:TList(name:String, LoadIfNotInMemory:Int = True) name:String = name.ToLower() Local ret:TList = CreateList() For Local r:TDataRecord = EachIn mrecords If r.mDataType.ToLower() = name.ToLower() If LoadIfNotInMemory If r.InMemory = False Local ms:Int = MilliSecs() r.read() r.InMemory = True Print "Loaded Record:" + r.Name + " in ms:" + (MilliSecs() - ms) End If End If ret.AddLast(r) End If Next Return ret End Method Method FindRecord:TDataRecord(name:String, LoadIfNotInMemory:Int = True) name = name.ToLower() For Local r:TDataRecord = EachIn mRecords If r.Name.ToLower() = name If r.InMemory = False And LoadIfNotInMemory = True And r.LoadThread = Null r.Read() r.InMemory = True EndIf Return r EndIf Next Print "Record List" For Local r:TDataRecord = EachIn mRecords Print "Record:" + r.Name Next Print "Fin" Notify "Record Named:" + name + " was not found in db." End Method Method SyncIndex() mRecords.Clear() Open() mFile.Seek(0) Local i:Int = mFile.ReadInt() While i > 0 Local path:String = mfile.ReadLine() Local dtype:String = mFile.ReadLine() Local siz:Int = mFile.ReadInt() Local nam:String = mFile.ReadLine() Local d:TDataRecord Select dtype.ToLower() Case "zone" d = TDataRecord(New TZoneRecord) Case "texture" d = TDataRecord(New TTextureRecord) Case "map" d = TDataRecord(New TMapRecord) Case "light" d = TDataRecord(New TLightRecord) Default Notify "Unsupported Data Type." End Select d.mPath = path d.mDataType = dtype d.mSize = siz d.InMemory = False d.InFile = True d.Name = nam mRecords.AddLast(d) i:-1 Wend Close() End Method Method WriteIndex() Open() mFile.Seek(0) mFile.WriteInt(mRecords.Count()) For Local r:TDataRecord = EachIn mRecords mFile.WriteLine(r.mPath) mfile.WriteLine(r.mDataType) mFile.WriteInt(r.mSize) mFile.WriteLine(r.Name) Next Close() End Method Method Open() If FileType(mMainPath) = 0 mFile = WriteFile(mMainPath) CloseFile mFile End If mFile = OpenFile(mMainPath, True, True) If mFile = Null Notify "Could not open Database:" + mMainPath End End If End Method Method Close() mFile.Close() End Method Method SyncFrom() End Method End Type ' '--[ A.B.E Threading Component ]-- ' ' '-[ ' ' 'Threads are objects that you are supposed to extend to utilize their functionality. ' 'See the Examples/Threading test for an easy to follow example. ' '-] SuperStrict Import pub.threads Import brl.linkedList Type AMutex Field mHandle:Int Method New() mHandle = CreateMutex() End Method Method Delete() CloseMutex(mHandle) End Method Method Lock() LockMutex(mHandle) End Method Method Unlock() UnlockMutex(mHandle) End Method End Type Type AThread Field mHandle : Int Method Init() Abstract Method New() mHandle = 0 WaitOnDelete = False End Method Field WaitOnDelete:Int Method Delete() If WaitOnDelete WaitFor() Else detach() EndIf End Method Method Run() If mhandle <>0 Detach() EndIf Init() mHandle = CreateThread(RunThread_A,Object(Self)) End Method Method WaitFor:Object() If mHandle = 0 Return Null Local ret:Object = WaitThread(mHandle) mHandle = 0 Return ret End Method Method Detach() If mhandle=0 Return DetachThread(mHandle) mHandle = 0 End Method Method ThreadLogic:Object() Abstract End Type Function RunThread_A:Object(thread:Object) Local t:AThread = AThread(thread) Return t.ThreadLogic() End Function |
Comments
| ||
You'll have to comment out the example datarecord types. it just shows that to create a new type of record, you extend the base class and override a few methods. |
Code Archives Forum