1 package com.insanityengine.ghia.renderer;
2
3 import com.insanityengine.ghia.m3.*;
4 import com.insanityengine.ghia.libograf.*;
5 import com.insanityengine.ghia.pixels.*;
6
7 /***
8 *
9 * <P>
10 * This is a straight up port of Michael Abrash's DDA from chapter 56
11 * of the _Graphics Programming Black Book (Special Edition)_
12 * </P>
13 *
14 * $Header: /usr/local/cvsroot/ghia/src/java/com/insanityengine/ghia/renderer/Abrashed.java,v 1.3 2005/03/25 02:59:21 brian Exp $
15 *
16 * @author BrianHammond
17 *
18 */
19 public class Abrashed extends BufferBase implements RendererInterface {
20
21
22 /***
23 *
24 * render
25 *
26 * @param context
27 *
28 */
29 public void render( LiboGraf context ) {
30 invokeDrawers( context );
31 copyTo( context.getGraphics() );
32 }
33
34
35
36
37 /***
38 *
39 * Some renderers are big babys about when it is ok to mess with their goodies.
40 * Hence this cheesy add/remove Drawer mess
41 *
42 * @param drawer to call per frame
43 *
44 */
45 public void addDrawer( DrawingInterface drawer ) {
46 registry.addDrawer( drawer );
47 }
48
49 /***
50 *
51 * Some renderers are big babys about when it is ok to mess with their goodies.
52 * Hence this cheesy add/remove Drawer mess
53 *
54 * @param drawer to call per frame
55 *
56 */
57 public void removeDrawer( DrawingInterface drawer ) {
58 registry.removeDrawer( drawer );
59 }
60
61 /***
62 *
63 * Invoke any registered DrawingInterfaces
64 *
65 */
66 public void invokeDrawers( LiboGraf context ) {
67 registry.invokeDrawers( context );
68 }
69
70 /***
71 *
72 * drawPolygon
73 *
74 * @param number
75 * @param ptz
76 *
77 */
78 public void drawPolygon( int number, Pt3 ptz[] ) {
79
80 if ( normal.z < 0 ) return;
81 frustrum.toScreen( number, ptz );
82 if ( frustrum.offScreen( number, ptz ) ) return;
83
84 float MinY, MaxY;
85
86 int i;
87 int MinVert = 0;
88
89 NumVerts = number;
90 VertexPtr = ptz;
91
92
93 if ( number < 3 ) {
94 return;
95 }
96
97
98
99
100
101
102
103 MinVert = MaxVert = 0;
104 MaxY = MinY = VertexPtr[ 0 ].getY();
105 for ( i = 1 ; i < NumVerts ; i++ ) {
106 if ( VertexPtr[ i ].getY() < MinY ) {
107 MinY = VertexPtr[ i ].getY();
108 MinVert = i;
109 }
110 if ( VertexPtr[ i ].getY() > MaxY ) {
111 MaxY = VertexPtr[ i ].getY();
112 MaxVert = i;
113 }
114 }
115
116
117 if ( MinY >= MaxY ) {
118 return;
119 }
120
121
122
123
124
125 DestY = MinY;
126
127
128
129
130
131
132
133
134
135 LeftEdge.Direction = -1;
136 LeftEdge.setUpEdge( MinVert );
137
138
139 RightEdge.Direction = 1;
140 RightEdge.setUpEdge( MinVert );
141
142
143
144
145
146
147
148
149
150
151 for ( DestY = MinY; DestY < h ; DestY++ ) {
152
153
154 if ( DestY >= 0 ) {
155 ScanOutLine( LeftEdge, RightEdge );
156 }
157
158
159
160
161
162 if ( !stepEdge( LeftEdge ) || !stepEdge( RightEdge ) ) break;
163 }
164 }
165
166
167
168 private class EdgeScan {
169
170
171
172
173
174 int Direction;
175
176 float RemainingScans;
177 int CurrentEnd;
178
179 float SourceX;
180 float SourceY;
181 float SourceZ;
182 float SourceStepX;
183 float SourceStepY;
184 float SourceStepZ;
185
186
187
188
189
190 int DestX;
191 int DestXIntStep;
192 int DestXDirection;
193 int DestXErrTerm;
194 int DestXAdjUp;
195 int DestXAdjDown;
196
197 /***
198 *
199 * Sets up an edge to be scanned; the edge starts at StartVert and proceeds
200 * in direction Edge.Direction through the vertex list. Edge.Direction
201 * must be set prior to call; -1 to scan a left edge (backward through
202 * the vertex list), 1 to scan a right edge (forward through the
203 * vertex list). Automatically skips over 0-height edges. Returns
204 * 1 for success, or 0 if there are no more edges to scan.
205 *
206 * @param StartVert
207 *
208 * @return a boolean
209 *
210 */
211 boolean setUpEdge( int StartVert ) {
212
213 int NextVert;
214
215 for ( ; StartVert != MaxVert ; ) {
216 NextVert = StartVert + Direction;
217 if ( NextVert >= NumVerts ) {
218 NextVert = 0;
219 } else
220 if ( NextVert < 0 ) {
221 NextVert = NumVerts - 1;
222 }
223
224
225
226
227
228 RemainingScans = VertexPtr[ NextVert ].getY() - VertexPtr[ StartVert ].getY();
229 if ( RemainingScans != 0 ) {
230 return calcStepz( ( int ) RemainingScans, StartVert, NextVert );
231 }
232 StartVert = NextVert;
233 }
234
235 return false;
236 }
237
238 /***
239 *
240 * calcStepz
241 *
242 * @param RemainingScans
243 * @param StartVert
244 * @param NextVert
245 *
246 * @return true
247 *
248 */
249 private final boolean calcStepz( int RemainingScans, int StartVert, int NextVert ) {
250 if ( 0 == RemainingScans ) RemainingScans = 1;
251
252 float DestYHeight = RemainingScans;
253 CurrentEnd = NextVert;
254
255 SourceX = VertexPtr[ StartVert ].getS();
256 SourceY = VertexPtr[ StartVert ].getT();
257 SourceZ = VertexPtr[ StartVert ].getZ();
258
259 SourceStepX = ( VertexPtr[ NextVert ].getS() - SourceX );
260 SourceStepY = ( VertexPtr[ NextVert ].getT() - SourceY );
261 SourceStepZ = ( VertexPtr[ NextVert ].getZ() - SourceZ );
262
263 SourceStepX /= DestYHeight;
264 SourceStepY /= DestYHeight;
265 SourceStepZ /= DestYHeight;
266
267
268 DestX = ( int ) VertexPtr[ StartVert ].getX();
269 int DestXWidth = ( int ) ( VertexPtr[ NextVert ].getX() - VertexPtr[ StartVert ].getX() );
270 if ( DestXWidth < 0 ) {
271
272 DestXDirection = -1;
273 DestXWidth = -DestXWidth;
274 DestXErrTerm = 1 - RemainingScans;
275 DestXIntStep = ( int ) -( DestXWidth / RemainingScans );
276 } else {
277
278 DestXDirection = 1;
279 DestXErrTerm = 0;
280 DestXIntStep = ( int ) +( DestXWidth / RemainingScans );
281 }
282 DestXAdjUp = DestXWidth % RemainingScans;
283 DestXAdjDown = RemainingScans;
284
285 return true;
286 }
287
288
289 };
290
291 /***
292 *
293 * ScanOutLine: Texture-map-draw the scan line between two edges.
294 *
295 * @param LeftEdge
296 * @param RightEdge
297 *
298 */
299 private void ScanOutLine( EdgeScan LeftEdge, EdgeScan RightEdge ) {
300 float SourceX = LeftEdge.SourceX;
301 float SourceY = LeftEdge.SourceY;
302 float SourceZ = LeftEdge.SourceZ;
303
304 float DestX = LeftEdge.DestX;
305 float DestXMax = RightEdge.DestX;
306
307 float DestWidth;
308 float SourceXStep, SourceYStep, SourceZStep;
309
310
311 if ( ( DestXMax <= 0 ) || ( DestX >= w ) ) {
312 return;
313 }
314 if ( ( DestXMax - DestX ) <= 0 ) {
315 return;
316 }
317
318
319
320
321
322
323
324
325
326
327
328
329 DestWidth = DestXMax - DestX;
330
331
332 SourceXStep = ( RightEdge.SourceX - SourceX ) / DestWidth;
333 SourceYStep = ( RightEdge.SourceY - SourceY ) / DestWidth;
334 SourceZStep = ( RightEdge.SourceZ - SourceZ ) / DestWidth;
335
336
337 if ( DestXMax >= w ) {
338 DestXMax = w - 1;
339 }
340
341
342 if ( DestX < 0 ) {
343 SourceX += SourceXStep * ( 0 - DestX );
344 SourceY += SourceYStep * ( 0 - DestX );
345 SourceZ += SourceZStep * ( 0 - DestX );
346 DestX = 0;
347 }
348
349 int pix = 0x00FF0000;
350 int idx = ( int ) DestX + ( ( ( int ) DestY ) * w );
351
352
353
354
355
356 for (; DestX < DestXMax; DestX++, idx++ ) {
357
358
359
360
361 if ( zbuffer.set( idx, SourceZ ) ) {
362 if ( null != skin ) {
363 pix = ( int ) skin.getPixelAt( ( int ) SourceX, ( int ) SourceY );
364 }
365 pixels[ idx ] = pix;
366 }
367
368
369 SourceX += SourceXStep;
370 SourceY += SourceYStep;
371 SourceZ += SourceZStep;
372 }
373 }
374
375
376
377
378
379
380
381
382 private boolean stepEdge( EdgeScan Edge ) {
383
384
385
386
387
388
389 Edge.RemainingScans--;
390 if ( Edge.RemainingScans == 0 ) {
391
392 if ( !Edge.setUpEdge( Edge.CurrentEnd ) ) {
393 return false;
394 }
395 return true;
396 }
397
398
399 Edge.SourceX += Edge.SourceStepX;
400 Edge.SourceY += Edge.SourceStepY;
401
402
403
404
405
406 Edge.DestX += Edge.DestXIntStep;
407
408
409
410 Edge.DestXErrTerm += Edge.DestXAdjUp;
411 if ( Edge.DestXErrTerm > 0 ) {
412 Edge.DestX += Edge.DestXDirection;
413 Edge.DestXErrTerm -= Edge.DestXAdjDown;
414 }
415
416 return true;
417 }
418
419 private int MaxVert, NumVerts;
420 private float DestY;
421 private Pt3 VertexPtr[];
422 private int TexMapWidth;
423
424 private DrawerRegistry registry = new DrawerRegistry();
425
426 private EdgeScan LeftEdge = new EdgeScan();
427 private EdgeScan RightEdge = new EdgeScan();
428
429 };
430
431 /***
432 *
433 * $Log: Abrashed.java,v $
434 * Revision 1.3 2005/03/25 02:59:21 brian
435 * still doesn;t work...
436 *
437 * Revision 1.2 2005/03/25 01:44:06 brian
438 * added ScanOutLine
439 *
440 * Revision 1.1 2005/03/24 22:48:32 brian
441 * dda ala abrash
442 *
443 *
444 */