mirror of
https://github.com/AntonioND/nitro-engine.git
synced 2025-06-19 09:05:50 -04:00

This was a hack that was added to make up for an incorrect 2D projection
setup. It sometimes compensated the distortion caused by that
projection in order to display the 2D sprites correctly.
Commit 193a50c939
("library: Fix 2D projection") fixed it, so this
patch removes the hack.
471 lines
12 KiB
C
471 lines
12 KiB
C
// SPDX-License-Identifier: MIT
|
|
//
|
|
// Copyright (c) 2008-2011, 2019, 2022 Antonio Niño Díaz
|
|
//
|
|
// This file is part of Nitro Engine
|
|
|
|
#include "NEMain.h"
|
|
|
|
/// @file NE2D.c
|
|
|
|
static NE_Sprite **NE_spritepointers = NULL;
|
|
|
|
static int NE_MAX_SPRITES;
|
|
|
|
static bool ne_sprite_system_inited = false;
|
|
|
|
NE_Sprite *NE_SpriteCreate(void)
|
|
{
|
|
if (!ne_sprite_system_inited)
|
|
{
|
|
NE_DebugPrint("System not initialized");
|
|
return NULL;
|
|
}
|
|
|
|
for (int i = 0; i < NE_MAX_SPRITES; i++)
|
|
{
|
|
if (NE_spritepointers[i] != NULL)
|
|
continue;
|
|
|
|
NE_Sprite *sprite = calloc(1, sizeof(NE_Sprite));
|
|
if (sprite == NULL)
|
|
{
|
|
NE_DebugPrint("Not enough memory");
|
|
return NULL;
|
|
}
|
|
|
|
sprite->visible = true;
|
|
sprite->scale = inttof32(1);
|
|
sprite->color = NE_White;
|
|
sprite->mat = NULL;
|
|
sprite->alpha = 31;
|
|
|
|
NE_spritepointers[i] = sprite;
|
|
|
|
return sprite;
|
|
}
|
|
|
|
NE_DebugPrint("No free slots");
|
|
return NULL;
|
|
}
|
|
|
|
void NE_SpriteSetPos(NE_Sprite *sprite, int x, int y)
|
|
{
|
|
NE_AssertPointer(sprite, "NULL pointer");
|
|
sprite->x = x;
|
|
sprite->y = y;
|
|
}
|
|
|
|
void NE_SpriteSetSize(NE_Sprite *sprite, int w, int h)
|
|
{
|
|
NE_AssertPointer(sprite, "NULL pointer");
|
|
sprite->w = w;
|
|
sprite->h = h;
|
|
}
|
|
|
|
void NE_SpriteSetRot(NE_Sprite *sprite, int angle)
|
|
{
|
|
NE_AssertPointer(sprite, "NULL pointer");
|
|
sprite->rot_angle = angle;
|
|
}
|
|
|
|
void NE_SpriteSetScaleI(NE_Sprite *sprite, int scale)
|
|
{
|
|
NE_AssertPointer(sprite, "NULL pointer");
|
|
sprite->scale = scale;
|
|
}
|
|
|
|
void NE_SpriteSetMaterial(NE_Sprite *sprite, NE_Material *mat)
|
|
{
|
|
NE_AssertPointer(sprite, "NULL sprite pointer");
|
|
NE_AssertPointer(mat, "NULL material pointer");
|
|
sprite->mat = mat;
|
|
}
|
|
|
|
void NE_SpriteSetPriority(NE_Sprite *sprite, int priority)
|
|
{
|
|
NE_AssertPointer(sprite, "NULL pointer");
|
|
sprite->priority = priority;
|
|
}
|
|
|
|
void NE_SpriteVisible(NE_Sprite *sprite, bool visible)
|
|
{
|
|
NE_AssertPointer(sprite, "NULL pointer");
|
|
sprite->visible = visible;
|
|
}
|
|
|
|
void NE_SpriteSetParams(NE_Sprite *sprite, u8 alpha, u8 id, u32 color)
|
|
{
|
|
NE_AssertPointer(sprite, "NULL pointer");
|
|
NE_AssertMinMax(0, alpha, 31, "Invalid alpha value %d", alpha);
|
|
NE_AssertMinMax(0, id, 63, "Invalid polygon ID %d", id);
|
|
|
|
sprite->alpha = alpha;
|
|
sprite->id = id;
|
|
sprite->color = color;
|
|
}
|
|
|
|
void NE_SpriteDelete(NE_Sprite *sprite)
|
|
{
|
|
if (!ne_sprite_system_inited)
|
|
return;
|
|
|
|
NE_AssertPointer(sprite, "NULL pointer");
|
|
|
|
for (int i = 0; i < NE_MAX_SPRITES; i++)
|
|
{
|
|
if (NE_spritepointers[i] != sprite)
|
|
continue;
|
|
|
|
NE_spritepointers[i] = NULL;
|
|
free((void *)sprite);
|
|
|
|
return;
|
|
}
|
|
|
|
NE_DebugPrint("Object not found");
|
|
return;
|
|
}
|
|
|
|
void NE_SpriteDeleteAll(void)
|
|
{
|
|
if (!ne_sprite_system_inited)
|
|
return;
|
|
|
|
for (int i = 0; i < NE_MAX_SPRITES; i++)
|
|
NE_SpriteDelete(NE_spritepointers[i]);
|
|
}
|
|
|
|
int NE_SpriteSystemReset(int max_sprites)
|
|
{
|
|
if (ne_sprite_system_inited)
|
|
NE_SpriteSystemEnd();
|
|
|
|
if (max_sprites < 1)
|
|
NE_MAX_SPRITES = NE_DEFAULT_SPRITES;
|
|
else
|
|
NE_MAX_SPRITES = max_sprites;
|
|
|
|
NE_spritepointers = calloc(NE_MAX_SPRITES, sizeof(NE_spritepointers));
|
|
if (NE_spritepointers == NULL)
|
|
{
|
|
NE_DebugPrint("Not enough memory");
|
|
return -1;
|
|
}
|
|
|
|
ne_sprite_system_inited = true;
|
|
return 0;
|
|
}
|
|
|
|
void NE_SpriteSystemEnd(void)
|
|
{
|
|
if (!ne_sprite_system_inited)
|
|
return;
|
|
|
|
NE_SpriteDeleteAll();
|
|
|
|
free(NE_spritepointers);
|
|
|
|
ne_sprite_system_inited = false;
|
|
}
|
|
|
|
void NE_SpriteDraw(const NE_Sprite *sprite)
|
|
{
|
|
if (!ne_sprite_system_inited)
|
|
return;
|
|
|
|
NE_AssertPointer(sprite, "NULL pointer");
|
|
|
|
if (!sprite->visible)
|
|
return;
|
|
|
|
if (sprite->rot_angle)
|
|
{
|
|
MATRIX_PUSH = 0;
|
|
|
|
NE_2DViewRotateScaleByPositionI(sprite->x + (sprite->w >> 1),
|
|
sprite->y + (sprite->h >> 1),
|
|
sprite->rot_angle,
|
|
sprite->scale);
|
|
}
|
|
else
|
|
{
|
|
NE_2DViewScaleByPositionI(sprite->x + (sprite->w >> 1),
|
|
sprite->y + (sprite->h >> 1),
|
|
sprite->scale);
|
|
}
|
|
|
|
GFX_POLY_FORMAT = POLY_ALPHA(sprite->alpha) | POLY_ID(sprite->id) |
|
|
NE_CULL_NONE;
|
|
|
|
NE_2DDrawTexturedQuadColor(sprite->x, sprite->y,
|
|
sprite->x + sprite->w, sprite->y + sprite->h,
|
|
sprite->priority, sprite->mat, sprite->color);
|
|
|
|
if (sprite->rot_angle)
|
|
MATRIX_POP = 1;
|
|
}
|
|
|
|
void NE_SpriteDrawAll(void)
|
|
{
|
|
if (!ne_sprite_system_inited)
|
|
return;
|
|
|
|
for (int i = 0; i < NE_MAX_SPRITES; i++)
|
|
{
|
|
if (NE_spritepointers[i] == NULL)
|
|
continue;
|
|
|
|
NE_Sprite *sprite = NE_spritepointers[i];
|
|
|
|
if (!sprite->visible)
|
|
continue;
|
|
|
|
if (sprite->rot_angle)
|
|
{
|
|
MATRIX_PUSH = 0;
|
|
|
|
NE_2DViewRotateScaleByPositionI(sprite->x + (sprite->w >> 1),
|
|
sprite->y + (sprite->h >> 1),
|
|
sprite->rot_angle,
|
|
sprite->scale);
|
|
}
|
|
else
|
|
{
|
|
NE_2DViewScaleByPositionI(sprite->x + (sprite->w >> 1),
|
|
sprite->y + (sprite->h >> 1),
|
|
sprite->scale);
|
|
}
|
|
|
|
GFX_POLY_FORMAT = POLY_ALPHA(sprite->alpha) |
|
|
POLY_ID(sprite->id) | NE_CULL_NONE;
|
|
|
|
NE_2DDrawTexturedQuadColor(sprite->x, sprite->y,
|
|
sprite->x + sprite->w,
|
|
sprite->y + sprite->h,
|
|
sprite->priority,
|
|
sprite->mat, sprite->color);
|
|
|
|
if (sprite->rot_angle)
|
|
MATRIX_POP = 1;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------
|
|
//
|
|
// Functions to draw freely in 2D.
|
|
//
|
|
//----------------------------------------------------------
|
|
|
|
// Internal use. See NETexture.c
|
|
|
|
int __NE_TextureGetRawX(const NE_Material *tex);
|
|
int __NE_TextureGetRawY(const NE_Material *tex);
|
|
|
|
//--------------------------------------------
|
|
|
|
void NE_2DViewInit(void)
|
|
{
|
|
GFX_VIEWPORT = 0 | (0 << 8) | (255 << 16) | (191 << 24);
|
|
|
|
// The projection matrix actually thinks that the size of the DS is
|
|
// (256 << factor) x (192 << factor). After this, we scale the MODELVIEW
|
|
// matrix to match this scale factor.
|
|
//
|
|
// This way, it is possible to draw on the screen by using numbers up to 256
|
|
// x 192, but internally the DS has more digits when it does transformations
|
|
// like a rotation. Not having this factor results in noticeable flickering,
|
|
// specially in some emulators.
|
|
//
|
|
// Unfortunately, applying this factor reduces the accuracy of the Y
|
|
// coordinate a lot (nothing is noticeable in the X coordinate). Any factor
|
|
// over 4 starts showing a noticeable accuracy loss: some sprites start
|
|
// being slightly distorted, with missing some horizontal lines as the
|
|
// height is reduced. When the number is higher, like 12, the Y coordinate
|
|
// is significantly compressed. When the number is even higher, like 18, the
|
|
// polygons disappear because too much accuracy has been lost.
|
|
//
|
|
// The current solution is to compromise, and use a factor of 2, which
|
|
// doesn't cause any distortion, and solves most of the flickering. Ideally
|
|
// we would use 0 to simplify the calculations, but we want to reduce the
|
|
// flickering.
|
|
//
|
|
// On hardware, the difference in flickering between 0 and 2 isn't too
|
|
// noticeable, but it is noticeable. In DeSmuMe it is very noticeable.
|
|
// In my tests, Y axis distortion starts to happen with a factor of 4, so a
|
|
// factor of 2 should be safe and reduce enough flickering.
|
|
|
|
MATRIX_CONTROL = GL_PROJECTION;
|
|
MATRIX_IDENTITY = 0;
|
|
|
|
int factor = 2;
|
|
|
|
glOrthof32(0, 256 << factor, 192 << factor, 0, inttof32(1), inttof32(-1));
|
|
|
|
MATRIX_CONTROL = GL_MODELVIEW;
|
|
MATRIX_IDENTITY = 0;
|
|
|
|
MATRIX_SCALE = inttof32(1 << factor);
|
|
MATRIX_SCALE = inttof32(1 << factor);
|
|
MATRIX_SCALE = inttof32(1);
|
|
|
|
NE_PolyFormat(31, 0, 0, NE_CULL_NONE, 0);
|
|
}
|
|
|
|
void NE_2DViewRotateScaleByPositionI(int x, int y, int rotz, int scale)
|
|
{
|
|
NE_ViewMoveI(x, y, 0);
|
|
|
|
MATRIX_SCALE = scale;
|
|
MATRIX_SCALE = scale;
|
|
MATRIX_SCALE = inttof32(1);
|
|
|
|
glRotateZi(rotz << 6);
|
|
|
|
NE_ViewMoveI(-x, -y, 0);
|
|
}
|
|
|
|
void NE_2DViewRotateByPosition(int x, int y, int rotz)
|
|
{
|
|
NE_ViewMoveI(x, y, 0);
|
|
|
|
glRotateZi(rotz << 6);
|
|
|
|
NE_ViewMoveI(-x, -y, 0);
|
|
}
|
|
|
|
void NE_2DViewScaleByPositionI(int x, int y, int scale)
|
|
{
|
|
NE_ViewMoveI(x, y, 0);
|
|
|
|
MATRIX_SCALE = scale;
|
|
MATRIX_SCALE = scale;
|
|
MATRIX_SCALE = inttof32(1);
|
|
|
|
NE_ViewMoveI(-x, -y, 0);
|
|
}
|
|
|
|
void NE_2DDrawQuad(s16 x1, s16 y1, s16 x2, s16 y2, s16 z, u32 color)
|
|
{
|
|
GFX_BEGIN = GL_QUADS;
|
|
|
|
GFX_TEX_FORMAT = 0;
|
|
|
|
GFX_COLOR = color;
|
|
|
|
GFX_VERTEX16 = (y1 << 16) | (x1 & 0xFFFF); // Up-left
|
|
GFX_VERTEX16 = z;
|
|
|
|
GFX_VERTEX_XY = (y2 << 16) | (x1 & 0xFFFF); // Down-left
|
|
|
|
GFX_VERTEX_XY = (y2 << 16) | (x2 & 0xFFFF); // Down-right
|
|
|
|
GFX_VERTEX_XY = (y1 << 16) | (x2 & 0xFFFF); // Up-right
|
|
}
|
|
|
|
void NE_2DDrawQuadGradient(s16 x1, s16 y1, s16 x2, s16 y2, s16 z, u32 color1,
|
|
u32 color2, u32 color3, u32 color4)
|
|
{
|
|
GFX_BEGIN = GL_QUADS;
|
|
|
|
GFX_TEX_FORMAT = 0;
|
|
|
|
GFX_COLOR = color1;
|
|
GFX_VERTEX16 = (y1 << 16) | (x1 & 0xFFFF); // Up-left
|
|
GFX_VERTEX16 = z;
|
|
|
|
GFX_COLOR = color4;
|
|
GFX_VERTEX_XY = (y2 << 16) | (x1 & 0xFFFF); // Down-left
|
|
|
|
GFX_COLOR = color3;
|
|
GFX_VERTEX_XY = (y2 << 16) | (x2 & 0xFFFF); // Down-right
|
|
|
|
GFX_COLOR = color2;
|
|
GFX_VERTEX_XY = (y1 << 16) | (x2 & 0xFFFF); // Up-right
|
|
}
|
|
|
|
void NE_2DDrawTexturedQuad(s16 x1, s16 y1, s16 x2, s16 y2, s16 z,
|
|
const NE_Material *mat)
|
|
{
|
|
NE_AssertPointer(mat, "NULL pointer");
|
|
NE_Assert(mat->texindex != NE_NO_TEXTURE, "No texture");
|
|
|
|
int x = NE_TextureGetSizeX(mat), y = NE_TextureGetSizeY(mat);
|
|
|
|
NE_MaterialUse(mat);
|
|
|
|
GFX_BEGIN = GL_QUADS;
|
|
|
|
GFX_TEX_COORD = TEXTURE_PACK(0, 0);
|
|
GFX_VERTEX16 = (y1 << 16) | (x1 & 0xFFFF); // Up-left
|
|
GFX_VERTEX16 = z;
|
|
|
|
GFX_TEX_COORD = TEXTURE_PACK(0, inttot16(y));
|
|
GFX_VERTEX_XY = (y2 << 16) | (x1 & 0xFFFF); // Down-left
|
|
|
|
GFX_TEX_COORD = TEXTURE_PACK(inttot16(x), inttot16(y));
|
|
GFX_VERTEX_XY = (y2 << 16) | (x2 & 0xFFFF); // Down-right
|
|
|
|
GFX_TEX_COORD = TEXTURE_PACK(inttot16(x), 0);
|
|
GFX_VERTEX_XY = (y1 << 16) | (x2 & 0xFFFF); // Up-right
|
|
}
|
|
|
|
void NE_2DDrawTexturedQuadColor(s16 x1, s16 y1, s16 x2, s16 y2, s16 z,
|
|
const NE_Material *mat, u32 color)
|
|
{
|
|
NE_AssertPointer(mat, "NULL pointer");
|
|
NE_Assert(mat->texindex != NE_NO_TEXTURE, "No texture");
|
|
|
|
int x = NE_TextureGetSizeX(mat), y = NE_TextureGetSizeY(mat);
|
|
|
|
NE_MaterialUse(mat);
|
|
|
|
GFX_COLOR = color;
|
|
|
|
GFX_BEGIN = GL_QUADS;
|
|
|
|
GFX_TEX_COORD = TEXTURE_PACK(0, 0);
|
|
GFX_VERTEX16 = (y1 << 16) | (x1 & 0xFFFF); // Up-left
|
|
GFX_VERTEX16 = z;
|
|
|
|
GFX_TEX_COORD = TEXTURE_PACK(0, inttot16(y));
|
|
GFX_VERTEX_XY = (y2 << 16) | (x1 & 0xFFFF); // Down-left
|
|
|
|
GFX_TEX_COORD = TEXTURE_PACK(inttot16(x), inttot16(y));
|
|
GFX_VERTEX_XY = (y2 << 16) | (x2 & 0xFFFF); // Down-right
|
|
|
|
GFX_TEX_COORD = TEXTURE_PACK(inttot16(x), 0);
|
|
GFX_VERTEX_XY = (y1 << 16) | (x2 & 0xFFFF); // Up-right
|
|
}
|
|
|
|
void NE_2DDrawTexturedQuadGradient(s16 x1, s16 y1, s16 x2, s16 y2, s16 z,
|
|
const NE_Material *mat, u32 color1,
|
|
u32 color2, u32 color3, u32 color4)
|
|
{
|
|
NE_AssertPointer(mat, "NULL pointer");
|
|
NE_Assert(mat->texindex != NE_NO_TEXTURE, "No texture");
|
|
|
|
int x = NE_TextureGetSizeX(mat), y = NE_TextureGetSizeY(mat);
|
|
|
|
NE_MaterialUse(mat);
|
|
|
|
GFX_BEGIN = GL_QUADS;
|
|
|
|
GFX_COLOR = color1;
|
|
GFX_TEX_COORD = TEXTURE_PACK(0, 0);
|
|
GFX_VERTEX16 = (y1 << 16) | (x1 & 0xFFFF); // Up-left
|
|
GFX_VERTEX16 = z;
|
|
|
|
GFX_COLOR = color4;
|
|
GFX_TEX_COORD = TEXTURE_PACK(0, inttot16(y));
|
|
GFX_VERTEX_XY = (y2 << 16) | (x1 & 0xFFFF); // Down-left
|
|
|
|
GFX_COLOR = color3;
|
|
GFX_TEX_COORD = TEXTURE_PACK(inttot16(x), inttot16(y));
|
|
GFX_VERTEX_XY = (y2 << 16) | (x2 & 0xFFFF); // Down-right
|
|
|
|
GFX_COLOR = color2;
|
|
GFX_TEX_COORD = TEXTURE_PACK(inttot16(x), 0);
|
|
GFX_VERTEX_XY = (y1 << 16) | (x2 & 0xFFFF); // Up-right
|
|
}
|