Kart-Public/src/nds/r_nds3d.c

390 lines
9.2 KiB
C

// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// Copyright (C) 1993-1996 by id Software, Inc.
// Portions Copyright (C) 1998-2000 by DooM Legacy Team.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//-----------------------------------------------------------------------------
/// \file
/// \brief NDS 3D API for SRB2.
//
// In an ideal world, we would share as much code as possible with r_opengl.c,
// but this will do for now.
#include "../doomtype.h"
#include "../hardware/hw_defs.h"
#include "../hardware/hw_dll.h"
#include "../hardware/hw_md2.h"
#include "r_nds3d.h"
static I_Error_t I_Error_GL = NULL;
#define NOTEXTURE_NUM 0 // small white texture
#define FIRST_TEX_AVAIL (NOTEXTURE_NUM + 1)
#define MAX_SRB2_TEXTURES 256
FCOORD NEAR_CLIPPING_PLANE = 0.9f;
float fov = 90.0f;
static FBITFIELD CurrentPolyFlags = 0xFFFFFFFF;
static UINT32 CurrentGLPolyFmt = POLY_CULL_NONE;
static UINT8 CurrentPolyAlpha = 31;
static UINT16 myPaletteData[256];
static FTextureInfo* gr_cachetail = NULL;
static FTextureInfo* gr_cachehead = NULL;
static INT32 NextTexAvail = FIRST_TEX_AVAIL;
static UINT32 tex_downloaded = 0;
static INT32 texids[MAX_SRB2_TEXTURES];
static boolean scalehack = false;
static void GenerateTextureNames(void)
{
glGenTextures(MAX_SRB2_TEXTURES - 1, texids + 1);
texids[NOTEXTURE_NUM] = 0;
}
static void Flush(void)
{
// Delete all textures at once, since libnds's glDeleteTextures seems to be buggy.
glResetTextures();
GenerateTextureNames();
while (gr_cachehead)
{
gr_cachehead->downloaded = 0;
gr_cachehead = gr_cachehead->nextmipmap;
}
gr_cachetail = gr_cachehead = NULL;
NextTexAvail = FIRST_TEX_AVAIL;
tex_downloaded = 0;
}
static void SetNoTexture(void)
{
// Set small white texture.
if (tex_downloaded != NOTEXTURE_NUM)
{
glBindTexture(GL_TEXTURE_2D, texids[NOTEXTURE_NUM]);
tex_downloaded = NOTEXTURE_NUM;
}
}
static void SetAlpha(UINT8 alpha)
{
CurrentPolyAlpha = alpha >> 3;
glPolyFmt(CurrentGLPolyFmt | POLY_ALPHA(CurrentPolyAlpha));
}
boolean NDS3D_Init(I_Error_t ErrorFunction)
{
I_Error_GL = ErrorFunction;
glPolyFmt(CurrentGLPolyFmt | POLY_ALPHA(CurrentPolyAlpha));
GenerateTextureNames();
return true;
}
void NDS3D_Shutdown(void) {}
void NDS3D_SetPalette(RGBA_t *ppal, RGBA_t *pgamma)
{
INT32 i;
for (i = 0; i < 256; i++)
{
UINT8 red = (UINT8)min((ppal[i].s.red*pgamma->s.red)/127, 255) >> 3;
UINT8 green = (UINT8)min((ppal[i].s.green*pgamma->s.green)/127, 255) >> 3;
UINT8 blue = (UINT8)min((ppal[i].s.blue*pgamma->s.blue)/127, 255) >> 3;
myPaletteData[i] = ARGB16(ppal[i].s.alpha ? 1 : 0, red, green, blue);
}
Flush();
}
void NDS3D_FinishUpdate(INT32 waitvbl)
{
(void)waitvbl;
glFlush(0);
}
void NDS3D_Draw2DLine(F2DCoord *v1, F2DCoord *v2, RGBA_t Color)
{
(void)v1;
(void)v2;
(void)Color;
}
void NDS3D_DrawPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags)
{
FUINT i;
NDS3D_SetBlend(PolyFlags);
// If Modulated, mix the surface colour to the texture
if ((CurrentPolyFlags & PF_Modulated) && pSurf)
{
glColor3b(pSurf->FlatColor.s.red, pSurf->FlatColor.s.green, pSurf->FlatColor.s.blue);
SetAlpha(pSurf->FlatColor.s.alpha);
}
// libnds doesn't have GL_TRIANGLE_FAN, so use GL_TRIANGLE_STRIP instead
glBegin(GL_TRIANGLE_STRIP);
for (i = 0; i < iNumPts; i++)
{
FUINT index = (i & 1) ? (i >> 1) : (iNumPts - 1 - (i >> 1));
FLOAT x, y, z;
if (scalehack)
{
x = pOutVerts[index].x/4096.0f;
y = pOutVerts[index].y/4096.0f;
z = pOutVerts[index].z/4096.0f;
}
else
{
x = pOutVerts[index].x;
y = pOutVerts[index].y;
z = pOutVerts[index].z;
}
glTexCoord2f(pOutVerts[index].s, pOutVerts[index].tow);
glVertex3f(x,y,z);
}
glEnd();
}
void NDS3D_SetBlend(FBITFIELD PolyFlags)
{
FBITFIELD Xor = PolyFlags ^ CurrentPolyFlags;
if (Xor & (PF_NoTexture|PF_Modulated))
{
if (Xor&PF_Modulated)
{
if(!(PolyFlags & PF_Modulated))
{
glColor3b(255, 255, 255);
CurrentPolyAlpha = 31;
}
}
if (PolyFlags & PF_NoTexture)
{
SetNoTexture();
}
}
CurrentPolyFlags = PolyFlags;
glPolyFmt(CurrentGLPolyFmt | POLY_ALPHA(CurrentPolyAlpha));
}
void NDS3D_ClearBuffer(FBOOLEAN ColorMask, FBOOLEAN DepthMask, FRGBAFloat *ClearColor)
{
(void)ClearColor;
if (ColorMask && ClearColor)
{
// TODO: Fixed-ify
glClearColor((uint8)(ClearColor->red*31),
(uint8)(ClearColor->green*31),
(uint8)(ClearColor->blue*31),
(uint8)(ClearColor->alpha*31));
}
if (DepthMask)
glClearDepth(GL_MAX_DEPTH);
NDS3D_SetBlend(DepthMask ? PF_Occlude | CurrentPolyFlags : CurrentPolyFlags&~PF_Occlude);
}
void NDS3D_SetTexture(FTextureInfo *TexInfo)
{
if (!TexInfo)
{
SetNoTexture();
return;
}
else if (TexInfo->downloaded)
{
if (TexInfo->downloaded != tex_downloaded)
{
glBindTexture(GL_TEXTURE_2D, texids[TexInfo->downloaded]);
tex_downloaded = TexInfo->downloaded;
}
}
else if (TexInfo->grInfo.data)
{
UINT8 wtype, htype;
INT32 texparam = GL_TEXTURE_COLOR0_TRANSPARENT;
// We rely on the numerical values of GL_TEXTURE_SIZE_ENUM here.
wtype = TEXTURE_SIZE_8;
while(TexInfo->width > 1 << (wtype + 3)) wtype++;
htype = TEXTURE_SIZE_8;
while(TexInfo->height > 1 << (htype + 3)) htype++;
TexInfo->downloaded = NextTexAvail++;
tex_downloaded = TexInfo->downloaded;
glBindTexture(GL_TEXTURE_2D, texids[TexInfo->downloaded]);
if(!glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB256, wtype, htype, 0, TEXGEN_TEXCOORD, TexInfo->grInfo.data))
{
// HACK: If we're out of memory, flush and try again.
// This will result in artefacts for one frame.
Flush();
TexInfo->downloaded = 0;
NDS3D_SetTexture(TexInfo);
return;
}
if (TexInfo->downloaded > FIRST_TEX_AVAIL)
{
// We already have a texture using the palette, so it's already in VRAM
glAssignColorTable(GL_TEXTURE_2D, texids[FIRST_TEX_AVAIL]);
}
else
{
// Generate the palette in hardware
glColorTableEXT(0, 0, 256, 0, 0, myPaletteData);
}
if (TexInfo->flags & TF_WRAPX)
texparam |= GL_TEXTURE_WRAP_S;
if (TexInfo->flags & TF_WRAPY)
texparam |= GL_TEXTURE_WRAP_T;
glTexParameter(0, texparam);
TexInfo->nextmipmap = NULL;
if (gr_cachetail)
{
gr_cachetail->nextmipmap = TexInfo;
gr_cachetail = TexInfo;
}
else
gr_cachetail = gr_cachehead = TexInfo;
}
}
void NDS3D_ReadRect(INT32 x, INT32 y, INT32 width, INT32 height, INT32 dst_stride, UINT16 *dst_data)
{
(void)x;
(void)y;
(void)width;
(void)height;
(void)dst_stride;
(void)dst_data;
}
void NDS3D_GClipRect(INT32 minx, INT32 miny, INT32 maxx, INT32 maxy, float nearclip)
{
(void)minx;
(void)miny;
(void)maxx;
(void)maxy;
//glViewport(minx, vid.height-maxy, maxx-minx, maxy-miny);
NEAR_CLIPPING_PLANE = nearclip;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(fov, ASPECT_RATIO, NEAR_CLIPPING_PLANE, FAR_CLIPPING_PLANE);
glMatrixMode(GL_MODELVIEW);
}
void NDS3D_ClearMipMapCache(void) {}
void NDS3D_SetSpecialState(hwdspecialstate_t IdState, INT32 Value)
{
(void)IdState;
(void)Value;
}
void NDS3D_DrawMD2(INT32 *gl_cmd_buffer, md2_frame_t *frame, FTransform *pos, float scale)
{
(void)gl_cmd_buffer;
(void)frame;
(void)pos;
(void)scale;
}
void NDS3D_DrawMD2i(INT32 *gl_cmd_buffer, md2_frame_t *frame, UINT32 duration, UINT32 tics, md2_frame_t *nextframe, FTransform *pos, float scale, UINT8 flipped, UINT8 *color)
{
(void)gl_cmd_buffer;
(void)frame;
(void)duration;
(void)tics;
(void)nextframe;
(void)pos;
(void)scale;
(void)flipped;
(void)color;
}
void NDS3D_SetTransform(FTransform *ptransform)
{
static INT32 special_splitscreen;
glLoadIdentity();
if (ptransform)
{
scalehack = true;
glScalef(ptransform->scalex*4096.0f, ptransform->scaley*4096.0f, -ptransform->scalez*4096.0f);
glRotatef(ptransform->anglex , 1.0f, 0.0f, 0.0f);
glRotatef(ptransform->angley+270.0f, 0.0f, 1.0f, 0.0f);
glTranslatef(-ptransform->x/4096.0f, -ptransform->z/4096.0f, -ptransform->y/4096.0f);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
special_splitscreen = (ptransform->splitscreen && ptransform->fovxangle == 90.0f);
if (special_splitscreen)
gluPerspective(53.13l, 2*ASPECT_RATIO, // 53.13 = 2*atan(0.5)
NEAR_CLIPPING_PLANE, FAR_CLIPPING_PLANE);
else
gluPerspective(ptransform->fovxangle, ASPECT_RATIO, NEAR_CLIPPING_PLANE, FAR_CLIPPING_PLANE);
glMatrixMode(GL_MODELVIEW);
}
else
{
scalehack = false;
glScalef(1.0f, 1.0f, -1.0f);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (special_splitscreen)
gluPerspective(53.13l, 2*ASPECT_RATIO, // 53.13 = 2*atan(0.5)
NEAR_CLIPPING_PLANE, FAR_CLIPPING_PLANE);
else
//Hurdler: is "fov" correct?
gluPerspective(fov, ASPECT_RATIO, NEAR_CLIPPING_PLANE, FAR_CLIPPING_PLANE);
glMatrixMode(GL_MODELVIEW);
}
}
INT32 NDS3D_GetTextureUsed(void)
{
return 0;
}
INT32 NDS3D_GetRenderVersion(void)
{
return 0;
}