mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2024-12-28 04:23: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 @@
|
|||
#
|
||||
# fx-9860g lib Makefile.
|
||||
#
|
||||
#! /usr/bin/make -f
|
||||
|
||||
.PHONY: all clean fclean re install
|
||||
#---
|
||||
# fx-9860g lib Makefile.
|
||||
#---
|
||||
|
||||
|
||||
|
||||
|
@ -23,8 +23,7 @@ bin = build/ginttest.bin
|
|||
elf = build/ginttest.elf
|
||||
|
||||
# Command-line options
|
||||
cflags = -m3 -mb -nostdlib -ffreestanding \
|
||||
-W -Wall -pedantic -std=c11 \
|
||||
cflags = -m3 -mb -nostdlib -ffreestanding -W -Wall \
|
||||
-I . -isystem include
|
||||
lib = -lgcc -L. -lgint -lc
|
||||
|
||||
|
@ -42,20 +41,20 @@ src-lib = crt0.c syscalls.s \
|
|||
hea-lib = 7305.h 7705.h gint.h \
|
||||
stdlib.h \
|
||||
mpu.h keyboard.h screen.h display.h gray.h timer.h tales.h
|
||||
obj-lib = $(addprefix build/, $(addsuffix .o, $(src-lib)))
|
||||
hdr-lib = $(addprefix include/, $(hea-lib))
|
||||
obj-lib = $(patsubst %, build/%.o, $(src-lib))
|
||||
hdr-lib = $(patsubst %, include/%, $(hea-lib))
|
||||
|
||||
# Standard library.
|
||||
src-std = setjmp.s string.c
|
||||
hea-std = setjmp.h string.h ctype.h
|
||||
obj-std = $(addprefix build/, $(addsuffix .o, $(src-std)))
|
||||
hdr-std = $(addprefix include/, $(hea-std))
|
||||
obj-std = $(patsubst %, build/%.o, $(src-std))
|
||||
hdr-std = $(patsubst %, include/%, $(hea-str))
|
||||
|
||||
# Test application.
|
||||
src-app = ginttest.c
|
||||
img-app = bitmap_opt.bmp swords.bmp sprites.bmp symbol.bmp symbol2.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` \
|
||||
"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)
|
||||
$(ob) -R .comment -R .bss -O binary $(elf) $(bin)
|
||||
$(wr) $(bin) -o ginttest.g1a -i icon.bmp
|
||||
|
@ -97,7 +96,7 @@ build/%.s.o: src/%.s
|
|||
$(as) -c $^ -o $@
|
||||
|
||||
build/%.bmp.o: resources/%.bmp
|
||||
fxconv $^ -o $@
|
||||
fxconv $^ -o $@ --preview
|
||||
|
||||
build/font.o: resources/font.bmp
|
||||
fxconv --font $^ -o $@
|
||||
|
@ -136,3 +135,7 @@ re: distclean all
|
|||
|
||||
install:
|
||||
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
|
||||
- information masks for text
|
||||
- test all font encodings
|
||||
- font clipping
|
||||
--------------
|
||||
Lots of things to do
|
||||
--------------
|
||||
|
||||
- bitmap parts
|
||||
- bitmap clipping
|
||||
@ known bugs
|
||||
+ 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
|
||||
- full rtc driver (time)
|
||||
- callbacks and complete user API
|
||||
@ vram overflow
|
||||
@ keyboard test threading interface
|
||||
|
||||
- exhaustive save for setjmp()
|
||||
- registers that need to be saved when configuring gint
|
||||
+ compute frequencies
|
||||
+ 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
|
||||
- libc
|
||||
~ shadowy rectangle effect for Shift + Alpha + Left + Down
|
||||
~ 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 *sybl2 = &binary_resources_symbol2_start;
|
||||
|
||||
enum BlendingMode blend = Blend_Or;
|
||||
// enum BlendingMode blend = Blend_Or;
|
||||
uint32_t a32 = 0xffffffff;
|
||||
int black_bg = 0;
|
||||
int key;
|
||||
|
@ -223,20 +223,22 @@ void bitmap_test(void)
|
|||
dclear();
|
||||
|
||||
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(sybl, 30 & a32, 40, blend);
|
||||
dimage(sybl2, 62 & a32, 40, blend);
|
||||
dimage(sprites, 2 & a32, 2);
|
||||
dimage(sybl, 30 & a32, 40);
|
||||
dimage(sybl2, 62 & a32, 40);
|
||||
|
||||
dupdate();
|
||||
|
||||
key = getkey();
|
||||
if(key == KEY_EXIT) break;
|
||||
|
||||
/*
|
||||
if(key == KEY_F1) blend = Blend_Or;
|
||||
if(key == KEY_F2) blend = Blend_And;
|
||||
if(key == KEY_F3) blend = Blend_Invert;
|
||||
*/
|
||||
|
||||
if(key == KEY_F4) black_bg = !black_bg;
|
||||
if(key == KEY_F5) a32 ^= 31;
|
||||
|
@ -257,7 +259,7 @@ void text_test(void)
|
|||
extern Font binary_resources_font_start;
|
||||
Font *font = &binary_resources_font_start;
|
||||
|
||||
print_configure(font, Blend_Or);
|
||||
print_configure(font);
|
||||
|
||||
dclear();
|
||||
|
||||
|
@ -290,18 +292,23 @@ void gray_test(void)
|
|||
|
||||
gray_getDelays(&light, &dark);
|
||||
gray_start();
|
||||
dimage(illustration, 0, 0, Blend_Or);
|
||||
|
||||
while(1)
|
||||
{
|
||||
gclear();
|
||||
dimage(illustration, 0, 0);
|
||||
gclear_area(64, 0, 127, 63);
|
||||
// gupdate();
|
||||
|
||||
key = getkey();
|
||||
if(key == KEY_EXIT) break;
|
||||
|
||||
/*
|
||||
if(key == KEY_F1) gray_setDelays(--light, dark);
|
||||
if(key == KEY_F2) gray_setDelays(++light, dark);
|
||||
|
||||
if(key == KEY_F5) gray_setDelays(light, --dark);
|
||||
if(key == KEY_F6) gray_setDelays(light, ++dark);
|
||||
*/
|
||||
}
|
||||
|
||||
gray_stop();
|
||||
|
@ -367,7 +374,7 @@ int main(void)
|
|||
extern Font binary_resources_font_start;
|
||||
Font *font = &binary_resources_font_start;
|
||||
|
||||
print_configure(font, Blend_Or);
|
||||
print_configure(font);
|
||||
|
||||
int app;
|
||||
|
||||
|
|
BIN
ginttest.g1a
BIN
ginttest.g1a
Binary file not shown.
|
@ -21,7 +21,7 @@
|
|||
((c) >= 'a' && (c) <= 'f'))
|
||||
|
||||
// Character manipulation macros.
|
||||
#define tolower(c) (isupper(c) ? (c)|32 : (c))
|
||||
#define toupper(c) (islower(c) ? (c)&~32 : (c))
|
||||
#define tolower(c) (isupper(c) ? (c) | 32 : (c))
|
||||
#define toupper(c) (islower(c) ? (c) & ~32 : (c))
|
||||
|
||||
#endif // _CTYPE_H
|
||||
|
|
|
@ -1,62 +1,29 @@
|
|||
//---
|
||||
//
|
||||
// gint drawing module: display
|
||||
//
|
||||
// Handles vram manipulation and drawing for plain monochrome display.
|
||||
//
|
||||
//---
|
||||
|
||||
#ifndef _DISPLAY_H
|
||||
#define _DISPLAY_H 1
|
||||
|
||||
|
||||
//---
|
||||
// Included submodules.
|
||||
// Heading declarations.
|
||||
//---
|
||||
|
||||
#include <tales.h>
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Types and constants.
|
||||
//---
|
||||
|
||||
enum Color
|
||||
{
|
||||
Color_White = 0, // White (AND 0)
|
||||
Color_Black = 1, // Black (OR 1)
|
||||
Color_None = 2, // Transparent (NOP)
|
||||
Color_Invert = 3, // Invert (XOR 1)
|
||||
};
|
||||
|
||||
/*
|
||||
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,
|
||||
Color_White = 0,
|
||||
Color_Light = 1,
|
||||
Color_Dark = 2,
|
||||
Color_Black = 3,
|
||||
Color_None = 4,
|
||||
Color_Invert = 5,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -69,10 +36,10 @@ enum ImageFormat
|
|||
struct Image
|
||||
{
|
||||
unsigned char magic;
|
||||
unsigned char format;
|
||||
|
||||
unsigned char width;
|
||||
unsigned char height;
|
||||
unsigned char format;
|
||||
|
||||
const unsigned char __attribute__((aligned(4))) data[];
|
||||
|
||||
|
@ -94,12 +61,10 @@ typedef struct Image Image;
|
|||
|
||||
/*
|
||||
display_getLocalVRAM()
|
||||
Returns the local video ram. This function always return the same
|
||||
address.
|
||||
Returns the local video ram address. This function always return the
|
||||
same address.
|
||||
The buffer returned by this function should not be used directly when
|
||||
running the gray engine.
|
||||
|
||||
@return Video ram address of the monochrome display module.
|
||||
*/
|
||||
void *display_getLocalVRAM(void);
|
||||
|
||||
|
@ -114,13 +79,11 @@ void *display_getCurrentVRAM(void);
|
|||
|
||||
/*
|
||||
display_useVRAM()
|
||||
Changes the current video ram address. The argument *MUST* be a
|
||||
4-aligned 1024 buffer ; otherwise any drawing operation will crash the
|
||||
program.
|
||||
Changes the current video ram address. The argument MUST be a 4-
|
||||
aligned 1024-byte buffer; otherwise any drawing operation will crash
|
||||
the program.
|
||||
This function will most likely have no effect when running the gray
|
||||
engine.
|
||||
|
||||
@arg New video ram address.
|
||||
*/
|
||||
void display_useVRAM(void *vram);
|
||||
|
||||
|
@ -132,7 +95,8 @@ void display_useVRAM(void *vram);
|
|||
|
||||
/*
|
||||
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);
|
||||
|
||||
|
@ -144,23 +108,15 @@ void dclear(void);
|
|||
|
||||
/*
|
||||
dclear_area()
|
||||
Clears an area of the video ram.
|
||||
|
||||
@arg x1
|
||||
@arg y1
|
||||
@arg x2
|
||||
@arg y2
|
||||
Clears an area of the video ram. Both (x1, y1) and (x2, y2) are
|
||||
cleared.
|
||||
*/
|
||||
void dclear_area(int x1, int y1, int x2, int y2);
|
||||
|
||||
/*
|
||||
dreverse_area()
|
||||
Reverses an area of the screen.
|
||||
|
||||
@arg x1
|
||||
@arg y1
|
||||
@arg x2
|
||||
@arg y2
|
||||
Reverses an area of the vram. (x1, y1) and (x2, y2) are reversed as
|
||||
well.
|
||||
*/
|
||||
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()
|
||||
Puts a pixel on the screen.
|
||||
|
||||
@arg x
|
||||
@arg y
|
||||
@arg color
|
||||
Puts a pixel in the vram.
|
||||
*/
|
||||
void dpixel(int x, int y, enum Color color);
|
||||
|
||||
/*
|
||||
dline()
|
||||
Draws a line on the screen. Automatically optimizes horizontal and
|
||||
Draws a line in the vram. Automatically optimizes horizontal and
|
||||
vertical lines.
|
||||
|
||||
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);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Image drawing.
|
||||
//---
|
||||
|
||||
/*
|
||||
dimage()
|
||||
Displays an image in the vram. Does a real lot of optimization.
|
||||
|
||||
@arg image
|
||||
@arg x
|
||||
@arg y
|
||||
@arg mode
|
||||
Displays a monochrome image in the vram. Does a real lot of
|
||||
optimization.
|
||||
*/
|
||||
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
|
||||
#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()
|
||||
Starts the gray engine. The control of the screen is transferred to the
|
||||
|
@ -33,10 +49,7 @@ void *gray_darkVRAM(void);
|
|||
|
||||
/*
|
||||
gray_getDelays()
|
||||
Returns the gray engine delays.
|
||||
|
||||
@arg light Will be set if non-NULL.
|
||||
@arg dark Will be set if non-NULL.
|
||||
Returns the gray engine delays. Pointers are not set if NULL.
|
||||
*/
|
||||
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
|
||||
gray engine. Usual values are about 1000, with light being between 75
|
||||
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);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// 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.
|
||||
// Referenced here for documentation purposes only. Do not call.
|
||||
//--
|
||||
|
||||
/*
|
||||
gray_swap()
|
||||
Swaps the vram buffers.
|
||||
*/
|
||||
void gray_swap(void);
|
||||
|
||||
/*
|
||||
gray_interrupt()
|
||||
Answers a timer interrupt. Swaps the two buffers.
|
||||
|
|
|
@ -23,8 +23,6 @@ void abort(void);
|
|||
exit()
|
||||
Stops the program execution with the given status code, after calling
|
||||
the exit handlers.
|
||||
|
||||
@arg status
|
||||
*/
|
||||
void exit(int status);
|
||||
|
||||
|
@ -38,10 +36,6 @@ void exit(int status);
|
|||
malloc()
|
||||
Allocs 'size' bytes and returns a pointer to a free memory area.
|
||||
Returns NULL on error.
|
||||
|
||||
@arg size Size to allocate, in bytes.
|
||||
|
||||
@return Memory area address, or NULL.
|
||||
*/
|
||||
void *malloc(size_t size);
|
||||
|
||||
|
@ -49,19 +43,12 @@ void *malloc(size_t size);
|
|||
calloc()
|
||||
Allocs 'n' elements of size 'size' and wipes the memory area. Returns
|
||||
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);
|
||||
|
||||
/*
|
||||
free()
|
||||
Frees a memory block allocated with malloc().
|
||||
|
||||
@arg ptr Pointer to free.
|
||||
*/
|
||||
void free(void *ptr);
|
||||
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
// Types and constants.
|
||||
//---
|
||||
|
||||
enum BlendingMode;
|
||||
|
||||
/*
|
||||
enum ImageFormat
|
||||
This type holds information about the characters in the font. Each bit
|
||||
|
@ -78,7 +76,6 @@ typedef struct Font Font;
|
|||
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Generic functions.
|
||||
//---
|
||||
|
@ -90,7 +87,7 @@ typedef struct Font Font;
|
|||
@arg font
|
||||
@arg mode
|
||||
*/
|
||||
void print_configure(struct Font *font, enum BlendingMode mode);
|
||||
void print_configure(struct Font *font);
|
||||
|
||||
/*
|
||||
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 <stdint.h>
|
||||
#include <gray.h>
|
||||
|
||||
|
||||
//---
|
||||
// Image drawing. There is only one public function dimage(), but there
|
||||
// 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.
|
||||
// Heading declarations.
|
||||
//---
|
||||
|
||||
// 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()
|
||||
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
|
||||
to 0 for Or and Invert operations... 1 for And operations. Which means
|
||||
that the calling procedure must indicate what part of the operator
|
||||
belongs to the image, which is done through the image_mask argument.
|
||||
|
||||
@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.
|
||||
image information. Since neutral bits are not the same for all
|
||||
operations, the op_mask argument indicates which bits should be used
|
||||
for the operation. Which operation has to be done is determined by the
|
||||
channel setting.
|
||||
*/
|
||||
static void bopti_op(int offset, uint32_t operator, uint32_t image_mask,
|
||||
enum BlendingMode mode)
|
||||
static void bopti_op_mono(int offset, uint32_t operator, uint32_t op_mask)
|
||||
{
|
||||
if(mode & Blend_Checker) operator &= 0x55555555;
|
||||
if(mode & Blend_Or) vram[offset] |= operator;
|
||||
if(mode & Blend_Invert) vram[offset] ^= operator;
|
||||
operator |= ~image_mask;
|
||||
if(mode & Blend_And) vram[offset] &= operator;
|
||||
operator &= op_mask;
|
||||
|
||||
switch(channel)
|
||||
{
|
||||
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_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,
|
||||
because one of the bit shifts in bopti_grid() will reach 32 when x is
|
||||
a multiple 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
|
||||
because bopti_grid() will perform a 32-bit shift when x is a multiple
|
||||
of 32, which is undefined behavior.
|
||||
*/
|
||||
|
||||
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_offset = vram_column_offset;
|
||||
int column, row;
|
||||
|
||||
for(column = 0; column < column_number; column++)
|
||||
for(column = 0; column < column_count; column++)
|
||||
{
|
||||
for(row = 0; row < height; row++)
|
||||
{
|
||||
bopti_op(vram_offset, *layer, 0xffffffff, mode);
|
||||
(*op)(vram_offset, *layer, 0xffffffff);
|
||||
layer++;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static void bopti_grid(const uint32_t *layer, int x, int y, int column_number,
|
||||
int height, enum BlendingMode mode)
|
||||
static void bopti_grid(const uint32_t *layer, int x, int y, int column_count)
|
||||
{
|
||||
if(!column_count) return;
|
||||
if(!(x & 31))
|
||||
{
|
||||
bopti_grid_a32(layer, x, y, column_count);
|
||||
return;
|
||||
}
|
||||
|
||||
const uint32_t *p1, *p2;
|
||||
uint32_t l1, l2;
|
||||
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_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
|
||||
// another, they will be updated directly to parse the whole grid.
|
||||
p1 = layer - height;
|
||||
p2 = layer;
|
||||
|
||||
// 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;
|
||||
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++)
|
||||
{
|
||||
l1 = (right_column > 0) ? (*p1) : (0);
|
||||
l2 = (right_column < column_number) ? (*p2) : (0);
|
||||
l2 = (right_column < column_count) ? (*p2) : (0);
|
||||
p1++, p2++;
|
||||
|
||||
operator = (l1 << shift1) | (l2 >> shift2);
|
||||
bopti_op(vram_offset, operator, and_mask, mode);
|
||||
(*op)(vram_offset, operator, and_mask);
|
||||
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()
|
||||
Returns the line of a bitmap, whose width is lower than 32. The given
|
||||
pointer is read and set according to the bitmap width.
|
||||
|
||||
@arg ptr Address of data pointer.
|
||||
@arg size Element size (should be 1, 2, or 4 bytes).
|
||||
bopti_end_get()
|
||||
Returns an operator for the end of a line, whose width is lower than 32
|
||||
(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
|
||||
the operation.
|
||||
*/
|
||||
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;
|
||||
|
||||
if(size == 4)
|
||||
{
|
||||
line = *((uint32_t *)*data);
|
||||
*data += 4;
|
||||
return line;
|
||||
}
|
||||
|
||||
else if(size == 2)
|
||||
{
|
||||
line = *((uint16_t *)*data);
|
||||
*data += 2;
|
||||
return line;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
line = **data;
|
||||
(*data)++;
|
||||
return line;
|
||||
}
|
||||
uint32_t operator = **data;
|
||||
*data += 1;
|
||||
return operator;
|
||||
}
|
||||
static uint32_t bopti_end_get2(const unsigned char **data)
|
||||
{
|
||||
uint32_t operator = *((uint16_t *)*data);
|
||||
*data += 2;
|
||||
return operator;
|
||||
}
|
||||
|
||||
/*
|
||||
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'
|
||||
since the biggest part will be drawn by bopti_grid().
|
||||
|
||||
@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
|
||||
Draws the end of a layer, which can be considered as a whole layer
|
||||
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).
|
||||
*/
|
||||
|
||||
static void bopti_rest_nover(const unsigned char *rest, int x, int y,
|
||||
int width, int height, enum BlendingMode mode)
|
||||
static void bopti_end_nover(const unsigned char *end, int x, int y, int width)
|
||||
{
|
||||
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 row;
|
||||
|
||||
// We *have* shift >= 0 because of this function's 'no overlap'
|
||||
// requirement.
|
||||
int shift_base = (4 - element_size) << 3;
|
||||
int shift_base = (width > 8) ? 16 : 24;
|
||||
int shift = shift_base - (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++)
|
||||
{
|
||||
operator = bopti_rest_get(&rest, element_size);
|
||||
operator = (*get)(&end);
|
||||
operator <<= shift;
|
||||
|
||||
bopti_op(vram_offset, operator, and_mask, mode);
|
||||
(*op)(vram_offset, operator, and_mask);
|
||||
vram_offset += 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void bopti_rest(const unsigned char *rest, int x, int y, int width,
|
||||
int height, enum BlendingMode mode)
|
||||
static void bopti_end(const unsigned char *end, int x, int y, int width)
|
||||
{
|
||||
if((x & 31) + width <= 32)
|
||||
{
|
||||
bopti_rest_nover(rest, x, y, width, height, mode);
|
||||
bopti_end_nover(end, x, y, width);
|
||||
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 row;
|
||||
|
||||
int shift_base = (4 - element_size) << 3;
|
||||
int shift_base = (width > 8) ? 16 : 24;
|
||||
int shift1 = (x & 31) - shift_base;
|
||||
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++)
|
||||
{
|
||||
row_data = bopti_rest_get(&rest, element_size);
|
||||
row_data = (*get)(&end);
|
||||
|
||||
operator = row_data >> shift1;
|
||||
bopti_op(vram_offset, operator, and_mask_0, mode);
|
||||
(*op)(vram_offset, operator, and_mask_0);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Wrappers and various functions.
|
||||
//---
|
||||
|
||||
/*
|
||||
bopti()
|
||||
Draws an image layer in the video ram.
|
||||
|
||||
@arg bitmap Raw layer data.
|
||||
@arg x
|
||||
@arg y
|
||||
@arg width
|
||||
@arg height
|
||||
@arg mode
|
||||
Draws a layer in the video ram.
|
||||
*/
|
||||
|
||||
static void bopti(const unsigned char *layer, int x, int y, int width,
|
||||
int height, enum BlendingMode mode)
|
||||
static void bopti(const unsigned char *layer, int x, int y, int columns,
|
||||
int end_size)
|
||||
{
|
||||
int column_number = width >> 5;
|
||||
int rest_width = width & 31;
|
||||
const unsigned char *end = layer + ((columns * height) << 2);
|
||||
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);
|
||||
int rest_x = x + (width - rest_width);
|
||||
/*
|
||||
getStructure()
|
||||
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);
|
||||
if(!rest_width) return;
|
||||
bopti_rest(rest, rest_x, y, rest_width, height, mode);
|
||||
// Large images.
|
||||
if(!img->width && !img->height)
|
||||
{
|
||||
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()
|
||||
Displays an image in the vram.
|
||||
|
||||
@arg image
|
||||
@arg x
|
||||
@arg y
|
||||
@arg mode
|
||||
Displays a monochrome image in the video ram.
|
||||
*/
|
||||
|
||||
void dimage(struct Image *image, int x, int y, enum BlendingMode mode)
|
||||
void dimage(struct Image *img, int x, int y)
|
||||
{
|
||||
int width = image->width;
|
||||
int height = image->height;
|
||||
const unsigned char *data = (const unsigned char *)&(image->data);
|
||||
int width, layer_size, columns, end;
|
||||
int format = img->format, i = 0;
|
||||
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.
|
||||
int columns = image->width >> 5;
|
||||
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);
|
||||
// 'height' refers to a static variable for this file.
|
||||
getStructure(img, &width, &height, &layer_size, &data, &columns, &end);
|
||||
|
||||
switch(image->format & ImageFormat_ColorMask)
|
||||
vram = display_getCurrentVRAM();
|
||||
|
||||
while(format)
|
||||
{
|
||||
case ImageFormat_Mono:
|
||||
if(image->format & ImageFormat_Alpha)
|
||||
// Drawing every layer, in order of formats.
|
||||
if(format & 1)
|
||||
{
|
||||
bopti(data + layer_size, x, y, width, height,
|
||||
Blend_And);
|
||||
}
|
||||
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);
|
||||
channel = (1 << i);
|
||||
bopti(data, x, y, columns, end);
|
||||
data += layer_size;
|
||||
}
|
||||
|
||||
display_useVRAM(gray_darkVRAM());
|
||||
bopti(data, x, y, width, height, mode);
|
||||
display_useVRAM(gray_lightVRAM());
|
||||
bopti(data + layer_size, x, y, width, height, mode);
|
||||
break;
|
||||
format >>= 1;
|
||||
i++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
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
|
||||
|
||||
Handles vram manipulation and drawing.
|
||||
|
||||
:: Rectangle masks
|
||||
|
||||
The concept of 'rectangle masks' is used several times in this module.
|
||||
It consists in saying that an operation that affects a rectangle acts
|
||||
the same on all the lines (considering that only the lines that
|
||||
intersect the rectangle are changed) and therefore it is possible to
|
||||
represent the behavior on a single line using 'masks' that 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
|
||||
the following values : 0000ffff, ffffffff, ffffffff and ffff0000. These
|
||||
masks can then be used by setting vram[offset] &= ~masks[i]. This
|
||||
appears to be very flexible : for instance, reversing a rectangle of
|
||||
vram only needs vram[offset] ^= masks[i].
|
||||
|
||||
This technique can also be used in more subtle cases with more complex
|
||||
patterns, but within this module it is unlikely to happen.
|
||||
*/
|
||||
//---
|
||||
//
|
||||
// gint drawing module: display
|
||||
//
|
||||
// Handles vram manipulation and drawing.
|
||||
//
|
||||
//
|
||||
// :: Rectangle masks
|
||||
//
|
||||
// The concept of 'rectangle masks' is used several times in this module.
|
||||
// It is based on the fact that an operation that affects a rectangle acts
|
||||
// the same on all its lines. Therefore the behavior of the operation is
|
||||
// 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
|
||||
// the following values : 0000ffff, ffffffff, ffffffff and ffff0000. These
|
||||
// masks can then be used by setting vram[offset] &= ~masks[i]. This
|
||||
// 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.
|
||||
//
|
||||
//---
|
||||
|
||||
#include <screen.h>
|
||||
#include <display.h>
|
||||
|
@ -47,14 +49,10 @@ static int *vram = local_vram;
|
|||
/*
|
||||
adjust()
|
||||
Adjusts the given rectangle coordinates to ensure that :
|
||||
- The rectangle is entirely contained in the screen,
|
||||
- x1 < x2 and y1 < y2,
|
||||
- the rectangle is entirely contained in the screen
|
||||
- x1 < x2
|
||||
- y1 < y2
|
||||
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)
|
||||
{
|
||||
|
@ -75,11 +73,8 @@ static void adjust(int *x1, int *y1, int *x2, int *y2)
|
|||
getmasks()
|
||||
|
||||
Computes the rectangle masks needed to affect pixels located between x1
|
||||
and x2 (both included).
|
||||
|
||||
@arg x1
|
||||
@arg x2
|
||||
@arg masks Four-integer-array pointer.
|
||||
and x2 (both included). The four masks are stored in the third argument
|
||||
(seen as an array).
|
||||
*/
|
||||
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.
|
||||
x1 &= 31;
|
||||
// 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
|
||||
// ones are removed by the bitwise-and mask).
|
||||
// power of 2 (positive bits at the left are removed by the mask).
|
||||
x2 = ~x2 & 31;
|
||||
|
||||
// Setting the last masks.
|
||||
// Setting the first and last masks.
|
||||
masks[l1] &= (0xffffffff >> x1);
|
||||
masks[l2] &= (0xffffffff << x2);
|
||||
}
|
||||
|
@ -116,34 +110,37 @@ static void getmasks(int x1, int x2, unsigned int *masks)
|
|||
|
||||
/*
|
||||
display_getLocalVRAM()
|
||||
Returns the local video ram.
|
||||
|
||||
@return Video ram address.
|
||||
Returns the local video ram address. This function always return the
|
||||
same 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;
|
||||
}
|
||||
|
||||
/*
|
||||
display_getCurrentVRAM()
|
||||
Returns the current vido ram.
|
||||
|
||||
@return Video ram address.
|
||||
Returns the current video ram. This function usually returns the
|
||||
parameter of the last call to display_useVRAM(), unless the gray engine
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
display_useVRAM()
|
||||
Changes the current video ram address. Expects a *4-aligned* 1024-byte
|
||||
buffer.
|
||||
|
||||
@arg New video ram address.
|
||||
Changes the current video ram address. The argument MUST be a 4-
|
||||
aligned 1024-byte buffer ; otherwise any drawing operation will crash
|
||||
the program.
|
||||
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;
|
||||
}
|
||||
|
@ -160,6 +157,7 @@ void display_useVRAM(void *ptr)
|
|||
*/
|
||||
void dupdate(void)
|
||||
{
|
||||
if(gray_runs()) return;
|
||||
screen_display((const void *)local_vram);
|
||||
}
|
||||
|
||||
|
@ -175,12 +173,8 @@ void dclear(void)
|
|||
|
||||
/*
|
||||
dclear_area()
|
||||
Clears an area of the vram using rectangle masks.
|
||||
|
||||
@arg x1
|
||||
@arg y1
|
||||
@arg x2
|
||||
@arg y2
|
||||
Clears an area of the vram using rectangle masks. Both (x1, y1) and
|
||||
(x2, y2) are cleared.
|
||||
*/
|
||||
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);
|
||||
getmasks(x1, x2, masks);
|
||||
|
||||
int offset = y1 << 2;
|
||||
int begin = y1 << 2;
|
||||
int end = (y2 + 1) << 2;
|
||||
int 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()
|
||||
Reverses an area of the vram. This function is a simple application of
|
||||
the rectangle masks concept.
|
||||
|
||||
@arg x1
|
||||
@arg y1
|
||||
@arg x2
|
||||
@arg y2
|
||||
the rectangle masks concept. (x1, y1) and (x2, y2) are reversed as
|
||||
well.
|
||||
*/
|
||||
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);
|
||||
getmasks(x1, x2, masks);
|
||||
|
||||
int offset = y1 << 2;
|
||||
int begin = y1 << 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()
|
||||
Puts a pixel on the screen.
|
||||
|
||||
@arg x
|
||||
@arg y
|
||||
@arg color
|
||||
Puts a pixel in the vram.
|
||||
*/
|
||||
void dpixel(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);
|
||||
|
||||
|
@ -248,12 +250,12 @@ void dpixel(int x, int y, enum Color color)
|
|||
vram[offset] |= mask;
|
||||
break;
|
||||
|
||||
case Color_None:
|
||||
return;
|
||||
|
||||
case Color_Invert:
|
||||
vram[offset] ^= mask;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -261,12 +263,6 @@ void dpixel(int x, int y, enum Color color)
|
|||
dline()
|
||||
Draws a line on the screen. Automatically optimizes horizontal and
|
||||
vertical lines.
|
||||
|
||||
@arg x1
|
||||
@arg y1
|
||||
@arg x2
|
||||
@arg y2
|
||||
@arg 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 i;
|
||||
|
||||
// Swapping x1 and x2 if needed.
|
||||
if(x1 > x2) x1 ^= x2, x2 ^= x1, x1 ^= x2;
|
||||
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:
|
||||
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];
|
||||
break;
|
||||
|
||||
case Color_None:
|
||||
return;
|
||||
|
||||
case Color_Invert:
|
||||
for(i = 0; i < 4; i++) vram[offset + i] ^= masks[i];
|
||||
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 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:
|
||||
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;
|
||||
break;
|
||||
|
||||
case Color_None:
|
||||
return;
|
||||
|
||||
case Color_Invert:
|
||||
while(offset <= end) vram[offset] ^= mask, offset += 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -91,10 +91,6 @@ static void kdelay(void)
|
|||
krow()
|
||||
Reads a keyboard row. Works like krow() for SH7705. See gint_7705.c for
|
||||
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)
|
||||
{
|
||||
|
|
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 <gray.h>
|
||||
#include <screen.h>
|
||||
|
@ -9,8 +17,25 @@ const void *vrams[4];
|
|||
static int current = 0;
|
||||
static int delays[2];
|
||||
|
||||
static int runs = 0;
|
||||
|
||||
#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()
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
timer_stop(TIMER_GRAY);
|
||||
runs = 0;
|
||||
|
||||
display_useVRAM(display_getLocalVRAM());
|
||||
}
|
||||
|
||||
|
@ -36,26 +64,23 @@ void gray_stop(void)
|
|||
gray_lightVRAM()
|
||||
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()
|
||||
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()
|
||||
Returns the gray engine delays.
|
||||
|
||||
@arg light Will be set if non-NULL.
|
||||
@arg dark Will be set if non-NULL.
|
||||
Returns the gray engine delays. Pointers are not set if NULL.
|
||||
*/
|
||||
void gray_getDelays(int *light, int *dark)
|
||||
{
|
||||
|
@ -66,9 +91,6 @@ void gray_getDelays(int *light, int *dark)
|
|||
/*
|
||||
gray_setDelays()
|
||||
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)
|
||||
{
|
||||
|
@ -82,15 +104,6 @@ void gray_setDelays(int light, int dark)
|
|||
// Internal API.
|
||||
//---
|
||||
|
||||
/*
|
||||
gray_swap()
|
||||
Swaps the vram buffers.
|
||||
*/
|
||||
void gray_swap(void)
|
||||
{
|
||||
current = (current + 2) & 3;
|
||||
}
|
||||
|
||||
/*
|
||||
gray_interrupt()
|
||||
Answers a timer interrupt. Swaps the buffers.
|
||||
|
@ -113,6 +126,130 @@ void gray_init(void)
|
|||
vrams[2] = (const void *)internal_vrams[1];
|
||||
vrams[3] = (const void *)internal_vrams[2];
|
||||
|
||||
delays[0] = 3269;
|
||||
delays[1] = 6987;
|
||||
delays[0] = 900;
|
||||
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>
|
||||
|
||||
static struct Font *font;
|
||||
static enum BlendingMode mode;
|
||||
|
||||
//---
|
||||
// Local functions.
|
||||
|
@ -198,10 +197,9 @@ static int update(uint32_t *operators, int height, int available,
|
|||
@arg font
|
||||
@arg mode
|
||||
*/
|
||||
void print_configure(struct Font *next_font, enum BlendingMode next_mode)
|
||||
void print_configure(struct Font *next_font)
|
||||
{
|
||||
font = next_font;
|
||||
mode = next_mode;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue