summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bitmap.rs110
-rw-r--r--src/gl_renderer.rs16
-rw-r--r--src/main.rs4
3 files changed, 76 insertions, 54 deletions
diff --git a/src/bitmap.rs b/src/bitmap.rs
index 120f9d1..6733515 100644
--- a/src/bitmap.rs
+++ b/src/bitmap.rs
@@ -17,6 +17,7 @@
extern crate byteorder;
extern crate simple_error;
+use std::collections::HashMap;
use std::error::Error;
use std::io::{Cursor, Read, Seek, SeekFrom};
@@ -38,7 +39,7 @@ use grp::GroupManager;
/// Colors are extracted from each individual integer via bitwise operations.
///
/// ```
-/// let bitmap = bitmaps.get(277); // Arbitrary choice of tile number.
+/// let bitmap = bitmaps.get_tile(277); // Arbitrary choice of tile number.
/// let corner = bitmap.data[0];
///
/// let b = corner & 0xff;
@@ -56,7 +57,8 @@ pub struct Bitmap {
/// Implementation of a bitmap cache, which is used for obtaining a bitmap
/// conversion of the individual tiles in a group file.
pub struct BitmapManager {
- bitmaps: Vec<Bitmap>,
+ fonts: HashMap<String, Bitmap>,
+ tiles: Vec<Bitmap>,
}
impl BitmapManager {
@@ -67,8 +69,8 @@ impl BitmapManager {
///
/// This will fail if no 'PALETTE.DAT' entry exists in the GRP archive, or
/// if there is no 'TILES000.ART' entry.
- pub fn new(grp: &GroupManager) -> Result<BitmapManager, Box<Error>> {
- let mut bitmaps = Vec::new();
+ pub fn new(groups: &GroupManager) -> Result<BitmapManager, Box<Error>> {
+ let mut tiles = Vec::new();
// What's the PALETTE.DAT format?
//
@@ -120,7 +122,7 @@ impl BitmapManager {
// - 'loadpalette' in Build's 'ENGINE.C'
// - 'LoadPalette' in Transfusion's 'arttools/art2tga.c'
- let palette = if let Some(data) = grp.get("PALETTE.DAT") {
+ let palette = if let Some(data) = groups.get("PALETTE.DAT") {
let mut palette = Vec::new();
for i in 0..256 {
@@ -148,13 +150,13 @@ impl BitmapManager {
// until an art file is not found.
for i in 0.. {
- if let Some(data) = grp.get(&format!("TILES{:03}.ART", i)) {
+ if let Some(data) = groups.get(&format!("TILES{:03}.ART", i)) {
// FIXME: Passing the Error back up the stack is suboptimal (?)
let parsed = BitmapManager::load_art(data, &palette)?;
- bitmaps.extend_from_slice(&parsed);
+ tiles.extend_from_slice(&parsed);
} else {
// Indicates that we didn't even load TILES000.ART, meaning that
- // literally NO bitmaps were loaded. That's a pretty big issue.
+ // literally NO tiles were loaded. That's a pretty big issue.
if i == 0 {
bail!("No TILES000.ART in GRP archive.");
}
@@ -164,16 +166,44 @@ impl BitmapManager {
}
}
- Ok(BitmapManager { bitmaps })
+ // TABLES.DAT contains the 'textfont' and 'smalltextfont' blobs at
+ // specific offsets.
+
+ let tables = match groups.get("TABLES.DAT") {
+ Some(tables) => tables,
+ None => bail!("GRP does not contain a TABLES.DAT"),
+ };
+
+ let mut fonts = HashMap::new();
+
+ // Both blobs are 1024 bytes in length.
+
+ let textfont = load_font(&tables[5376..6400]);
+ let smalltextfont = load_font(&tables[6400..7424]);
+
+ fonts.insert("textfont".to_string(), textfont);
+ fonts.insert("smalltextfont".to_string(), smalltextfont);
+
+ Ok(BitmapManager { fonts, tiles })
}
/// Load the tile given by the specified index, or None if no tile with the
/// specified index exists.
- pub fn get(&self, index: i32) -> Option<&Bitmap> {
+ pub fn get_tile(&self, index: i32) -> Option<&Bitmap> {
let index = index as usize;
- if index < self.bitmaps.len() {
- Some(&self.bitmaps[index])
+ if index < self.tiles.len() {
+ Some(&self.tiles[index])
+ } else {
+ None
+ }
+ }
+
+ /// Load the glyph atlas given by the specified name, or None if no font
+ /// with the specified name exists.
+ pub fn get_font(&self, name: &str) -> Option<&Bitmap> {
+ if self.fonts.contains_key(name) {
+ Some(&self.fonts.get(name).unwrap())
} else {
None
}
@@ -188,7 +218,7 @@ impl BitmapManager {
}
let mut data = Cursor::new(data);
- let mut bitmaps = Vec::new();
+ let mut tiles = Vec::new();
// From BUILDINF.TXT
//
@@ -327,52 +357,54 @@ impl BitmapManager {
let width = width as u16;
let height = height as u16;
- bitmaps.push(Bitmap { width, height, data });
+ tiles.push(Bitmap { width, height, data });
}
- Ok(bitmaps)
+ Ok(tiles)
}
}
-// FIXME: This documentation is bare and undescriptive.
-/// Loads a font blob into a Bitmap.
-pub fn load_font(font: &[u8]) -> Bitmap {
- // TODO: There is no error checking, as I plan to dynamically generate a
- // number of glyphs and appropriate dimensions from the size of 'data'.
-
- // FIXME: Width and height constants are arbitrary and should ideally be
- // dynamically calculated for a set of glyphs with arbitrary length.
- let width = 128;
- let height = 256;
+/// Creates a bitmap glyph atlas from the TABLES.DAT font blob. The bitmap will
+/// be a square, with dimensions that are multiples of 8 -- each glyph is 8
+/// pixels by 8 pixels. They are ordered left-to-right, top-to-bottom, in the
+/// order of the font blob. In the case of Duke Nukem 3D's TABLES.DAT, this
+/// generally follows ASCII ordering.
+fn load_font(font: &[u8]) -> Bitmap {
+ // Each glyph is 8 bytes in length (8 rows, where each row has 8 pixels of
+ // 1-bit data)
+ let glyph_count = font.len() / 8;
- let mut data = vec![0; height * width];
+ let bitmap_length = (glyph_count as f64).sqrt().ceil() as usize;
+ let bitmap_length = bitmap_length * 8;
+ let mut data = vec![0; bitmap_length * bitmap_length];
- // FIXME: Again, this MAX_GLYPH, which isn't even referred to by a static
- // constant, should be dynamically calculated.
- for glyph in 0..256 {
- let x_off = (glyph % 32) * 8;
- let y_off = (glyph / 32) * 8;
+ for glyph in 0..glyph_count {
+ let x_off = (glyph % (bitmap_length / 8)) * 8;
+ let y_off = (glyph / (bitmap_length / 8)) * 8;
- for i in 0..8 {
- for j in 0..8 {
- let byte = font[(glyph * 8 + i) as usize];
- let bit = 2 << (7 - j);
+ for y in 0..8 {
+ for x in 0..8 {
+ let byte = font[glyph * 8 + y];
+ let bit = 2 << (7 - x);
if byte & bit != 0 {
// The font files don't convey any color information, just
// the pixel that's set, so we default to a plain white.
let pixel = 0xffffffff;
- let x = x_off + i;
- let y = y_off + j;
+ let x = x_off + x;
+ let y = y_off + y;
- data[x * width + y] = pixel;
+ data[y * bitmap_length + x] = pixel;
}
}
}
}
- Bitmap { width: width as u16, height: height as u16, data }
+ let width = bitmap_length as u16;
+ let height = bitmap_length as u16;
+
+ Bitmap { width, height, data }
}
#[cfg(test)]
diff --git a/src/gl_renderer.rs b/src/gl_renderer.rs
index 97ecc86..64f9151 100644
--- a/src/gl_renderer.rs
+++ b/src/gl_renderer.rs
@@ -19,25 +19,15 @@ extern crate simple_error;
use std::error::Error;
-use bitmap::{Bitmap, load_font};
-use grp::GroupManager;
+use bitmap::BitmapManager;
/// Renderer using the OpenGL library.
pub struct GLRenderer;
impl GLRenderer {
/// Instantiate a new instance of the renderer.
- pub fn new(groups: &GroupManager) -> Result<GLRenderer, Box<Error>> {
- let tables = match groups.get("TABLES.DAT") {
- Some(tables) => tables,
- None => bail!("GRP does not contain a TABLES.DAT"),
- };
-
- // TODO: Separate bitmaps for textfont and smalltextfont?
- let data = &tables[5376..7424];
-
- // TODO: The BitmapManager should maintain the font.
- let _font: Bitmap = load_font(data);
+ pub fn new(bitmaps: &BitmapManager) -> Result<GLRenderer, Box<Error>> {
+ let _font = bitmaps.get_font("textfont").unwrap();
Ok(GLRenderer { })
}
diff --git a/src/main.rs b/src/main.rs
index a515809..3b7660b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -40,7 +40,7 @@ fn main() {
let _world = world::World::from_map(map).unwrap();
let bitmaps = bitmap::BitmapManager::new(&groups).unwrap();
- let _tile = bitmaps.get(0);
+ let _tile = bitmaps.get_tile(0);
- let _renderer = gl_renderer::GLRenderer::new(&groups);
+ let _renderer = gl_renderer::GLRenderer::new(&bitmaps);
}