mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2024-10-01 15:46:17 -04:00
Added font rendering and label support
This commit is contained in:
parent
78190b12d6
commit
3d98be98fe
@ -6,7 +6,8 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace OpenDiablo2.Common.Interfaces
|
||||
{
|
||||
public interface IFont
|
||||
public interface IFont : IDisposable
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
17
OpenDiablo2.Common/Interfaces/ILabel.cs
Normal file
17
OpenDiablo2.Common/Interfaces/ILabel.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OpenDiablo2.Common.Interfaces
|
||||
{
|
||||
public interface ILabel : IDisposable
|
||||
{
|
||||
string Text { get; set; }
|
||||
Point Position { get; set; }
|
||||
Size TextArea { get; set; }
|
||||
Color TextColor { get; set; }
|
||||
}
|
||||
}
|
@ -17,8 +17,14 @@ namespace OpenDiablo2.Common.Interfaces
|
||||
void Sync();
|
||||
ISprite LoadSprite(string resourcePath, string palette, Point location);
|
||||
ISprite LoadSprite(string resourcePath, string palette);
|
||||
IFont LoadFont(string resourcePath, string palette);
|
||||
ILabel CreateLabel(IFont font);
|
||||
ILabel CreateLabel(IFont font, string text);
|
||||
ILabel CreateLabel(IFont font, Point position, string text);
|
||||
void Draw(ISprite sprite);
|
||||
void Draw(ISprite sprite, Point location);
|
||||
void Draw(ISprite sprite, int frame);
|
||||
void Draw(ISprite sprite, int xSegments, int ySegments, int offset);
|
||||
void Draw(ILabel label);
|
||||
}
|
||||
}
|
||||
|
43
OpenDiablo2.Common/Models/MPQFont.cs
Normal file
43
OpenDiablo2.Common/Models/MPQFont.cs
Normal file
@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OpenDiablo2.Common.Models
|
||||
{
|
||||
public sealed class MPQFont
|
||||
{
|
||||
public ImageSet FontImageSet;
|
||||
public Dictionary<byte, Size> CharacterMetric = new Dictionary<byte, Size>();
|
||||
|
||||
public static MPQFont LoadFromStream(Stream fontStream, Stream tableStream)
|
||||
{
|
||||
var result = new MPQFont
|
||||
{
|
||||
FontImageSet = ImageSet.LoadFromStream(fontStream)
|
||||
};
|
||||
|
||||
var br = new BinaryReader(tableStream);
|
||||
var wooCheck = Encoding.UTF8.GetString(br.ReadBytes(4));
|
||||
if (wooCheck != "Woo!")
|
||||
throw new ApplicationException("Error loading font. Missing the Woo!");
|
||||
br.ReadBytes(8);
|
||||
|
||||
while (tableStream.Position < tableStream.Length)
|
||||
{
|
||||
br.ReadBytes(3);
|
||||
var size = new Size(br.ReadByte(), br.ReadByte());
|
||||
br.ReadBytes(3);
|
||||
var charCode = br.ReadByte();
|
||||
result.CharacterMetric[charCode] = size;
|
||||
br.ReadBytes(5);
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
@ -19,10 +19,11 @@ namespace OpenDiablo2.Common.Models
|
||||
public string Name { get; set; }
|
||||
public PaletteEntry[] Colors;
|
||||
|
||||
public static Palette LoadFromStream(Stream stream)
|
||||
public static Palette LoadFromStream(Stream stream, string paletteName)
|
||||
{
|
||||
var result = new Palette
|
||||
{
|
||||
Name = paletteName,
|
||||
Colors = new PaletteEntry[256]
|
||||
};
|
||||
|
||||
|
@ -70,6 +70,7 @@
|
||||
<Compile Include="Enums\eMPQFormatVersion.cs" />
|
||||
<Compile Include="Interfaces\IFont.cs" />
|
||||
<Compile Include="Interfaces\IGameEngine.cs" />
|
||||
<Compile Include="Interfaces\ILabel.cs" />
|
||||
<Compile Include="Interfaces\IMPQProvider.cs" />
|
||||
<Compile Include="Interfaces\IMusicProvider.cs" />
|
||||
<Compile Include="Interfaces\IPaletteProvider.cs" />
|
||||
@ -80,6 +81,7 @@
|
||||
<Compile Include="Interfaces\IMouseInfoProvider.cs" />
|
||||
<Compile Include="Interfaces\ITextLabel.cs" />
|
||||
<Compile Include="Models\BitStream.cs" />
|
||||
<Compile Include="Models\MPQFont.cs" />
|
||||
<Compile Include="Models\GlobalConfiguration.cs" />
|
||||
<Compile Include="Models\ImageSet.cs" />
|
||||
<Compile Include="Models\MPQ.cs" />
|
||||
|
@ -20,5 +20,12 @@ namespace OpenDiablo2.Common
|
||||
|
||||
// --- Mouse Pointers ---
|
||||
public static string CursorDefault = "data\\global\\ui\\CURSOR\\ohand.DC6";
|
||||
|
||||
// --- Fonts ---
|
||||
public static string Font8 = "data\\local\\font\\latin\\font8";
|
||||
public static string Font16 = "data\\local\\font\\latin\\font16";
|
||||
public static string FontFormal12 = "data\\local\\font\\latin\\fontformal12";
|
||||
public static string FontFormal10 = "data\\local\\font\\latin\\fontformal10";
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ namespace OpenDiablo2.Core
|
||||
{
|
||||
var paletteNameParts = paletteFile.Split('\\');
|
||||
var paletteName = paletteNameParts[paletteNameParts.Count() - 2];
|
||||
PaletteTable[paletteName] = Palette.LoadFromStream(mpqProvider.GetStream(paletteFile));
|
||||
PaletteTable[paletteName] = Palette.LoadFromStream(mpqProvider.GetStream(paletteFile), paletteName);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,6 +75,8 @@
|
||||
<Compile Include="SDL2-CS\SDL2_image.cs" />
|
||||
<Compile Include="SDL2-CS\SDL2_mixer.cs" />
|
||||
<Compile Include="SDL2-CS\SDL2_ttf.cs" />
|
||||
<Compile Include="SDL2Font.cs" />
|
||||
<Compile Include="SDL2Label.cs" />
|
||||
<Compile Include="SDL2MusicPlayer.cs" />
|
||||
<Compile Include="SDL2RenderWindow.cs" />
|
||||
<Compile Include="SDL2Sprite.cs" />
|
||||
|
34
OpenDiablo2.SDL2/SDL2Font.cs
Normal file
34
OpenDiablo2.SDL2/SDL2Font.cs
Normal file
@ -0,0 +1,34 @@
|
||||
using OpenDiablo2.Common.Interfaces;
|
||||
using OpenDiablo2.Common.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OpenDiablo2.SDL2_
|
||||
{
|
||||
internal sealed class SDL2Font : IFont
|
||||
{
|
||||
internal readonly MPQFont font;
|
||||
internal readonly SDL2Sprite sprite;
|
||||
|
||||
public Palette CurrentPalette
|
||||
{
|
||||
get => sprite.CurrentPalette;
|
||||
set => sprite.CurrentPalette = value;
|
||||
}
|
||||
|
||||
internal SDL2Font(MPQFont font, IntPtr renderer)
|
||||
{
|
||||
this.font = font;
|
||||
|
||||
sprite = new SDL2Sprite(font.FontImageSet, renderer);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
sprite.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
123
OpenDiablo2.SDL2/SDL2Label.cs
Normal file
123
OpenDiablo2.SDL2/SDL2Label.cs
Normal file
@ -0,0 +1,123 @@
|
||||
using OpenDiablo2.Common.Interfaces;
|
||||
using SDL2;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OpenDiablo2.SDL2_
|
||||
{
|
||||
internal sealed class SDL2Label : ILabel
|
||||
{
|
||||
private readonly SDL2Font font;
|
||||
private readonly IntPtr renderer;
|
||||
internal IntPtr texture;
|
||||
internal Size textureSize = new Size();
|
||||
public Point Position { get; set; }
|
||||
public Size TextArea { get; set; } = new Size();
|
||||
|
||||
private Color textColor = Color.White;
|
||||
public Color TextColor
|
||||
{
|
||||
get => textColor;
|
||||
set
|
||||
{
|
||||
textColor = value;
|
||||
RegenerateTexture();
|
||||
}
|
||||
}
|
||||
|
||||
private string text;
|
||||
public string Text
|
||||
{
|
||||
get => text;
|
||||
set
|
||||
{
|
||||
text = value;
|
||||
RegenerateTexture();
|
||||
}
|
||||
}
|
||||
|
||||
internal SDL2Label(IFont font, IntPtr renderer)
|
||||
{
|
||||
this.renderer = renderer;
|
||||
this.font = font as SDL2Font;
|
||||
texture = IntPtr.Zero;
|
||||
}
|
||||
|
||||
internal Size CalculateSize()
|
||||
{
|
||||
int w = 0;
|
||||
int h = 0;
|
||||
foreach (var ch in text)
|
||||
{
|
||||
var metric = font.font.CharacterMetric[(byte)ch];
|
||||
w += metric.Width;
|
||||
h = Math.Max(h, metric.Height);
|
||||
}
|
||||
|
||||
return new Size(w, h);
|
||||
}
|
||||
|
||||
internal int Pow2(int input)
|
||||
{
|
||||
var result = 1;
|
||||
while (result < input)
|
||||
result *= 2;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void RegenerateTexture()
|
||||
{
|
||||
if (texture != IntPtr.Zero)
|
||||
SDL.SDL_DestroyTexture(texture);
|
||||
|
||||
TextArea = CalculateSize();
|
||||
textureSize = new Size(Pow2(TextArea.Width), Pow2(TextArea.Height));
|
||||
texture = SDL.SDL_CreateTexture(renderer, SDL.SDL_PIXELFORMAT_ARGB8888, (int)SDL.SDL_TextureAccess.SDL_TEXTUREACCESS_TARGET, textureSize.Width, textureSize.Height);
|
||||
|
||||
if (texture == IntPtr.Zero)
|
||||
throw new ApplicationException("Unaple to initialize texture.");
|
||||
|
||||
SDL.SDL_SetTextureBlendMode(texture, SDL.SDL_BlendMode.SDL_BLENDMODE_BLEND);
|
||||
SDL.SDL_SetRenderTarget(renderer, texture);
|
||||
SDL.SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
|
||||
SDL.SDL_RenderFillRect(renderer, IntPtr.Zero);
|
||||
SDL.SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
|
||||
|
||||
int cx = 0;
|
||||
int cy = 0;
|
||||
foreach (var ch in text)
|
||||
{
|
||||
WriteCharacter(cx, cy, (byte)ch);
|
||||
cx += font.font.CharacterMetric[(byte)ch].Width;
|
||||
}
|
||||
|
||||
SDL.SDL_SetRenderTarget(renderer, IntPtr.Zero);
|
||||
}
|
||||
|
||||
internal void WriteCharacter(int cx, int cy, byte character)
|
||||
{
|
||||
var rect = new SDL.SDL_Rect
|
||||
{
|
||||
x = cx,
|
||||
y = cy,
|
||||
w = font.sprite.FrameSize.Width,
|
||||
h = font.sprite.FrameSize.Height
|
||||
};
|
||||
|
||||
SDL.SDL_SetTextureColorMod(font.sprite.textures[character], TextColor.R, TextColor.G, TextColor.B);
|
||||
SDL.SDL_RenderCopy(renderer, font.sprite.textures[character], IntPtr.Zero, ref rect);
|
||||
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (texture != IntPtr.Zero)
|
||||
SDL.SDL_DestroyTexture(texture);
|
||||
}
|
||||
}
|
||||
}
|
@ -92,6 +92,11 @@ namespace OpenDiablo2.SDL2_
|
||||
}
|
||||
}
|
||||
|
||||
public void Draw(ISprite sprite, Point location)
|
||||
{
|
||||
sprite.Location = location;
|
||||
Draw(sprite);
|
||||
}
|
||||
|
||||
public void Draw(ISprite sprite, int frame)
|
||||
{
|
||||
@ -143,10 +148,61 @@ namespace OpenDiablo2.SDL2_
|
||||
public ISprite LoadSprite(string resourcePath, string palette) => LoadSprite(resourcePath, palette, Point.Empty);
|
||||
public ISprite LoadSprite(string resourcePath, string palette, Point location)
|
||||
{
|
||||
var result = new SDL2Sprite(ImageSet.LoadFromStream(mpqProvider.GetStream(resourcePath)), renderer);
|
||||
result.CurrentPalette = paletteProvider.PaletteTable[palette];
|
||||
result.Location = location;
|
||||
var result = new SDL2Sprite(ImageSet.LoadFromStream(mpqProvider.GetStream(resourcePath)), renderer)
|
||||
{
|
||||
CurrentPalette = paletteProvider.PaletteTable[palette],
|
||||
Location = location
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
public IFont LoadFont(string resourcePath, string palette)
|
||||
{
|
||||
var result = new SDL2Font(MPQFont.LoadFromStream(mpqProvider.GetStream($"{resourcePath}.DC6"), mpqProvider.GetStream($"{resourcePath}.tbl")), renderer)
|
||||
{
|
||||
CurrentPalette = paletteProvider.PaletteTable[palette]
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public ILabel CreateLabel(IFont font)
|
||||
{
|
||||
var result = new SDL2Label(font, renderer);
|
||||
return result;
|
||||
}
|
||||
|
||||
public ILabel CreateLabel(IFont font, string text)
|
||||
{
|
||||
var result = CreateLabel(font);
|
||||
result.Text = text;
|
||||
return result;
|
||||
}
|
||||
|
||||
public ILabel CreateLabel(IFont font, Point position, string text)
|
||||
{
|
||||
var result = new SDL2Label(font, renderer)
|
||||
{
|
||||
Text = text,
|
||||
Position = position
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void Draw(ILabel label)
|
||||
{
|
||||
var lbl = label as SDL2Label;
|
||||
var loc = lbl.Position;
|
||||
|
||||
var destRect = new SDL.SDL_Rect
|
||||
{
|
||||
x = loc.X,
|
||||
y = loc.Y,
|
||||
w = lbl.textureSize.Width,
|
||||
h = lbl.textureSize.Height
|
||||
};
|
||||
SDL.SDL_RenderCopy(renderer, lbl.texture, IntPtr.Zero, ref destRect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ using OpenDiablo2.Common.Models;
|
||||
|
||||
namespace OpenDiablo2.SDL2_
|
||||
{
|
||||
public sealed class SDL2Sprite : ISprite
|
||||
internal sealed class SDL2Sprite : ISprite
|
||||
{
|
||||
public Point Location { get; set; } = new Point();
|
||||
public Size FrameSize { get; set; } = new Size();
|
||||
@ -71,9 +71,9 @@ namespace OpenDiablo2.SDL2_
|
||||
private Color AdjustColor(Color source)
|
||||
=> Color.FromArgb(
|
||||
source.A,
|
||||
(byte)Math.Min((float)source.R * 1.0, 255),
|
||||
(byte)Math.Min((float)source.G * 1.0, 255),
|
||||
(byte)Math.Min((float)source.B * 1.0, 255)
|
||||
(byte)Math.Min((float)source.R * 1.2, 255),
|
||||
(byte)Math.Min((float)source.G * 1.2, 255),
|
||||
(byte)Math.Min((float)source.B * 1.2, 255)
|
||||
);
|
||||
|
||||
private IntPtr LoadFrame(ImageFrame frame, IntPtr renderer)
|
||||
|
@ -25,6 +25,8 @@ namespace OpenDiablo2.Scenes
|
||||
|
||||
private float logoFrame;
|
||||
private ISprite backgroundSprite, diabloLogoLeft, diabloLogoRight, diabloLogoLeftBlack, diabloLogoRightBlack, mouseSprite, wideButton;
|
||||
private IFont labelFont;
|
||||
private ILabel versionLabel, urlLabel;
|
||||
|
||||
public MainMenu(
|
||||
IRenderWindow renderWindow,
|
||||
@ -48,6 +50,10 @@ namespace OpenDiablo2.Scenes
|
||||
mouseSprite = renderWindow.LoadSprite(ResourcePaths.CursorDefault, Palettes.Units);
|
||||
wideButton = renderWindow.LoadSprite("data\\global\\ui\\FrontEnd\\WideButtonBlank.dc6", "ACT1");
|
||||
|
||||
labelFont = renderWindow.LoadFont(ResourcePaths.Font16, Palettes.Static);
|
||||
versionLabel = renderWindow.CreateLabel(labelFont, new Point(50, 555), "v0.01 Pre-Alpha");
|
||||
urlLabel = renderWindow.CreateLabel(labelFont, new Point(50, 569), "https://github.com/essial/OpenDiablo2/");
|
||||
urlLabel.TextColor = Color.Magenta;
|
||||
|
||||
var loadingSprite = renderWindow.LoadSprite(ResourcePaths.LoadingScreen, Palettes.Loading, new Point(300, 400));
|
||||
|
||||
@ -76,19 +82,25 @@ namespace OpenDiablo2.Scenes
|
||||
{
|
||||
renderWindow.Clear();
|
||||
|
||||
// Render the background
|
||||
renderWindow.Draw(backgroundSprite, 4, 3, 0);
|
||||
|
||||
// Render the flaming diablo 2 logo
|
||||
renderWindow.Draw(diabloLogoLeftBlack, (int)((float)diabloLogoLeftBlack.TotalFrames * logoFrame));
|
||||
renderWindow.Draw(diabloLogoRightBlack, (int)((float)diabloLogoRightBlack.TotalFrames * logoFrame));
|
||||
|
||||
renderWindow.Draw(diabloLogoLeft, (int)((float)diabloLogoLeft.TotalFrames * logoFrame));
|
||||
renderWindow.Draw(diabloLogoRight, (int)((float)diabloLogoRight.TotalFrames * logoFrame));
|
||||
|
||||
// Render the text
|
||||
renderWindow.Draw(versionLabel);
|
||||
renderWindow.Draw(urlLabel);
|
||||
|
||||
// Render the UI buttons
|
||||
wideButton.Location = new Point(264, 290);
|
||||
renderWindow.Draw(wideButton, 2, 1, 0);
|
||||
|
||||
mouseSprite.Location = new Point(mouseInfoProvider.MouseX, mouseInfoProvider.MouseY + mouseSprite.FrameSize.Height - 1);
|
||||
renderWindow.Draw(mouseSprite);
|
||||
// Draw the mouse
|
||||
renderWindow.Draw(mouseSprite, new Point(mouseInfoProvider.MouseX, mouseInfoProvider.MouseY + 3));
|
||||
|
||||
renderWindow.Sync();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user