mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2024-11-25 15:15:40 +00:00
c039d08c03
Late christmas present. Due to the way alpha works on the model3 adding regular anti-aliasing doesn't really work. Supersampling is very much a brute force solution, render the scene at a higher resolution and mipmap it. It's enabled via command line with the -ss option, for example -ss=4 for 4x supersampling or by adding Supersampling = 4 in the config file. Note non power of two values work as well, so 3 gives a very good balance between speed and quality. 8 will make your GPU bleed, since it is essentially rendering 64 pixels for every visible pixel on the screen.
538 lines
18 KiB
C++
538 lines
18 KiB
C++
/**
|
|
** Supermodel
|
|
** A Sega Model 3 Arcade Emulator.
|
|
** Copyright 2011 Bart Trzynadlowski, Nik Henson
|
|
**
|
|
** This file is part of Supermodel.
|
|
**
|
|
** Supermodel 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 3 of the License, or (at your option)
|
|
** any later version.
|
|
**
|
|
** Supermodel 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.
|
|
**
|
|
** You should have received a copy of the GNU General Public License along
|
|
** with Supermodel. If not, see <http://www.gnu.org/licenses/>.
|
|
**/
|
|
|
|
/*
|
|
* Legacy3D.h
|
|
*
|
|
* Header file defining the CLegacy3D class: Supermodel's original OpenGL
|
|
* Real3D graphics engine.
|
|
*/
|
|
|
|
#ifndef INCLUDED_LEGACY3D_H
|
|
#define INCLUDED_LEGACY3D_H
|
|
|
|
#include "TextureRefs.h"
|
|
#include "Graphics/IRender3D.h"
|
|
#include <GL/glew.h>
|
|
#include "Util/NewConfig.h"
|
|
#include "Types.h"
|
|
|
|
namespace Legacy3D {
|
|
|
|
/******************************************************************************
|
|
Internal Definitions and Data Structures
|
|
******************************************************************************/
|
|
|
|
// Model caches sort models by alpha (translucency) state
|
|
enum POLY_STATE
|
|
{
|
|
POLY_STATE_NORMAL = 0,
|
|
POLY_STATE_ALPHA
|
|
};
|
|
|
|
struct Vertex
|
|
{
|
|
GLfloat x,y,z; // vertex
|
|
GLfloat n[3]; // normal X, Y, Z
|
|
GLfloat u,v; // texture U, V coordinates (in texels, relative to selected texture)
|
|
GLfloat intensity; // shading intensity (if using per-vertex fixed shading)
|
|
};
|
|
|
|
struct Poly
|
|
{
|
|
Vertex Vert[4];
|
|
GLfloat n[3]; // polygon normal (used for backface culling and flat shading)
|
|
POLY_STATE state; // alpha or normal?
|
|
unsigned numVerts; // triangle (3) or quad (4)
|
|
const UINT32 *header; // pointer to Real3D 7-word polygon header
|
|
};
|
|
|
|
/*
|
|
* VBORef:
|
|
*
|
|
* Reference to model polygons stored in a VBO. Each reference has two sets of
|
|
* vertices: normal and alpha. Copies of the model with different texture
|
|
* offsets applied are searchable via the linked list of texture offset states.
|
|
*
|
|
* Technically, a model may contain a mix of layered and non-layered polygons
|
|
* but we can't support that level of granularity in the current engine. The
|
|
* useStencil flag is set only when all polygons in a model are layered, and
|
|
* also may be set when we detect that a polygon is likely to be used as a
|
|
* shadow. On the actual hardware, these are not stenciled but are most likely
|
|
* implemented with stipple masks. We cheat here to make shadows look nicer.
|
|
*/
|
|
|
|
struct VBORef
|
|
{
|
|
unsigned index[2]; // index of model polygons in VBO
|
|
unsigned numVerts[2]; // number of vertices
|
|
unsigned lutIdx; // LUT index associated with this model (for fast LUT clearing)
|
|
|
|
VBORef *nextTextureOffsetState; // linked list of models with different texture offset states
|
|
uint16_t textureOffsetState; // texture offset data for this model
|
|
bool useStencil; // whether to draw with stencil mask ("layered" polygons)
|
|
|
|
CTextureRefs texRefs; // unique texture references contained in this model
|
|
|
|
/*
|
|
* Clear():
|
|
*
|
|
* Clears the VBORef by setting all fields to 0 and clearing the texture
|
|
* references.
|
|
*/
|
|
inline void Clear(void)
|
|
{
|
|
texRefs.Clear();
|
|
lutIdx = 0;
|
|
textureOffsetState = 0;
|
|
nextTextureOffsetState = NULL;
|
|
useStencil = false;
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
index[i] = 0;
|
|
numVerts[i] = 0;
|
|
}
|
|
}
|
|
};
|
|
|
|
// Display list items: model instances and viewport settings
|
|
struct DisplayList
|
|
{
|
|
// Viewport instance data
|
|
struct ViewportInstance
|
|
{
|
|
GLfloat projectionMatrix[4*4]; // projection matrix
|
|
GLfloat lightingParams[6]; // lighting parameters (see RenderViewport() and vertex shader)
|
|
GLfloat spotEllipse[4]; // spotlight ellipse (see RenderViewport())
|
|
GLfloat spotRange[2]; // Z range
|
|
GLfloat spotColor[3]; // color
|
|
GLfloat fogParams[5]; // fog parameters (...)
|
|
GLint x, y; // viewport coordinates (scaled and in OpenGL format)
|
|
GLint width, height; // viewport dimensions (scaled for display surface size)
|
|
};
|
|
|
|
// Model instance data
|
|
struct ModelInstance
|
|
{
|
|
GLfloat modelViewMatrix[4*4]; // model-view matrix
|
|
unsigned index; // index in VBO
|
|
unsigned numVerts; // number of vertices
|
|
GLint frontFace; // GL_CW (default), GL_CCW, or -GL_CW to indicate no culling
|
|
bool useStencil; // draw with stencil testing
|
|
};
|
|
|
|
bool isViewport; // if true, this is a viewport node
|
|
union
|
|
{
|
|
ModelInstance Model;
|
|
ViewportInstance Viewport;
|
|
} Data;
|
|
DisplayList *next; // next display list item with the same state (alpha or non-alpha)
|
|
};
|
|
|
|
/*
|
|
* ModelCache:
|
|
*
|
|
* A model cache tracks all models in a particular region (ie., VROM or polygon
|
|
* RAM). It contains a look-up table to quickly obtain VBO indices. Be careful
|
|
* when accessing the LUT, there are some special cases.
|
|
*
|
|
* If the model cache is marked dynamic, cached models may not necessarily be
|
|
* retained. Clearing the model cache is also much faster. The LUT entry for
|
|
* the last model cached will be valid, but because the LUT may not be
|
|
* cleared, one cannot assume a model exists because there is a LUT entry
|
|
* pointing to it. Always use NeedToCache() to determine whether caching is
|
|
* necessary before reading the LUT!
|
|
*/
|
|
struct ModelCache
|
|
{
|
|
// Cache type
|
|
bool dynamic;
|
|
|
|
// Vertex buffer object
|
|
unsigned vboMaxOffset; // size of VBO (in bytes)
|
|
unsigned vboCurOffset; // current offset in VBO (in bytes)
|
|
GLuint vboID; // OpenGL VBO handle
|
|
|
|
// Local vertex buffers (enough for a single model)
|
|
unsigned maxVertIdx; // size of each local vertex buffer (in vertices)
|
|
unsigned curVertIdx[2]; // current vertex index (in vertices)
|
|
GLfloat *verts[2];
|
|
|
|
// Array of cached models
|
|
unsigned maxModels; // maximum number of models
|
|
unsigned numModels; // current number stored
|
|
VBORef *Models;
|
|
|
|
/*
|
|
* Look-Up Table:
|
|
*
|
|
* Can be accessed directly with a LUT index to determine the model index.
|
|
* However, it should not be used to determine whether a model needs to be
|
|
* cached. Use NeedToCache() instead. A valid index, for example, may still
|
|
* have to be re-cached if the model cache is dynamic (polygon RAM).
|
|
*/
|
|
unsigned lutSize; // number of elements in LUT
|
|
INT16 *lut; // stores indices into Models[] or -1 if not yet cached
|
|
|
|
// Display list
|
|
unsigned maxListSize; // maximum number of display list items
|
|
unsigned listSize; // number of items in display list
|
|
DisplayList *List; // holds all display list items
|
|
DisplayList *ListHead[2]; // heads of linked lists for each state
|
|
DisplayList *ListTail[2]; // current tail node for each state
|
|
};
|
|
|
|
struct TexSheet
|
|
{
|
|
unsigned sheetNum;
|
|
unsigned mapNum;
|
|
unsigned xOffset;
|
|
unsigned yOffset;
|
|
|
|
/*
|
|
* Texture Format Buffer
|
|
*
|
|
* Records the format that a texture (at a given location within the
|
|
* texture sheet) is currently stored in. A negative value indicates the
|
|
* texture has not been accessed and converted yet and non-negative values
|
|
* correspond to the texture format bits in the polygon headers. They can
|
|
* be used to determine whether a texture needs to be updated.
|
|
*/
|
|
int texWidth[2048/32][2048/32];
|
|
int texHeight[2048/32][2048/32];
|
|
INT8 texFormat[2048/32][2048/32];
|
|
};
|
|
|
|
/******************************************************************************
|
|
CLegacy3D Classes
|
|
******************************************************************************/
|
|
|
|
/*
|
|
* CLegacy3D:
|
|
*
|
|
* 3D renderer. Lots of work to do here :)
|
|
*/
|
|
class CLegacy3D: public IRender3D
|
|
{
|
|
friend class CTextureRefs;
|
|
|
|
public:
|
|
/*
|
|
* RenderFrame(void):
|
|
*
|
|
* Renders the complete scene database. Must be called between BeginFrame() and
|
|
* EndFrame(). This function traverses the scene database and builds up display
|
|
* lists.
|
|
*/
|
|
void RenderFrame(void);
|
|
|
|
/*
|
|
* BeginFrame(void):
|
|
*
|
|
* Prepare to render a new frame. Must be called once per frame prior to
|
|
* drawing anything.
|
|
*/
|
|
void BeginFrame(void);
|
|
|
|
/*
|
|
* EndFrame(void):
|
|
*
|
|
* Signals the end of rendering for this frame. Must be called last during
|
|
* the frame.
|
|
*/
|
|
void EndFrame(void);
|
|
|
|
/*
|
|
* UploadTextures(x, y, width, height):
|
|
*
|
|
* Signals that a portion of texture RAM has been updated.
|
|
*
|
|
* Parameters:
|
|
* x X position within texture RAM.
|
|
* y Y position within texture RAM.
|
|
* width Width of texture data in texels.
|
|
* height Height.
|
|
*/
|
|
void UploadTextures(unsigned level, unsigned x, unsigned y, unsigned width, unsigned height);
|
|
|
|
/*
|
|
* AttachMemory(cullingRAMLoPtr, cullingRAMHiPtr, polyRAMPtr, vromPtr,
|
|
* textureRAMPtr):
|
|
*
|
|
* Attaches RAM and ROM areas. This must be done prior to any rendering
|
|
* otherwise the program may crash with an access violation.
|
|
*
|
|
* Parameters:
|
|
* cullingRAMLoPtr Pointer to low culling RAM (4 MB).
|
|
* cullingRAMHiPtr Pointer to high culling RAM (1 MB).
|
|
* polyRAMPtr Pointer to polygon RAM (4 MB).
|
|
* vromPtr Pointer to video ROM (64 MB).
|
|
* textureRAMPtr Pointer to texture RAM (8 MB).
|
|
*/
|
|
void AttachMemory(const UINT32 *cullingRAMLoPtr,
|
|
const UINT32 *cullingRAMHiPtr, const UINT32 *polyRAMPtr,
|
|
const UINT32 *vromPtr, const UINT16 *textureRAMPtr);
|
|
|
|
/*
|
|
* SetStepping(stepping):
|
|
*
|
|
* Sets the Model 3 hardware stepping, which also determines the Real3D
|
|
* functionality. The default is Step 1.0. This should be called prior to
|
|
* any other emulation functions and after Init().
|
|
*
|
|
* Parameters:
|
|
* stepping 0x10 for Step 1.0, 0x15 for Step 1.5, 0x20 for Step 2.0, or
|
|
* 0x21 for Step 2.1. Anything else defaults to 1.0.
|
|
*/
|
|
void SetStepping(int stepping);
|
|
|
|
/*
|
|
* Init(xOffset, yOffset, xRes, yRes, totalXRes, totalYRes):
|
|
*
|
|
* One-time initialization of the context. Must be called before any other
|
|
* members (meaning it should be called even before being attached to any
|
|
* other objects that want to use it).
|
|
*
|
|
* External shader files are loaded according to configuration settings.
|
|
*
|
|
* Parameters:
|
|
* xOffset X offset of the viewable area within OpenGL display
|
|
* surface, in pixels.
|
|
* yOffset Y offset.
|
|
* xRes Horizontal resolution of the viewable area.
|
|
* yRes Vertical resolution.
|
|
* totalXRes Horizontal resolution of the complete display area.
|
|
* totalYRes Vertical resolution.
|
|
*
|
|
* Returns:
|
|
* OKAY is successful, otherwise FAILED if a non-recoverable error
|
|
* occurred. Any allocated memory will not be freed until the
|
|
* destructor is called. Prints own error messages.
|
|
*/
|
|
bool Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes, unsigned totalXRes, unsigned totalYRes, unsigned aaTarget);
|
|
|
|
/*
|
|
* SetSunClamp(bool enable);
|
|
*
|
|
* Sets or unsets the clamped light model
|
|
*
|
|
* Parameters:
|
|
* enable Set clamp mode
|
|
*/
|
|
void SetSunClamp(bool enable);
|
|
|
|
/*
|
|
* SetSignedShade(bool enable);
|
|
*
|
|
* Sets the sign-ness of fixed shading value
|
|
*
|
|
* Parameters:
|
|
* enable Fixed shading is expressed as signed value
|
|
*/
|
|
void SetSignedShade(bool enable);
|
|
|
|
/*
|
|
* GetLosValue(int layer);
|
|
*
|
|
* Gets the line of sight value for the priority layer
|
|
*
|
|
* Parameters:
|
|
* layer Priority layer to read from
|
|
*/
|
|
float GetLosValue(int layer);
|
|
|
|
/*
|
|
* CLegacy3D(void):
|
|
* ~CLegacy3D(void):
|
|
*
|
|
* Parameters:
|
|
* config Configuration object.
|
|
*
|
|
* Constructor and destructor.
|
|
*/
|
|
CLegacy3D(const Util::Config::Node &config);
|
|
~CLegacy3D(void);
|
|
|
|
private:
|
|
/*
|
|
* Private Members
|
|
*/
|
|
|
|
// Real3D address translation
|
|
const UINT32 *TranslateCullingAddress(UINT32 addr);
|
|
const UINT32 *TranslateModelAddress(UINT32 addr);
|
|
|
|
// Model caching and display list management
|
|
void DrawDisplayList(ModelCache *Cache, POLY_STATE state);
|
|
bool AppendDisplayList(ModelCache *Cache, bool isViewport, const struct VBORef *Model);
|
|
void ClearDisplayList(ModelCache *Cache);
|
|
int GetTextureBaseX(const Poly *P) const;
|
|
int GetTextureBaseY(const Poly *P) const;
|
|
bool InsertPolygon(ModelCache *cache, const Poly *p);
|
|
void InsertVertex(ModelCache *cache, const Vertex *v, const Poly *p, float normFlip);
|
|
struct VBORef *BeginModel(ModelCache *cache);
|
|
void EndModel(ModelCache *cache, struct VBORef *Model, int lutIdx, UINT16 textureOffsetState, bool useStencil);
|
|
struct VBORef *CacheModel(ModelCache *cache, int lutIdx, UINT16 textureOffsetState, const UINT32 *data);
|
|
struct VBORef *LookUpModel(ModelCache *cache, int lutIdx, UINT16 textureOffsetState);
|
|
void ClearModelCache(ModelCache *cache);
|
|
bool CreateModelCache(ModelCache *cache, unsigned vboMaxVerts, unsigned localMaxVerts, unsigned maxNumModels, unsigned numLUTEntries, unsigned displayListSize, bool isDynamic);
|
|
void DestroyModelCache(ModelCache *cache);
|
|
|
|
// Texture management
|
|
void DecodeTexture(int format, int x, int y, int width, int height);
|
|
|
|
// Matrix stack
|
|
void MultMatrix(UINT32 matrixOffset);
|
|
void InitMatrixStack(UINT32 matrixBaseAddr);
|
|
|
|
// Scene database traversal
|
|
bool DrawModel(UINT32 modelAddr);
|
|
void DescendCullingNode(UINT32 addr);
|
|
void DescendPointerList(UINT32 addr);
|
|
void DescendNodePtr(UINT32 nodeAddr);
|
|
void RenderViewport(UINT32 addr, int pri, bool wideScreen);
|
|
|
|
// In-frame error reporting
|
|
bool ErrorLocalVertexOverflow(void);
|
|
bool ErrorUnableToCacheModel(UINT32 modelAddr);
|
|
void ClearErrors(void);
|
|
|
|
/*
|
|
* Data
|
|
*/
|
|
|
|
const Util::Config::Node &m_config;
|
|
|
|
#ifdef DEBUG
|
|
// Debug
|
|
int m_debugHighlightPolyHeaderIdx = -1;
|
|
uint32_t m_debugHighlightPolyHeaderMask = 0;
|
|
int m_debugHighlightCullingNodeIdx = -1;
|
|
uint32_t m_debugHighlightCullingNodeMask = 0;
|
|
bool m_debugHighlightAll = false;
|
|
#endif
|
|
|
|
// Stepping
|
|
int step;
|
|
int offset; // offset to subtract for words 3 and higher of culling nodes
|
|
GLfloat vertexFactor; // fixed-point conversion factor for vertices
|
|
|
|
// Memory (passed from outside)
|
|
const UINT32 *cullingRAMLo; // 4 MB
|
|
const UINT32 *cullingRAMHi; // 1 MB
|
|
const UINT32 *polyRAM; // 4 MB
|
|
const UINT32 *vrom; // 64 MB
|
|
const UINT16 *textureRAM; // 8 MB
|
|
|
|
// Error reporting
|
|
unsigned errorMsgFlags; // tracks which errors have been printed this frame
|
|
|
|
// Real3D Base Matrix Pointer
|
|
const float *matrixBasePtr;
|
|
|
|
// Current viewport parameters (updated as viewports are traversed)
|
|
GLfloat lightingParams[6];
|
|
GLfloat fogParams[5];
|
|
GLfloat spotEllipse[4];
|
|
GLfloat spotRange[2];
|
|
GLfloat spotColor[3];
|
|
GLint viewportX, viewportY;
|
|
GLint viewportWidth, viewportHeight;
|
|
GLuint m_aaTarget;
|
|
|
|
// Scene graph processing
|
|
int listDepth; // how many lists have we recursed into
|
|
int stackDepth; // for debugging and error handling purposes
|
|
struct TextureOffset
|
|
{
|
|
int x; // x offset
|
|
int y; // y offset (wraps within 2048x1023 texel bank)
|
|
int switchBank; // 0: use bank from polygon header, 1024: swap banks
|
|
uint16_t state; // x, y, and bank states compromise a unique key
|
|
TextureOffset(uint32_t data)
|
|
: x(32 * ((data >> 7) & 0x7F)),
|
|
y(32 * (data & 0x7F)),
|
|
switchBank((data & 0x4000) >> 4),
|
|
state(data & 0x7FFF)
|
|
{}
|
|
TextureOffset()
|
|
: x(0),
|
|
y(0),
|
|
switchBank(false),
|
|
state(0)
|
|
{}
|
|
} m_textureOffset;
|
|
UINT32 m_colorTableAddr = 0x400; // address of color table in polygon RAM
|
|
|
|
// Resolution and scaling factors (to support resolutions higher than 496x384) and offsets
|
|
GLfloat xRatio, yRatio;
|
|
unsigned xOffs, yOffs;
|
|
unsigned totalXRes, totalYRes;
|
|
|
|
// Texture details
|
|
static int defaultFmtToTexSheetNum[8]; // default mapping from Model3 texture format to texture sheet
|
|
unsigned numTexMaps; // total number of texture maps
|
|
GLuint texMapIDs[9]; // GL texture IDs of texture maps
|
|
unsigned numTexSheets; // total number of texture sheets
|
|
TexSheet *texSheets; // texture sheet objects
|
|
TexSheet *fmtToTexSheet[8]; // final mapping from Model3 texture format to texture sheet
|
|
|
|
// Shader programs and input data locations
|
|
GLuint shaderProgram; // shader program object
|
|
GLuint vertexShader; // vertex shader handle
|
|
GLuint fragmentShader; // fragment shader
|
|
GLint textureMapLoc; // location of "textureMap" uniform (if available)
|
|
GLint textureMapLocs[8]; // location of "textureMap[0-7]" uniforms (if available)
|
|
GLint modelViewMatrixLoc; // uniform
|
|
GLint projectionMatrixLoc; // uniform
|
|
GLint lightingLoc; // uniform
|
|
GLint mapSizeLoc; // uniform
|
|
GLint spotEllipseLoc; // uniform
|
|
GLint spotRangeLoc; // uniform
|
|
GLint spotColorLoc; // uniform
|
|
GLint subTextureLoc; // attribute
|
|
GLint texParamsLoc; // attribute
|
|
GLint texFormatLoc; // attribute
|
|
GLint texMapLoc; // attribute
|
|
GLint transLevelLoc; // attribute
|
|
GLint lightEnableLoc; // attribute
|
|
GLint specularLoc; // attribute
|
|
GLint shininessLoc; // attribute
|
|
GLint fogIntensityLoc; // attribute
|
|
|
|
// Model caching
|
|
ModelCache VROMCache; // VROM (static) models
|
|
ModelCache PolyCache; // polygon RAM (dynamic) models
|
|
|
|
/*
|
|
* Texture Decode Buffer
|
|
*
|
|
* Textures are decoded and copied from texture RAM into this temporary buffer
|
|
* before being uploaded. Dimensions are 512x512.
|
|
*/
|
|
GLfloat *textureBuffer; // RGBA8 format
|
|
};
|
|
|
|
} // Legacy3D
|
|
|
|
#endif // INCLUDED_LEGACY3D_H
|