dreamcast/scene.cpp
Zack Buhman 9610c428bd draw a textured triangle strip
This draws a nice macaw texture in a square-shaped triangle
strip. The square is then rotated around the y-axis.

I dealt with myriad bugs while experimenting with this, all of them
entirely my fault:

- macaw texture colors were incorrect because GIMP was exporting raw
  RGB data in gamma-corrected sRGB space, whereas the Dreamcast is in
  linear color space.

- macaw texture colors were incorrect because I truncated color values
  to the least significant rather than most significant bits.

- macaw rotation around the Y axis caused the macaw texture to
  distort, stretch and recurse in interesting and unexpected ways. This
  was caused by sending Z values in the wrong coordinate space (Z)
  contrast to what is expected by the Dreamcast (1/z). Reordering
  z-coordinate operations so that the reciprocal is computed last
  resolved this.

- macaw rotation around the Y axis caused the macaw texture to warp
  unexpectedly, but only on real hardware. This was caused by
  unnecessarily negating Z coordinate values.

Behavior for each of the Z-coordinate issues differed between Flycast
and real Dreamcast hardware.

I also did several tests related to SH4 cache behavior, particularly
related to the "copy-back" mode. I verified copy-back behavior on a
real dreamcast, and experimented with the operand cache write-back
instruction, "ocbwb".

In particular, when the `scene` buffer is access from cacheable
memory, e.g: the P1 area, and CCR__CB is enabled, DMA from physical
memory to the TA FIFO polygon converter will fail because the scene
data has not yet been written to physical memory yet. `ocbwb` can be
used to "write back" scene from the SH4 operand cache to physical
memory--only the latter is visible from the CH2-DMA perspective.
2023-12-06 21:18:14 +08:00

78 lines
1.7 KiB
C++

#include <cstdint>
#include <cstddef>
#include "holly/ta_parameter.h"
#include "holly/texture_memory_alloc.h"
/*
-0.5,-0.5 0.5,-0.5
|
---
-0.5,0.5 | 0.5,0.5
*/
struct triangle {
float x;
float y;
float z;
float u;
float v;
uint32_t color;
};
const struct triangle scene_triangle[4] = {
{ -0.5f, 0.5f, 0.f, 0.f , 128.f/128.f, 0x00000000}, // the first two base colors in a
{ -0.5f, -0.5f, 0.f, 0.f , 0.f , 0x00000000}, // triangle strip are ignored
{ 0.5f, 0.5f, 0.f, 128.f/128.f, 128.f/128.f, 0xffff00ff},
{ 0.5f, -0.5f, 0.f, 128.f/128.f, 0.f , 0xffffff00},
};
static float theta = 0;
constexpr float one_degree = 0.01745329f / 2.f;
uint32_t scene_transform(volatile uint32_t * scene)
{
uint32_t ix = 0;
uint32_t address = (offsetof (struct texture_memory_alloc, texture));
textured_triangle(&scene[(32 * ix) / 4],
address);
ix++;
for (int i = 0; i < 4; i++) {
bool end_of_strip = i == 3;
float x = scene_triangle[i].x;
float y = scene_triangle[i].y;
float z = scene_triangle[i].z;
float x1;
x1 = x * __builtin_cosf(theta) - z * __builtin_sinf(theta);
z = x * __builtin_sinf(theta) + z * __builtin_cosf(theta);
x = x1;
x *= 240.f;
y *= 240.f;
x += 320.f;
y += 240.f;
textured_vertex(&scene[(32 * ix) / 4],
x, // x
y, // y
1.f / (z + 10.f), // z
scene_triangle[i].u, // u
scene_triangle[i].v, // v
scene_triangle[i].color, // base_color
0, // offset_color
end_of_strip);
ix++;
}
end_of_list(&scene[(32 * ix) / 4]);
ix++;
theta += one_degree;
return ix;
}