Legend of Faerghail Remake
Community Forums/Showcase/Legend of Faerghail Remake
| ||
![]() My current project beside Extrasolar is a old one - I started 8 years ago with simple Blitz3D tests and now it's becoming better and better. A remake of the old Amiga RPG "Legend of Faerghail" from 1990. Well, I'm getting very familar with OpenB3D now, got my shaders running and I'm still optimizing the BSP loader. At the moment I only have a few screenshots to show the progress, it's still not optimized enough to post a running demo (click images for high resolution). But a demo will follow later when I think its ok, promised. The torchlight is actually a type 3 spotlight which looks much better than a type 2, all textures use normalmaps and I have a lot of alpha brush models and additional custom B3D models loaded in this level (the knights and the chandliers are plain B3D models (with a shader, too) while the piano and the table are precalculated in the BSP map with a lightmap assigned). I'm not using any dynamic lights except the player torch and a "ambient light torch" to lighten up very dark areas with a decent dark blue tone. The candles, the torches and the fireplaces are simple sprites, not optimized in a single surface mesh yet. The level is absolutely dark except where your "torch" lights it up or the lightmap exists, hard to describe but looks very realistic. The demo currently runs at 2560x1440 with 280 FPS and has been created using Microsoft Excel ;-) for the basic 2D level structure, a highly sophisticated CSV to MAP tool I wrote myself and the detailed work / compile has been done with a Netradiant fork and Q3MAP2. I'm using 105 different shaded surfaces right now but hope to decrease this number implementing a better shader cache for the BSP meshes like I already did with the B3D models. See some statistics below the screenshots. Oh and compare the screenshots with my old Blitzmax Demo using DOT3 lights I made two years ago, which was too colorful and limited to vertex lighting. ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Excel view of the level (just basic infos and height information are set) ![]() Output of my CSV2MAP tool (starting a the green square at the top, looking south). All Walls, Doors, Event fields, treasure chests and lights are places automatically by just parsing the CSV file ![]() If you're interested how it's done here is the Blitz3D source of it (still hadn't time to convert this to BMAX) You can download the Excel Map and the CSV Output. Netradiant view of the level ![]() BSP Size: 6.820.596 Bytes Parsing BSP Entities... 1 worldspawn 249 misc_gamemodel 46 func_door 67 info_event 3 info_darkness 3 info_vortex 3 info_trap 4 info_stair 266 light 1 info_player_start 3 fireplace 9 info_candle 10 func_brush 665 Entities found. Final Map statistics: Total BSP Surfaces: 94 Total BSP Vertices: 136149 Total BSP Triangles: 45383 Total BSP Models: 57 Solid BSP Level Meshes: 7 Alpha BSP Level Meshes: 50 Level Shaders: 94 Ingame Models (unique): 8 Ingame Models (reused): 241 in Instances Model Shaders (unique): 11 Model Shaders (reused): 274 Torch Sprites: 16 Candle Sprites: 257 Fireplace Sprites: 3 Parse Time: 831ms Assemble Time: 189ms Total Build Time: 1020ms |
| ||
Can't wait to see a demo(you know I love your work) ;-) |
| ||
Look great Krischan, very atmospheric! |
| ||
Fantastic |
| ||
Wow! Is OpenB3D a version of MiniB3D for BMax? |
| ||
I like it, it reminds me of Thief 1/2 ambiance (with better graphics) |
| ||
Looking good :) |
| ||
Incredible - looks amazing! |
| ||
looking forward to seeing this :) |
| ||
@therevills: well, at least it shares the same syntax. If you know miniB3D you can get into OpenB3D very quick, too. Thanks for the comments, I really appreciate your feedback. But currently I'm desperate because I can only use one lightmap using shaders. To speed things up I implemented a shadercache and it works really good but see yourself: Brushtexture Lightmap ![]() Shader Lightmap ![]() With the "classic" brush to surface method the lightmap (which consists of two separate textures stored in the BSP_LightmapHandle[BSP_FaceLightmap[i], 0] handle) aligns perfect. BSP_FaceLightmap[i] stores the index [0...x] of the lightmap and the BSP_LightmapHandle[] stores the corresponding texture loaded. If I uncomment the last line with "ShadeSurface" command the lightmap is broken, it looks like only Lightmap index 0 is applied while there are 0 and 1. The problem can be "bypassed" increasing the lightmapsize so that only one lightmap exists but this is only a temporary workaround and no solution I'd prefer. I really don't get it where the problem is, do you have an idea what I've missed here? I don't understand why the brush works and the shader doesn't even they are both using the same variables set before. I've added the BSP shaders, too. There, the "lmCoords" variable holds the Texture Coordinates (Set 1) and the "lightMap" variable in the fragment shader the lightmap texture set in the shader. I'm not sure if I implemented this correct, I couldn't find any example in the OpenB3D package so I had to perform try and error until it worked. The Mesh Assemble Method from my BSP loader ' -------------------------------------------------------------------------------- ' assemble map submodel ' -------------------------------------------------------------------------------- Method Q3BSP_AssembleModel:Int(num:Int) Local i:Int, t:Int, surf:TSurface, e:Int, newsurf:Int, texname:String Local index:Int, indexb:Int, indexc:Int, indexd:Int Local V0:Int, V1:Int, V2:Int Local sx:Float, sy:Float, sz:Float Local texture:TTexture Local normalmap:TTexture Local lightmap:TTexture Local brush:TBrush Local Class:Int = Null BSP_Model[num] = CreateMesh() For i = BSP_ModelFacestart[num] To BSP_ModelFaceend[num] texname = BSP_TextureName[BSP_FaceTexture[i]] ' Flag for Alpha Models If Instr(texname, "alpha") Then Class = 1 ' skip skybox If (Not Instr(texname, "sky")) Then ' always create a new surface newsurf = 1 lightmap = BSP_LightmapHandle[BSP_FaceLightmap[i], 0] ' or recycle available surfaces For t = 1 To BSP_SurfaceCount[num] ' Texture and Lightmap match? recycle! If BSP_SurfaceTexture[t] = BSP_FaceTexture[i] And BSP_SurfaceLightmap[t] = BSP_FaceLightmap[i] Then surf = GetSurface(BSP_model[num], t) newsurf = 0 Exit EndIf Next ' still new surface? If newsurf Then brush = CreateBrush() ' create a new surface surf = CreateSurface(BSP_Model[num], brush) BSP_SurfaceCount[num] = BSP_SurfaceCount[num] + 1 BSP_SurfaceTexture[BSP_SurfaceCount[num]] = BSP_FaceTexture[i] BSP_SurfaceLightmap[BSP_SurfaceCount[num]] = BSP_FaceLightmap[i] EndIf ' set faceindex start index = BSP_FaceVertex[i] ' build the mesh For e = BSP_FaceMeshVertex[i] To BSP_FaceMeshVertex[i] + BSP_FaceMeshNumber[i] - 1 Step 3 indexb = index + BSP_MeshVertexOffset[e + 0] indexc = index + BSP_MeshVertexOffset[e + 1] indexd = index + BSP_MeshVertexOffset[e + 2] ' position correction sx = -BSP_ModelBoxXstart[num] - (BSP_ModelScaleX[num] / 2.0) sy = -BSP_ModelBoxYstart[num] - (BSP_ModelScaleY[num] / 2.0) sz = -BSP_ModelBoxZstart[num] - (BSP_ModelScaleZ[num] / 2.0) ' vertices V0 = AddVertex(surf, BSP_VertexCoordX[indexb] + sx, BSP_VertexCoordZ[indexb] + sy, BSP_VertexCoordY[indexb] + sz, BSP_VertexTexCoordU[indexb], BSP_VertexTexCoordV[indexb]) V1 = AddVertex(surf, BSP_VertexCoordX[indexc] + sx, BSP_VertexCoordZ[indexc] + sy, BSP_VertexCoordY[indexc] + sz, BSP_VertexTexCoordU[indexc], BSP_VertexTexCoordV[indexc]) V2 = AddVertex(surf, BSP_VertexCoordX[indexd] + sx, BSP_VertexCoordZ[indexd] + sy, BSP_VertexCoordY[indexd] + sz, BSP_VertexTexCoordU[indexd], BSP_VertexTexCoordV[indexd]) ' vertex colors VertexColor surf, V0, BSP_VertexRed[indexb], BSP_VertexGreen[indexb], BSP_VertexBlue[indexb] VertexColor surf, V1, BSP_VertexRed[indexc], BSP_VertexGreen[indexc], BSP_VertexBlue[indexc] VertexColor surf, V2, BSP_VertexRed[indexd], BSP_VertexGreen[indexd], BSP_VertexBlue[indexd] ' vertex normals VertexNormal surf, V0, BSP_VertexNX[indexb], BSP_VertexNZ[indexb], BSP_VertexNY[indexb] VertexNormal surf, V1, BSP_VertexNX[indexc], BSP_VertexNZ[indexc], BSP_VertexNY[indexc] VertexNormal surf, V2, BSP_VertexNX[indexd], BSP_VertexNZ[indexd], BSP_VertexNY[indexd] ' second coordinate set (lightmap) VertexTexCoords surf, V0, BSP_VertexLightmapCoordU[indexb], BSP_VertexLightmapCoordV[indexb], 1, 1 VertexTexCoords surf, V1, BSP_VertexLightmapCoordU[indexc], BSP_VertexLightmapCoordV[indexc], 1, 1 VertexTexCoords surf, V2, BSP_VertexLightmapCoordU[indexd], BSP_VertexLightmapCoordV[indexd], 1, 1 ' combine vertices to triangles AddTriangle(surf, V0, V1, V2) Next ' set second UV set for lightmap texture coordinates TextureCoords lightmap, 1 ' check for texture For Local tx:TBSPTexture = EachIn TBSPTexture.list ' texture found? If tx.Name = texname Then ' prepare for shader use texture = tx.id normalmap = tx.nm ' has the shader already been used before? If MapValueForKey(ShaderCache, tx.id) Then sc = TBSPshadercache(MapValueForKey(ShaderCache, tx.id)) ShaderCacheReused:+1 Else sc = New TBSPshadercache ' Create the Shader from the preloaded files to speed this up sc.shader = CreateShader("", BSP_VertShader, BSP_FragShader) SetFloat4(sc.shader, "tangent", 1.0, 1.0, 1.0, 1.0) SetFloat3(sc.shader, "emission", 0.015, 0.015, 0.015) SetFloat(sc.shader, "attspec", 0.0025) SetFloat3(sc.shader, "fogColor", FogColor[0], FogColor[1], FogColor[2]) ' different specularity for alpha models If Class = 1 Then SetFloat(sc.shader, "attspec", 0.005) ' Apply Level Shader ShaderTexture(sc.shader, texture, "diffuseMap", 0) ShaderTexture(sc.shader, normalmap, "normalMap", 1) ShaderTexture(sc.shader, lightmap, "lightMap", 2) ' count shaders ShaderCacheUnique:+1 ' store Type for shader recycling MapInsert(ShaderCache, tx.id, sc) EndIf EndIf Next ' old method to paint the surface with a brush (works) BrushTexture brush, lightmap PaintSurface surf, brush ' new method to paint the surface with a shader (broken) ShadeSurface(surf, sc.shader) EndIf Next Return Class End Method The Vertex Shader The Fragment Shader |
| ||
Looks great! Would a transition to BMX help to speed things up a bit? |
| ||
Ehm Grisu, this IS already done in BMX :-p |
| ||
Oh... so you already support DirectX11 as well? |
| ||
No, OpenB3D is based on OpenGL. As you can read here: https://sourceforge.net/projects/minib3d/ "OpenB3d is a library that allows easy access to 3d features of OpenGL, and quick game development" |
| ||
Nice work Krischan! I'm not really familiar with BSP but did you consider using something like distance to determine which lightmap is used for each area? I'm not sure how far on Kfprimm is with it now but MaxB3d has both DX and GL drivers. |
| ||
Mark, I don't understand what you mean with the "lightmap distance". I think it is either a logical problem I've overseen in the Method I've posted how to apply the lightmap to the shader or a problem within the shader itself. As I wrote, the BrushTexture/Paintsurface stuff works fine, so I guess the Method is ok. BSP is a very simple file format, the faces are indexed with a lightmap index ID and the lightmap UVs are stored together with the vertices using the second texture coordinate set, nothing special here. It could be the call of the Texturecoordinates in the vertex shader but I'm not very experienced in GLSL shader programming yet to debug this on my own. I've already read tons of tutorials and documentation but couldn't really find a solution for this problem. Oh by the way - walking through the level looks much better than the screenshots can show :-D I still need to add some features, embed everything in my MaxGUI Framework and add other props but anyway I made a short sneak preview clip running through a part of the level (I hope you don't get dizzy of the unoptimized camera movement and the 115° FOV :-) The video is limited to 30FPS while the demo could run up to 280FPS currently. I didn't implement any timing yet, so this is plain spaghetti code :-D But in this video you should clearly see all Shader effects done with OpenB3D (the Torchlight / Bumpmapping and the Lightning strikes and even the fireplace animation is a spritesheet passed to a shader). The hardest part are good normal maps like the floor texture while I'm not very happy with the wall and the ceiling but that's the best I found so far. Legend of Faerghail Sneak Preview (the demo looks much better than this video, I don't know why my youtube uploads always look messy compared to the original) For the engine I think I'll stay with OpenGL as it is a open standard and works on Linux and MacOS, too. And so I would really appreciate if OpenB3D gets developed further. IMHO it is a real successor of miniB3D and the first easy to use 3D engine for Blitzmax since then :-) |
| ||
Nice work !!! |
| ||
Awesome video! - The footsteps sound a bit strange though. |
| ||
By the way - here is an example how I upscaled the Amiga "texture" to use it in my engine. I want the original art of the game but more polished without losing the original texture character. So I experimented a long time and came up with this 6-step process. I started with a rip of the original image from WinUAE: 1. Original "Texture" 120x119 Pixel ![]() 2. Upscaled using ImageResizer and its XBR 4x filter applied (2x) and downsized it from 1920x1920 to 1024x1024 Pixel ![]() 3. Running my 1st Photoshop Action script to improve it further ![]() 4. Running my 2nd Photoshop Action script to add more details ![]() 5. Adding details / ageing using Genetica 4.0 (Basic Edition) and some trim textures from textures.com (this is the final Diffusemap). I'm sure you can achieve similar effects using the free Neo Texture Edit tool. ![]() 6. Creating a Normalmap from this Diffusemap with the free NormalMap-Online tool ![]() Easy, huh? ;-) |
| ||
The footstep is a mix of the original footstep sound from the Amiga remastered in Stereo. I think it sounds strange to you because of the 30 FPS recording (the timing code playing the sample doesn't match the movement correctly below 60 FPS). I think in a final game you could choose between the Retro sounds and optimized sounds :-D |
| ||
Oh sorry, I am a bit rusty with GL currently having been away from coding for many months, so please ignore my lightmap distance suggestion! I've never looked at ShadeSurface, so don't have anything to say, perhaps you should define texcoords 1 in the shader? It could also be a bug, as I remember there are some. Have you been using the version by DruggedBunny or Spinduluz? I will probably take a month or two to get round to an update. Thanks for the video, the bumpmap is looking good! I wish you success for it. Also thanks for the how-to information! |
| ||
Wow, impressive! |
| ||
I'm using your latest wrapper (including the OpenB3D source included in it) from here only. |
| ||
I want the original art of the game but more polished without losing the original texture character. So I experimented a long time and came up with this 6-step process. Very impressive. Character not lost, and no artwork to be produced! :) |
| ||
Well, the downside is that this HQ wall texture uses more diskspace than the whole Amiga game occupied on three SD floppy disks (a 24bit uncompressed TGA uses 3.145.746 Bytes and one ADF floppy image has 901.120 x 3 = 2.703.360 Bytes for the whole game) :-p And we have to multiplicate the TGA size x 2 because there is a normal map, too! But hey, it really looks better than 120x119 Pixels with 4 colors ;-) |
| ||
Great graphics and atmosphere! Very creapy. Especially in the darker sections it feels like you can expect something to jump at you any second. All I missed was a thunder and wind blowing sfx hehehe. |
| ||
Umm Rick, did you watch the video? There are lightnings, thunder, wind blowing and rain SFX :-) |
| ||
So true. In beginning of video I hear the thunder sound indeed, at which point I previously had the audio muted, but further down the video there's no thunder/weather sound anymore so missed that before - silly me. |
| ||
Unfortunately the sound quality of the video is very bad, I used Fraps here and the stereo grab of the windows sound card sounds different compared to the demo (in the video it sounds like you are inside a large metal tank). |
| ||
Ah, that's a pity then. |
| ||
Badicam It is faster than fraps. is Free. https://www.bandicam.com/ |
| ||
FWIW, Windows 10 has (game) screen recording built-in if your graphics card is good enough. |
| ||
Ah you mean the XBOX app - I tried it but it sounds similar. I really don't know why - perhaps I'm using too many channels at the same time (currently 9, with the brl.DirectSoundAudio import) but the demo sounds normal. Which sound driver do you prefer? |
| ||
great.. stuff.. impressed.. |