gfx api can override perspective matrix calculation, partially port Player to C.

This commit is contained in:
UnknownShadow200 2017-12-14 11:01:07 +11:00
parent 080868b157
commit 3bb02e56b8
17 changed files with 301 additions and 46 deletions

View File

@ -432,6 +432,13 @@ namespace ClassicalSharp.GraphicsAPI {
}
}
public override void CalcOrthoMatrix(float width, float height, out Matrix4 matrix) {
Matrix4.CreateOrthographicOffCenter(0, width, height, 0, -10000, 10000, out matrix);
const float zN = -10000, zF = 10000;
matrix.Row2.Z = 1 / (zN - zF);
matrix.Row3.Z = zN / (zN - zF);
}
#endregion
public override void BeginFrame(Game game) {
@ -563,15 +570,6 @@ namespace ClassicalSharp.GraphicsAPI {
id = -1;
}
protected unsafe override void LoadOrthoMatrix(float width, float height) {
Matrix4 matrix;
Matrix4.CreateOrthographicOffCenter(0, width, height, 0, -10000, 10000, out matrix);
const float zN = -10000, zF = 10000;
matrix.Row2.Z = 1 / (zN - zF);
matrix.Row3.Z = zN / (zN - zF);
curStack.SetTop(ref matrix);
}
public override void Dispose() {
base.Dispose();
device.Dispose();

View File

@ -1,5 +1,6 @@
// Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
using System;
using OpenTK;
namespace ClassicalSharp.GraphicsAPI {
@ -119,7 +120,10 @@ namespace ClassicalSharp.GraphicsAPI {
public void Mode2D(int width, int height) {
SetMatrixMode(MatrixType.Projection);
PushMatrix();
LoadOrthoMatrix(width, height);
Matrix4 ortho;
CalcOrthoMatrix(width, height, out ortho);
LoadMatrix(ref ortho);
SetMatrixMode(MatrixType.Modelview);
PushMatrix();
LoadIdentityMatrix();

View File

@ -240,10 +240,9 @@ namespace ClassicalSharp.GraphicsAPI {
internal abstract void MakeApiInfo();
public string[] ApiInfo;
protected virtual void LoadOrthoMatrix(float width, float height) {
Matrix4 matrix;
Matrix4.CreateOrthographicOffCenter(0, width, height, 0, -10000, 10000, out matrix);
LoadMatrix(ref matrix);
public abstract void CalcOrthoMatrix(float width, float height, out Matrix4 matrix);
public virtual void CalcPerspectiveMatrix(float fov, float aspect, float zNear, float zFar, out Matrix4 matrix) {
Matrix4.CreatePerspectiveFieldOfView(fov, aspect, zNear, zFar, out matrix);
}
/// <summary> Sets the appropriate alpha testing/blending states necessary to render the given block. </summary>

View File

@ -501,6 +501,10 @@ namespace ClassicalSharp.GraphicsAPI {
GL.MultMatrixf(ptr);
}
public override void CalcOrthoMatrix(float width, float height, out Matrix4 result) {
Matrix4.CreateOrthographicOffCenter(0, width, height, 0, -10000, 10000, out matrix);
}
#endregion
public override void BeginFrame(Game game) {

View File

@ -128,10 +128,10 @@ namespace ClassicalSharp.Renderers {
}
void ProjectionChanged(object sender, EventArgs e) {
float fov = 70 * Utils.Deg2Rad;
float aspectRatio = (float)game.Width / game.Height;
float zNear = game.Graphics.MinZNear;
Matrix4.CreatePerspectiveFieldOfView(70 * Utils.Deg2Rad,
aspectRatio, zNear, game.ViewDistance, out heldBlockProj);
game.Graphics.CalcPerspectiveMatrix(fov, aspectRatio, zNear, game.ViewDistance, out heldBlockProj);
}

View File

@ -71,10 +71,10 @@ namespace ClassicalSharp {
}
public override void GetProjection(out Matrix4 m) {
float fovy = game.Fov * Utils.Deg2Rad;
float fov = game.Fov * Utils.Deg2Rad;
float aspectRatio = (float)game.Width / game.Height;
float zNear = game.Graphics.MinZNear;
Matrix4.CreatePerspectiveFieldOfView(fovy, aspectRatio, zNear, game.ViewDistance, out m);
game.Graphics.CalcPerspectiveMatrix(fov, aspectRatio, zNear, game.ViewDistance, out m);
}
public override void GetPickedBlock(PickedPos pos) {

View File

@ -214,9 +214,9 @@ namespace SharpDX.Direct3D9 {
D15S1 = 73,
D24S8 = 75,
D24X8 = 77,
D32F_Lockable = 82,
D24X4S4 = 79,
D16 = 80,
D32F_Lockable = 82,
VertexData = 100,
Index16 = 101,
Index32 = 102,

View File

@ -113,13 +113,8 @@ void Chat_AppendLog(STRING_PURE String* text) {
String_Append(&str, ':'); String_AppendPaddedInt32(&str, now.Minute, 2);
String_Append(&str, ':'); String_AppendPaddedInt32(&str, now.Second, 2);
String_Append(&str, ']'); String_Append(&str, ' ');
String_AppendColorless(&str, text);
Int32 i;
for (i = 0; i < text->length; i++) {
UInt8 c = text->buffer[i];
if (c == '&') { i++; continue; } /* Skip over the following colour code */
String_Append(&str, c);
}
Stream_WriteLine(&Chat_LogStream, &str);
}

View File

@ -619,14 +619,13 @@ void Gfx_PopMatrix(void) {
#define d3d9_zN -10000.0f
#define d3d9_zF 10000.0f
void Gfx_LoadOrthoMatrix(Real32 width, Real32 height) {
Matrix matrix;
Matrix_OrthographicOffCenter(&matrix, 0.0f, width, height, 0.0f, d3d9_zN, d3d9_zF);
matrix.Row2.Y = 1.0f / (d3d9_zN - d3d9_zF);
matrix.Row2.Z = d3d9_zN / (d3d9_zN - d3d9_zF);
matrix.Row3.Z = 1.0f;
Gfx_LoadMatrix(&matrix);
void Gfx_CalcOrthoMatrix(Real32 width, Real32 height, Matrix* matrix) {
Matrix_OrthographicOffCenter(matrix, 0.0f, width, height, 0.0f, d3d9_zN, d3d9_zF);
matrix->Row2.Z = 1.0f / (d3d9_zN - d3d9_zF);
matrix->Row3.Z = d3d9_zN / (d3d9_zN - d3d9_zF);
}
void Gfx_CalcPerspectiveMatrix(Real32 fov, Real32 aspect, Real32 zNear, Real32 zFar, Matrix* matrix) {
Matrix_PerspectiveFieldOfView(matrix, fov, aspect, zNear, zFar);
}

View File

@ -86,9 +86,8 @@ typedef struct Entity_ {
Vector3 Size;
Matrix Transform;
UInt8 SkinType;
UInt8 EntityType;
bool NoShade;
UInt8 SkinType, EntityType;
bool NoShade, Ground;
GfxResourceID TextureId, MobTextureId;
Real32 uScale, vScale;

View File

@ -104,7 +104,8 @@ void Gfx_LoadIdentityMatrix(void);
void Gfx_MultiplyMatrix(Matrix* matrix);
void Gfx_PushMatrix(void);
void Gfx_PopMatrix(void);
void Gfx_LoadOrthoMatrix(Real32 width, Real32 height);
void Gfx_CalcOrthoMatrix(Real32 width, Real32 height, Matrix* matrix);
void Gfx_CalcPerspectiveMatrix(Real32 fov, Real32 aspect, Real32 zNear, Real32 zFar, Matrix* matrix);
/* Outputs a .png screenshot of the backbuffer to the specified file. */
void Gfx_TakeScreenshot(STRING_PURE String* output, Int32 width, Int32 height);

View File

@ -104,7 +104,9 @@ bool gfx_hadFog;
void GfxCommon_Mode2D(Int32 width, Int32 height) {
Gfx_SetMatrixMode(MATRIX_TYPE_PROJECTION);
Gfx_PushMatrix();
Gfx_LoadOrthoMatrix((Real32)width, (Real32)height);
Matrix ortho;
Gfx_CalcOrthoMatrix((Real32)width, (Real32)height, &ortho);
Gfx_LoadMatrix(&ortho);
Gfx_SetMatrixMode(MATRIX_TYPE_MODELVIEW);
Gfx_PushMatrix();
Gfx_LoadIdentityMatrix();

View File

@ -493,10 +493,11 @@ void Gfx_MultiplyMatrix(Matrix* matrix) { glMultMatrixf((Real32*)matrix); }
void Gfx_PushMatrix(void) { glPushMatrix(); }
void Gfx_PopMatrix(void) { glPopMatrix(); }
void Gfx_LoadOrthoMatrix(Real32 width, Real32 height) {
Matrix matrix;
Matrix_OrthographicOffCenter(&matrix, 0.0f, width, height, 0.0f, -10000.0f, 10000.0f);
Gfx_LoadMatrix(&matrix);
void Gfx_CalcOrthoMatrix(Real32 width, Real32 height, Matrix* matrix) {
Matrix_OrthographicOffCenter(matrix, 0.0f, width, height, 0.0f, -10000.0f, 10000.0f);
}
void Gfx_CalcPerspectiveMatrix(Real32 fov, Real32 aspect, Real32 zNear, Real32 zFar, Matrix* matrix) {
Matrix_PerspectiveFieldOfView(matrix, fov, aspect, zNear, zFar);
}

View File

@ -1,2 +1,245 @@
#include "Player.h"
#include "Platform.h"
#include "GraphicsAPI.h"
#include "Drawer2D.h"
void Player_Init(Player* player) {
/* TODO should we just remove the memset from entity_Init and player_init?? */
Platform_MemSet(player + sizeof(Entity), 0, sizeof(Player) - sizeof(Entity));
Entity* entity = &player->Base;
Entity_Init(entity);
entity->StepSize = 0.5f;
entity->EntityType = ENTITY_TYPE_PLAYER;
String model = String_FromConst("humanoid");
Entity_SetModel(&entity, &model);
/* TODO: Init vtable */
}
void Player_Despawn(Entity* entity) {
Player* player = (Player*)entity;
Player* first = FirstOtherWithSameSkin();
if (first == NULL) {
Gfx_DeleteTexture(&entity->TextureId);
ResetSkin();
}
entity->VTABLE->ContextLost(entity);
}
void Player_ContextLost(Entity* entity) {
Player* player = (Player*)entity;
Gfx_DeleteTexture(&player->NameTex.ID);
}
void Player_ContextRecreated(Entity* entity) {
Player* player = (Player*)entity;
Player_UpdateName(player);
}
void Player_MakeNameTexture(Player* player) {
using (Font font = new Font(game.FontName, 24)) {
String displayName = String_FromRaw(player->DisplayNameRaw, STRING_SIZE);
DrawTextArgs args = new DrawTextArgs(displayName, font, false);
bool bitmapped = Drawer2D_UseBitmappedChat; /* we want names to always be drawn without */
Drawer2D_UseBitmappedChat = true;
Size2D size = Drawer2D_MeasureSize(&args);
if (size.Width == 0) {
nameTex = new Texture(-1, 0, 0, 0, 0, 1, 1);
} else {
UInt8 buffer[String_BufferSize(STRING_SIZE * 2)];
String shadowName = String_InitAndClear(buffer, STRING_SIZE * 2);
size.Width += 3; size.Height += 3;
Bitmap bmp; Bitmap_AllocatePow2(&bmp, size.Width, size.Height);
Drawer2D_Begin(&bmp);
Drawer2D_Cols[0xFF] = PackedCol_Create3(80, 80, 80);
String_Append(&shadowName, 0xFF);
String_AppendColorless(&shadowName, &displayName);
args->Text = shadowName;
Drawer2D_DrawText(args, 3, 3);
Drawer2D_Cols[0xFF] = PackedCol_Create4(0, 0, 0, 0);
args->Text = displayName;
Drawer2D_DrawText(args, 0, 0);
Drawer2D_End();
nameTex = Drawer2D_Make2DTexture(&bmp, size, 0, 0);
}
Drawer2D_UseBitmappedChat = bitmapped;
}
}
void Player_UpdateName(Player* player) {
Entity* entity = &player->Base;
entity->VTABLE->ContextLost(entity);
if (Gfx_LostContext) return;
Player_MakeNameTexture(player);
}
void Player_DrawName(Player* player) {
Entity* entity = &player->Base;
IModel* model = entity->Model;
if (nameTex.ID == 0) MakeNameTexture();
if (nameTex.ID == -1) return;
Gfx_BindTexture(player->NameTex.ID);
Vector3 pos;
model->RecalcProperties(entity);
Vector3_TransformY(&pos, model->NameYOffset, &entity->Transform);
Real32 scale = Math.Min(1, Model.NameScale * ModelScale.Y) / 70.0f;
Int32 col = FastColour.WhitePacked;
Vector2 size = Vector2_Create2(nameTex.Width * scale, nameTex.Height * scale);
if (Entities_NameMode == NAME_MODE_ALL_UNSCALED && game.LocalPlayer.Hacks.CanSeeAllNames) {
/* Get W component of transformed position */
Matrix mat;
Matrix_Mul(&mat, &Game_View, &Game_Projection); /* TODO: This mul is slow, avoid it */
Real32 tempW = pos.X * mat.Row0.W + pos.Y * mat.Row1.W + pos.Z * mat.Row2.W + mat.Row3.W;
size.X *= tempW * 0.2f; size.Y *= tempW * 0.2f;
}
Int32 index = 0;
TextureRec rec; rec.U1 = 0.0f; rec.V1 = 0.0f; rec.U2 = nameTex.U2; rec.V2 = nameTex.V2;
Particle.DoRender(game, ref size, ref pos, ref rec, col, gfx.texVerts, ref index);
gfx.SetBatchFormat(VertexFormat.P3fT2fC4b);
gfx.UpdateDynamicVb_IndexedTris(gfx.texVb, gfx.texVerts, 4);
}
void Player_CheckSkin(Player* player) {
if (!fetchedSkin && Model.UsesSkin) {
Player first = FirstOtherWithSameSkinAndFetchedSkin();
if (first == null) {
game.AsyncDownloader.DownloadSkin(SkinName, SkinName);
} else {
ApplySkin(first);
}
fetchedSkin = true;
}
Request item;
if (!game.AsyncDownloader.TryGetItem(SkinName, out item)) return;
if (item == null || item.Data == null) { SetSkinAll(true); return; }
Bitmap bmp = (Bitmap)item.Data;
game.Graphics.DeleteTexture(ref TextureId);
SetSkinAll(true);
EnsurePow2(ref bmp);
SkinType = Utils.GetSkinType(bmp);
if (SkinType == SkinType.Invalid) {
SetSkinAll(true);
} else {
if (Model.UsesHumanSkin) ClearHat(bmp, SkinType);
TextureId = game.Graphics.CreateTexture(bmp, true, false);
SetSkinAll(false);
}
bmp.Dispose();
}
Player* Player_FirstOtherWithSameSkin(Player* player) {
UInt32 i;
for (i = 0; i < ENTITIES_MAX_COUNT; i++) {
if (Entities_List[i] == NULL || Entities_List[i] == player) continue;
if (Entities_List[i]->EntityType != ENTITY_TYPE_PLAYER) continue;
Player* p = (Player*)Entities_List[i];
if (p.SkinName == SkinName) return p;
}
return NULL;
}
Player* Player_FirstOtherWithSameSkinAndFetchedSkin(Player* player) {
UInt32 i;
for (i = 0; i < ENTITIES_MAX_COUNT; i++) {
if (Entities_List[i] == NULL || Entities_List[i] == player) continue;
if (Entities_List[i]->EntityType != ENTITY_TYPE_PLAYER) continue;
Player* p = (Player*)Entities_List[i];
if (p.SkinName == SkinName && p->FetchedSkin) return p;
}
return NULL;
}
/* Apply or reset skin, for all players with same skin */
void Player_SetSkinAll(Player* player, bool reset) {
UInt32 i;
for (i = 0; i < ENTITIES_MAX_COUNT; i++) {
if (Entities_List[i] == NULL || Entities_List[i] == player) continue;
if (Entities_List[i]->EntityType != ENTITY_TYPE_PLAYER) continue;
Player* p = (Player*)Entities_List[i];
if (p.SkinName != SkinName) continue;
if (reset) { p.ResetSkin(); } else { p.ApplySkin(this); }
}
}
void Player_ApplySkin(Player* player, Player* from) {
TextureId = from.TextureId;
MobTextureId = -1;
SkinType = from.SkinType;
uScale = from.uScale; vScale = from.vScale;
/* Custom mob textures */
if (Utils.IsUrlPrefix(SkinName, 0)) MobTextureId = TextureId;
}
void Player_ResetSkin(Player* player) {
uScale = 1; vScale = 1;
MobTextureId = -1;
TextureId = -1;
SkinType = game.DefaultPlayerSkinType;
}
void Player_ClearHat(Bitmap bmp, UInt8 skinType) {
Int32 sizeX = (bmp.Width / 64) * 32;
Int32 yScale = skinType == SkinType_64x32 ? 32 : 64;
Int32 sizeY = (bmp.Height / yScale) * 16;
/* determine if we actually need filtering */
for (Int32 y = 0; y < sizeY; y++) {
int* row = fastBmp.GetRowPtr(y);
row += sizeX;
for (Int32 x = 0; x < sizeX; x++) {
byte alpha = (byte)(row[x] >> 24);
if (alpha != 255) return;
}
}
/* only perform filtering when the entire hat is opaque */
UInt32 fullWhite = PackedCol_ARGB(255, 255, 255, 255);
UInt32 fullBlack = PackedCol_ARGB(0, 0, 0, 255);
for (Int32 y = 0; y < sizeY; y++) {
int* row = fastBmp.GetRowPtr(y);
row += sizeX;
for (Int32 x = 0; x < sizeX; x++) {
Int32 pixel = row[x];
if (pixel == fullWhite || pixel == fullBlack) row[x] = 0;
}
}
}
void Player_EnsurePow2(ref Bitmap bmp) {
Int32 width = Utils.NextPowerOf2(bmp.Width);
Int32 height = Utils.NextPowerOf2(bmp.Height);
if (width == bmp.Width && height == bmp.Height) return;
Bitmap scaled = Platform.CreateBmp(width, height);
using (FastBitmap src = new FastBitmap(bmp, true, true))
using (FastBitmap dst = new FastBitmap(scaled, true, false))
{
for (Int32 y = 0; y < src.Height; y++)
FastBitmap.CopyRow(y, y, src, dst, src.Width);
}
uScale = (float)bmp.Width / width;
vScale = (float)bmp.Height / height;
bmp.Dispose();
bmp = scaled;
}

View File

@ -167,6 +167,17 @@ bool String_AppendString(STRING_TRANSIENT String* str, STRING_PURE String* toApp
return true;
}
bool String_AppendColorless(STRING_TRANSIENT String* str, STRING_PURE String* toAppend) {
Int32 i;
for (i = 0; i < toAppend->length; i++) {
UInt8 c = toAppend->buffer[i];
if (c == '&') { i++; continue; } /* Skip over the following colour code */
if (!String_Append(str, c)) return false;
}
return true;
}
Int32 String_IndexOf(STRING_PURE String* str, UInt8 c, Int32 offset) {
Int32 i;

View File

@ -57,6 +57,7 @@ bool String_AppendInt32(STRING_TRANSIENT String* str, Int32 num);
bool String_AppendPaddedInt32(STRING_TRANSIENT String* str, Int32 num, Int32 minDigits);
bool String_AppendConst(STRING_TRANSIENT String* str, const UInt8* toAppend);
bool String_AppendString(STRING_TRANSIENT String* str, STRING_PURE String* toAppend);
bool String_AppendColorless(STRING_TRANSIENT String* str, STRING_PURE String* toAppend);
Int32 String_IndexOf(STRING_PURE String* str, UInt8 c, Int32 offset);
Int32 String_LastIndexOf(STRING_PURE String* str, UInt8 c);

View File

@ -42,8 +42,6 @@ typedef UInt8 EntityID;
typedef UInt8 TextureLoc;
/* Sides of a block. TODO: Map this to CPE PlayerClicked blockface enums. */
typedef UInt8 Face;
/* Skin layout a humanoid skin texture can have. */
typedef UInt8 SkinType;
typedef UInt32 ReturnCode;
typedef struct FontDesc_ { void* Handle; UInt16 Size, Style; } FontDesc;