Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for creating 3DO IMAG files #18

Merged
merged 1 commit into from
Apr 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ Subcommands:
docs print links to relevant documentation
info prints info about the file
list-chunks list 3DO file chunks
to-cel convert image to CEL
to-cel convert image to 3DO CEL
to-banner convert image to banner
to-imag convert image to 3DO IMAG
to-bmp convert image to BMP
to-png convert image to PNG
to-jpg convert image to JPG
Expand All @@ -41,7 +42,6 @@ All subcommands have their own help and arguments. Use `--help` or
* dump APPSCRN from ISO
* dump-chunks
* concat-chunks
* to IMAG
* to ANIM
* ability to write text chunks
* figure out NFS HSPT chunk
Expand All @@ -57,14 +57,15 @@ different ideas so the code is not entirely consistent. Will clean up as needed.

## Documentation

* https://3dodev.com
* https://3dodev.com/documentation/file_formats
* https://3dodev.com/documentation/development/opera/pf25/ppgfldr/ggsfldr/gpgfldr/3gpg
* https://3dodev.com/documentation/development/opera/pf25/ppgfldr/ggsfldr/gpgfldr/5gpg
* https://3dodev.com/documentation/file_formats/media/container/3do
* https://3dodev.com/documentation/file_formats/media/image/bannerscreen
* https://3dodev.com/documentation/file_formats/games/nfs
* https://3dodev.com/documentation/development/opera/pf25/ppgfldr/ggsfldr/gpgfldr/00gpg1


## Other Links

* https://3dodev.com
* https://github.com/trapexit/3dt
* https://github.com/trapexit/3do-devkit
* 3DO Dev Repo: https://3dodev.com
* 3DO Disc Tool: https://github.com/trapexit/3dt
* 'Modern' 3DO DevKit: https://github.com/trapexit/3do-devkit
85 changes: 45 additions & 40 deletions src/byteswap.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,35 +21,43 @@
#include "endian.hpp"

#include <cstdint>
#include <type_traits>


static
inline
uint32_t
byteswap(const uint32_t v_)
int8_t
byteswap(const int8_t v_)
{
return (((v_ & UINT32_C(0x000000FF)) << 24) |
((v_ & UINT32_C(0x0000FF00)) << 8) |
((v_ & UINT32_C(0x00FF0000)) >> 8) |
((v_ & UINT32_C(0xFF000000)) >> 24));
return v_;
}

static
inline
uint32_t
byteswap_if_little_endian(const uint32_t v_)
uint8_t
byteswap(const uint8_t v_)
{
if(is_little_endian())
return byteswap(v_);
return v_;
}

static
inline
void
byteswap_if_little_endian(uint32_t *v_)
int16_t
byteswap(const int16_t v_)
{
*v_ = byteswap_if_little_endian(*v_);
return (((v_ & INT16_C(0x00FF)) << 8) |
((v_ & INT16_C(0xFF00)) >> 8));

}

static
inline
uint16_t
byteswap(const uint16_t v_)
{
return (((v_ & UINT16_C(0x00FF)) << 8) |
((v_ & UINT16_C(0xFF00)) >> 8));

}

static
Expand All @@ -65,54 +73,51 @@ byteswap(const int32_t v_)

static
inline
int32_t
byteswap_if_little_endian(const int32_t v_)
uint32_t
byteswap(const uint32_t v_)
{
if(is_little_endian())
return byteswap(v_);
return v_;
return (((v_ & UINT32_C(0x000000FF)) << 24) |
((v_ & UINT32_C(0x0000FF00)) << 8) |
((v_ & UINT32_C(0x00FF0000)) >> 8) |
((v_ & UINT32_C(0xFF000000)) >> 24));
}

template<typename T>
static
inline
void
byteswap_if_little_endian(int32_t *v_)
typename std::enable_if<std::is_fundamental<T>::value, T>::type
byteswap_if_little_endian(const T v_)
{
*v_ = byteswap_if_little_endian(*v_);
if(is_little_endian())
return byteswap(v_);
return v_;
}

template<typename T>
static
inline
uint16_t
byteswap(const uint16_t v_)
typename std::enable_if<std::is_pointer<T>::value, void>::type
byteswap_if_little_endian(const T v_)
{
return (((v_ & UINT16_C(0x00FF)) << 8) |
((v_ & UINT16_C(0xFF00)) >> 8));

*v_ = byteswap_if_little_endian(*v_);
}

