Here's what I use as a model viewer.
It's almost as old as B3D itself and has had new features hacked in over the years, as they've become available or as I've needed them. So the things pretty crusty.
It's *far* from being *the* model viewer, but I still find it useful...
I should really rewrite this from scratch...But..If it ain't broke... etc. ;o)
It's almost as old as B3D itself and has had new features hacked in over the years, as they've become available or as I've needed them. So the things pretty crusty.
It's *far* from being *the* model viewer, but I still find it useful...
;Compile Me ;Then drop any model onto me to view ;KEYS:- ;space toggles bone mode ;i for more model info (just mesh size ATM) ;h Show help ;w toggles wireframe ;r to reload model (handy for texture changes etc) ;c toggles camera between map and model mode ;s toggles flat shading ;l toggles full bright ;v toggles vertex colour ;b toggles backfaces ;t toggles textures ;-= Model Mode =- ;LMB to rotate model ;RMB to reset model (and camera) rotation / position ;MMB to move model along X / Y axis ;MWHEEL to scale model (up / down CSR) + SHIFT for x10 (just zooms camera) ;0,1,2,3 to animate model ;Left / Right CSR to adjust anim speed ;-= Map Mode =- ;Mouse X/Y to rotate camera ;Up / Down CSR to move camera backward and forward ;Left / Right CSR to strafe camera ;RMB to increase speed x5 ChangeDir SystemProperty("AppDir") Const screen_w = 640 Const screen_h = 480 Global tab Global polys Global surfaces Global textures Type texture Field texture[256], used Field name$ End Type AppTitle "Yan's Rough'N'Ready model Viewer" Graphics3D screen_w, screen_h, 0, 2 input_model$ = Lower$(CommandLine$()) input_model$ = Replace$(input_model$, Chr$(34), "") TextureFilter "#a", 514 TextureFilter "#c", 128 TextureFilter "#e", 64 TextureFilter "#m", 4 mtype$ = Right$(input_model$, 4) If mtype$ = ".md2" md2 = 1 Else If (mtype$ = ".3ds") Or (mtype$ = ".b3d") Or (Right$(mtype$, 2) = ".x") md2 = 0 Else RuntimeError input_model$ + " is not a supported model type" EndIf EndIf If md2 model = LoadMD2(input_model$) texture_md2(model, input_model$) PositionEntity model, 0, 0, 0 length = MD2AnimLength(model) Else model = LoadAnimMesh(input_model$) PositionEntity model, 0, 0, 0 length = AnimLength(model) get_textures(model) ; For t.texture=Each texture ; DebugLog "Name : " + t\name$ ; For ti=1 To t\used ; DebugLog "Handle : " + t\texture[ti] ; Next ; DebugLog "Used : " + t\used ; DebugLog "" ; Next count_polys(model) EndIf cam = CreateCamera() PositionEntity cam, 0, 0, -75 light = CreateLight(1) LightColor light, 148 , 148, 148 PositionEntity light, 0, 250, -200 anim_text$ = "0 - Stopped" scale# = 1 inc# = 0.01 speed# = 1 mz = 0 mx = 0 my = 0 axis = 1 info = 0 help = 0 wf = 0 t_on = 2 camera_mode = 0 camera_text$ = "Model" cam_speed = 1 fx = 0 htw = 262 hth = 212 htx = (screen_w Shr 1) hty = (screen_h Shr 1) - (hth - 12) Repeat mz = MouseZSpeed() If KeyHit(19) surfaces = 0 textures = 0 polys = 0 tp# = EntityPitch(model) ty# = EntityYaw(model) tr# = EntityRoll(model) txa# = EntityX(model) tya# = EntityY(model) tza# = EntityZ(model) FreeEntity model For t.texture = Each texture For ti=1 To t\used FreeTexture t\texture[ti] Next Delete t Next If md2 model = LoadMD2(input_model$) texture_md2(model, input_model$) PositionEntity model, txa#, tya#, tza# length = MD2AnimLength(model) Else model = LoadAnimMesh(input_model$) PositionEntity model, txa#, tya#, tza# length = AnimLength(model) get_textures(model) count_polys(model) EndIf RotateEntity model, tp#, ty#, tr# ScaleEntity model, scale#, scale#, scale# EndIf If camera_mode = 0 If md2 If length > 1 If KeyHit(2) AnimateMD2 model, 1, 0.1, 1, length anim_text$ = "1 - Loop" EndIf If KeyHit(3) AnimateMD2 model, 2, 0.1, 1, length anim_text$ = "2 - Ping Pong" EndIf If KeyHit(4) AnimateMD2 model, 3, 0.1, 1, length anim_text$ = "3 - Single Shot" EndIf If KeyHit(11) AnimateMD2 model, 0 anim_text$ = "0 - Stop" EndIf EndIf Else If length > 1 If KeyHit(2) Animate model, 1, 0.1 anim_text$ = "1 - Loop" EndIf If KeyHit(3) Animate model, 2, 0.1 anim_text$ = "2 - Ping Pong" EndIf If KeyHit(4) Animate model, 3, 0.1 anim_text$ = "3 - Single Shot" EndIf If KeyHit(11) Animate model, 0 anim_text$ = "0 - Stopped" EndIf EndIf EndIf If KeyDown(42) Or KeyDown(54) inc# = 0.1 Else inc# = 0.01 EndIf If KeyDown(200) Or (mz = 1) scale# = scale# + inc# If scale# > 50 Then scale# = 50 ScaleEntity model, scale#, scale#, scale# EndIf If KeyDown(208) Or (mz = -1) scale# = scale# - inc# If scale# < 0 Then scale# = 0 ScaleEntity model, scale#, scale#, scale# EndIf If KeyHit(205) speed# = speed# + inc# If speed# > 10 Then speed# = 10 EndIf If KeyHit(203) speed# = speed# - inc# If speed# < 0 Then speed# = 0 EndIf If KeyHit(46) camera_mode = 1 camera_text$ = "Map" RotateEntity model, 0, 0, 0 FlushMouse() HidePointer() EndIf If MouseDown(1) TurnEntity model, -MouseYSpeed(), 0, 0, 1 TurnEntity model, 0, MouseXSpeed(), 0 Else If MouseDown(3) TranslateEntity model, MouseXSpeed() * 0.1, -(MouseYSpeed() * 0.1), 0, 1 Else MouseXSpeed() MouseYSpeed() EndIf EndIf If MouseHit(2) RotateEntity model, 0, 0, 0 PositionEntity model, 0, 0, 0 PositionEntity cam, 0, 0, -75 RotateEntity cam, 0, 0, 0 EndIf Else mxs# = MouseXSpeed() * 0.25 mys# = MouseYSpeed() * 0.25 MoveMouse screen_w Shr 1, screen_h Shr 1 TurnEntity cam, -mys#, 0, 0, 0 TurnEntity cam, 0, -mxs#, 0, 1 If KeyDown(200) Or (mz = 1) MoveEntity cam, 0, 0, cam_speed EndIf If KeyDown(208) Or (mz = -1) MoveEntity cam, 0, 0, -cam_speed EndIf If KeyDown(205) MoveEntity cam, cam_speed, 0, 0 EndIf If KeyDown(203) MoveEntity cam, -cam_speed, 0, 0 EndIf If MouseDown(2) cam_speed = 5 Else cam_speed = 1 EndIf If KeyHit(46) camera_mode = 0 camera_text$ = "Model" FlushMouse() ShowPointer() EndIf EndIf If KeyHit(23) Then info = 1 - info If KeyHit(35) Then help = 1 - help If KeyHit(17) wf = (wf + 1) Mod 3 WireFrame wf Mod 2 EndIf If KeyHit(31) fx = fx Xor 4 rec_fx(model, fx) EndIf If KeyHit(38) fx = fx Xor 1 rec_fx(model, fx) EndIf If KeyHit(47) fx = fx Xor 2 rec_fx(model, fx) EndIf If KeyHit(48) fx = fx Xor 16 rec_fx(model, fx) EndIf If KeyHit(20) t_on = 2 - t_on For t.texture = Each texture For ti=1 To t\used TextureBlend t\texture[ti], t_on Next Next EndIf If KeyHit(57) axis = axis + 1 If axis = 5 Then axis = 0 EndIf UpdateWorld speed# RenderWorld If md2 frame# = MD2AnimTime(model) Else frame# = AnimTime(model) EndIf If axis Then draw_bone_axis(model, cam, axis) If wf = 2 Then wire_frame(model, cam) Color 255, 255, 255 Text screen_w - 180, 0, "Total Length : " + length Text 0, 0, "Triangles : " + polys Text 0, 12, "Surfaces : " + surfaces Text 0, 24, "Textures : " + textures Text screen_w - 180, 12, "Current Frame : " + Left$(String$("0", 4 - Instr(frame#, ".")) + Str$(frame#), 6) Text screen_w - 180, 24, "Current Speed : " + Left$(String$("0", 4 - Instr(speed#, ".")) + Str$(speed#), 6) Text 0, screen_h - 14, "Anim Mode : " + anim_text$ Text 0, screen_h - 26, "Camera Mode : " + camera_text$ Text screen_w - 110, screen_h - 14, "Scale : " + Left$(String$("0", 3 - Instr(scale#, ".")) + Str$(scale#), 5) If info If md2 = 0 Text screen_w Shr 1, (screen_h Shr 1) - 12, "Width : " + MeshWidth(model), 1, 1 Text screen_w Shr 1, screen_h Shr 1, "Height : " + MeshHeight(model), 1, 1 Text screen_w Shr 1, (screen_h Shr 1) + 12, "Depth : " + MeshDepth(model), 1, 1 EndIf EndIf If help Color 0, 0, 200 Rect htx - htw, hty - 12, (htw Shl 1), (hth Shl 1), 1 Color 255, 255, 255 Rect htx - htw, hty - 12, (htw Shl 1), (hth Shl 1), 0 Text htx, hty, "-= General =-", 1, 1 Text htx, (hty + 12), "space toggles bone mode", 1, 1 Text htx, (hty + 24), "i for more model info (just mesh size ATM)", 1, 1 Text htx, (hty + 36), "h Show help", 1, 1 Text htx, (hty + 48), "w toggles wireframe", 1, 1 Text htx, (hty + 60), "r to reload model (handy for texture changes etc)", 1, 1 Text htx, (hty + 72), "c toggles camera between map and model mode", 1, 1 Text htx, (hty + 84), "s toggles flat shading", 1, 1 Text htx, (hty + 96), "l toggles full bright", 1, 1 Text htx, (hty + 108), "v toggles vertex colour", 1, 1 Text htx, (hty + 120), "b toggles backfaces", 1, 1 Text htx, (hty + 132), "t toggles textures", 1, 1 Text htx, (hty + 156), "-= Model Mode =-", 1, 1 Text htx, (hty + 168), "LMB to rotate model", 1, 1 Text htx, (hty + 180), "RMB to reset model (and camera) rotation / position", 1, 1 Text htx, (hty + 192), "MMB to move model along X / Y axis", 1, 1 Text htx, (hty + 204), "MWHEEL to scale model (up / down CSR) + SHIFT for x10", 1, 1 Text htx, (hty + 216), "0,1,2,3 to animate model", 1, 1 Text htx, (hty + 228), "Left / Right CSR to adjust anim speed", 1, 1 Text htx, (hty + 252), "-= Map Mode =-", 1, 1 Text htx, (hty + 266), "Mouse X/Y to rotate camera", 1, 1 Text htx, (hty + 278), "Up / Down CSR to move camera backward and forward", 1, 1 Text htx, (hty + 290), "Left / Right CSR to strafe camera", 1, 1 Text htx, (hty + 302), "RMB to increase speed x5", 1, 1 EndIf Flip 0 Delay(33) Until KeyDown(1) End Function draw_bone_axis(root, cam, mode, pjx_2d=-1, pjy_2d=-1) Local j, jx_2d, jy_2d, child, tz# ; Joints position CameraProject cam, EntityX(root, 1), EntityY(root, 1), EntityZ(root, 1) jx_2d = ProjectedX() : jy_2d = ProjectedY() ; X axis Color 255, 0, 0 TFormPoint 2, 0, 0, root, 0 CameraProject cam, TFormedX(), TFormedY(), TFormedZ() Line jx_2d, jy_2d, ProjectedX(), ProjectedY() ; Y axis Color 0, 255, 0 TFormPoint 0, 2, 0, root, 0 CameraProject cam, TFormedX(), TFormedY(), TFormedZ() Line jx_2d, jy_2d, ProjectedX(), ProjectedY() ; Z axis Color 0, 0, 255 TFormPoint 0, 0, 2, root, 0 CameraProject cam, TFormedX(), TFormedY(), TFormedZ() Line jx_2d, jy_2d, ProjectedX(), ProjectedY() ; Pivot Color 255, 255, 255 Oval jx_2d - 2, jy_2d - 2, 4, 4, 1 If (mode = 2) Or (mode = 4) Color 255, 255, 255 Text jx_2d, jy_2d, EntityName$(root), 0, 1 EndIf If (mode = 3) Or (mode = 4) If (pjx_2d <> -1) If (pjy_2d <> -1) Color 255, 0, 255 Line jx_2d, jy_2d, pjx_2d, pjy_2d EndIf EndIf EndIf If EntityClass$(root) <> "Pivot" jx_2d = -1 jy_2d = -1 EndIf For j=1 To CountChildren(root) child = GetChild(root, j) If child Then draw_bone_axis(child, cam, mode, jx_2d, jy_2d) Next End Function Function count_polys(mesh) Local s, c If EntityClass$(mesh) = "Mesh" For s=1 To CountSurfaces(mesh) polys = polys + CountTriangles(GetSurface(mesh, s)) Next EndIf For c=1 To CountChildren(mesh) count_polys(GetChild(mesh, c)) Next End Function ;Function count_surfaces(mesh) ; Local c ; ; If EntityClass$(mesh) = "Mesh" Then surfaces = surfaces + CountSurfaces(mesh) ; ; For c=1 To CountChildren(mesh) ; count_surfaces(GetChild(mesh, c)) ; Next ;End Function Function wire_frame(mesh, cam) Local si, s, ti, v, tvx[2], tvy[2], child, j If EntityClass$(mesh) = "Mesh" LockBuffer For si=1 To CountSurfaces(mesh) s = GetSurface(mesh, si) For ti=0 To CountTriangles(s) - 1 For v=0 To 2 vi = TriangleVertex(s, ti, v) TFormPoint VertexX(s, vi), VertexY(s, vi), VertexZ(s, vi), mesh, 0 CameraProject cam, TFormedX(), TFormedY(), TFormedZ() tvx[v] = ProjectedX() tvy[v] = ProjectedY() Next If (((tvx[0] - tvx[1]) * (tvy[2] - tvy[1])) - ((tvy[0] - tvy[1]) * (tvx[2] - tvx[1]))) < 0 Color 255, 255, 255 Line tvx[0], tvy[0], tvx[1], tvy[1] Line tvx[1], tvy[1], tvx[2], tvy[2] Line tvx[2], tvy[2], tvx[0], tvy[0] EndIf Next Next UnlockBuffer EndIf For j=1 To CountChildren(mesh) child = GetChild(mesh, j) If child Then wire_frame(child, cam) Next End Function Function get_textures(mesh) Local c, b, cs, bt, bi, match, ttex$, tname$ If EntityClass$(mesh) = "Mesh" surfaces = surfaces + CountSurfaces(mesh) For cs=1 To CountSurfaces(mesh) b = GetSurfaceBrush(GetSurface(mesh, cs)) For bi=0 To 7 bt = GetBrushTexture(b, bi) ttex$ = TextureName$(bt) tname$ = Right$(ttex$, Len(ttex$) - last_slash(ttex$)) If tname$ <> "" match = 0 For t.texture = Each texture If tname$ = t\name$ t\used = t\used + 1 t\texture[t\used] = bt match = 1 Exit EndIf Next If (Not match) t.texture = New texture t\texture[1] = bt t\used = 1 t\name$ = tname$ textures = textures + 1 EndIf Else FreeTexture bt EndIf Next FreeBrush b Next EndIf For c=1 To CountChildren(mesh) get_textures(GetChild(mesh, c)) Next End Function Function texture_md2(mesh, fname$) Local name$, path$, p$, sp, dir, d$, ext$ = ".jpg.bmp.tif.png.pcx",txt fname$ = Lower$(fname$) sp = last_slash(fname$) p$ = Left$(fname$, sp) name$ = Right$(fname$, Len(fname$) - sp) name$ = Left$(name$, Instr(name$, ".") - 1) dir = ReadDir(p$) d$ = NextFile(dir) While d$ <> "" If FileType(p$ + d$) = 1 If Instr(d$, name$) > 0 If Instr(ext$, Right$(d$, 4)) > 0 txt = LoadTexture(p$ + d$) EntityTexture mesh, txt FreeTexture txt Return EndIf EndIf EndIf d$ = NextFile(dir) Wend End Function Function last_slash(path$) Local sp For sp=Len(path$) To 1 Step -1 If (Mid$(path$, sp, 1) = "/") Or (Mid$(path$, sp, 1) = "") Then Return sp Next Return Len(path$) End Function Function rec_fx(mesh, flags) Local c If EntityClass$(mesh) = "Mesh" Then EntityFX mesh, flags For c=1 To CountChildren(mesh) rec_fx(GetChild(mesh, c), flags) Next End Function
I should really rewrite this from scratch...But..If it ain't broke... etc. ;o)