mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2024-12-28 20:43:36 +01:00
Major update for bopti (gray, light still not tested). Reworked out gray engine.
This commit is contained in:
parent
aa0f4b7285
commit
ab17532f67
17 changed files with 1105 additions and 463 deletions
29
Makefile
29
Makefile
|
@ -1,8 +1,8 @@
|
||||||
#
|
#! /usr/bin/make -f
|
||||||
# fx-9860g lib Makefile.
|
|
||||||
#
|
|
||||||
|
|
||||||
.PHONY: all clean fclean re install
|
#---
|
||||||
|
# fx-9860g lib Makefile.
|
||||||
|
#---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,8 +23,7 @@ bin = build/ginttest.bin
|
||||||
elf = build/ginttest.elf
|
elf = build/ginttest.elf
|
||||||
|
|
||||||
# Command-line options
|
# Command-line options
|
||||||
cflags = -m3 -mb -nostdlib -ffreestanding \
|
cflags = -m3 -mb -nostdlib -ffreestanding -W -Wall \
|
||||||
-W -Wall -pedantic -std=c11 \
|
|
||||||
-I . -isystem include
|
-I . -isystem include
|
||||||
lib = -lgcc -L. -lgint -lc
|
lib = -lgcc -L. -lgint -lc
|
||||||
|
|
||||||
|
@ -42,20 +41,20 @@ src-lib = crt0.c syscalls.s \
|
||||||
hea-lib = 7305.h 7705.h gint.h \
|
hea-lib = 7305.h 7705.h gint.h \
|
||||||
stdlib.h \
|
stdlib.h \
|
||||||
mpu.h keyboard.h screen.h display.h gray.h timer.h tales.h
|
mpu.h keyboard.h screen.h display.h gray.h timer.h tales.h
|
||||||
obj-lib = $(addprefix build/, $(addsuffix .o, $(src-lib)))
|
obj-lib = $(patsubst %, build/%.o, $(src-lib))
|
||||||
hdr-lib = $(addprefix include/, $(hea-lib))
|
hdr-lib = $(patsubst %, include/%, $(hea-lib))
|
||||||
|
|
||||||
# Standard library.
|
# Standard library.
|
||||||
src-std = setjmp.s string.c
|
src-std = setjmp.s string.c
|
||||||
hea-std = setjmp.h string.h ctype.h
|
hea-std = setjmp.h string.h ctype.h
|
||||||
obj-std = $(addprefix build/, $(addsuffix .o, $(src-std)))
|
obj-std = $(patsubst %, build/%.o, $(src-std))
|
||||||
hdr-std = $(addprefix include/, $(hea-std))
|
hdr-std = $(patsubst %, include/%, $(hea-str))
|
||||||
|
|
||||||
# Test application.
|
# Test application.
|
||||||
src-app = ginttest.c
|
src-app = ginttest.c
|
||||||
img-app = bitmap_opt.bmp swords.bmp sprites.bmp symbol.bmp symbol2.bmp \
|
img-app = bitmap_opt.bmp swords.bmp sprites.bmp symbol.bmp symbol2.bmp \
|
||||||
illustration.bmp
|
illustration.bmp
|
||||||
res-app = build/font.o $(addprefix build/, $(addsuffix .o, $(img-app)))
|
res-app = $(patsubst %, build/%.o, $(img-app)) build/font.o
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -77,7 +76,7 @@ libc.a: $(obj-std)
|
||||||
@ echo "\033[32;1mStandard file size: "`stat -c %s libc.a` \
|
@ echo "\033[32;1mStandard file size: "`stat -c %s libc.a` \
|
||||||
"bytes\033[0m"
|
"bytes\033[0m"
|
||||||
|
|
||||||
ginttest.g1a: libgint.a $(src-app) $(res-app)
|
$(g1a): libgint.a $(src-app) $(res-app)
|
||||||
$(cc) $(src-app) $(res-app) -T ginttest.ld -o $(elf) $(cflags) $(lib)
|
$(cc) $(src-app) $(res-app) -T ginttest.ld -o $(elf) $(cflags) $(lib)
|
||||||
$(ob) -R .comment -R .bss -O binary $(elf) $(bin)
|
$(ob) -R .comment -R .bss -O binary $(elf) $(bin)
|
||||||
$(wr) $(bin) -o ginttest.g1a -i icon.bmp
|
$(wr) $(bin) -o ginttest.g1a -i icon.bmp
|
||||||
|
@ -97,7 +96,7 @@ build/%.s.o: src/%.s
|
||||||
$(as) -c $^ -o $@
|
$(as) -c $^ -o $@
|
||||||
|
|
||||||
build/%.bmp.o: resources/%.bmp
|
build/%.bmp.o: resources/%.bmp
|
||||||
fxconv $^ -o $@
|
fxconv $^ -o $@ --preview
|
||||||
|
|
||||||
build/font.o: resources/font.bmp
|
build/font.o: resources/font.bmp
|
||||||
fxconv --font $^ -o $@
|
fxconv --font $^ -o $@
|
||||||
|
@ -136,3 +135,7 @@ re: distclean all
|
||||||
|
|
||||||
install:
|
install:
|
||||||
usb-connector SEND ginttest.g1a ginttest.g1a fls0
|
usb-connector SEND ginttest.g1a ginttest.g1a fls0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: all clean mrproper distclean re install
|
||||||
|
|
47
TODO
47
TODO
|
@ -1,27 +1,34 @@
|
||||||
@ vram overflow
|
|
||||||
@ keyboard interface
|
|
||||||
|
|
||||||
- upgraded blending modes
|
--------------
|
||||||
- blending modes for text
|
Lots of things to do
|
||||||
- information masks for text
|
--------------
|
||||||
- test all font encodings
|
|
||||||
- font clipping
|
|
||||||
|
|
||||||
- bitmap parts
|
@ known bugs
|
||||||
- bitmap clipping
|
+ simple improvements
|
||||||
|
- important milestones
|
||||||
|
~ needs investigation
|
||||||
|
|
||||||
- multi-getkey repeats (if possible, which doesn't seem likely)
|
|
||||||
- it appears that multi-getkey does not always trigger rectangle effects on
|
|
||||||
sh7305
|
|
||||||
|
|
||||||
- write and test gray engine
|
@ vram overflow
|
||||||
- full rtc driver (time)
|
@ keyboard test threading interface
|
||||||
- callbacks and complete user API
|
|
||||||
|
|
||||||
- exhaustive save for setjmp()
|
+ compute frequencies
|
||||||
- registers that need to be saved when configuring gint
|
+ gray text
|
||||||
|
+ effective rtc callback
|
||||||
|
+ properly test gray drawing
|
||||||
|
+ upgraded blending modes
|
||||||
|
+ blending modes for text
|
||||||
|
+ information masks for text
|
||||||
|
+ test all font encodings
|
||||||
|
+ font clipping
|
||||||
|
+ bitmap parts
|
||||||
|
+ bitmap clipping
|
||||||
|
|
||||||
- check possible bug for optimization of __attribute__((interrupt_handler))
|
- write and test gray engine
|
||||||
|
- full rtc driver (time)
|
||||||
|
- callbacks and complete user API
|
||||||
|
|
||||||
- 7305.h
|
~ shadowy rectangle effect for Shift + Alpha + Left + Down
|
||||||
- libc
|
~ exhaustive save for setjmp()
|
||||||
|
~ registers that need to be saved when configuring gint
|
||||||
|
~ possible bug when -O2 __attribute__((interrupt_handler))
|
||||||
|
|
305
doc/bopti.md
Normal file
305
doc/bopti.md
Normal file
|
@ -0,0 +1,305 @@
|
||||||
|
|
||||||
|
# gint documentation: bitmap rendering #
|
||||||
|
|
||||||
|
|
||||||
|
*Warning: this is a draft. The current implementation of bopti is different*
|
||||||
|
*from this description, though similar.*
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Basics
|
||||||
|
|
||||||
|
The bitmap drawing module, *bopti*, is based on video-ram (vram) bitwise
|
||||||
|
operations. The images are made of layers that describe (more or less) which
|
||||||
|
pixels of the image an operation applies to. Rendering the image consists in
|
||||||
|
applying an operation function to the existing vram pixels.
|
||||||
|
|
||||||
|
*bopti* makes an extensive use of longword operations and 4-alignment to take
|
||||||
|
advantage of the bit-based structure of the monochrome vram and enhance
|
||||||
|
performance. Among all possible optimizations, avoiding direct pixel access has
|
||||||
|
proven to be the most efficient.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Operations
|
||||||
|
|
||||||
|
Operations are functions applied to update a vram longword in accordance with
|
||||||
|
an operation mask. Bits that are set in the mask indicate pixels which have to
|
||||||
|
be updated by the operation. Bits that are reset indicate pixels that must not
|
||||||
|
be changed.
|
||||||
|
|
||||||
|
All the point is, the functions must not access the bit information in the mask
|
||||||
|
or the vram data individually. They must operate globally using longword
|
||||||
|
bitwise instructions, so that performance is maintained.
|
||||||
|
|
||||||
|
Consider for instance a logical and operation (`(a, b) -> a & b`).
|
||||||
|
Operating on pixels would need to move some data, test the value of a bit in
|
||||||
|
the mask, edit the vram data, and eventually shift both the data and the mask, for all of the 32 pixels.
|
||||||
|
One could not expect this from happening in less than 150 processor cycles
|
||||||
|
(in comparison, using generic-purpose `setPixel()`-like functions would be at
|
||||||
|
least 10 times as long). The smarter method operates directly on the longword
|
||||||
|
parameters, and performs `data = data & ~mask`, which is 2 processor cycles
|
||||||
|
long.
|
||||||
|
|
||||||
|
The following operations are defined by *bopti*:
|
||||||
|
|
||||||
|
- `Draw `: Draws black pixels.
|
||||||
|
- `Alpha `: Erases non-transparent pixels.
|
||||||
|
- `Change `: Changes the pixels' color.
|
||||||
|
- `Lighten `: Lightens gray pixels.
|
||||||
|
- `Lighten2`: Lightens gray pixels more.
|
||||||
|
- `Darken `: Darkens gray pixels.
|
||||||
|
- `Darken2 `: Darkens gray pixels more.
|
||||||
|
|
||||||
|
To perform an operation, *bopti* uses the mask data, which is taken from a
|
||||||
|
layer, and calls the associated operation function. Every operation has its
|
||||||
|
default layer mask (except `change`), but this setting may be overridden.
|
||||||
|
*bopti* allows user programs to use any monochrome image as a mask for an
|
||||||
|
operation. For instance, a black rectangle may be drawn by any of the operation
|
||||||
|
functions, resulting in various results.
|
||||||
|
|
||||||
|
An additional operation, `fill`, is defined by the library. It does all the job
|
||||||
|
necessary to render the full image, which often falls back to performing the
|
||||||
|
operations that correspond to the kind of image.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Operation on gray pixels
|
||||||
|
|
||||||
|
*Detailed article: [Gray engine](gray-engine)*
|
||||||
|
|
||||||
|
Gray pixels are made of one four colors, each of which is represented by two
|
||||||
|
bits. Arguments `light` and `dark` of gray operation functions are longwords
|
||||||
|
containing the least significant and most significant of these bits,
|
||||||
|
respectively.
|
||||||
|
|
||||||
|
white = 0 [00]
|
||||||
|
lightgray = 1 [01]
|
||||||
|
darkgray = 2 [10]
|
||||||
|
black = 3 [11]
|
||||||
|
|
||||||
|
The `Lighten` operation affects pixels as if decrementing their value (white
|
||||||
|
pixels are not changed), and `darken` does the opposite (black pixels are not
|
||||||
|
changed).
|
||||||
|
Operations `Lighten2` and `darken2` do the same two times.
|
||||||
|
|
||||||
|
From this description, and considering two bits `light` and `dark`, it follows
|
||||||
|
that:
|
||||||
|
|
||||||
|
```c
|
||||||
|
lighten2 (light, dark) = (0, light & dark)
|
||||||
|
lighten (light, dark) = (light & dark, light & ~dark)
|
||||||
|
darken (light, dark) = (light | dark, light | ~dark)
|
||||||
|
darken2 (light, dark) = (1, light | dark)
|
||||||
|
```
|
||||||
|
|
||||||
|
This does not take account of a possible operation mask. See section
|
||||||
|
[Operation functions](#operation-functions) for more flexible functions.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Partial transparency
|
||||||
|
|
||||||
|
*bopti* allows monochrome images to have semi-transparent pixels. Consider for
|
||||||
|
example a white background. An opaque black pixel will render black, while a
|
||||||
|
1/3-transparent black pixel will render dark gray, and a 2/3-transparent black
|
||||||
|
pixel will render light gray. Which means that:
|
||||||
|
|
||||||
|
* 1/3-transparent white pixels form the mask for `lighten2`
|
||||||
|
* 2/3-transparent white pixels form the mask for `lighten`
|
||||||
|
* 2/3-transparent black pixels form the mask for `darken`
|
||||||
|
* 1/3-transparent black pixels form the mask for `darken2`
|
||||||
|
|
||||||
|
Partial transparency on gray pixels is not allowed. Apart from the complexity
|
||||||
|
of the generic partial transparency rendering operation, semi-transparent gray
|
||||||
|
pixels are not of any use.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Operation functions
|
||||||
|
|
||||||
|
Operations on monochrome buffers are defined as functions of two parameters:
|
||||||
|
the vram data longword to update, `data`, and the operation mask, `x`. Every
|
||||||
|
of these functions must satisfy `f(data, 0) = data`.
|
||||||
|
|
||||||
|
Operations on gray buffers take three arguments: `light` and `dark`, which are
|
||||||
|
longwords from the [gray buffers](gray-engine), and the operation mask `x`.
|
||||||
|
They update both longwords and return them. These functions must satisfy
|
||||||
|
`f(light, dark, 0) = (light, dark)`.
|
||||||
|
|
||||||
|
The functions for each of the operations are the following:
|
||||||
|
|
||||||
|
~~~c
|
||||||
|
# Draw function
|
||||||
|
draw(data, x) = data | x
|
||||||
|
|
||||||
|
# Alpha function
|
||||||
|
alpha(data, x) = data & ~x
|
||||||
|
|
||||||
|
# Change function
|
||||||
|
change(data, x) = data ^ x
|
||||||
|
|
||||||
|
# Lighten function
|
||||||
|
lighten(light, dark, x) = (light & (dark | ~x), (light | ~x) & (x ^ dark))
|
||||||
|
|
||||||
|
# Lighten2 function
|
||||||
|
lighten2(light, dark, x) = (light & ~x, (light | ~x) & dark)
|
||||||
|
|
||||||
|
# Darken function
|
||||||
|
darken(light, dark, x) = (light | (dark & x), (light & x) | (x ^ dark))
|
||||||
|
|
||||||
|
# Darken2 function
|
||||||
|
darken2(light, dark, x) = (light | x, (light & x) | dark)
|
||||||
|
~~~
|
||||||
|
|
||||||
|
One could easily check that these functions do their jobs when `x = 1` and
|
||||||
|
leave the data unchanged when `x = 0`.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Image format
|
||||||
|
|
||||||
|
Images are made of *layers*, each of which describe the mask for an operation.
|
||||||
|
When an image is rendered, *bopti* draws some of those layers in the vram
|
||||||
|
using the operation functions.
|
||||||
|
|
||||||
|
* Non-transparent monochrome images only have one layer, which describes the mask for the `draw` operation.
|
||||||
|
* Transparent monochrome images have two layers. The first describes the mask
|
||||||
|
for the `draw` operation, while the other is the `alpha` operation mask (which
|
||||||
|
means that it indicates which pixels are transparent).
|
||||||
|
* Non-transparent gray images also have two layers: one for each
|
||||||
|
[gray buffer](gray-engine). Both are for the `draw` operation.
|
||||||
|
* Transparent gray images have three layers. Two of them constitute the two-bit
|
||||||
|
color information for the `draw` operation, and the third is the `alpha`
|
||||||
|
operation mask.
|
||||||
|
* Semi-transparent monochrome images also have three layers. Two are used to
|
||||||
|
store the two-bit transparency level information (0 is opaque, 3 is fully
|
||||||
|
transparent), and the third indicates the color.
|
||||||
|
|
||||||
|
Layers are encoded as a bit map. The image is split into a *grid*, which is
|
||||||
|
made of 32-pixel *columns*, and an *end*.
|
||||||
|
|
||||||
|
32 32 32 e
|
||||||
|
+------+------+------+---+
|
||||||
|
| | | | |
|
||||||
|
| | | | |
|
||||||
|
| | | | |
|
||||||
|
+------+------+------+---+
|
||||||
|
|
||||||
|
Bitmap
|
||||||
|
|
||||||
|
The first bytes of the layer data is the column data. Each column is encoded
|
||||||
|
as a 32-bit integer array from top to bottom. Columns are written from left to
|
||||||
|
right. The end is encoded as an 8-bit or 16-bit integer array depending on its
|
||||||
|
size, and written from top to bottom. Additionally, 0 to 3 NUL (0x00) bytes are
|
||||||
|
added to make the layer size a multiple of 4 (to allow 32-bit access to the
|
||||||
|
column data of the following layer).
|
||||||
|
|
||||||
|
In case of big images (see the image structure below), the end is expanded to
|
||||||
|
a 32-pixel column to improve performance.
|
||||||
|
|
||||||
|
The image itself is a structure of the following kind (in case of small
|
||||||
|
images):
|
||||||
|
|
||||||
|
```c
|
||||||
|
struct Image
|
||||||
|
{
|
||||||
|
unsigned char magic;
|
||||||
|
unsigned char format;
|
||||||
|
|
||||||
|
unsigned char width;
|
||||||
|
unsigned char height;
|
||||||
|
|
||||||
|
const uint32_t data[];
|
||||||
|
|
||||||
|
} __attribute__((aligned(4)));
|
||||||
|
```
|
||||||
|
|
||||||
|
For bigger images (`width` > 255 or `height` > 255), both `width` and `height`
|
||||||
|
are set to `0` and the actual size information is written on two shorts just
|
||||||
|
where the data resides:
|
||||||
|
|
||||||
|
```c
|
||||||
|
struct BigImage
|
||||||
|
{
|
||||||
|
unsigned char magic;
|
||||||
|
unsigned char format;
|
||||||
|
|
||||||
|
unsigned char null_width; /* contains 0 */
|
||||||
|
unsigned char null_height; /* contains 0 */
|
||||||
|
|
||||||
|
unsigned short width;
|
||||||
|
unsigned short height;
|
||||||
|
|
||||||
|
const uint32_t data[];
|
||||||
|
|
||||||
|
} __attribute__((aligned(4)));
|
||||||
|
```
|
||||||
|
|
||||||
|
This does not create a memory loss because a two-byte gap was needed to make
|
||||||
|
the data 4-aligned.
|
||||||
|
|
||||||
|
* The `magic` number, which is common to all the file formats of *gint*,
|
||||||
|
identifies the file type and version of the structure. *bopti* will not render
|
||||||
|
an image which is not encoded for its specific version.
|
||||||
|
|
||||||
|
* The `format` attribute describes the layer distribution, as specified by the
|
||||||
|
following enum:
|
||||||
|
|
||||||
|
```c
|
||||||
|
enum ImageFormat
|
||||||
|
{
|
||||||
|
ImageFormat_Mono = 0x01,
|
||||||
|
ImageFormat_MonoAlpha = 0x09,
|
||||||
|
ImageFormat_Gray = 0x06,
|
||||||
|
ImageFormat_GrayAlpha = 0x0e,
|
||||||
|
ImageFormat_GreaterAlpha = 0x31,
|
||||||
|
|
||||||
|
ImageFormat_ColorMask = 0x07,
|
||||||
|
ImageFormat_AlphaMask = 0x38,
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
`Alpha` refers to uniform transparency. The only format that supports
|
||||||
|
partial transparency is `GreaterAlpha`, and it is always encoded as
|
||||||
|
monochrome (because using gray pixels would lead to 9 different colors,
|
||||||
|
which is rather unoptimized). Gray images with partial transparency
|
||||||
|
will be refused by *fxconv*.
|
||||||
|
|
||||||
|
|
||||||
|
* The `width` and `height` attributes are exactly what you expect.
|
||||||
|
|
||||||
|
* The `data` is simply made of all the layers put one after another. Layers are
|
||||||
|
put in the following order:
|
||||||
|
|
||||||
|
[0] Monochrome `draw` layer
|
||||||
|
[1] Dark gray `draw` layer
|
||||||
|
[2] Light gray `draw` layer
|
||||||
|
[3] Uniform `alpha` layer
|
||||||
|
[4] First semi-`alpha` layer
|
||||||
|
[5] Second semi-`alpha` layer
|
||||||
|
|
||||||
|
Not every format uses the six layers, of course. The layers used by
|
||||||
|
each format may be found by reading the position of the `1`'s in the
|
||||||
|
corresponding `enum ImageFormat` entry. Layers that are not needed are
|
||||||
|
skipped.
|
25
ginttest.c
25
ginttest.c
|
@ -213,7 +213,7 @@ void bitmap_test(void)
|
||||||
Image *sybl = &binary_resources_symbol_start;
|
Image *sybl = &binary_resources_symbol_start;
|
||||||
Image *sybl2 = &binary_resources_symbol2_start;
|
Image *sybl2 = &binary_resources_symbol2_start;
|
||||||
|
|
||||||
enum BlendingMode blend = Blend_Or;
|
// enum BlendingMode blend = Blend_Or;
|
||||||
uint32_t a32 = 0xffffffff;
|
uint32_t a32 = 0xffffffff;
|
||||||
int black_bg = 0;
|
int black_bg = 0;
|
||||||
int key;
|
int key;
|
||||||
|
@ -223,20 +223,22 @@ void bitmap_test(void)
|
||||||
dclear();
|
dclear();
|
||||||
|
|
||||||
if(black_bg) dreverse_area(0, 0, 127, 63);
|
if(black_bg) dreverse_area(0, 0, 127, 63);
|
||||||
dimage(opt, 0, 57, Blend_Invert);
|
dimage(opt, 0, 57);
|
||||||
|
|
||||||
dimage(sprites, 2 & a32, 2, blend);
|
dimage(sprites, 2 & a32, 2);
|
||||||
dimage(sybl, 30 & a32, 40, blend);
|
dimage(sybl, 30 & a32, 40);
|
||||||
dimage(sybl2, 62 & a32, 40, blend);
|
dimage(sybl2, 62 & a32, 40);
|
||||||
|
|
||||||
dupdate();
|
dupdate();
|
||||||
|
|
||||||
key = getkey();
|
key = getkey();
|
||||||
if(key == KEY_EXIT) break;
|
if(key == KEY_EXIT) break;
|
||||||
|
|
||||||
|
/*
|
||||||
if(key == KEY_F1) blend = Blend_Or;
|
if(key == KEY_F1) blend = Blend_Or;
|
||||||
if(key == KEY_F2) blend = Blend_And;
|
if(key == KEY_F2) blend = Blend_And;
|
||||||
if(key == KEY_F3) blend = Blend_Invert;
|
if(key == KEY_F3) blend = Blend_Invert;
|
||||||
|
*/
|
||||||
|
|
||||||
if(key == KEY_F4) black_bg = !black_bg;
|
if(key == KEY_F4) black_bg = !black_bg;
|
||||||
if(key == KEY_F5) a32 ^= 31;
|
if(key == KEY_F5) a32 ^= 31;
|
||||||
|
@ -257,7 +259,7 @@ void text_test(void)
|
||||||
extern Font binary_resources_font_start;
|
extern Font binary_resources_font_start;
|
||||||
Font *font = &binary_resources_font_start;
|
Font *font = &binary_resources_font_start;
|
||||||
|
|
||||||
print_configure(font, Blend_Or);
|
print_configure(font);
|
||||||
|
|
||||||
dclear();
|
dclear();
|
||||||
|
|
||||||
|
@ -290,18 +292,23 @@ void gray_test(void)
|
||||||
|
|
||||||
gray_getDelays(&light, &dark);
|
gray_getDelays(&light, &dark);
|
||||||
gray_start();
|
gray_start();
|
||||||
dimage(illustration, 0, 0, Blend_Or);
|
|
||||||
|
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
|
gclear();
|
||||||
|
dimage(illustration, 0, 0);
|
||||||
|
gclear_area(64, 0, 127, 63);
|
||||||
|
// gupdate();
|
||||||
|
|
||||||
key = getkey();
|
key = getkey();
|
||||||
if(key == KEY_EXIT) break;
|
if(key == KEY_EXIT) break;
|
||||||
|
/*
|
||||||
if(key == KEY_F1) gray_setDelays(--light, dark);
|
if(key == KEY_F1) gray_setDelays(--light, dark);
|
||||||
if(key == KEY_F2) gray_setDelays(++light, dark);
|
if(key == KEY_F2) gray_setDelays(++light, dark);
|
||||||
|
|
||||||
if(key == KEY_F5) gray_setDelays(light, --dark);
|
if(key == KEY_F5) gray_setDelays(light, --dark);
|
||||||
if(key == KEY_F6) gray_setDelays(light, ++dark);
|
if(key == KEY_F6) gray_setDelays(light, ++dark);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
gray_stop();
|
gray_stop();
|
||||||
|
@ -367,7 +374,7 @@ int main(void)
|
||||||
extern Font binary_resources_font_start;
|
extern Font binary_resources_font_start;
|
||||||
Font *font = &binary_resources_font_start;
|
Font *font = &binary_resources_font_start;
|
||||||
|
|
||||||
print_configure(font, Blend_Or);
|
print_configure(font);
|
||||||
|
|
||||||
int app;
|
int app;
|
||||||
|
|
||||||
|
|
BIN
ginttest.g1a
BIN
ginttest.g1a
Binary file not shown.
|
@ -21,7 +21,7 @@
|
||||||
((c) >= 'a' && (c) <= 'f'))
|
((c) >= 'a' && (c) <= 'f'))
|
||||||
|
|
||||||
// Character manipulation macros.
|
// Character manipulation macros.
|
||||||
#define tolower(c) (isupper(c) ? (c)|32 : (c))
|
#define tolower(c) (isupper(c) ? (c) | 32 : (c))
|
||||||
#define toupper(c) (islower(c) ? (c)&~32 : (c))
|
#define toupper(c) (islower(c) ? (c) & ~32 : (c))
|
||||||
|
|
||||||
#endif // _CTYPE_H
|
#endif // _CTYPE_H
|
||||||
|
|
|
@ -1,62 +1,29 @@
|
||||||
|
//---
|
||||||
|
//
|
||||||
|
// gint drawing module: display
|
||||||
|
//
|
||||||
|
// Handles vram manipulation and drawing for plain monochrome display.
|
||||||
|
//
|
||||||
|
//---
|
||||||
|
|
||||||
#ifndef _DISPLAY_H
|
#ifndef _DISPLAY_H
|
||||||
#define _DISPLAY_H 1
|
#define _DISPLAY_H 1
|
||||||
|
|
||||||
|
|
||||||
//---
|
//---
|
||||||
// Included submodules.
|
// Heading declarations.
|
||||||
//---
|
//---
|
||||||
|
|
||||||
#include <tales.h>
|
#include <tales.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//---
|
|
||||||
// Types and constants.
|
|
||||||
//---
|
|
||||||
|
|
||||||
enum Color
|
enum Color
|
||||||
{
|
{
|
||||||
Color_White = 0, // White (AND 0)
|
Color_White = 0,
|
||||||
Color_Black = 1, // Black (OR 1)
|
Color_Light = 1,
|
||||||
Color_None = 2, // Transparent (NOP)
|
Color_Dark = 2,
|
||||||
Color_Invert = 3, // Invert (XOR 1)
|
Color_Black = 3,
|
||||||
};
|
Color_None = 4,
|
||||||
|
Color_Invert = 5,
|
||||||
/*
|
|
||||||
enum BlendingMode
|
|
||||||
Describes the various blending modes available for drawing images.
|
|
||||||
Blending modes may be combined for special effects! For instance:
|
|
||||||
- Or Only sets black pixels.
|
|
||||||
- And Only erases white pixels.
|
|
||||||
- Or | And Fully draws the bitmap.
|
|
||||||
- Invert Inverts pixels where the bitmap is black.
|
|
||||||
- Or | Invert Erases black pixels.
|
|
||||||
Adding Checker to an existing combination limits the operation to
|
|
||||||
pixels (x, y) that satisfy (x + y) & 1 == 1.
|
|
||||||
Operations are done in the following order : Or - Invert - And.
|
|
||||||
*/
|
|
||||||
enum BlendingMode
|
|
||||||
{
|
|
||||||
Blend_Or = 0x01,
|
|
||||||
Blend_Invert = 0x02,
|
|
||||||
Blend_And = 0x04,
|
|
||||||
|
|
||||||
Blend_Checker = 0x10,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
enum ImageFormat
|
|
||||||
Describes the various image formats available. Colors may be encoded
|
|
||||||
as monochrome (1 layer) or gray (2 layers). Whatever the color map, any
|
|
||||||
bitmap may also have an additional alpha layer.
|
|
||||||
*/
|
|
||||||
enum ImageFormat
|
|
||||||
{
|
|
||||||
ImageFormat_Mono = 0x01,
|
|
||||||
ImageFormat_Gray = 0x02,
|
|
||||||
|
|
||||||
ImageFormat_Alpha = 0x10,
|
|
||||||
|
|
||||||
ImageFormat_ColorMask = 0x0f,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -69,10 +36,10 @@ enum ImageFormat
|
||||||
struct Image
|
struct Image
|
||||||
{
|
{
|
||||||
unsigned char magic;
|
unsigned char magic;
|
||||||
|
unsigned char format;
|
||||||
|
|
||||||
unsigned char width;
|
unsigned char width;
|
||||||
unsigned char height;
|
unsigned char height;
|
||||||
unsigned char format;
|
|
||||||
|
|
||||||
const unsigned char __attribute__((aligned(4))) data[];
|
const unsigned char __attribute__((aligned(4))) data[];
|
||||||
|
|
||||||
|
@ -94,12 +61,10 @@ typedef struct Image Image;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
display_getLocalVRAM()
|
display_getLocalVRAM()
|
||||||
Returns the local video ram. This function always return the same
|
Returns the local video ram address. This function always return the
|
||||||
address.
|
same address.
|
||||||
The buffer returned by this function should not be used directly when
|
The buffer returned by this function should not be used directly when
|
||||||
running the gray engine.
|
running the gray engine.
|
||||||
|
|
||||||
@return Video ram address of the monochrome display module.
|
|
||||||
*/
|
*/
|
||||||
void *display_getLocalVRAM(void);
|
void *display_getLocalVRAM(void);
|
||||||
|
|
||||||
|
@ -114,13 +79,11 @@ void *display_getCurrentVRAM(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
display_useVRAM()
|
display_useVRAM()
|
||||||
Changes the current video ram address. The argument *MUST* be a
|
Changes the current video ram address. The argument MUST be a 4-
|
||||||
4-aligned 1024 buffer ; otherwise any drawing operation will crash the
|
aligned 1024-byte buffer; otherwise any drawing operation will crash
|
||||||
program.
|
the program.
|
||||||
This function will most likely have no effect when running the gray
|
This function will most likely have no effect when running the gray
|
||||||
engine.
|
engine.
|
||||||
|
|
||||||
@arg New video ram address.
|
|
||||||
*/
|
*/
|
||||||
void display_useVRAM(void *vram);
|
void display_useVRAM(void *vram);
|
||||||
|
|
||||||
|
@ -132,7 +95,8 @@ void display_useVRAM(void *vram);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
dupdate()
|
dupdate()
|
||||||
Displays the vram on the physical screen.
|
Displays the vram on the physical screen. Does nothing when the gray
|
||||||
|
engine is running.
|
||||||
*/
|
*/
|
||||||
void dupdate(void);
|
void dupdate(void);
|
||||||
|
|
||||||
|
@ -144,23 +108,15 @@ void dclear(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
dclear_area()
|
dclear_area()
|
||||||
Clears an area of the video ram.
|
Clears an area of the video ram. Both (x1, y1) and (x2, y2) are
|
||||||
|
cleared.
|
||||||
@arg x1
|
|
||||||
@arg y1
|
|
||||||
@arg x2
|
|
||||||
@arg y2
|
|
||||||
*/
|
*/
|
||||||
void dclear_area(int x1, int y1, int x2, int y2);
|
void dclear_area(int x1, int y1, int x2, int y2);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
dreverse_area()
|
dreverse_area()
|
||||||
Reverses an area of the screen.
|
Reverses an area of the vram. (x1, y1) and (x2, y2) are reversed as
|
||||||
|
well.
|
||||||
@arg x1
|
|
||||||
@arg y1
|
|
||||||
@arg x2
|
|
||||||
@arg y2
|
|
||||||
*/
|
*/
|
||||||
void dreverse_area(int x1, int y1, int x2, int y2);
|
void dreverse_area(int x1, int y1, int x2, int y2);
|
||||||
|
|
||||||
|
@ -172,45 +128,25 @@ void dreverse_area(int x1, int y1, int x2, int y2);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
dpixel()
|
dpixel()
|
||||||
Puts a pixel on the screen.
|
Puts a pixel in the vram.
|
||||||
|
|
||||||
@arg x
|
|
||||||
@arg y
|
|
||||||
@arg color
|
|
||||||
*/
|
*/
|
||||||
void dpixel(int x, int y, enum Color color);
|
void dpixel(int x, int y, enum Color color);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
dline()
|
dline()
|
||||||
Draws a line on the screen. Automatically optimizes horizontal and
|
Draws a line in the vram. Automatically optimizes horizontal and
|
||||||
vertical lines.
|
vertical lines.
|
||||||
|
|
||||||
Uses an algorithm written by PierrotLL for MonochromeLib.
|
Uses an algorithm written by PierrotLL for MonochromeLib.
|
||||||
|
|
||||||
@arg x1
|
|
||||||
@arg y1
|
|
||||||
@arg x2
|
|
||||||
@arg y2
|
|
||||||
@arg color
|
|
||||||
*/
|
*/
|
||||||
void dline(int x1, int y1, int x2, int y2, enum Color color);
|
void dline(int x1, int y1, int x2, int y2, enum Color color);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//---
|
|
||||||
// Image drawing.
|
|
||||||
//---
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
dimage()
|
dimage()
|
||||||
Displays an image in the vram. Does a real lot of optimization.
|
Displays a monochrome image in the vram. Does a real lot of
|
||||||
|
optimization.
|
||||||
@arg image
|
|
||||||
@arg x
|
|
||||||
@arg y
|
|
||||||
@arg mode
|
|
||||||
*/
|
*/
|
||||||
void dimage(struct Image *image, int x, int y, enum BlendingMode mode);
|
void dimage(struct Image *image, int x, int y);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,26 @@
|
||||||
|
//---
|
||||||
|
//
|
||||||
|
// gint core/drawing module: gray
|
||||||
|
//
|
||||||
|
// Runs the gray engine and handles drawing for the dual-buffer system.
|
||||||
|
//
|
||||||
|
//---
|
||||||
|
|
||||||
#ifndef _GRAY_H
|
#ifndef _GRAY_H
|
||||||
#define _GRAY_H 1
|
#define _GRAY_H 1
|
||||||
|
|
||||||
|
#include <display.h>
|
||||||
|
|
||||||
//---
|
//---
|
||||||
// Public API.
|
// Engine control.
|
||||||
//---
|
//---
|
||||||
|
|
||||||
|
/*
|
||||||
|
gray_runs()
|
||||||
|
Returns 1 if the gray engine is running, 0 otherwise.
|
||||||
|
*/
|
||||||
|
int gray_runs(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
gray_start()
|
gray_start()
|
||||||
Starts the gray engine. The control of the screen is transferred to the
|
Starts the gray engine. The control of the screen is transferred to the
|
||||||
|
@ -33,10 +49,7 @@ void *gray_darkVRAM(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
gray_getDelays()
|
gray_getDelays()
|
||||||
Returns the gray engine delays.
|
Returns the gray engine delays. Pointers are not set if NULL.
|
||||||
|
|
||||||
@arg light Will be set if non-NULL.
|
|
||||||
@arg dark Will be set if non-NULL.
|
|
||||||
*/
|
*/
|
||||||
void gray_getDelays(int *light, int *dark);
|
void gray_getDelays(int *light, int *dark);
|
||||||
|
|
||||||
|
@ -47,23 +60,72 @@ void gray_getDelays(int *light, int *dark);
|
||||||
Finding values that give proper grays is quite the hard part of the
|
Finding values that give proper grays is quite the hard part of the
|
||||||
gray engine. Usual values are about 1000, with light being between 75
|
gray engine. Usual values are about 1000, with light being between 75
|
||||||
and 90% of dark.
|
and 90% of dark.
|
||||||
|
|
||||||
@arg light Light gray duration (the lower).
|
|
||||||
@arg dark Dark gray duration (the higher).
|
|
||||||
*/
|
*/
|
||||||
void gray_setDelays(int light, int dark);
|
void gray_setDelays(int light, int dark);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Global drawing functions.
|
||||||
|
//---
|
||||||
|
|
||||||
|
/*
|
||||||
|
gupdate()
|
||||||
|
Swaps the vram buffer sets.
|
||||||
|
*/
|
||||||
|
void gupdate(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
gclear()
|
||||||
|
Clears the video ram.
|
||||||
|
*/
|
||||||
|
void gclear(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
gclear_area()
|
||||||
|
Clears an area of the video ram. End points (x1, y1) and (x2, y2) are
|
||||||
|
included.
|
||||||
|
*/
|
||||||
|
void gclear_area(int x1, int y1, int x2, int y2);
|
||||||
|
|
||||||
|
/*
|
||||||
|
greverse_area()
|
||||||
|
Reverses an area of the vram. End points (x1, y1) and (x2, y2) are
|
||||||
|
included.
|
||||||
|
*/
|
||||||
|
void greverse_area(int x1, int y1, int x2, int y2);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Local drawing functions.
|
||||||
|
//---
|
||||||
|
|
||||||
|
/*
|
||||||
|
gpixel()
|
||||||
|
Puts a pixel in the vram.
|
||||||
|
*/
|
||||||
|
void gpixel(int x, int y, enum Color color);
|
||||||
|
|
||||||
|
/*
|
||||||
|
gline()
|
||||||
|
Draws a line in the vram. Automatically optimizes special cases.
|
||||||
|
*/
|
||||||
|
void gline(int x1, int y1, int x2, int y2, enum Color color);
|
||||||
|
|
||||||
|
/*
|
||||||
|
gimage()
|
||||||
|
Displays a gray image in the vram.
|
||||||
|
*/
|
||||||
|
void gimage(struct Image *image, int x, int y);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//---
|
//---
|
||||||
// Internal API.
|
// Internal API.
|
||||||
// Referenced here for documentation purposes only. Do not call.
|
// Referenced here for documentation purposes only. Do not call.
|
||||||
//--
|
//--
|
||||||
|
|
||||||
/*
|
|
||||||
gray_swap()
|
|
||||||
Swaps the vram buffers.
|
|
||||||
*/
|
|
||||||
void gray_swap(void);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
gray_interrupt()
|
gray_interrupt()
|
||||||
Answers a timer interrupt. Swaps the two buffers.
|
Answers a timer interrupt. Swaps the two buffers.
|
||||||
|
|
|
@ -23,8 +23,6 @@ void abort(void);
|
||||||
exit()
|
exit()
|
||||||
Stops the program execution with the given status code, after calling
|
Stops the program execution with the given status code, after calling
|
||||||
the exit handlers.
|
the exit handlers.
|
||||||
|
|
||||||
@arg status
|
|
||||||
*/
|
*/
|
||||||
void exit(int status);
|
void exit(int status);
|
||||||
|
|
||||||
|
@ -38,10 +36,6 @@ void exit(int status);
|
||||||
malloc()
|
malloc()
|
||||||
Allocs 'size' bytes and returns a pointer to a free memory area.
|
Allocs 'size' bytes and returns a pointer to a free memory area.
|
||||||
Returns NULL on error.
|
Returns NULL on error.
|
||||||
|
|
||||||
@arg size Size to allocate, in bytes.
|
|
||||||
|
|
||||||
@return Memory area address, or NULL.
|
|
||||||
*/
|
*/
|
||||||
void *malloc(size_t size);
|
void *malloc(size_t size);
|
||||||
|
|
||||||
|
@ -49,19 +43,12 @@ void *malloc(size_t size);
|
||||||
calloc()
|
calloc()
|
||||||
Allocs 'n' elements of size 'size' and wipes the memory area. Returns
|
Allocs 'n' elements of size 'size' and wipes the memory area. Returns
|
||||||
NULL on error.
|
NULL on error.
|
||||||
|
|
||||||
@arg n Element number.
|
|
||||||
@arg size Element size.
|
|
||||||
|
|
||||||
@return Memory area address, or NULL.
|
|
||||||
*/
|
*/
|
||||||
void *calloc(size_t n, size_t size);
|
void *calloc(size_t n, size_t size);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
free()
|
free()
|
||||||
Frees a memory block allocated with malloc().
|
Frees a memory block allocated with malloc().
|
||||||
|
|
||||||
@arg ptr Pointer to free.
|
|
||||||
*/
|
*/
|
||||||
void free(void *ptr);
|
void free(void *ptr);
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,6 @@
|
||||||
// Types and constants.
|
// Types and constants.
|
||||||
//---
|
//---
|
||||||
|
|
||||||
enum BlendingMode;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
enum ImageFormat
|
enum ImageFormat
|
||||||
This type holds information about the characters in the font. Each bit
|
This type holds information about the characters in the font. Each bit
|
||||||
|
@ -78,7 +76,6 @@ typedef struct Font Font;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//---
|
//---
|
||||||
// Generic functions.
|
// Generic functions.
|
||||||
//---
|
//---
|
||||||
|
@ -90,7 +87,7 @@ typedef struct Font Font;
|
||||||
@arg font
|
@arg font
|
||||||
@arg mode
|
@arg mode
|
||||||
*/
|
*/
|
||||||
void print_configure(struct Font *font, enum BlendingMode mode);
|
void print_configure(struct Font *font);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
print_raw()
|
print_raw()
|
||||||
|
|
BIN
libc.a
BIN
libc.a
Binary file not shown.
BIN
libgint.a
BIN
libgint.a
Binary file not shown.
450
src/bopti.c
450
src/bopti.c
|
@ -1,74 +1,152 @@
|
||||||
|
//---
|
||||||
|
//
|
||||||
|
// gint drawing module: bopti
|
||||||
|
//
|
||||||
|
// bopti does every job related to display images. There is only one
|
||||||
|
// public function, but there are lots of internal optimizations.
|
||||||
|
//
|
||||||
|
// Some bit-manipulation expressions may look written out of nowhere. The
|
||||||
|
// idea is always the same: get a part of the image in an 'operator',
|
||||||
|
// which is a 32-bit variable, shift this operator so that its bits
|
||||||
|
// correspond to the desired position for the bitmap on the screen, and
|
||||||
|
// edit the video-ram long entry which correspond to this position using
|
||||||
|
// a 'mask' that indicates which bits of the operator contain information.
|
||||||
|
//
|
||||||
|
//---
|
||||||
|
|
||||||
#include <display.h>
|
#include <display.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <gray.h>
|
#include <gray.h>
|
||||||
|
|
||||||
|
|
||||||
//---
|
//---
|
||||||
// Image drawing. There is only one public function dimage(), but there
|
// Heading declarations.
|
||||||
// are lots of local methods and optimizations.
|
|
||||||
//
|
|
||||||
// Some expressions may look nonsense sometimes. The procedure is always
|
|
||||||
// the same : get a part of the image in an operator, shift it depending
|
|
||||||
// on the drawing x-coordinate, compute a mask that indicates which bits
|
|
||||||
// of the operator contain information, and modify a vram long using the
|
|
||||||
// operator and the mask.
|
|
||||||
//---
|
//---
|
||||||
|
|
||||||
// This pointer is set by bopti().
|
/*
|
||||||
static int *vram;
|
enum Channel
|
||||||
|
Determines the kind of information written into a layer. Every image is
|
||||||
|
made of one or more channels.
|
||||||
|
*/
|
||||||
|
enum Channel
|
||||||
|
{
|
||||||
|
Channel_Mono = 0x01,
|
||||||
|
Channel_Light = 0x02,
|
||||||
|
Channel_Dark = 0x04,
|
||||||
|
|
||||||
|
Channel_FullAlpha = 0x08,
|
||||||
|
Channel_LightAlpha = 0x10,
|
||||||
|
Channel_DarkAlpha = 0x20,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
enum Format
|
||||||
|
Describes the various combination of channels allowed by bopti.
|
||||||
|
*/
|
||||||
|
enum Format
|
||||||
|
{
|
||||||
|
Format_Mono = Channel_Mono,
|
||||||
|
Format_MonoAlpha = Format_Mono | Channel_FullAlpha,
|
||||||
|
Format_Gray = Channel_Light | Channel_Dark,
|
||||||
|
Format_GrayAlpha = Format_Gray | Channel_FullAlpha,
|
||||||
|
Format_GreaterAlpha = Format_Mono | Channel_LightAlpha |
|
||||||
|
Channel_DarkAlpha
|
||||||
|
};
|
||||||
|
|
||||||
|
// These pointers are set by dimage() to avoid having to repeatedly determine
|
||||||
|
// which video ram to use.
|
||||||
|
static int *vram, *v1, *v2;
|
||||||
|
// The following variables refer to parameters that do not change during the
|
||||||
|
// drawing operation (at least for the time of a layer). They could be passed
|
||||||
|
// on by every function from the module, but this would be heavy and useless.
|
||||||
|
static enum Channel channel;
|
||||||
|
static int height;
|
||||||
|
static void (*op)(int offset, uint32_t operator, uint32_t op_mask);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Drawing operation.
|
||||||
|
//---
|
||||||
|
|
||||||
/*
|
/*
|
||||||
bopti_op()
|
bopti_op()
|
||||||
Operates on a vram long. The operator will often not contain 32 bits of
|
Operates on a vram long. The operator will often not contain 32 bits of
|
||||||
image information. In this case, the bits outside the image must be set
|
image information. Since neutral bits are not the same for all
|
||||||
to 0 for Or and Invert operations... 1 for And operations. Which means
|
operations, the op_mask argument indicates which bits should be used
|
||||||
that the calling procedure must indicate what part of the operator
|
for the operation. Which operation has to be done is determined by the
|
||||||
belongs to the image, which is done through the image_mask argument.
|
channel setting.
|
||||||
|
|
||||||
@arg offset Vram offset where edition is planned.
|
|
||||||
@arg operator Longword to operate with.
|
|
||||||
@arg image_mask Part of the operator that is inside the image.
|
|
||||||
@arg mode Operation mode.
|
|
||||||
*/
|
*/
|
||||||
static void bopti_op(int offset, uint32_t operator, uint32_t image_mask,
|
static void bopti_op_mono(int offset, uint32_t operator, uint32_t op_mask)
|
||||||
enum BlendingMode mode)
|
|
||||||
{
|
{
|
||||||
if(mode & Blend_Checker) operator &= 0x55555555;
|
operator &= op_mask;
|
||||||
if(mode & Blend_Or) vram[offset] |= operator;
|
|
||||||
if(mode & Blend_Invert) vram[offset] ^= operator;
|
switch(channel)
|
||||||
operator |= ~image_mask;
|
{
|
||||||
if(mode & Blend_And) vram[offset] &= operator;
|
case Channel_Mono:
|
||||||
|
vram[offset] |= operator;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Channel_FullAlpha:
|
||||||
|
vram[offset] &= ~operator;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void bopti_op_gray(int offset, uint32_t operator, uint32_t op_mask)
|
||||||
|
{
|
||||||
|
operator &= op_mask;
|
||||||
|
|
||||||
|
switch(channel)
|
||||||
|
{
|
||||||
|
case Channel_Mono:
|
||||||
|
v1[offset] |= operator;
|
||||||
|
v2[offset] |= operator;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Channel_Light:
|
||||||
|
v1[offset] |= operator;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Channel_Dark:
|
||||||
|
v2[offset] |= operator;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Channel_FullAlpha:
|
||||||
|
v1[offset] &= ~operator;
|
||||||
|
v2[offset] &= ~operator;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Channel_LightAlpha:
|
||||||
|
case Channel_DarkAlpha:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
bopti_grid() -- general form
|
bopti_grid() -- general form
|
||||||
bopti_grid_a32() -- when x is a multiple of 32
|
bopti_grid_a32() -- when x is a multiple of 32
|
||||||
|
|
||||||
Draws a layer whose length is a multiple of 32.
|
Draws the grid at the beginning of a layer's data. The length of this
|
||||||
|
grid is always a multiple of 32.
|
||||||
The need for bopti_grid_a32() is not only linked to optimization,
|
The need for bopti_grid_a32() is not only linked to optimization,
|
||||||
because one of the bit shifts in bopti_grid() will reach 32 when x is
|
because bopti_grid() will perform a 32-bit shift when x is a multiple
|
||||||
a multiple of 32, which is undefined behavior.
|
of 32, which is undefined behavior.
|
||||||
|
|
||||||
@arg layer Raw column data (column data is located at the
|
|
||||||
beginning of layer data).
|
|
||||||
@arg x
|
|
||||||
@arg y
|
|
||||||
@arg column_number
|
|
||||||
@arg height
|
|
||||||
@arg mode
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void bopti_grid_a32(const uint32_t *layer, int x, int y,
|
static void bopti_grid_a32(const uint32_t *layer, int x, int y,
|
||||||
int column_number, int height, enum BlendingMode mode)
|
int column_count)
|
||||||
{
|
{
|
||||||
int vram_column_offset = (y << 2) + (x >> 5);
|
int vram_column_offset = (y << 2) + (x >> 5);
|
||||||
int vram_offset = vram_column_offset;
|
int vram_offset = vram_column_offset;
|
||||||
int column, row;
|
int column, row;
|
||||||
|
|
||||||
for(column = 0; column < column_number; column++)
|
for(column = 0; column < column_count; column++)
|
||||||
{
|
{
|
||||||
for(row = 0; row < height; row++)
|
for(row = 0; row < height; row++)
|
||||||
{
|
{
|
||||||
bopti_op(vram_offset, *layer, 0xffffffff, mode);
|
(*op)(vram_offset, *layer, 0xffffffff);
|
||||||
layer++;
|
layer++;
|
||||||
vram_offset += 4;
|
vram_offset += 4;
|
||||||
}
|
}
|
||||||
|
@ -77,10 +155,15 @@ static void bopti_grid_a32(const uint32_t *layer, int x, int y,
|
||||||
vram_offset = vram_column_offset;
|
vram_offset = vram_column_offset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static void bopti_grid(const uint32_t *layer, int x, int y, int column_count)
|
||||||
static void bopti_grid(const uint32_t *layer, int x, int y, int column_number,
|
|
||||||
int height, enum BlendingMode mode)
|
|
||||||
{
|
{
|
||||||
|
if(!column_count) return;
|
||||||
|
if(!(x & 31))
|
||||||
|
{
|
||||||
|
bopti_grid_a32(layer, x, y, column_count);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const uint32_t *p1, *p2;
|
const uint32_t *p1, *p2;
|
||||||
uint32_t l1, l2;
|
uint32_t l1, l2;
|
||||||
int right_column, line;
|
int right_column, line;
|
||||||
|
@ -95,33 +178,26 @@ static void bopti_grid(const uint32_t *layer, int x, int y, int column_number,
|
||||||
uint32_t and_mask_0 = 0xffffffff >> shift2;
|
uint32_t and_mask_0 = 0xffffffff >> shift2;
|
||||||
uint32_t and_mask_1 = 0xffffffff << shift1;
|
uint32_t and_mask_1 = 0xffffffff << shift1;
|
||||||
|
|
||||||
if(!column_number) return;
|
|
||||||
if(!(x & 31))
|
|
||||||
{
|
|
||||||
bopti_grid_a32(layer, x, y, column_number, height, mode);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initializing two pointers. Since the columns are written one after
|
// Initializing two pointers. Since the columns are written one after
|
||||||
// another, they will be updated directly to parse the whole grid.
|
// another, they will be updated directly to parse the whole grid.
|
||||||
p1 = layer - height;
|
p1 = layer - height;
|
||||||
p2 = layer;
|
p2 = layer;
|
||||||
|
|
||||||
// Drawing vram longwords, using pairs of columns.
|
// Drawing vram longwords, using pairs of columns.
|
||||||
for(right_column = 0; right_column <= column_number; right_column++)
|
for(right_column = 0; right_column <= column_count; right_column++)
|
||||||
{
|
{
|
||||||
and_mask = 0xffffffff;
|
and_mask = 0xffffffff;
|
||||||
if(right_column == 0) and_mask &= and_mask_0;
|
if(right_column == 0) and_mask &= and_mask_0;
|
||||||
if(right_column == column_number) and_mask &= and_mask_1;
|
if(right_column == column_count) and_mask &= and_mask_1;
|
||||||
|
|
||||||
for(line = 0; line < height; line++)
|
for(line = 0; line < height; line++)
|
||||||
{
|
{
|
||||||
l1 = (right_column > 0) ? (*p1) : (0);
|
l1 = (right_column > 0) ? (*p1) : (0);
|
||||||
l2 = (right_column < column_number) ? (*p2) : (0);
|
l2 = (right_column < column_count) ? (*p2) : (0);
|
||||||
p1++, p2++;
|
p1++, p2++;
|
||||||
|
|
||||||
operator = (l1 << shift1) | (l2 >> shift2);
|
operator = (l1 << shift1) | (l2 >> shift2);
|
||||||
bopti_op(vram_offset, operator, and_mask, mode);
|
(*op)(vram_offset, operator, and_mask);
|
||||||
vram_offset += 4;
|
vram_offset += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,65 +207,44 @@ static void bopti_grid(const uint32_t *layer, int x, int y, int column_number,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
bopti_rest_get()
|
bopti_end_get()
|
||||||
Returns the line of a bitmap, whose width is lower than 32. The given
|
Returns an operator for the end of a line, whose width is lower than 32
|
||||||
pointer is read and set according to the bitmap width.
|
(by design: otherwise, it would have been a column). The given pointer
|
||||||
|
is read and updated so that it points to the next line at the end of
|
||||||
@arg ptr Address of data pointer.
|
the operation.
|
||||||
@arg size Element size (should be 1, 2, or 4 bytes).
|
|
||||||
*/
|
*/
|
||||||
static uint32_t bopti_rest_get(const unsigned char **data, int size)
|
static uint32_t bopti_end_get1(const unsigned char **data)
|
||||||
{
|
{
|
||||||
uint32_t line;
|
uint32_t operator = **data;
|
||||||
|
*data += 1;
|
||||||
if(size == 4)
|
return operator;
|
||||||
{
|
}
|
||||||
line = *((uint32_t *)*data);
|
static uint32_t bopti_end_get2(const unsigned char **data)
|
||||||
*data += 4;
|
{
|
||||||
return line;
|
uint32_t operator = *((uint16_t *)*data);
|
||||||
}
|
*data += 2;
|
||||||
|
return operator;
|
||||||
else if(size == 2)
|
|
||||||
{
|
|
||||||
line = *((uint16_t *)*data);
|
|
||||||
*data += 2;
|
|
||||||
return line;
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
line = **data;
|
|
||||||
(*data)++;
|
|
||||||
return line;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
bopti_rest() -- general form
|
bopti_rest() -- general form
|
||||||
bopti_rest_nover() -- when the bitmap does not overlap two longs
|
bopti_rest_nover() -- when the end does not overlap two vram longs
|
||||||
|
|
||||||
Draws a bitmap, whose width is lower than 32. It is called the 'rest'
|
Draws the end of a layer, which can be considered as a whole layer
|
||||||
since the biggest part will be drawn by bopti_grid().
|
whose with is lower than 32. (Actually is it lower or equal to 16;
|
||||||
|
otherwise it would have been a column and the end would be empty).
|
||||||
@arg rest Ending data. Encoded on 1, 2 or 4 bytes per line
|
|
||||||
depending on the rest width.
|
|
||||||
@arg x
|
|
||||||
@arg y
|
|
||||||
@arg width Rest width.
|
|
||||||
@arg height
|
|
||||||
@arg mode
|
|
||||||
*/
|
*/
|
||||||
|
static void bopti_end_nover(const unsigned char *end, int x, int y, int width)
|
||||||
static void bopti_rest_nover(const unsigned char *rest, int x, int y,
|
|
||||||
int width, int height, enum BlendingMode mode)
|
|
||||||
{
|
{
|
||||||
int element_size = (width > 16) ? (4) : (width > 8) ? (2) : (1);
|
uint32_t (*get)(const unsigned char **data) =
|
||||||
|
(width > 8) ? bopti_end_get2 : bopti_end_get1;
|
||||||
|
|
||||||
int vram_offset = (y << 2) + (x >> 5);
|
int vram_offset = (y << 2) + (x >> 5);
|
||||||
int row;
|
int row;
|
||||||
|
|
||||||
// We *have* shift >= 0 because of this function's 'no overlap'
|
// We *have* shift >= 0 because of this function's 'no overlap'
|
||||||
// requirement.
|
// requirement.
|
||||||
int shift_base = (4 - element_size) << 3;
|
int shift_base = (width > 8) ? 16 : 24;
|
||||||
int shift = shift_base - (x & 31);
|
int shift = shift_base - (x & 31);
|
||||||
|
|
||||||
uint32_t and_mask = (0xffffffff << (32 - width)) >> (x & 31);
|
uint32_t and_mask = (0xffffffff << (32 - width)) >> (x & 31);
|
||||||
|
@ -197,28 +252,28 @@ static void bopti_rest_nover(const unsigned char *rest, int x, int y,
|
||||||
|
|
||||||
for(row = 0; row < height; row++)
|
for(row = 0; row < height; row++)
|
||||||
{
|
{
|
||||||
operator = bopti_rest_get(&rest, element_size);
|
operator = (*get)(&end);
|
||||||
operator <<= shift;
|
operator <<= shift;
|
||||||
|
|
||||||
bopti_op(vram_offset, operator, and_mask, mode);
|
(*op)(vram_offset, operator, and_mask);
|
||||||
vram_offset += 4;
|
vram_offset += 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static void bopti_end(const unsigned char *end, int x, int y, int width)
|
||||||
static void bopti_rest(const unsigned char *rest, int x, int y, int width,
|
|
||||||
int height, enum BlendingMode mode)
|
|
||||||
{
|
{
|
||||||
if((x & 31) + width <= 32)
|
if((x & 31) + width <= 32)
|
||||||
{
|
{
|
||||||
bopti_rest_nover(rest, x, y, width, height, mode);
|
bopti_end_nover(end, x, y, width);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int element_size = (width > 16) ? (4) : (width > 8) ? (2) : (1);
|
uint32_t (*get)(const unsigned char **data) =
|
||||||
|
(width > 8) ? (bopti_end_get2) : (bopti_end_get1);
|
||||||
|
|
||||||
int vram_offset = (y << 2) + (x >> 5);
|
int vram_offset = (y << 2) + (x >> 5);
|
||||||
int row;
|
int row;
|
||||||
|
|
||||||
int shift_base = (4 - element_size) << 3;
|
int shift_base = (width > 8) ? 16 : 24;
|
||||||
int shift1 = (x & 31) - shift_base;
|
int shift1 = (x & 31) - shift_base;
|
||||||
int shift2 = shift_base + 32 - (x & 31);
|
int shift2 = shift_base + 32 - (x & 31);
|
||||||
|
|
||||||
|
@ -229,99 +284,150 @@ static void bopti_rest(const unsigned char *rest, int x, int y, int width,
|
||||||
|
|
||||||
for(row = 0; row < height; row++)
|
for(row = 0; row < height; row++)
|
||||||
{
|
{
|
||||||
row_data = bopti_rest_get(&rest, element_size);
|
row_data = (*get)(&end);
|
||||||
|
|
||||||
operator = row_data >> shift1;
|
operator = row_data >> shift1;
|
||||||
bopti_op(vram_offset, operator, and_mask_0, mode);
|
(*op)(vram_offset, operator, and_mask_0);
|
||||||
|
|
||||||
operator = row_data << shift2;
|
operator = row_data << shift2;
|
||||||
bopti_op(vram_offset + 1, operator, and_mask_1, mode);
|
(*op)(vram_offset + 1, operator, and_mask_1);
|
||||||
|
|
||||||
vram_offset += 4;
|
vram_offset += 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Wrappers and various functions.
|
||||||
|
//---
|
||||||
|
|
||||||
/*
|
/*
|
||||||
bopti()
|
bopti()
|
||||||
Draws an image layer in the video ram.
|
Draws a layer in the video ram.
|
||||||
|
|
||||||
@arg bitmap Raw layer data.
|
|
||||||
@arg x
|
|
||||||
@arg y
|
|
||||||
@arg width
|
|
||||||
@arg height
|
|
||||||
@arg mode
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void bopti(const unsigned char *layer, int x, int y, int width,
|
static void bopti(const unsigned char *layer, int x, int y, int columns,
|
||||||
int height, enum BlendingMode mode)
|
int end_size)
|
||||||
{
|
{
|
||||||
int column_number = width >> 5;
|
const unsigned char *end = layer + ((columns * height) << 2);
|
||||||
int rest_width = width & 31;
|
int end_x = x + (columns << 5);
|
||||||
|
|
||||||
vram = display_getCurrentVRAM();
|
bopti_grid((const uint32_t *)layer, x, y, columns);
|
||||||
|
if(end_size) bopti_end(end, end_x, y, end_size);
|
||||||
|
}
|
||||||
|
|
||||||
// Skipping 'column_number' columns of 'height' longs.
|
/*
|
||||||
const unsigned char *rest = layer + ((column_number * height) << 2);
|
getStructure()
|
||||||
int rest_x = x + (width - rest_width);
|
Determines the image size and data pointer.
|
||||||
|
*/
|
||||||
|
static void getStructure(struct Image *img, int *width, int *height,
|
||||||
|
int *layer_size, const unsigned char **data, int *columns,
|
||||||
|
int *end_size)
|
||||||
|
{
|
||||||
|
int column_count, end, end_bytes, layer;
|
||||||
|
|
||||||
bopti_grid((const uint32_t *)layer, x, y, column_number, height, mode);
|
// Large images.
|
||||||
if(!rest_width) return;
|
if(!img->width && !img->height)
|
||||||
bopti_rest(rest, rest_x, y, rest_width, height, mode);
|
{
|
||||||
|
if(width) *width = (img->data[0] << 8) | img->data[1];
|
||||||
|
if(height) *height = (img->data[2] << 8) | img->data[3];
|
||||||
|
if(data) *data = img->data + 4;
|
||||||
|
|
||||||
|
column_count = (*width + 31) >> 5;
|
||||||
|
end = end_bytes = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(width) *width = img->width;
|
||||||
|
if(height) *height = img->height;
|
||||||
|
if(data) *data = img->data;
|
||||||
|
|
||||||
|
column_count = img->width >> 5;
|
||||||
|
end = img->width & 31;
|
||||||
|
end_bytes =
|
||||||
|
!end ? 0 :
|
||||||
|
end <= 8 ? 1 :
|
||||||
|
end <= 16 ? 2 :
|
||||||
|
4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The layer size must be rounded to a multiple of 4.
|
||||||
|
layer = img->height * ((column_count << 2) + end_bytes);
|
||||||
|
if(layer & 3) layer += 4 - (layer & 3);
|
||||||
|
|
||||||
|
if(columns) *columns = column_count;
|
||||||
|
if(end_size) *end_size = end;
|
||||||
|
if(layer_size) *layer_size = layer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
dimage()
|
dimage()
|
||||||
Displays an image in the vram.
|
Displays a monochrome image in the video ram.
|
||||||
|
|
||||||
@arg image
|
|
||||||
@arg x
|
|
||||||
@arg y
|
|
||||||
@arg mode
|
|
||||||
*/
|
*/
|
||||||
|
void dimage(struct Image *img, int x, int y)
|
||||||
void dimage(struct Image *image, int x, int y, enum BlendingMode mode)
|
|
||||||
{
|
{
|
||||||
int width = image->width;
|
int width, layer_size, columns, end;
|
||||||
int height = image->height;
|
int format = img->format, i = 0;
|
||||||
const unsigned char *data = (const unsigned char *)&(image->data);
|
const unsigned char *data;
|
||||||
|
|
||||||
if(image->magic != 0xb7) return;
|
if(img->magic != 0xb7) return;
|
||||||
|
if(img->format != Format_Mono && img->format != Format_MonoAlpha)
|
||||||
|
return;
|
||||||
|
op = bopti_op_mono;
|
||||||
|
|
||||||
// Computing the layer size.
|
// 'height' refers to a static variable for this file.
|
||||||
int columns = image->width >> 5;
|
getStructure(img, &width, &height, &layer_size, &data, &columns, &end);
|
||||||
int rest = image->width & 31;
|
|
||||||
int rest_size =
|
|
||||||
!rest ? 0 :
|
|
||||||
rest <= 8 ? 1 :
|
|
||||||
rest <= 16 ? 2 :
|
|
||||||
4;
|
|
||||||
int layer_size = ((columns << 2) + rest_size) * image->height;
|
|
||||||
// The layer size must be a multiple of 4.
|
|
||||||
if(layer_size & 3) layer_size += 4 - (layer_size & 3);
|
|
||||||
|
|
||||||
switch(image->format & ImageFormat_ColorMask)
|
vram = display_getCurrentVRAM();
|
||||||
|
|
||||||
|
while(format)
|
||||||
{
|
{
|
||||||
case ImageFormat_Mono:
|
// Drawing every layer, in order of formats.
|
||||||
if(image->format & ImageFormat_Alpha)
|
if(format & 1)
|
||||||
{
|
{
|
||||||
bopti(data + layer_size, x, y, width, height,
|
channel = (1 << i);
|
||||||
Blend_And);
|
bopti(data, x, y, columns, end);
|
||||||
}
|
data += layer_size;
|
||||||
bopti(data, x, y, width, height, mode);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ImageFormat_Gray:
|
|
||||||
if(image->format & ImageFormat_Alpha)
|
|
||||||
{
|
|
||||||
bopti(data + 2 * layer_size, x, y, width, height,
|
|
||||||
Blend_And);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
display_useVRAM(gray_darkVRAM());
|
format >>= 1;
|
||||||
bopti(data, x, y, width, height, mode);
|
i++;
|
||||||
display_useVRAM(gray_lightVRAM());
|
|
||||||
bopti(data + layer_size, x, y, width, height, mode);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
gimage()
|
||||||
|
Displays a gray image in the video ram.
|
||||||
|
*/
|
||||||
|
void gimage(struct Image *img, int x, int y)
|
||||||
|
{
|
||||||
|
int width, layer_size, columns, end;
|
||||||
|
int format = img->format, i = 0;
|
||||||
|
const unsigned char *data;
|
||||||
|
|
||||||
|
if(img->magic != 0xb7) return;
|
||||||
|
op = bopti_op_gray;
|
||||||
|
|
||||||
|
// 'height' refers to a static variable for this file.
|
||||||
|
getStructure(img, &width, &height, &layer_size, &data, &columns, &end);
|
||||||
|
|
||||||
|
v1 = gray_lightVRAM();
|
||||||
|
v2 = gray_darkVRAM();
|
||||||
|
|
||||||
|
while(format)
|
||||||
|
{
|
||||||
|
// Drawing every layer, in order of formats.
|
||||||
|
if(format & 1)
|
||||||
|
{
|
||||||
|
channel = (1 << i);
|
||||||
|
bopti(data, x, y, columns, end);
|
||||||
|
data += layer_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
format >>= 1;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
281
src/display.c
281
src/display.c
|
@ -1,27 +1,29 @@
|
||||||
/*
|
//---
|
||||||
display
|
//
|
||||||
|
// gint drawing module: display
|
||||||
Handles vram manipulation and drawing.
|
//
|
||||||
|
// Handles vram manipulation and drawing.
|
||||||
:: Rectangle masks
|
//
|
||||||
|
//
|
||||||
The concept of 'rectangle masks' is used several times in this module.
|
// :: Rectangle masks
|
||||||
It consists in saying that an operation that affects a rectangle acts
|
//
|
||||||
the same on all the lines (considering that only the lines that
|
// The concept of 'rectangle masks' is used several times in this module.
|
||||||
intersect the rectangle are changed) and therefore it is possible to
|
// It is based on the fact that an operation that affects a rectangle acts
|
||||||
represent the behavior on a single line using 'masks' that indicate
|
// the same on all its lines. Therefore the behavior of the operation is
|
||||||
whether a pixel is affected (1) or not (0).
|
// determined by its behavior on a single line, which is represented using
|
||||||
|
// 'masks' whose bits indicate whether a pixel is affected (1) or not (0).
|
||||||
For example when clearing the screen rectangle (16, 16, 112, 48), the
|
//
|
||||||
masks will represent information '16 to 112 on x-axis', and will hold
|
// For example when clearing the screen rectangle (16, 16, 112, 48), the
|
||||||
the following values : 0000ffff, ffffffff, ffffffff and ffff0000. These
|
// masks will represent information '16 to 112 on x-axis', and will hold
|
||||||
masks can then be used by setting vram[offset] &= ~masks[i]. This
|
// the following values : 0000ffff, ffffffff, ffffffff and ffff0000. These
|
||||||
appears to be very flexible : for instance, reversing a rectangle of
|
// masks can then be used by setting vram[offset] &= ~masks[i]. This
|
||||||
vram only needs vram[offset] ^= masks[i].
|
// appears to be very flexible : for instance, vram[offset] ^= masks[i]
|
||||||
|
// will reverse the pixels in the same rectangle.
|
||||||
This technique can also be used in more subtle cases with more complex
|
//
|
||||||
patterns, but within this module it is unlikely to happen.
|
// This technique can also be used in more subtle cases with more complex
|
||||||
*/
|
// patterns, but within this module it is unlikely to happen.
|
||||||
|
//
|
||||||
|
//---
|
||||||
|
|
||||||
#include <screen.h>
|
#include <screen.h>
|
||||||
#include <display.h>
|
#include <display.h>
|
||||||
|
@ -47,14 +49,10 @@ static int *vram = local_vram;
|
||||||
/*
|
/*
|
||||||
adjust()
|
adjust()
|
||||||
Adjusts the given rectangle coordinates to ensure that :
|
Adjusts the given rectangle coordinates to ensure that :
|
||||||
- The rectangle is entirely contained in the screen,
|
- the rectangle is entirely contained in the screen
|
||||||
- x1 < x2 and y1 < y2,
|
- x1 < x2
|
||||||
|
- y1 < y2
|
||||||
which is needed when working with screen rectangles.
|
which is needed when working with screen rectangles.
|
||||||
|
|
||||||
@arg x1
|
|
||||||
@arg y1
|
|
||||||
@arg x2
|
|
||||||
@arg y2
|
|
||||||
*/
|
*/
|
||||||
static void adjust(int *x1, int *y1, int *x2, int *y2)
|
static void adjust(int *x1, int *y1, int *x2, int *y2)
|
||||||
{
|
{
|
||||||
|
@ -75,11 +73,8 @@ static void adjust(int *x1, int *y1, int *x2, int *y2)
|
||||||
getmasks()
|
getmasks()
|
||||||
|
|
||||||
Computes the rectangle masks needed to affect pixels located between x1
|
Computes the rectangle masks needed to affect pixels located between x1
|
||||||
and x2 (both included).
|
and x2 (both included). The four masks are stored in the third argument
|
||||||
|
(seen as an array).
|
||||||
@arg x1
|
|
||||||
@arg x2
|
|
||||||
@arg masks Four-integer-array pointer.
|
|
||||||
*/
|
*/
|
||||||
static void getmasks(int x1, int x2, unsigned int *masks)
|
static void getmasks(int x1, int x2, unsigned int *masks)
|
||||||
{
|
{
|
||||||
|
@ -99,11 +94,10 @@ static void getmasks(int x1, int x2, unsigned int *masks)
|
||||||
// number of null bits to add in l1 and l2.
|
// number of null bits to add in l1 and l2.
|
||||||
x1 &= 31;
|
x1 &= 31;
|
||||||
// Inverting x2 is here the same as computing 32 - x, since 32 is a
|
// Inverting x2 is here the same as computing 32 - x, since 32 is a
|
||||||
// power of 2 (actually it creates positive bits at the left but those
|
// power of 2 (positive bits at the left are removed by the mask).
|
||||||
// ones are removed by the bitwise-and mask).
|
|
||||||
x2 = ~x2 & 31;
|
x2 = ~x2 & 31;
|
||||||
|
|
||||||
// Setting the last masks.
|
// Setting the first and last masks.
|
||||||
masks[l1] &= (0xffffffff >> x1);
|
masks[l1] &= (0xffffffff >> x1);
|
||||||
masks[l2] &= (0xffffffff << x2);
|
masks[l2] &= (0xffffffff << x2);
|
||||||
}
|
}
|
||||||
|
@ -116,34 +110,37 @@ static void getmasks(int x1, int x2, unsigned int *masks)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
display_getLocalVRAM()
|
display_getLocalVRAM()
|
||||||
Returns the local video ram.
|
Returns the local video ram address. This function always return the
|
||||||
|
same address.
|
||||||
@return Video ram address.
|
The buffer returned by this function should not be used directly when
|
||||||
|
running the gray engine.
|
||||||
*/
|
*/
|
||||||
void *display_getLocalVRAM(void)
|
inline void *display_getLocalVRAM(void)
|
||||||
{
|
{
|
||||||
return (void *)local_vram;
|
return (void *)local_vram;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
display_getCurrentVRAM()
|
display_getCurrentVRAM()
|
||||||
Returns the current vido ram.
|
Returns the current video ram. This function usually returns the
|
||||||
|
parameter of the last call to display_useVRAM(), unless the gray engine
|
||||||
@return Video ram address.
|
is running (in which case the result is undefined). Returns the local
|
||||||
|
vram address by default.
|
||||||
*/
|
*/
|
||||||
void *display_getCurrentVRAM(void)
|
inline void *display_getCurrentVRAM(void)
|
||||||
{
|
{
|
||||||
return (void *)vram;
|
return (void *)vram;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
display_useVRAM()
|
display_useVRAM()
|
||||||
Changes the current video ram address. Expects a *4-aligned* 1024-byte
|
Changes the current video ram address. The argument MUST be a 4-
|
||||||
buffer.
|
aligned 1024-byte buffer ; otherwise any drawing operation will crash
|
||||||
|
the program.
|
||||||
@arg New video ram address.
|
This function will most likely have no effect when running the gray
|
||||||
|
engine.
|
||||||
*/
|
*/
|
||||||
void display_useVRAM(void *ptr)
|
inline void display_useVRAM(void *ptr)
|
||||||
{
|
{
|
||||||
vram = (int *)ptr;
|
vram = (int *)ptr;
|
||||||
}
|
}
|
||||||
|
@ -160,6 +157,7 @@ void display_useVRAM(void *ptr)
|
||||||
*/
|
*/
|
||||||
void dupdate(void)
|
void dupdate(void)
|
||||||
{
|
{
|
||||||
|
if(gray_runs()) return;
|
||||||
screen_display((const void *)local_vram);
|
screen_display((const void *)local_vram);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,12 +173,8 @@ void dclear(void)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
dclear_area()
|
dclear_area()
|
||||||
Clears an area of the vram using rectangle masks.
|
Clears an area of the vram using rectangle masks. Both (x1, y1) and
|
||||||
|
(x2, y2) are cleared.
|
||||||
@arg x1
|
|
||||||
@arg y1
|
|
||||||
@arg x2
|
|
||||||
@arg y2
|
|
||||||
*/
|
*/
|
||||||
void dclear_area(int x1, int y1, int x2, int y2)
|
void dclear_area(int x1, int y1, int x2, int y2)
|
||||||
{
|
{
|
||||||
|
@ -188,23 +182,19 @@ void dclear_area(int x1, int y1, int x2, int y2)
|
||||||
adjust(&x1, &y1, &x2, &y2);
|
adjust(&x1, &y1, &x2, &y2);
|
||||||
getmasks(x1, x2, masks);
|
getmasks(x1, x2, masks);
|
||||||
|
|
||||||
int offset = y1 << 2;
|
int begin = y1 << 2;
|
||||||
int end = (y2 + 1) << 2;
|
int end = (y2 + 1) << 2;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i = 0; i < 4; i++) masks[i] = ~masks[i];
|
for(i = 0; i < 4; i++) masks[i] = ~masks[i];
|
||||||
while(offset < end) vram[offset] &= masks[offset & 3], offset++;
|
for(i = begin; i < end; i++) vram[i] &= masks[i & 3];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
dreverse_area()
|
dreverse_area()
|
||||||
Reverses an area of the vram. This function is a simple application of
|
Reverses an area of the vram. This function is a simple application of
|
||||||
the rectangle masks concept.
|
the rectangle masks concept. (x1, y1) and (x2, y2) are reversed as
|
||||||
|
well.
|
||||||
@arg x1
|
|
||||||
@arg y1
|
|
||||||
@arg x2
|
|
||||||
@arg y2
|
|
||||||
*/
|
*/
|
||||||
void dreverse_area(int x1, int y1, int x2, int y2)
|
void dreverse_area(int x1, int y1, int x2, int y2)
|
||||||
{
|
{
|
||||||
|
@ -212,10 +202,25 @@ void dreverse_area(int x1, int y1, int x2, int y2)
|
||||||
adjust(&x1, &y1, &x2, &y2);
|
adjust(&x1, &y1, &x2, &y2);
|
||||||
getmasks(x1, x2, masks);
|
getmasks(x1, x2, masks);
|
||||||
|
|
||||||
int offset = y1 << 2;
|
int begin = y1 << 2;
|
||||||
int end = (y2 + 1) << 2;
|
int end = (y2 + 1) << 2;
|
||||||
|
int i;
|
||||||
|
|
||||||
while(offset < end) vram[offset] ^= masks[offset & 3], offset++;
|
if(gray_runs())
|
||||||
|
{
|
||||||
|
int *v1 = gray_lightVRAM();
|
||||||
|
int *v2 = gray_darkVRAM();
|
||||||
|
|
||||||
|
for(i = begin; i < end; i++)
|
||||||
|
{
|
||||||
|
v1[i] ^= masks[i & 3];
|
||||||
|
v2[i] ^= masks[i & 3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else for(i = begin; i < end; i++)
|
||||||
|
{
|
||||||
|
vram[i] ^= masks[i & 3];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -226,15 +231,12 @@ void dreverse_area(int x1, int y1, int x2, int y2)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
dpixel()
|
dpixel()
|
||||||
Puts a pixel on the screen.
|
Puts a pixel in the vram.
|
||||||
|
|
||||||
@arg x
|
|
||||||
@arg y
|
|
||||||
@arg color
|
|
||||||
*/
|
*/
|
||||||
void dpixel(int x, int y, enum Color color)
|
void dpixel(int x, int y, enum Color color)
|
||||||
{
|
{
|
||||||
if((unsigned int)x > 127 || (unsigned int)y > 63) return;
|
if((unsigned int)x > 127 || (unsigned int)y > 63) return;
|
||||||
|
|
||||||
int offset = (y << 2) + (x >> 5);
|
int offset = (y << 2) + (x >> 5);
|
||||||
int mask = 0x80000000 >> (x & 31);
|
int mask = 0x80000000 >> (x & 31);
|
||||||
|
|
||||||
|
@ -248,12 +250,12 @@ void dpixel(int x, int y, enum Color color)
|
||||||
vram[offset] |= mask;
|
vram[offset] |= mask;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Color_None:
|
|
||||||
return;
|
|
||||||
|
|
||||||
case Color_Invert:
|
case Color_Invert:
|
||||||
vram[offset] ^= mask;
|
vram[offset] ^= mask;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,12 +263,6 @@ void dpixel(int x, int y, enum Color color)
|
||||||
dline()
|
dline()
|
||||||
Draws a line on the screen. Automatically optimizes horizontal and
|
Draws a line on the screen. Automatically optimizes horizontal and
|
||||||
vertical lines.
|
vertical lines.
|
||||||
|
|
||||||
@arg x1
|
|
||||||
@arg y1
|
|
||||||
@arg x2
|
|
||||||
@arg y2
|
|
||||||
@arg color
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void dhline(int x1, int x2, int y, enum Color color)
|
static void dhline(int x1, int x2, int y, enum Color color)
|
||||||
|
@ -275,9 +271,60 @@ static void dhline(int x1, int x2, int y, enum Color color)
|
||||||
int offset = y << 2;
|
int offset = y << 2;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
// Swapping x1 and x2 if needed.
|
||||||
|
if(x1 > x2) x1 ^= x2, x2 ^= x1, x1 ^= x2;
|
||||||
getmasks(x1, x2, masks);
|
getmasks(x1, x2, masks);
|
||||||
|
|
||||||
switch(color)
|
int *v1 = gray_lightVRAM();
|
||||||
|
int *v2 = gray_darkVRAM();
|
||||||
|
|
||||||
|
if(gray_runs()) switch(color)
|
||||||
|
{
|
||||||
|
case Color_White:
|
||||||
|
for(i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
v1[offset + i] &= ~masks[i];
|
||||||
|
v2[offset + i] &= ~masks[i];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Color_Light:
|
||||||
|
for(i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
v1[offset + i] |= masks[i];
|
||||||
|
v2[offset + i] &= ~masks[i];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Color_Dark:
|
||||||
|
for(i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
v1[offset + i] &= ~masks[i];
|
||||||
|
v2[offset + i] |= masks[i];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Color_Black:
|
||||||
|
for(i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
v1[offset + i] |= masks[i];
|
||||||
|
v2[offset + i] |= masks[i];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Color_Invert:
|
||||||
|
for(i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
v1[offset + i] ^= masks[i];
|
||||||
|
v2[offset + i] ^= masks[i];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
else switch(color)
|
||||||
{
|
{
|
||||||
case Color_White:
|
case Color_White:
|
||||||
for(i = 0; i < 4; i++) vram[offset + i] &= ~masks[i];
|
for(i = 0; i < 4; i++) vram[offset + i] &= ~masks[i];
|
||||||
|
@ -287,12 +334,12 @@ static void dhline(int x1, int x2, int y, enum Color color)
|
||||||
for(i = 0; i < 4; i++) vram[offset + i] |= masks[i];
|
for(i = 0; i < 4; i++) vram[offset + i] |= masks[i];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Color_None:
|
|
||||||
return;
|
|
||||||
|
|
||||||
case Color_Invert:
|
case Color_Invert:
|
||||||
for(i = 0; i < 4; i++) vram[offset + i] ^= masks[i];
|
for(i = 0; i < 4; i++) vram[offset + i] ^= masks[i];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,7 +349,61 @@ static void dvline(int y1, int y2, int x, enum Color color)
|
||||||
int end = (y2 << 2) + (x >> 5);
|
int end = (y2 << 2) + (x >> 5);
|
||||||
int mask = 0x80000000 >> (x & 31);
|
int mask = 0x80000000 >> (x & 31);
|
||||||
|
|
||||||
switch(color)
|
int *v1 = gray_lightVRAM();
|
||||||
|
int *v2 = gray_darkVRAM();
|
||||||
|
|
||||||
|
if(gray_runs()) switch(color)
|
||||||
|
{
|
||||||
|
case Color_White:
|
||||||
|
while(offset <= end)
|
||||||
|
{
|
||||||
|
v1[offset] &= ~mask;
|
||||||
|
v2[offset] &= ~mask;
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Color_Light:
|
||||||
|
while(offset <= end)
|
||||||
|
{
|
||||||
|
v1[offset] |= mask;
|
||||||
|
v2[offset] &= ~mask;
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Color_Dark:
|
||||||
|
while(offset <= end)
|
||||||
|
{
|
||||||
|
v1[offset] &= ~mask;
|
||||||
|
v2[offset] |= mask;
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Color_Black:
|
||||||
|
while(offset <= end)
|
||||||
|
{
|
||||||
|
v1[offset] |= mask;
|
||||||
|
v2[offset] |= mask;
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Color_Invert:
|
||||||
|
while(offset <= end)
|
||||||
|
{
|
||||||
|
v1[offset] ^= mask;
|
||||||
|
v2[offset] ^= mask;
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
else switch(color)
|
||||||
{
|
{
|
||||||
case Color_White:
|
case Color_White:
|
||||||
while(offset <= end) vram[offset] &= ~mask, offset += 4;
|
while(offset <= end) vram[offset] &= ~mask, offset += 4;
|
||||||
|
@ -312,12 +413,12 @@ static void dvline(int y1, int y2, int x, enum Color color)
|
||||||
while(offset <= end) vram[offset] |= mask, offset += 4;
|
while(offset <= end) vram[offset] |= mask, offset += 4;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Color_None:
|
|
||||||
return;
|
|
||||||
|
|
||||||
case Color_Invert:
|
case Color_Invert:
|
||||||
while(offset <= end) vram[offset] ^= mask, offset += 4;
|
while(offset <= end) vram[offset] ^= mask, offset += 4;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -91,10 +91,6 @@ static void kdelay(void)
|
||||||
krow()
|
krow()
|
||||||
Reads a keyboard row. Works like krow() for SH7705. See gint_7705.c for
|
Reads a keyboard row. Works like krow() for SH7705. See gint_7705.c for
|
||||||
more details.
|
more details.
|
||||||
|
|
||||||
@arg row Row to check (0 <= row <= 9).
|
|
||||||
|
|
||||||
@return Bit-based representation of pressed keys in the checked row.
|
|
||||||
*/
|
*/
|
||||||
static int krow(int row)
|
static int krow(int row)
|
||||||
{
|
{
|
||||||
|
|
181
src/gray.c
181
src/gray.c
|
@ -1,3 +1,11 @@
|
||||||
|
//---
|
||||||
|
//
|
||||||
|
// gint core/drawing module: gray
|
||||||
|
//
|
||||||
|
// Runs the gray engine and handles drawing for the dual-buffer system.
|
||||||
|
//
|
||||||
|
//---
|
||||||
|
|
||||||
#include <display.h>
|
#include <display.h>
|
||||||
#include <gray.h>
|
#include <gray.h>
|
||||||
#include <screen.h>
|
#include <screen.h>
|
||||||
|
@ -9,8 +17,25 @@ const void *vrams[4];
|
||||||
static int current = 0;
|
static int current = 0;
|
||||||
static int delays[2];
|
static int delays[2];
|
||||||
|
|
||||||
|
static int runs = 0;
|
||||||
|
|
||||||
#define GRAY_PRESCALER TIMER_Po_64
|
#define GRAY_PRESCALER TIMER_Po_64
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Engine control.
|
||||||
|
//---
|
||||||
|
|
||||||
|
/*
|
||||||
|
gray_runs()
|
||||||
|
Returns 1 if the gray engine is running, 0 otherwise.
|
||||||
|
*/
|
||||||
|
inline int gray_runs(void)
|
||||||
|
{
|
||||||
|
return runs;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
gray_start()
|
gray_start()
|
||||||
Starts the gray engine. The control of the screen is transferred to the
|
Starts the gray engine. The control of the screen is transferred to the
|
||||||
|
@ -19,6 +44,7 @@ static int delays[2];
|
||||||
void gray_start(void)
|
void gray_start(void)
|
||||||
{
|
{
|
||||||
timer_start(TIMER_GRAY, delays[0], GRAY_PRESCALER, gray_interrupt, 0);
|
timer_start(TIMER_GRAY, delays[0], GRAY_PRESCALER, gray_interrupt, 0);
|
||||||
|
runs = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -29,6 +55,8 @@ void gray_start(void)
|
||||||
void gray_stop(void)
|
void gray_stop(void)
|
||||||
{
|
{
|
||||||
timer_stop(TIMER_GRAY);
|
timer_stop(TIMER_GRAY);
|
||||||
|
runs = 0;
|
||||||
|
|
||||||
display_useVRAM(display_getLocalVRAM());
|
display_useVRAM(display_getLocalVRAM());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,26 +64,23 @@ void gray_stop(void)
|
||||||
gray_lightVRAM()
|
gray_lightVRAM()
|
||||||
Returns the module's gray vram address.
|
Returns the module's gray vram address.
|
||||||
*/
|
*/
|
||||||
void *gray_lightVRAM(void)
|
inline void *gray_lightVRAM(void)
|
||||||
{
|
{
|
||||||
return (void *)vrams[current];
|
return (void *)vrams[current & 2];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
gray_lightVRAM()
|
gray_lightVRAM()
|
||||||
Returns the module's dark vram address.
|
Returns the module's dark vram address.
|
||||||
*/
|
*/
|
||||||
void *gray_darkVRAM(void)
|
inline void *gray_darkVRAM(void)
|
||||||
{
|
{
|
||||||
return (void *)vrams[current + 1];
|
return (void *)vrams[(current & 2) | 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
gray_getDelays()
|
gray_getDelays()
|
||||||
Returns the gray engine delays.
|
Returns the gray engine delays. Pointers are not set if NULL.
|
||||||
|
|
||||||
@arg light Will be set if non-NULL.
|
|
||||||
@arg dark Will be set if non-NULL.
|
|
||||||
*/
|
*/
|
||||||
void gray_getDelays(int *light, int *dark)
|
void gray_getDelays(int *light, int *dark)
|
||||||
{
|
{
|
||||||
|
@ -66,9 +91,6 @@ void gray_getDelays(int *light, int *dark)
|
||||||
/*
|
/*
|
||||||
gray_setDelays()
|
gray_setDelays()
|
||||||
Changes the gray engine delays.
|
Changes the gray engine delays.
|
||||||
|
|
||||||
@arg light Light gray duration (the lower).
|
|
||||||
@arg dark Dark gray duration (the higher).
|
|
||||||
*/
|
*/
|
||||||
void gray_setDelays(int light, int dark)
|
void gray_setDelays(int light, int dark)
|
||||||
{
|
{
|
||||||
|
@ -82,15 +104,6 @@ void gray_setDelays(int light, int dark)
|
||||||
// Internal API.
|
// Internal API.
|
||||||
//---
|
//---
|
||||||
|
|
||||||
/*
|
|
||||||
gray_swap()
|
|
||||||
Swaps the vram buffers.
|
|
||||||
*/
|
|
||||||
void gray_swap(void)
|
|
||||||
{
|
|
||||||
current = (current + 2) & 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
gray_interrupt()
|
gray_interrupt()
|
||||||
Answers a timer interrupt. Swaps the buffers.
|
Answers a timer interrupt. Swaps the buffers.
|
||||||
|
@ -113,6 +126,130 @@ void gray_init(void)
|
||||||
vrams[2] = (const void *)internal_vrams[1];
|
vrams[2] = (const void *)internal_vrams[1];
|
||||||
vrams[3] = (const void *)internal_vrams[2];
|
vrams[3] = (const void *)internal_vrams[2];
|
||||||
|
|
||||||
delays[0] = 3269;
|
delays[0] = 900;
|
||||||
delays[1] = 6987;
|
delays[1] = 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Global drawing functions
|
||||||
|
//---
|
||||||
|
|
||||||
|
/*
|
||||||
|
gupdate()
|
||||||
|
Swaps the vram buffer sets.
|
||||||
|
*/
|
||||||
|
inline void gupdate(void)
|
||||||
|
{
|
||||||
|
current ^= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
gclear()
|
||||||
|
Clears the video ram.
|
||||||
|
*/
|
||||||
|
void gclear(void)
|
||||||
|
{
|
||||||
|
int *v1 = gray_lightVRAM();
|
||||||
|
int *v2 = gray_darkVRAM();
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < 256; i++) v1[i] = v2[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
gclear_area()
|
||||||
|
Clears an area of the video ram. End points (x1, y1) and (x2, y2) are
|
||||||
|
included.
|
||||||
|
*/
|
||||||
|
void gclear_area(int x1, int y1, int x2, int y2)
|
||||||
|
{
|
||||||
|
display_useVRAM(gray_lightVRAM());
|
||||||
|
dclear_area(x1, y1, x2, y2);
|
||||||
|
display_useVRAM(gray_darkVRAM());
|
||||||
|
dclear_area(x1, y1, x2, y2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
greverse_area()
|
||||||
|
Reverses an area of the vram. End points (x1, y1) and (x2, y2) are
|
||||||
|
included.
|
||||||
|
*/
|
||||||
|
void greverse_area(int x1, int y1, int x2, int y2)
|
||||||
|
{
|
||||||
|
display_useVRAM(gray_lightVRAM());
|
||||||
|
dreverse_area(x1, y1, x2, y2);
|
||||||
|
display_useVRAM(gray_darkVRAM());
|
||||||
|
dreverse_area(x1, y1, x2, y2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Local drawing functions.
|
||||||
|
//---
|
||||||
|
|
||||||
|
/*
|
||||||
|
gpixel()
|
||||||
|
Puts a pixel in the vram.
|
||||||
|
*/
|
||||||
|
void gpixel(int x, int y, enum Color color)
|
||||||
|
{
|
||||||
|
if((unsigned int)x > 127 || (unsigned int)y > 63) return;
|
||||||
|
|
||||||
|
int offset = (y << 2) + (x >> 5);
|
||||||
|
int mask = 0x80000000 >> (x & 31);
|
||||||
|
|
||||||
|
int *v1 = gray_lightVRAM();
|
||||||
|
int *v2 = gray_lightVRAM();
|
||||||
|
|
||||||
|
switch(color)
|
||||||
|
{
|
||||||
|
case Color_White:
|
||||||
|
v1[offset] &= ~mask;
|
||||||
|
v2[offset] &= ~mask;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Color_Light:
|
||||||
|
v1[offset] |= mask;
|
||||||
|
v2[offset] &= ~mask;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Color_Dark:
|
||||||
|
v1[offset] &= ~mask;
|
||||||
|
v2[offset] |= mask;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Color_Black:
|
||||||
|
v1[offset] |= mask;
|
||||||
|
v2[offset] |= mask;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Color_Invert:
|
||||||
|
v1[offset] ^= mask;
|
||||||
|
v2[offset] ^= mask;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
gline()
|
||||||
|
Draws a line in the vram. Automatically optimizes special cases.
|
||||||
|
*/
|
||||||
|
void gline(int x1, int y1, int x2, int y2, enum Color color)
|
||||||
|
{
|
||||||
|
enum Color c1, c2;
|
||||||
|
|
||||||
|
if(color == Color_None) return;
|
||||||
|
else if(color == Color_Invert) c1 = c2 = Color_Invert;
|
||||||
|
else c1 = color & 1, c2 = color >> 1;
|
||||||
|
|
||||||
|
display_useVRAM(gray_lightVRAM());
|
||||||
|
dline(x1, y1, x2, y2, c1);
|
||||||
|
display_useVRAM(gray_darkVRAM());
|
||||||
|
dline(x1, y1, x2, y2, c2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
#include <tales.h>
|
#include <tales.h>
|
||||||
|
|
||||||
static struct Font *font;
|
static struct Font *font;
|
||||||
static enum BlendingMode mode;
|
|
||||||
|
|
||||||
//---
|
//---
|
||||||
// Local functions.
|
// Local functions.
|
||||||
|
@ -198,10 +197,9 @@ static int update(uint32_t *operators, int height, int available,
|
||||||
@arg font
|
@arg font
|
||||||
@arg mode
|
@arg mode
|
||||||
*/
|
*/
|
||||||
void print_configure(struct Font *next_font, enum BlendingMode next_mode)
|
void print_configure(struct Font *next_font)
|
||||||
{
|
{
|
||||||
font = next_font;
|
font = next_font;
|
||||||
mode = next_mode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in a new issue