template<typename T>
static
inline
uint16_t
byteswap_if_little_endian(const uint16_t v_)
typename std::enable_if<std::is_fundamental<T>::value, T>::type
byteswap_if_big_endian(const T v_)
{
if(is_little_endian())
if(is_big_endian())
return byteswap(v_);
return v_;
}

template<typename T>
static
inline
uint8_t
byteswap(const uint8_t v_)
{
return v_;
}

static
inline
uint8_t
byteswap_if_little_endian(const uint8_t v_)
typename std::enable_if<std::is_pointer<T>::value, void>::type
byteswap_if_big_endian(const T v_)
{
return v_;
*v_ = byteswap_if_big_endian(*v_);
}
65 changes: 65 additions & 0 deletions src/convert_bitmap_to_imag.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
ISC License

Copyright (c) 2023, Antonio SJ Musumeci <trapexit@spawn.link>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include "convert_bitmap_to_imag.hpp"

#include "image_control_chunk.hpp"
#include "pdat.hpp"
#include "convert.hpp"

void
convert::bitmap_to_imag(const Bitmap &bitmap_,
DataRW &data_)
{
ByteVec pdat;
ImageControlChunk icc;

icc.id = "IMAG";
icc.chunk_size = sizeof(icc);
icc.w = bitmap_.w;
icc.h = bitmap_.h;
icc.bytesperrow = (2 * bitmap_.w);
icc.bitsperpixel = 16;
icc.numcomponents = 3;
icc.numplanes = 1;
icc.colorspace = 0;
icc.comptype = 0;
icc.hvformat = 0;
icc.pixelorder = 1;
icc.version = 0;

data_.write((const uint8_t*)"IMAG",4);
data_.writebe(icc.chunk_size);
data_.writebe(icc.w);
data_.writebe(icc.h);
data_.writebe(icc.bytesperrow);
data_.writebe(icc.bitsperpixel);
data_.writebe(icc.numcomponents);
data_.writebe(icc.numplanes);
data_.writebe(icc.colorspace);
data_.writebe(icc.comptype);
data_.writebe(icc.hvformat);
data_.writebe(icc.pixelorder);
data_.writebe(icc.version);

convert::bitmap_to_uncoded_unpacked_lrform_16bpp(bitmap_,pdat);

data_.write((const uint8_t*)"PDAT",4);
data_.writebe((uint32_t)(4 + 4 + pdat.size()));
data_.write(pdat.data(),pdat.size());
}
29 changes: 29 additions & 0 deletions src/convert_bitmap_to_imag.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
ISC License

Copyright (c) 2023, Antonio SJ Musumeci <trapexit@spawn.link>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#pragma once

#include "bitmap.hpp"
#include "datarw.hpp"

namespace convert
{
void
bitmap_to_imag(const Bitmap &bitmap,
DataRW &data);
}
88 changes: 88 additions & 0 deletions src/datarw.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#include "datarw.hpp"
#include "byteswap.hpp"

void
DataRW::rewind()
{
return seek(0);
}

void
DataRW::rewind(const size_t bytes_)
{
return seek(tell() - bytes_);
}

void
DataRW::skip(const size_t bytes_)
{
return seek(tell() + bytes_);
}

void
DataRW::skip_to_2byte_boundary()
{
return skip(tell() & 1);
}

void
DataRW::skip_to_4byte_boundary()
{
size_t offset;

offset = tell();
if(offset & 0x3)
return skip(4 - (offset & 0x3));
}

void
DataRW::skip_to_8byte_boundary()
{
size_t offset;

offset = tell();
if(offset & 0x7)
return skip(8 - (offset & 0x7));
}

char
DataRW::c()
{
char c;

read((uint8_t*)&c,sizeof(c));

return c;
}

int8_t
DataRW::i8()
{
return (int8_t)c();
}

uint8_t
DataRW::u8()
{
return (uint8_t)c();
}

int16_t
DataRW::i16be()
{
int16_t i;

read((uint8_t*)&i,sizeof(i));

return byteswap_if_little_endian(i);
}

int16_t
DataRW::i16le()
{
int16_t i;

read((uint8_t*)&i,sizeof(i));

return byteswap_if_big_endian(i);
}
Loading