diff options
Diffstat (limited to 'apps/plugins/xworld/xworld.c')
-rw-r--r-- | apps/plugins/xworld/xworld.c | 244 |
1 files changed, 244 insertions, 0 deletions
diff --git a/apps/plugins/xworld/xworld.c b/apps/plugins/xworld/xworld.c new file mode 100644 index 0000000000..932ff1c3e1 --- /dev/null +++ b/apps/plugins/xworld/xworld.c | |||
@@ -0,0 +1,244 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2014 Franklin Wei, Benjamin Brown | ||
11 | * Copyright (C) 2004 Gregory Montoir | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * as published by the Free Software Foundation; either version 2 | ||
16 | * of the License, or (at your option) any later version. | ||
17 | * | ||
18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
19 | * KIND, either express or implied. | ||
20 | * | ||
21 | ***************************************************************************/ | ||
22 | |||
23 | #include "plugin.h" | ||
24 | #include "engine.h" | ||
25 | #include "sys.h" | ||
26 | #include "util.h" | ||
27 | |||
28 | /* we don't want these on the stack, they're big and could cause a stack overflow */ | ||
29 | static struct Engine e; | ||
30 | static struct System sys; | ||
31 | |||
32 | enum plugin_status plugin_start(const void* parameter) | ||
33 | { | ||
34 | (void) parameter; | ||
35 | |||
36 | /* no trailing slashes */ | ||
37 | const char *dataPath = "/.rockbox/xworld"; | ||
38 | const char *savePath = "/.rockbox/xworld"; | ||
39 | g_debugMask = 0; | ||
40 | |||
41 | engine_create(&e, &sys, dataPath, savePath); | ||
42 | engine_init(&e); | ||
43 | sys_menu(&sys); | ||
44 | |||
45 | engine_run(&e); | ||
46 | |||
47 | engine_finish(&e); | ||
48 | return PLUGIN_OK; | ||
49 | } | ||
50 | |||
51 | |||
52 | |||
53 | /* | ||
54 | Game was originally made with 16. SIXTEEN colors. Running on 320x200 (64,000 pixels.) | ||
55 | |||
56 | Great fan site here: https://sites.google.com/site/interlinkknight/anotherworld | ||
57 | Contains the wheelcode :P ! | ||
58 | |||
59 | A lot of details can be found regarding the game and engine architecture at: | ||
60 | http://www.anotherworld.fr/anotherworld_uk/another_world.htm | ||
61 | |||
62 | The chronology of the game implementation can retraced via the ordering of the opcodes: | ||
63 | The sound and music opcode are at the end: Music and sound was done at the end. | ||
64 | |||
65 | Call tree: | ||
66 | ========= | ||
67 | |||
68 | SDLSystem systemImplementaion ; | ||
69 | System *sys = & systemImplementaion ; | ||
70 | |||
71 | main | ||
72 | { | ||
73 | |||
74 | Engine *e = new Engine(); | ||
75 | e->run() | ||
76 | { | ||
77 | sys->init("Out Of This World"); | ||
78 | setup(); | ||
79 | vm.restartAt(0x3E80); // demo starts at 0x3E81 | ||
80 | |||
81 | while (!_stub->_pi.quit) | ||
82 | { | ||
83 | vm.setupScripts(); | ||
84 | vm.inp_updatePlayer(); | ||
85 | processInput(); | ||
86 | vm.runScripts(); | ||
87 | } | ||
88 | |||
89 | finish(); | ||
90 | } | ||
91 | } | ||
92 | |||
93 | |||
94 | Virtual Machine: | ||
95 | ================ | ||
96 | |||
97 | Seems the threading model is collaborative multi-tasking (as opposed to preemptive multitasking): | ||
98 | A thread (called a Channel on Eric Chahi's website) will release the hand to the next one via the | ||
99 | break opcode. | ||
100 | |||
101 | It seems that even when a setvec is requested by a thread, we cannot set the instruction pointer | ||
102 | yet. The thread is allowed to keep on executing its code for the remaining of the vm frame. | ||
103 | |||
104 | A virtual machine frame has a variable duration. The unit of time is 20ms and the frame can be set | ||
105 | to live for 1 (20ms ; 50Hz) up to 5 (100ms ; 10Hz). | ||
106 | |||
107 | |||
108 | There are 30 something opcodes. The graphic opcode are more complex, not only the declare the operation to perform | ||
109 | they also define where to find the vertices (segVideo1 or segVideo2). | ||
110 | |||
111 | No stack available but a thread can save its pc (Program Counter) once: One method call and return is possible. | ||
112 | |||
113 | |||
114 | Video : | ||
115 | ======= | ||
116 | Double buffer architecture. AW opcodes even has a special instruction for blitting from one | ||
117 | frame buffer to an other. | ||
118 | |||
119 | Double buffering is implemented in software | ||
120 | |||
121 | According to Eric Chahi's webpage there are 4 framebuffer. Since on full screenbuffer is 320x200/2 = 32kB | ||
122 | that would mean the total size consumed is 128KB ? | ||
123 | |||
124 | Sound : | ||
125 | ======= | ||
126 | Mixing is done on software. | ||
127 | |||
128 | Since the virtual machine and SDL are running simultaneously in two different threads: | ||
129 | Any read or write to an elements of the sound channels MUST be synchronized with a | ||
130 | mutex. | ||
131 | |||
132 | FastMode : | ||
133 | ========== | ||
134 | |||
135 | The game engine features a "fast-mode"...what it to be able to respond to the now defunct | ||
136 | TURBO button commonly found on 386/486 era PC ?! | ||
137 | |||
138 | |||
139 | Endianess: | ||
140 | ========== | ||
141 | |||
142 | Atari and Amiga used bigEndian CPUs. Data are hence stored within BANK in big endian format. | ||
143 | On an Intel or ARM CPU data will have to be transformed when read. | ||
144 | |||
145 | |||
146 | |||
147 | The original codebase contained a looooot of cryptic hexa values. | ||
148 | 0x100 (for 256 variables) | ||
149 | 0x400 (for one kilobyte) | ||
150 | 0x40 (for num threads) | ||
151 | 0x3F (num thread mask) | ||
152 | I cleaned that up. | ||
153 | |||
154 | Questions & Answers : | ||
155 | ===================== | ||
156 | |||
157 | Q: How does the interpreter deals with the CPU speed ?! A pentium is a tad faster than a Motorola 68000 | ||
158 | after all. | ||
159 | A: See vm frame time: The vm frame duration is variable. The vm actually write for how long a video frame | ||
160 | should be displayed in variable 0xFF. The value is the number of 20ms slice | ||
161 | |||
162 | Q: Why is a palette 2048 bytes if there are only 16 colors ? I would have expected 48 bytes... | ||
163 | A: ??? | ||
164 | |||
165 | Q: Why does Resource::load() search for ressource to load from higher to lower....since it will load stuff | ||
166 | until no more ressources are marked as "Need to be loaded". | ||
167 | A: ??? | ||
168 | |||
169 | Original DOS version : | ||
170 | ====================== | ||
171 | |||
172 | Banks: 1,236,519 B | ||
173 | exe : 20,293 B | ||
174 | |||
175 | |||
176 | Total bank size: 1236519 (100%) | ||
177 | --------------------------------- | ||
178 | Total RT_SOUND size: 585052 ( 47%) | ||
179 | Total RT_MUSIC size: 3540 ( 0%) | ||
180 | Total RT_POLY_ANIM size: 106676 ( 9%) | ||
181 | Total RT_PALETTE size: 11032 ( 1%) | ||
182 | Total RT_BYTECODE size: 135948 ( 11%) | ||
183 | Total RT_POLY_CINEMATIC size: 291008 ( 24%) | ||
184 | |||
185 | As usual sounds are the most consuming assets (Quake1,Quake2 etc.....) | ||
186 | |||
187 | |||
188 | memlist.bin features 146 entries : | ||
189 | ================================== | ||
190 | |||
191 | Most important part in an entry are: | ||
192 | |||
193 | bankId : - Give the file were the resource is. | ||
194 | offset : - How much to skip in the file before hiting the resource. | ||
195 | size,packetSize : - How much to read, should we unpack what we read. | ||
196 | |||
197 | |||
198 | |||
199 | Polygons drawing : | ||
200 | ================= | ||
201 | |||
202 | Polygons can be given as: | ||
203 | - a pure screenspace sequence of points: I call those screenspace polygons. | ||
204 | - a list of delta to add or substract to the first vertex. I call those: objectspace polygons. | ||
205 | |||
206 | Video : | ||
207 | ======= | ||
208 | |||
209 | Q: Why 4 framebuffer ? | ||
210 | A: It seems the background is generated once (like in the introduction) and stored in a framebuffer. | ||
211 | Every frame the saved background is copied and new elements are drawn on top. | ||
212 | |||
213 | |||
214 | Trivia : | ||
215 | ======== | ||
216 | |||
217 | If you are used to RGBA 32bits per pixel framebuffer you are in for a shock: | ||
218 | Another world is 16 colors palette based, making it 4bits per pixel !! | ||
219 | |||
220 | Video generation : | ||
221 | ================== | ||
222 | |||
223 | Thank god the engine sets the palette before starting to drawing instead of after bliting. | ||
224 | I would have been unable to generate screenshots otherwise. | ||
225 | |||
226 | Memory managment : | ||
227 | ================= | ||
228 | |||
229 | There is 0 malloc during the game. All resources are loaded in one big buffer (Resource::load). | ||
230 | The entire buffer is "freed" at the end of a game part. | ||
231 | |||
232 | |||
233 | The renderer is actually capable of Blending a new poly in the framebuffer (Video::drawLineT) | ||
234 | |||
235 | |||
236 | I am almost sure that: | ||
237 | _curPagePtr1 is the backbuffer | ||
238 | _curPagePtr2 is the frontbuffer | ||
239 | _curPagePtr3 is the background builder. | ||
240 | |||
241 | |||
242 | * Why does memlist.bin uses a special state field 0xFF in order to mark the end of resources ??! | ||
243 | It would have been so much easier to write the number of resources at the beginning of the code. | ||
244 | */ | ||