librw/src/charset.cpp

234 lines
5.0 KiB
C++
Raw Normal View History

2020-04-19 09:58:53 +02:00
#include <cstdio>
#include "rwbase.h"
#include "rwerror.h"
#include "rwplg.h"
#include "rwrender.h"
#include "rwpipeline.h"
#include "rwobjects.h"
#include "rwengine.h"
#include "rwcharset.h"
#include "ps2/rwps2.h"
#include "d3d/rwd3d.h"
#include "gl/rwgl3.h"
#define PLUGIN_ID 1000 // TODO: find a better ID
#ifndef RW_NULL
#ifdef RWHALFPIXEL
#define HALFPX (0.5f)
#else
#define HALFPX (0.0f)
#endif
namespace rw {
const uint8 fontbits[256*256] = {
#include "vgafont.inc"
};
#define NUMCHARS 100
static uint16 *indices;
static RWDEVICE::Im2DVertex *vertices;
static int32 numChars;
static Raster *lastRaster;
bool32
Charset::open(void)
{
if(indices || vertices)
return 0;
numChars = 0;
lastRaster = nil;
indices = rwNewT(uint16, NUMCHARS*6, MEMDUR_EVENT);
vertices = rwNewT(RWDEVICE::Im2DVertex, NUMCHARS*4, MEMDUR_EVENT);
if(indices == nil || vertices == nil){
close();
return 0;
}
return 1;
}
void
Charset::close(void)
{
rwFree(indices);
rwFree(vertices);
}
Charset*
Charset::create(RGBA *foreground, RGBA *background)
{
Charset *charset = (Charset*)rwMalloc(sizeof(Charset), MEMDUR_EVENT);
if(charset == nil){
RWERROR((ERR_ALLOC, sizeof(Charset)));
return nil;
}
charset->raster = nil;
if(charset->setColors(foreground, background) == nil){
charset->destroy();
return nil;
}
charset->desc.count = 256;
charset->desc.tileWidth = 28;
charset->desc.tileHeight = 10;
charset->desc.width = 9;
charset->desc.height = 16;
charset->desc.width_internal = 9;
charset->desc.height_internal = 16;
return charset;
}
void
Charset::destroy(void)
{
if(raster)
raster->destroy();
rwFree(this);
}
Charset*
Charset::setColors(RGBA *foreground, RGBA *background)
{
Image *img = Image::create(256, 256, 8);
if(img == nil)
return nil;
img->pixels = (uint8*)fontbits;
img->stride = 256;
img->allocate();
img->palette[0] = background->red;
img->palette[1] = background->green;
img->palette[2] = background->blue;
img->palette[3] = background->alpha;
img->palette[4] = foreground->red;
img->palette[5] = foreground->green;
img->palette[6] = foreground->blue;
img->palette[7] = foreground->alpha;
Raster *newRaster = Raster::createFromImage(img);
if(newRaster == nil){
img->destroy();
return nil;
}
if(this->raster)
this->raster->destroy();
this->raster = newRaster;
return this;
}
void
Charset::flushBuffer(void)
{
if(numChars){
rw::SetRenderStatePtr(rw::TEXTURERASTER, lastRaster);
rw::SetRenderState(rw::TEXTUREADDRESS, rw::Texture::WRAP);
rw::SetRenderState(rw::TEXTUREFILTER, rw::Texture::NEAREST);
im2d::RenderIndexedPrimitive(rw::PRIMTYPETRILIST,
vertices, numChars*4, indices, numChars*6);
}
numChars = 0;
lastRaster = nil;
}
void
Charset::printChar(uint32 c, int32 x, int32 y)
{
Camera *cam;
float recipZ;
float u, v, du, dv;
RWDEVICE::Im2DVertex *vert;
uint16 *ix;
if(c >= this->desc.count)
return;
if(this->raster != lastRaster || numChars >= NUMCHARS)
flushBuffer();
lastRaster = this->raster;
cam = (Camera*)engine->currentCamera;
vert = &vertices[numChars*4];
ix = &indices[numChars*6];
recipZ = 1.0f/cam->nearPlane;
u = ((c % this->desc.tileWidth)*this->desc.width_internal + HALFPX) / (float32)this->raster->width;
v = ((c / this->desc.tileWidth)*this->desc.height_internal + HALFPX) / (float32)this->raster->height;
du = this->desc.width_internal/(float32)this->raster->width;
dv = this->desc.height_internal/(float32)this->raster->height;
vert->setScreenX(x);
vert->setScreenY(y);
vert->setScreenZ(rw::im2d::GetNearZ());
vert->setCameraZ(cam->nearPlane);
vert->setRecipCameraZ(recipZ);
vert->setColor(255, 255, 255, 255);
vert->setU(u, recipZ);
vert->setV(v, recipZ);
vert++;
vert->setScreenX(x+this->desc.width_internal);
vert->setScreenY(y);
vert->setScreenZ(rw::im2d::GetNearZ());
vert->setCameraZ(cam->nearPlane);
vert->setRecipCameraZ(recipZ);
vert->setColor(255, 255, 255, 255);
vert->setU(u+du, recipZ);
vert->setV(v, recipZ);
vert++;
vert->setScreenX(x);
vert->setScreenY(y+this->desc.height_internal);
vert->setScreenZ(rw::im2d::GetNearZ());
vert->setCameraZ(cam->nearPlane);
vert->setRecipCameraZ(recipZ);
vert->setColor(255, 255, 255, 255);
vert->setU(u, recipZ);
vert->setV(v+dv, recipZ);
vert++;
vert->setScreenX(x+this->desc.width_internal);
vert->setScreenY(y+this->desc.height_internal);
vert->setScreenZ(rw::im2d::GetNearZ());
vert->setCameraZ(cam->nearPlane);
vert->setRecipCameraZ(recipZ);
vert->setColor(255, 255, 255, 255);
vert->setU(u+du, recipZ);
vert->setV(v+dv, recipZ);
vert++;
*ix++ = numChars*4;
*ix++ = numChars*4+1;
*ix++ = numChars*4+2;
*ix++ = numChars*4+2;
*ix++ = numChars*4+1;
*ix++ = numChars*4+3;
numChars++;
}
void
Charset::print(const char *str, int32 x, int32 y, bool32 hideSpaces)
{
this->printBuffered(str, x, y, hideSpaces);
flushBuffer();
}
void
Charset::printBuffered(const char *str, int32 x, int32 y, bool32 hideSpaces)
{
while(*str){
if(!hideSpaces || *str != ' ')
printChar((uint8)*str, x, y);
x += this->desc.width;
str++;
}
}
}
#endif