507
|
1 #include "CreateSpan.h"
|
|
2 #include "viewer_types.h"
|
|
3
|
|
4 static const int SPAN_PACK_LOAD = 5;
|
|
5 static const int SPAN_PACK_STORE = 6;
|
|
6 static const int POLYGON_PACK_LOAD = 7;
|
|
7 static const int TILE_ALLOCATE = 8;
|
|
8 static const int TILE_LOAD = 9;
|
|
9 static const int TILE_STORE = 10;
|
|
10
|
|
11 static SpanPackPtr spack = NULL;
|
|
12 static SpanPackPtr send_spack = NULL;
|
|
13 static int prev_index = 0;
|
|
14
|
|
15 SchedDefineTask(CreateSpan);
|
|
16
|
|
17 static float
|
|
18 calc(float f1, float f2,int i, float base)
|
|
19 {
|
|
20 float ans;
|
|
21 ans = f1/f2*i + base;
|
|
22 return ans;
|
|
23 }
|
|
24
|
|
25
|
|
26 /**
|
|
27 * TrianglePack から、vMin, vMid, vMax を求める
|
|
28 *
|
|
29 * @param [triPack] TrianglePack
|
|
30 * @param [vMin] [vMid] [vMax]
|
|
31 */
|
|
32 static void
|
|
33 make_vertex(TrianglePack *triPack,
|
|
34 VertexPackPtr *vMin, VertexPackPtr *vMid, VertexPackPtr *vMax,
|
|
35 NormalPackPtr *normal1, NormalPackPtr *normal2, NormalPackPtr *normal3)
|
|
36 {
|
|
37 if (triPack->ver1.y <= triPack->ver2.y) {
|
|
38 if (triPack->ver2.y <= triPack->ver3.y) {
|
|
39 *vMin = &triPack->ver1;
|
|
40 *vMid = &triPack->ver2;
|
|
41 *vMax = &triPack->ver3;
|
|
42 } else if (triPack->ver3.y <= triPack->ver1.y) {
|
|
43 *vMin = &triPack->ver3;
|
|
44 *vMid = &triPack->ver1;
|
|
45 *vMax = &triPack->ver2;
|
|
46 } else {
|
|
47 *vMin = &triPack->ver1;
|
|
48 *vMid = &triPack->ver3;
|
|
49 *vMax = &triPack->ver2;
|
|
50 }
|
|
51 } else {
|
|
52 if (triPack->ver1.y <= triPack->ver3.y) {
|
|
53 *vMin = &triPack->ver2;
|
|
54 *vMid = &triPack->ver1;
|
|
55 *vMax = &triPack->ver3;
|
|
56 } else if (triPack->ver3.y <= triPack->ver2.y) {
|
|
57 *vMin = &triPack->ver3;
|
|
58 *vMid = &triPack->ver2;
|
|
59 *vMax = &triPack->ver1;
|
|
60 } else {
|
|
61 *vMin = &triPack->ver2;
|
|
62 *vMid = &triPack->ver3;
|
|
63 *vMax = &triPack->ver1;
|
|
64 }
|
|
65 }
|
|
66
|
|
67 *normal1 = &triPack->normal1;
|
|
68 *normal2 = &triPack->normal2;
|
|
69 *normal3 = &triPack->normal3;
|
|
70
|
|
71 }
|
|
72
|
|
73 static void
|
|
74 make_vMid10(VertexPack *v, VertexPack *vMin,
|
|
75 VertexPack *vMid, VertexPack *vMax)
|
|
76 {
|
|
77 //int d, d1;
|
|
78 float d;
|
|
79 int d1;
|
|
80
|
|
81 d = vMax->y - vMin->y;
|
|
82 d1 = (int)(vMid->y - vMin->y);
|
|
83
|
|
84 v->tex_x = calc(vMax->tex_x - vMin->tex_x, d, d1, vMin->tex_x);
|
|
85 v->tex_y = calc(vMax->tex_y - vMin->tex_y, d, d1, vMin->tex_y);
|
|
86 v->x = calc(vMax->x - vMin->x, d, d1, vMin->x);
|
|
87 v->y = vMid->y;
|
|
88 v->z = calc(vMax->z - vMin->z, d, d1, vMin->z);
|
|
89 }
|
|
90
|
|
91 /**
|
|
92 * 与えられた scale から、実際に使うテクスチャの Tapestry を選択する
|
|
93 *
|
|
94 * テクスチャは、オリジナルのサイズから、可能なかぎり 1/2 で縮小していき、
|
|
95 * 下の図の様に連続した領域に入れられる
|
|
96 *
|
|
97 * Tapestry (1)
|
|
98 * +---+---+---+---+
|
|
99 * | 0 | 1 | 2 | 3 |
|
|
100 * +---+---+---+---+
|
|
101 * | 4 | 5 | 6 | 7 | (2)
|
|
102 * +---+---+---+---+ +---+---+
|
|
103 * | 8 | 9 | 10| 11| | 16| 17| (3)
|
|
104 * +---+---+---+---+ +---+---+ +---+
|
|
105 * | 12| 13| 14| 15| | 18| 19| | 20|
|
|
106 * +---+---+---+---+ +---+---+ +---|
|
|
107 *
|
|
108 * (1) (2) (3)
|
|
109 * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
|
110 * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * | * | * | 14| 15| 16| 17| 18| 19| 20|
|
|
111 * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
|
112 *
|
|
113 * scale の値から、各 Tapestry の先頭アドレスを返す
|
|
114 *
|
|
115 * @param[in] tw Width of texture
|
|
116 * @param[in] th Height of texture
|
|
117 * @param[in] scale テクスチャの縮小率 (= 2^n)
|
|
118 * @param[in] addr_top テクスチャの先頭アドレス (上の図での (1)
|
|
119 * @return scale に対応する Tapestry のアドレス (上の図での (1) or (2) or(3)
|
|
120 */
|
|
121 static uint32*
|
|
122 getTapestry(int tw, int th, int scale, uint32 *addr_top)
|
|
123 {
|
|
124 int index = 0;
|
|
125
|
|
126 for (int s = 1; s < scale; s <<= 1) {
|
|
127 index += tw*th;
|
|
128 tw >>= 1; /* tw /= 2 */
|
|
129 th >>= 1;
|
|
130 }
|
|
131
|
|
132 return addr_top + index;
|
|
133 }
|
|
134
|
|
135
|
|
136 /**
|
|
137 * span の width,height と texture の width,height を比べて
|
|
138 * span を描画する際に使う texture の比率を求める
|
|
139 *
|
|
140 * @param[in] width Width of span
|
|
141 * @param[in] height Height of span
|
|
142 * @param[in] tex_width Width of 1/1 texture that span use
|
|
143 * @param[in] tex_height Height of 1/1 texture that span use
|
|
144 * @param[in] scale_max この Span で使う texture の最大縮小率
|
|
145 * 計算結果が scale_max 以上になるのを防ぐ
|
|
146 * @return 描画に使う texture の比率
|
|
147 * width と height は 1/scale の画像を使う
|
|
148 *
|
|
149 */
|
|
150 static int
|
|
151 getScale(int width, int height, int tex_width, int tex_height, int scale_max)
|
|
152 {
|
|
153 int base, tex_base;
|
|
154 int scale = 1;
|
|
155
|
|
156 /**
|
|
157 * width と height で、長い方を基準に、
|
|
158 * texture の scale を決める
|
|
159 */
|
|
160 if (width > height) {
|
|
161 base = width;
|
|
162 tex_base = tex_width;
|
|
163 } else {
|
|
164 base = height;
|
|
165 tex_base = tex_height;
|
|
166 }
|
|
167
|
|
168 if (tex_base > base) {
|
|
169 int t_scale = tex_base/base;
|
|
170 while (t_scale >>= 1) {
|
|
171 scale <<= 1;
|
|
172 }
|
|
173 }
|
|
174
|
|
175 return (scale > scale_max) ? scale_max : scale;
|
|
176 //return scale_max;
|
|
177 }
|
|
178
|
|
179 /**
|
|
180 * x軸に水平な辺を持つ三角形ポリゴンから、
|
|
181 * Span を抜き出す
|
|
182 *
|
|
183 * @param[in] spackList triangle から生成された span を格納する List
|
|
184 * @param[in] charge_y_top 担当する y の範囲開始地点
|
|
185 * @param[in] charge_y_end 担当する y の範囲終了地点
|
|
186 * @param[in] tex_addr triangle が参照するテクスチャの先頭アドレス
|
|
187 * @param[in] tex_width テクスチャの width
|
|
188 * @param[in] tex_height テクスチャの height
|
|
189 * @param[in] tex_scale_max テクスチャの最大縮小率 (2^n)
|
|
190 * @param[in] vMin triangle の座標
|
|
191 * @param[in] vMid triangle の座標。triangle を二つに分けて出来た新しい座標
|
|
192 * @param[in] vMid10 triangle の座標
|
|
193 * @param[in] length_y 分割する前の Triangle の y の長さ
|
|
194 * @param[in] tex_y_len 分割する前の Triangle に貼られている Texture の
|
|
195 * 長さの割合 (0 ... 1)
|
|
196 */
|
|
197 static void
|
|
198 half_triangle(SchedTask *smanager, SpanPackPtr *spackList,
|
|
199 int charge_y_top, int charge_y_end,
|
|
200 TriangleTexInfoPtr tex_info,
|
|
201 VertexPack *vMin,VertexPack *vMid,VertexPack *vMid10,
|
|
202 NormalPack *normal1, NormalPack *normal2, NormalPack *normal3,
|
|
203 int length_y, float tex_y_len)
|
|
204 {
|
|
205 float tmp_z,tmp_tex1, tmp_tex2 ,tmp_tey1,tmp_tey2;
|
|
206 float tmp_xpos,tmp_end,tmp_zpos;
|
|
207 float start_z, end_z;
|
|
208 float start_tex_x, end_tex_x, start_tex_y, end_tex_y;
|
|
209 int x, y, length;
|
|
210
|
|
211 #if 1
|
|
212 // これじゃないと
|
|
213 // テクスチャの貼りに微妙に隙間が。謎だ
|
|
214 int start_y = (int)vMid->y;
|
|
215 int end_y = (int)vMin->y;
|
|
216 #else
|
|
217 float start_y = vMid->y;
|
|
218 float end_y = vMin->y;
|
|
219 #endif
|
|
220 float div_y = start_y - end_y;
|
|
221 int k = 0;
|
|
222 int l = 1;
|
|
223
|
|
224 SpanPackPtr tmp_spack;
|
|
225
|
|
226 /**
|
|
227 * 三角形ポリゴンをx軸に水平に二つに分けようとして
|
|
228 * ある一辺がすでに水平だった場合、つまり
|
|
229 *
|
|
230 * |\
|
|
231 * | \
|
|
232 * | \
|
|
233 * -----
|
|
234 *
|
|
235 *
|
|
236 * 上のようなポリゴンだった場合は、本来なら上の部分の三角形にだけ
|
|
237 * half_triangle の処理をするべきだが、現在の処理だと
|
|
238 * この half_triangle に「上の部分の三角形」と、
|
|
239 * 「『下の部分の三角形と判断してしまった』直線」が来てしまう。
|
|
240 * 直線の部分が来ると、calc() で 0 除算とかで、値不定で暴走するので
|
|
241 * 現在はこれで代用。
|
|
242 * half_triangle 呼ぶ前にこれを判断できれば良いかもしれない。
|
|
243 * てかこんなんでいいのかよ。。。
|
|
244 */
|
|
245 #if 1
|
|
246 if ((int)div_y == 0) {
|
|
247 return;
|
|
248 }
|
|
249 #else
|
|
250 if (vMid10->x == vMin->x && vMid10->y == vMin->y) {
|
|
251 return;
|
|
252 }
|
|
253 #endif
|
|
254
|
|
255 if (div_y < 0) {
|
|
256 div_y = -div_y;
|
|
257 k = 1;
|
|
258 l = -1;
|
|
259 }
|
|
260
|
|
261 for (int i = k; i < (int)div_y+1; i++) {
|
|
262 y = (int)vMin->y + i*l;
|
|
263 #if 1
|
|
264
|
|
265 /**
|
|
266 * 担当 y 範囲内
|
|
267 */
|
|
268 if (charge_y_top <= y && y <= charge_y_end) {
|
|
269 // 1..8 を index0, 9..16 を index1 にするために y を -1
|
|
270 int index = (y-1) / split_screen_h;
|
|
271
|
|
272 /**
|
|
273 * 違う SpanPack を扱う場合、
|
|
274 * 現在の SpanPack をメインメモリに送り、
|
|
275 * 新しい SpanPack を取ってくる
|
|
276 */
|
|
277 if (index != prev_index) {
|
|
278 tmp_spack = spack;
|
|
279 spack = send_spack;
|
|
280 send_spack = tmp_spack;
|
|
281
|
|
282 smanager->dma_wait(SPAN_PACK_STORE);
|
|
283 smanager->dma_store(send_spack, (uint32)spackList[prev_index],
|
|
284 sizeof(SpanPack), SPAN_PACK_STORE);
|
|
285
|
|
286 smanager->dma_load(spack, (uint32)spackList[index],
|
|
287 sizeof(SpanPack), SPAN_PACK_LOAD);
|
|
288 prev_index = index;
|
|
289 smanager->dma_wait(SPAN_PACK_LOAD);
|
|
290 }
|
|
291
|
|
292 /**
|
|
293 * 書き込む SpanPack が満杯だったら
|
|
294 * メインメモリで allocate した領域 (next) を持ってきて
|
|
295 * 現在の spack->next につなぎ、next を次の spack とする。
|
|
296 */
|
|
297 if (spack->info.size >= MAX_SIZE_SPAN) {
|
|
298 SpanPackPtr next;
|
|
299
|
|
300 smanager->mainMem_alloc(0, sizeof(SpanPack));
|
|
301 smanager->mainMem_wait();
|
|
302 next = (SpanPackPtr)smanager->mainMem_get(0);
|
|
303
|
|
304 spack->next = next;
|
|
305
|
|
306 tmp_spack = spack;
|
|
307 spack = send_spack;
|
|
308 send_spack = tmp_spack;
|
|
309
|
|
310 smanager->dma_wait(SPAN_PACK_STORE);
|
|
311 smanager->dma_store(send_spack, (uint32)spackList[index],
|
|
312 sizeof(SpanPack), SPAN_PACK_STORE);
|
|
313
|
|
314 spackList[index] = next;
|
|
315
|
|
316 smanager->dma_load(spack, (uint32)spackList[index],
|
|
317 sizeof(SpanPack), SPAN_PACK_LOAD);
|
|
318 smanager->dma_wait(SPAN_PACK_LOAD);
|
|
319 spack->init((index+1)*split_screen_h);
|
|
320 }
|
|
321 } else {
|
|
322 /**
|
|
323 * 担当範囲外だったら無視
|
|
324 */
|
|
325 continue;
|
|
326 }
|
|
327
|
|
328 tmp_xpos = calc(vMid10->x - vMin->x ,div_y, i, vMin->x);
|
|
329 tmp_end = calc(vMid->x - vMin->x ,div_y, i, vMin->x);
|
|
330 tmp_z = calc(vMid10->z - vMin->z ,div_y, i, vMin->z);
|
|
331 tmp_zpos = calc(vMid->z - vMin->z ,div_y, i, vMin->z);
|
|
332
|
|
333 length = (tmp_xpos > tmp_end)
|
|
334 ? (int)tmp_xpos - (int)tmp_end : (int)tmp_end - (int)tmp_xpos;
|
|
335 if (length == 0) {
|
|
336 continue;
|
|
337 }
|
|
338
|
|
339 tmp_tex1 =((i/(div_y)) * vMid10->tex_x) +
|
|
340 ( ((div_y - i)/(div_y)) * vMin->tex_x);
|
|
341 tmp_tex2 =( (i/(div_y)) * vMid->tex_x) +
|
|
342 ( ((div_y - i)/(div_y)) * vMin->tex_x);
|
|
343
|
|
344 tmp_tey1 =( (i/(div_y)) * vMid10->tex_y) +
|
|
345 ( ((div_y - i)/(div_y)) * vMin->tex_y);
|
|
346 tmp_tey2 =( (i/(div_y)) * vMid->tex_y) +
|
|
347 ( ((div_y - i)/(div_y)) * vMin->tex_y);
|
|
348
|
|
349 if (tmp_xpos > tmp_end) {
|
|
350 x = (int)tmp_end;
|
|
351 length = (int)(tmp_xpos)-(int)(tmp_end)+1;
|
|
352 start_z = tmp_zpos;
|
|
353 end_z = tmp_z;
|
|
354 start_tex_x = tmp_tex2;
|
|
355 end_tex_x = tmp_tex1;
|
|
356 start_tex_y = tmp_tey2;
|
|
357 end_tex_y = tmp_tey1;
|
|
358 } else {
|
|
359 x = (int)tmp_xpos;
|
|
360 length = (int)(tmp_end)-(int)(tmp_xpos)+1;
|
|
361 start_z = tmp_z;
|
|
362 end_z = tmp_zpos;
|
|
363 start_tex_x = tmp_tex1;
|
|
364 end_tex_x = tmp_tex2;
|
|
365 start_tex_y = tmp_tey1;
|
|
366 end_tex_y = tmp_tey2;
|
|
367 }
|
|
368
|
|
369 smanager->dma_wait(SPAN_PACK_LOAD);
|
|
370
|
|
371 Span *span = &spack->span[spack->info.size++];
|
|
372
|
|
373 span->x = x;
|
|
374 span->y = y;
|
|
375 span->length_x = length;
|
|
376 span->start_z = start_z;
|
|
377 span->end_z = end_z;
|
|
378 span->tex_x1 = start_tex_x;
|
|
379 span->tex_x2 = end_tex_x;
|
|
380 span->tex_y1 = start_tex_y;
|
|
381 span->tex_y2 = end_tex_y;
|
|
382 /*ここで頂点分法線ベクトルがあったんだけど、
|
|
383 * 一つだけ取り出して、spanに一つの法線ベクトルを持たしている
|
|
384 *by yutaka
|
|
385 */
|
|
386 span->normal_x = normal1->x;
|
|
387 span->normal_y = normal1->y;
|
|
388 span->normal_z = normal1->z;
|
|
389
|
|
390
|
|
391 float tex_x_len = span->tex_x2 - span->tex_x1;
|
|
392
|
|
393 /**
|
|
394 * tex_x_len, tex_y_len を掛ける理由は
|
|
395 * Changelog の 2008-12-16 を参照
|
|
396 */
|
|
397 int scale = getScale(span->length_x, length_y,
|
|
398 (int)(span->tex_width*tex_x_len),
|
|
399 (int)(span->tex_height*tex_y_len),
|
|
400 tex_info->scale_max);
|
|
401 //scale = tex_info->scale_max;
|
|
402
|
|
403 uint32 *tapestry = getTapestry(tex_info->width,
|
|
404 tex_info->height, scale,
|
|
405 tex_info->addr);
|
|
406 span->tex_addr = tapestry;
|
|
407 span->tex_width = tex_info->width/scale;
|
|
408 span->tex_height = tex_info->height/scale;
|
|
409 }
|
|
410 #else
|
|
411
|
|
412 /**
|
|
413 * ここに SIMD 化した記述をしようとして断念
|
|
414 */
|
|
415
|
|
416 #endif
|
|
417
|
|
418 }
|
|
419
|
|
420
|
|
421 static int
|
|
422 run(SchedTask *smanager, void *rbuf, void *wbuf)
|
|
423 {
|
|
424 PolygonPack *pp = (PolygonPack*)smanager->get_input(0);
|
|
425 PolygonPack *next_pp =
|
|
426 (PolygonPack*)smanager->allocate(sizeof(PolygonPack));
|
|
427 PolygonPack *free_pp = next_pp;
|
|
428 PolygonPack *tmp_pp;
|
|
429
|
|
430 TrianglePackPtr triPack;
|
|
431 VertexPackPtr vMin, vMid, vMax;
|
|
432 VertexPackPtr vMid10
|
|
433 = (VertexPackPtr)smanager->allocate(sizeof(VertexPack));
|
|
434 NormalPackPtr normal1,normal2, normal3;
|
|
435 SpanPackPtr *spackList = (SpanPackPtr*)smanager->get_input(1);
|
|
436 spack = (SpanPackPtr)smanager->get_input(2);
|
|
437 send_spack = (SpanPackPtr)smanager->allocate(sizeof(SpanPack));
|
|
438 prev_index = smanager->get_param(0);
|
|
439
|
|
440 // spack と send_spack は swap しながら DMA を繰り返すので
|
|
441 // 自分で allocate した send_spack を覚えてないといけない
|
|
442 SpanPackPtr free_spack = send_spack;
|
|
443
|
|
444 int charge_y_top = smanager->get_param(1);
|
|
445 int charge_y_end = smanager->get_param(2);
|
|
446
|
|
447 do {
|
|
448 if (pp->next != NULL) {
|
|
449 smanager->dma_load(next_pp, (uint32)pp->next,
|
|
450 sizeof(PolygonPack), POLYGON_PACK_LOAD);
|
|
451 } else {
|
|
452 next_pp = NULL;
|
|
453 }
|
|
454
|
|
455 for (int i = 0; i < pp->info.size; i++) {
|
|
456 triPack = &pp->tri[i];
|
|
457
|
|
458 TriangleTexInfoPtr tri_tex_info = &triPack->tex_info;
|
|
459
|
|
460 make_vertex(triPack, &vMin, &vMid, &vMax, &normal1, &normal2, &normal3);
|
|
461 make_vMid10(vMid10, vMin, vMid, vMax);
|
|
462
|
|
463 /**
|
|
464 * ポリゴンを、x軸に水平に分割して二つの三角形を作り、
|
|
465 * それぞれから Span を求める
|
|
466 *
|
|
467 * vMax
|
|
468 * |\
|
|
469 * | \
|
|
470 * | \
|
|
471 * | \
|
|
472 * vMid10 ------ vMid
|
|
473 * | /
|
|
474 * | /
|
|
475 * | /
|
|
476 * |/
|
|
477 * vMin
|
|
478 *
|
|
479 * (vMax, vMid, vMin) という triangle を
|
|
480 * (vMax, vMid, vMid10) (vMin, vMid, vMid10) という
|
|
481 * 二つの Triangle に分けている
|
|
482 */
|
|
483 half_triangle(smanager, spackList, charge_y_top, charge_y_end,
|
|
484 tri_tex_info, vMin, vMid, vMid10,
|
|
485 normal1,normal2,normal3,
|
|
486 (int)(vMax->y - vMin->y), vMax->tex_y - vMin->tex_y);
|
|
487 half_triangle(smanager, spackList, charge_y_top, charge_y_end,
|
|
488 tri_tex_info, vMax, vMid, vMid10,
|
|
489 normal1,normal2,normal3,
|
|
490 (int)(vMax->y - vMin->y), vMax->tex_y - vMin->tex_y);
|
|
491 }
|
|
492
|
|
493 smanager->dma_wait(POLYGON_PACK_LOAD);
|
|
494
|
|
495 tmp_pp = pp;
|
|
496 pp = next_pp;
|
|
497 next_pp = tmp_pp;
|
|
498 } while (pp);
|
|
499
|
|
500 smanager->dma_wait(SPAN_PACK_STORE);
|
|
501 smanager->dma_store(spack, (uint32)spackList[prev_index],
|
|
502 sizeof(SpanPack), SPAN_PACK_STORE);
|
|
503 smanager->dma_wait(SPAN_PACK_STORE);
|
|
504
|
|
505 free(free_pp);
|
|
506 free(free_spack);
|
|
507 free(vMid10);
|
|
508
|
|
509 return 0;
|
|
510 }
|