mirror of
https://github.com/pkivolowitz/asm_book.git
synced 2026-06-23 07:28:04 +08:00
finished
This commit is contained in:
parent
6dccefe395
commit
66a92ec762
3 changed files with 141 additions and 1 deletions
140
projects/snow/README.md
Normal file
140
projects/snow/README.md
Normal file
|
|
@ -0,0 +1,140 @@
|
||||||
|
# Retro Snow
|
||||||
|
|
||||||
|
In this project, you will create a retro animation using terminal escape
|
||||||
|
sequences, that mimics falling snow. This is, in fact, a trivial
|
||||||
|
particle system. Sophisticated particle systems are a routine part of
|
||||||
|
visual effects in television and film as well as crucial tools in
|
||||||
|
scientific computing.
|
||||||
|
|
||||||
|
## A Particle
|
||||||
|
|
||||||
|
A single particle looks like this:
|
||||||
|
|
||||||
|
```c++
|
||||||
|
struct Particle {
|
||||||
|
int32_t line;
|
||||||
|
int32_t column;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Thus, a particle is made up of two 32 bit integers side-by-side. The
|
||||||
|
first provides the line of the particle, the second its column.
|
||||||
|
|
||||||
|
## Screen Size
|
||||||
|
|
||||||
|
A default terminal window measures 80 characters across and 24 lines
|
||||||
|
down. The origin is (1, 1) located at the top left corner.
|
||||||
|
|
||||||
|
## Cursor Movement
|
||||||
|
|
||||||
|
Snow flakes (particles) will be positioned using an old school VT100
|
||||||
|
escape sequence. This sequence is:
|
||||||
|
|
||||||
|
```text
|
||||||
|
ESC [ line ; column H
|
||||||
|
```
|
||||||
|
|
||||||
|
with no spaces.
|
||||||
|
|
||||||
|
Using `printf()`, a template string can be employed:
|
||||||
|
|
||||||
|
```text
|
||||||
|
"\033[%d;%dH"
|
||||||
|
```
|
||||||
|
|
||||||
|
In C++, you'd do something like this:
|
||||||
|
|
||||||
|
```c++
|
||||||
|
cout << "\033[" << line << ";" << column << "H";
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that there are no new lines being printed since this would in
|
||||||
|
itself move the cursor to the left edge of the next line and could
|
||||||
|
even cause scrolling - a disaster in this project.
|
||||||
|
|
||||||
|
## Erasing the Screen
|
||||||
|
|
||||||
|
To erase the screen, use this escape sequence after first having moved
|
||||||
|
to screen position (1, 1):
|
||||||
|
|
||||||
|
```text
|
||||||
|
"\033[2J"
|
||||||
|
```
|
||||||
|
|
||||||
|
## A C++ Object To Use As A Model
|
||||||
|
|
||||||
|
The following C++ can be used to start your thinking about how to go
|
||||||
|
about writing this project.
|
||||||
|
|
||||||
|
```c++
|
||||||
|
struct Particle {
|
||||||
|
int32_t line;
|
||||||
|
int32_t column;
|
||||||
|
void Step();
|
||||||
|
void Render();
|
||||||
|
void Reset();
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### `Step()`
|
||||||
|
|
||||||
|
All particles use the `Step()` function to move into the future. The
|
||||||
|
`line` is increased by one and the `column` can either remain unchanged,
|
||||||
|
move to the left or move to the right.
|
||||||
|
|
||||||
|
If the particle's `line` exceeds 24, the particle is `Reset()`.
|
||||||
|
|
||||||
|
### `Render()`
|
||||||
|
|
||||||
|
To draw a particle, `Move()` to its location then print a "*" all
|
||||||
|
without emitting a new line. Before printing the "*", check to ensure
|
||||||
|
both the `line` and `column` are within the boundaries of the default
|
||||||
|
terminal window (i.e. 1 ≤ line ≤ 24 and 1 ≤ column ≤ 80).
|
||||||
|
If the particle's position is outside this range, don't print anything.
|
||||||
|
|
||||||
|
### `Reset()`
|
||||||
|
|
||||||
|
A particle's initial `column` can be anywhere from 1 to 80 inclusive.
|
||||||
|
Special care is given to setting the particle's initial `line`.
|
||||||
|
Specifically, always place the particle above the visible screen...
|
||||||
|
chosen randomly from -1 to -48. This allows for sufficient spacing so
|
||||||
|
that the snow does not appear to fall in clumps.
|
||||||
|
|
||||||
|
## The Storm
|
||||||
|
|
||||||
|
A single snow flakes does not a blizzard make. Therefore, allocate a
|
||||||
|
large number of them - perhaps 150 to 200 flakes. Since assembly
|
||||||
|
language doesn't have actual C++ objects, each flake occupies only
|
||||||
|
the 2 `int32_t` values. Suppose *n* is the number of flakes you choose
|
||||||
|
to model. Then allocate *2 \* 4 \* n* bytes using `malloc()`. Since
|
||||||
|
you will then `Reset()` every one of them, initializing the newly
|
||||||
|
allocated memory is not needed.
|
||||||
|
|
||||||
|
Then, you'll need a `StepAll()` and a `RenderAll()`.
|
||||||
|
|
||||||
|
## The Main Loop
|
||||||
|
|
||||||
|
* Position cursor at (1, 1).
|
||||||
|
|
||||||
|
* Erase the screen.
|
||||||
|
|
||||||
|
* `StepAll()`
|
||||||
|
|
||||||
|
* `RenderAll()`
|
||||||
|
|
||||||
|
* Position cursor at (1, 1) again and print a new line.
|
||||||
|
|
||||||
|
* Delay a short time. In my implementation, I using `usleep()` to delay
|
||||||
|
2<sup>17</sup> microseconds.
|
||||||
|
|
||||||
|
Note only one new line is printed per frame - this is used to force all
|
||||||
|
output to be flushed to the terminal.
|
||||||
|
|
||||||
|
## Desired Outcome
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Solution
|
||||||
|
|
||||||
|
The solution is [here](./main.s).
|
||||||
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
.align 2
|
.align 2
|
||||||
.text
|
.text
|
||||||
|
|
||||||
.equ NUM_FLAKES, 150
|
.equ NUM_FLAKES, 250
|
||||||
.equ MAX_COLUMN, 80
|
.equ MAX_COLUMN, 80
|
||||||
.equ MAX_LINE, 24
|
.equ MAX_LINE, 24
|
||||||
.equ MAX_LINE_X2, 48
|
.equ MAX_LINE_X2, 48
|
||||||
|
|
|
||||||
BIN
projects/snow/snow.gif
Normal file
BIN
projects/snow/snow.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 MiB |
Loading…
Reference in a new issue