This commit is contained in:
2025-05-13 02:03:18 +03:00
parent 72860c7968
commit 90ef6120fd
463 changed files with 380758 additions and 2 deletions
+15
View File
@@ -0,0 +1,15 @@
Demo_TexturedTriangle/Debug/
*.filters
*.user
Debug/
*.suo
*.db
*.opendb
*.plog
Demo_TexturedTriangle/Release/Demo_Tex.C6A5DFA2.tlog/CL.command.1.tlog
Demo_TexturedTriangle/Release/
SoftGL/Release/
Release/
SoftGL/BlockRasterizer.i-58160ea9
SoftGL/BlockRasterizer.i-f3af7022
/build
+84
View File
@@ -0,0 +1,84 @@
add_library(SoftGL INTERFACE)
target_include_directories(SoftGL
INTERFACE
Src
)
target_link_libraries(SoftGL
INTERFACE
LMath
)
target_sources(SoftGL
INTERFACE
Src/SoftGL/Bitmap.h
Src/SoftGL/BlockRasterizer.h
Src/SoftGL/Buffer.h
Src/SoftGL/config.h
Src/SoftGL/Debug.h
Src/SoftGL/DisplayMode.h
Src/SoftGL/dynamic_buffer.h
Src/SoftGL/Engine/FpsCounter.h
Src/SoftGL/Graphics2D.h
Src/SoftGL/IndexBuffer.h
Src/SoftGL/InputLayout.h
Src/SoftGL/InputSystem.h
Src/SoftGL/IRenderWindow.h
Src/SoftGL/IShader.h
Src/SoftGL/LString.h
Src/SoftGL/mip_utils.h
Src/SoftGL/PixelShader.h
Src/SoftGL/PSDefault.h
Src/SoftGL/PSDefaultColor.h
Src/SoftGL/PSFont.h
Src/SoftGL/PSTextured.h
Src/SoftGL/RasterizerSettings.h
Src/SoftGL/Ray.h
Src/SoftGL/RegisterBlock.h
Src/SoftGL/ResourceManager.h
Src/SoftGL/StaticBuffer.h
Src/SoftGL/StaticTexture.h
Src/SoftGL/static_mip_chain.h
Src/SoftGL/static_vector.h
Src/SoftGL/Texture.h
Src/SoftGL/TextureSampler.h
Src/SoftGL/texture_utils.h
Src/SoftGL/Tools.h
Src/SoftGL/Vertex.h
Src/SoftGL/VertexShader.h
Src/SoftGL/Viewport.h
Src/SoftGL/VSDefault.h
Src/SoftGL/VSScreenSpace.h
Src/SoftGL/Engine/camera.h
Src/SoftGL/Engine/camera_controller.h
Src/SoftGL/Engine/cube_generator.h
Src/SoftGL/Engine/FpsCounter.h
Src/SoftGL/Engine/fresnel.h
Src/SoftGL/Engine/gameobject.h
Src/SoftGL/Engine/imesh.h
Src/SoftGL/Engine/mesh.h
Src/SoftGL/Engine/plane_generator.h
Src/SoftGL/Engine/PsNormalMap.h
Src/SoftGL/Engine/transform.h
Src/SoftGL/Engine/shaders/textured_no_lit.h
Src/SoftGL/ImageDataAccessorR5G6B5.h
Src/SoftGL/ImageDataAccessorR8G8B8.h
INTERFACE
Src/SoftGL/BlockRasterizer.cpp
)
if (WIN32)
target_sources(SoftGL
INTERFACE
Src/SoftGL/Platform/Windows/RenderWindow.cpp
)
endif (WIN32)
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 Sergey Serb
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+2
View File
@@ -0,0 +1,2 @@
# softgl
C++ Software 3D renderer
+88
View File
@@ -0,0 +1,88 @@
#ifndef lighting_core_h__
#define lighting_core_h__
#include <LMath/lmath.h>
#include <algorithm>
#ifndef MATH_PI
#define MATH_PI 3.1415926535
#endif
using namespace lm;
float FresnelSchlickDielectric(float ior, float3 l, float3 h) {
float f0 = std::pow((1.0f - ior) / (1.0f + ior), 2.0f);
return f0 + (1.0f - f0) * std::pow(1.0f - dot(l, h), 5.0f);
}
float FresnelSchlickConductor(float ior, float absorbtion, float3 l, float3 h) {
float n = ior;
float k = absorbtion;
return (std::pow(n - 1, 2) + 4.0f * n*std::pow(1.0f - dot(l, h), 5.0f) + k*k) / (std::pow(n + 1.0f, 2.0f) + k*k);
}
float G_implicit(float3 n, float3 h, float3 v, float3 l) {
return (std::max<float>)(0, dot(n, l)) * (std::max<float>)(0, dot(n, v));
}
float G_Cook_Torrance(float3 n, float3 h, float3 v, float3 l) {
float VdotH = dot(v, h) + 1e-5f;
float NdotV = dot(n, v);
float NdotH = dot(n, h);
float NdotL = dot(n, l);
float g1 = (2.0f * dot(n, h) * NdotV) / VdotH;
float g2 = (2.0f * dot(n, h) * dot(n, l)) / VdotH;
return (std::min)(1.0f, (std::min)(g1, g2));
}
float D_BlinnPhong(lm::float3 h, lm::float3 n, float power) {
float normalization = ((power + 2.0f) / (2.0f * MATH_PI));
//float normalization = 1;
//float normalization = ((power + 8) / (8.0f * MATH_PI));
//float normalization = (power + 2) / (4 * MATH_PI*(2 - exp(-power / 2)));
//float normalization = ((power + 2)*(power + 4)) / (2 * MATH_PI*(pow(2, -power / 2) + power));
return normalization * std::pow((std::max)(0.0f, lm::dot(n, h)), power);
}
float chiGGX(float v) {
return v > 0 ? 1 : 0;
}
float GGX_Distribution(float3 n, float3 h, float alpha) {
float NoH = dot(n, h);
float alpha2 = alpha * alpha;
float NoH2 = NoH * NoH;
float den = NoH2 * alpha2 + (1 - NoH2);
return (chiGGX(NoH) * alpha2) / (MATH_PI * den * den);
}
float GGX_PartialGeometryTerm(float3 v, float3 n, float3 h, float alpha) {
float VoH2 = (std::max)(0.0f, (dot(v, h)));
float chi = chiGGX(VoH2 / (std::max)(0.0f, dot(v, n)));
VoH2 = VoH2 * VoH2;
float tan2 = (1.0f - VoH2) / VoH2;
return (chi * 2.0f) / (1.0f + std::sqrt(1.0f + alpha * alpha * tan2));
}
inline float D_Beckmann(lm::float3 h, lm::float3 n, float m) {
float c = lm::dot(n, h);
float T = c * c;
float M = m*m;
return std::exp((T - 1.0f) / (M*T)) / (M * T * T);
}
float PhongToBeckmann(float a) {
return std::sqrt(2.0f / (a + 2.0f));
}
float BeckmannToPhong(float m) {
return 2.0f / (m*m) - 2.0f;
}
float Fresnel(float c, float ior) {
float g = std::sqrt(ior*ior + c*c - 1);
return 0.5f * std::pow(g - c, 2.0f) / std::pow(g + c, 2.0f) * (1.0f + std::pow(c*(g + c) - 1.0f, 2.0f) / std::pow(c*(g - c) + 1.0f, 2.0f));
}
#endif // lighting_core_h__
+45
View File
@@ -0,0 +1,45 @@
#ifndef BITMAP_H
#define BITMAP_H
#include <cstdint>
/*struct BITMAPFILEHEADER {
int16 bfType;
int32 bfSize;
int16 Reserved1;
int16 Reserved2;
int32 bfOffBits;
};*/
#if defined(_MSC_VER)
#include <Windows.h>
#else
#pragma pack(push,2)
typedef struct tagBITMAPFILEHEADER {
unsigned short bfType;
unsigned long bfSize;
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned long bfOffBits;
} BITMAPFILEHEADER, *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;
#pragma pack(pop)
#pragma pack(push,2)
typedef struct tagBITMAPINFOHEADER {
unsigned long biSize;
long biWidth;
long biHeight;
unsigned short biPlanes;
unsigned short biBitCount;
unsigned long biCompression;
unsigned long biSizeImage;
long biXPelsPerMeter;
long biYPelsPerMeter;
unsigned long biClrUsed;
unsigned long biClrImportant;
}BITMAPINFOHEADER, *PBITMAPINFOHEADER;
#pragma pack(pop)
#endif
#endif // BITMAP_H
+384
View File
@@ -0,0 +1,384 @@
#include "BlockRasterizer.h"
#include "TextureSampler.h"
#include <assert.h>
#include <iostream>
#include "ImageDataAccessorR5G6B5.h"
#include "ImageDataAccessorR8G8B8.h"
BlockRasterizer::BlockRasterizer()
:primitiveType(PT_TRIANGLE_LIST), vs(0), ps(0), geomLayout(0){
blendState.AlphaOperation = BLEND_OP_ADD;
blendState.SrcAlpha = BLEND_SRC_ALPHA;
blendState.DstAlpha = BLEND_INV_SRC_ALPHA;
blendState.BlendEnable = false;
NDCPlanes[0] = RasterizerPlane(1, 0, 0, 1);//left
NDCPlanes[1] = RasterizerPlane(-1, 0, 0, 1);//right
NDCPlanes[2] = RasterizerPlane(0, 1, 0, 1);//top
NDCPlanes[3] = RasterizerPlane(0, -1, 0, 1);//bottom
NDCPlanes[4] = RasterizerPlane(0, 0, 1, 0);//near plane (D3D NDC, NeraClip Z == 0)
NDCPlanes[5] = RasterizerPlane(0, 0, -1, 1);//far
//NDCPlanes[6] = RasterizerPlane(0, 0, 0, 1);//WTF?
}
BlockRasterizer::~BlockRasterizer() {
}
bool BlockRasterizer::ClipToFrustumPlane(RasterizerPlane plane, ClipVector& src, ClipVector& dst, size_t regCount) {
auto face_count = src.size();
bool clipped = false;
for (size_t i = 0; i < face_count; i++) {
//read face from input
ClipFace face = src[i];
int v0out, v1out, v2out, vout_cnt;
v0out = v1out = v2out = vout_cnt = 0;
if (lm::dot(plane, face.v0.reg[0]) <= 0) { v0out++; vout_cnt++; }
if (lm::dot(plane, face.v1.reg[0]) <= 0) { v1out++; vout_cnt++; }
if (lm::dot(plane, face.v2.reg[0]) <= 0) { v2out++; vout_cnt++; }
switch (vout_cnt) {
case 3://all 3 vertices behind plane! Clip entire triangle
clipped = true;
continue;
case 2:
{
//printf("2 vertices behind plane!\n");
clipped = true;
RegisterBlock* vert[3];
RegisterBlock vA, vB;
if (v0out && v1out) { vert[0] = &face.v0; vert[1] = &face.v1; vert[2] = &face.v2; }
if (v1out && v2out) { vert[0] = &face.v1; vert[1] = &face.v2; vert[2] = &face.v0; }
if (v2out && v0out) { vert[0] = &face.v2; vert[1] = &face.v0; vert[2] = &face.v1; }
float alpha_a = lm::dot(plane, vert[2]->reg[0]) / (lm::dot(plane, vert[2]->reg[0]) - lm::dot(plane, vert[1]->reg[0]));
float alpha_b = lm::dot(plane, vert[2]->reg[0]) / (lm::dot(plane, vert[2]->reg[0]) - lm::dot(plane, vert[0]->reg[0]));
for (size_t k = 0; k < regCount; k++) {
vA.reg[k] = vert[2]->reg[k] + (vert[1]->reg[k] - vert[2]->reg[k]) * alpha_a;
vB.reg[k] = vert[2]->reg[k] + (vert[0]->reg[k] - vert[2]->reg[k]) * alpha_b;
}
ClipFace fa;
fa.v0 = vA;
fa.v1 = *vert[2];
fa.v2 = vB;
dst.push_back(fa);
}
break;
case 1:
{
clipped = true;
RegisterBlock* vert[3];
RegisterBlock vA, vB;
if (v0out) { vert[0] = &face.v0; vert[1] = &face.v1; vert[2] = &face.v2; }
if (v1out) { vert[0] = &face.v1; vert[1] = &face.v2; vert[2] = &face.v0; }
if (v2out) { vert[0] = &face.v2; vert[1] = &face.v0; vert[2] = &face.v1; }
float alpha_a = lm::dot(plane, vert[2]->reg[0]) / (lm::dot(plane, vert[2]->reg[0]) - lm::dot(plane, vert[0]->reg[0]));
float alpha_b = lm::dot(plane, vert[1]->reg[0]) / (lm::dot(plane, vert[1]->reg[0]) - lm::dot(plane, vert[0]->reg[0]));
for (size_t k = 0; k < regCount; k++) {
vA.reg[k] = vert[2]->reg[k] + (vert[0]->reg[k] - vert[2]->reg[k]) * alpha_a;
vB.reg[k] = vert[1]->reg[k] + (vert[0]->reg[k] - vert[1]->reg[k]) * alpha_b;
}
ClipFace fa;
fa.v0 = vB;
fa.v1 = *vert[1];
fa.v2 = vA;
dst.push_back(fa);
ClipFace fb;
fb.v0 = vA;
fb.v1 = *vert[1];
fb.v2 = *vert[2];
dst.push_back(fb);
//DrawTriangle(rA_out, *vert[1], *vert[2]);
}
break;
case 0:
dst.push_back(face); //nothing to crop! Just push it
break;
}
}
return clipped;
}
void BlockRasterizer::ClipToFrustum(ClipFace face, ClipVector& dst, size_t regCount) {
cv1.clear();
cv2.clear();
dst.clear();
cv1.push_back(face);
if(ClipToFrustumPlane(NDCPlanes[0], cv1, cv2, regCount)){
std::cout << "Clipped with plane 0" << std::endl;
}
cv1.clear();
if (ClipToFrustumPlane(NDCPlanes[1], cv2, cv1, regCount)) {
std::cout << "Clipped with plane 1" << std::endl;
}
cv2.clear();
if (ClipToFrustumPlane(NDCPlanes[2], cv1, cv2, regCount)) {
std::cout << "Clipped with plane 2" << std::endl;
}
cv1.clear();
if (ClipToFrustumPlane(NDCPlanes[3], cv2, cv1, regCount)) {
std::cout << "Clipped with plane 3" << std::endl;
}
cv2.clear();
if (ClipToFrustumPlane(NDCPlanes[4], cv1, cv2, regCount)) {
std::cout << "Clipped with plane 4" << std::endl;
}
//cv1.clear();
if (ClipToFrustumPlane(NDCPlanes[5], cv2, dst, regCount)) {
std::cout << "Clipped with plane 5" << std::endl;
}
/*if (ClipToFrustumPlane(NDCPlanes[6], cv1, dst)) {
std::cout << "Clipped with plane 6" << std::endl;
}*/
}
Texture* BlockRasterizer::GetBackBuffer() {
return backBuffer;
}
Texture* BlockRasterizer::GetDepthBuffer() {
return depthBuffer;
}
void BlockRasterizer::setColorBuffer(Texture* buffer) {
backBuffer = buffer;
}
void BlockRasterizer::setDepthBuffer(Texture* buffer) {
depthBuffer = buffer;
}
void BlockRasterizer::SetPrimitiveType(int type) {
primitiveType = type;
}
void BlockRasterizer::Draw(size_t offset, size_t length) {
if (!length) return;
switch (primitiveType) {
case PT_TRIANGLE_LIST:
{
auto faceCount = length / 3;
Buffer* geom = vbSlots[0].buffer;
if (!faceCount){
DebugInfo("No faces to draw");
return;
}
if (!geom){
DebugError("Vertex Buffer is not set");
return;
}
auto stride = vbSlots[0].stride;
//Buffer is too small for this draw call
if (geom->Size() / stride < faceCount * 3) {
DebugError("[Draw] Vertex Buffer is too small!");
return;
}
uint8_t* data = (uint8_t*)geom->GetPointer();
for (size_t i = 0; i < faceCount; i++) {
//setup vertex data pointers
uint8_t* v0 = data + ((offset + 0 + i * 3) * stride);
uint8_t* v1 = data + ((offset + 1 + i * 3) * stride);
uint8_t* v2 = data + ((offset + 2 + i * 3) * stride);
draw_impl(v0, v1, v2);
}
}
break;
}
}
void BlockRasterizer::DrawIndexed(size_t index_count, size_t start_index_location)
{
if (index_count == 0) return;
switch (primitiveType) {
case PT_TRIANGLE_LIST:
{
int faceCount = index_count / 3;
Buffer* geom = vbSlots[0].buffer;
Buffer* indices = ibSlots[0];
if (!faceCount) {
DebugInfo("No faces to draw");
return;
}
if (!geom) {
DebugError("Vertex Buffer is not set");
return;
}
if (!indices) {
DebugError("Index Buffer is not set");
return;
}
int stride = vbSlots[0].stride;
uint8_t* vertex_data = (uint8_t*)geom->GetPointer();
auto vertices_count = geom->Size() / vbSlots[0].stride;
indices_t* index_data = (indices_t*)indices->GetPointer();
for (size_t i = 0; i < index_count; i+=3) {
//setup vertex data pointers
auto id0 = index_data[i + 0 + start_index_location];
auto id1 = index_data[i + 1 + start_index_location];
auto id2 = index_data[i + 2 + start_index_location];
uint8_t* v0 = vertex_data + id0 * stride;
uint8_t* v1 = vertex_data + id1 * stride;
uint8_t* v2 = vertex_data + id2 * stride;
draw_impl(v0, v1, v2);
}
}
break;
}
}
void BlockRasterizer::draw_impl(void* v0, void* v1, void* v2)
{
int elements = geomLayout->Size();
for (int i = 0; i < elements; i++) { //TODO: OMG WTF! Fix memory corruption!!!
InputElement* e = geomLayout->GetElement(i);
int rd = regMapping[i];
if(rd >= 0){
r0_in[rd] = reinterpret_cast<float4*>((uint8_t*)v0 + e->Offset);
r1_in[rd] = reinterpret_cast<float4*>((uint8_t*)v1 + e->Offset);
r2_in[rd] = reinterpret_cast<float4*>((uint8_t*)v2 + e->Offset);
}
}
vs->Execute(&r0_in[0], &r0_out.reg[0]);
vs->Execute(&r1_in[0], &r1_out.reg[0]);
int numInterpolators = vs->Execute(&r2_in[0], &r2_out.reg[0]);
//r0_out.reg[0].y() = -r0_out.reg[0].y();
//r1_out.reg[0].y() = -r1_out.reg[0].y();
//r2_out.reg[0].y() = -r2_out.reg[0].y();
ClipVector cv;
ClipFace cf;
cf.v0 = r0_out;
cf.v1 = r1_out;
cf.v2 = r2_out;
ClipToFrustum(cf, cv, numInterpolators);
auto bbDesc = backBuffer->Desc();
if (bbDesc.BytesPerPixel == 4) {
for (size_t l = 0; l < cv.size(); l++) {
ClipFace cf_render = cv[l];
DrawTriangle<ImageDataAccessorR8G8B8>(cf_render.v0, cf_render.v1, cf_render.v2);
}
}
else if (bbDesc.BytesPerPixel == 2) {
for (size_t l = 0; l < cv.size(); l++) {
ClipFace cf_render = cv[l];
DrawTriangle<ImageDataAccessorR5G6B5>(cf_render.v0, cf_render.v1, cf_render.v2);
}
}
else {
//Not supported
}
}
void BlockRasterizer::FixupMapping() {
if (geomLayout != 0) {
if (vs != 0) {
auto elements = geomLayout->Size();
for (size_t i = 0; i < elements; i++) {
regMapping[i] = vs->FindRegister(geomLayout->GetElement(i)->name);
}
}
}
}
void BlockRasterizer::SetVertexBuffer(Buffer* vb, size_t slot, size_t stride) {
vbSlots[slot].buffer = vb;
vbSlots[slot].stride = stride;
}
void BlockRasterizer::SetIndexBuffer(Buffer* ib, size_t slot){
ibSlots[slot] = ib;
}
void BlockRasterizer::SetInputLayout(IInputLayout* layout) {
geomLayout = layout;
FixupMapping();
}
void BlockRasterizer::SetPixelShader(PixelShader* shader) {
ps = shader;
}
void BlockRasterizer::SetVertexShader(VertexShader* shader) {
vs = shader;
FixupMapping();
}
void BlockRasterizer::SetBlendState(BlendState* state) {
blendState = *state;
}
float BlockRasterizer::GetBlendAlpha(BLEND_SOURCE src, const float4& srcColor, const float4& dstColor) {
switch (src) {
case BLEND_ZERO:
return 0.0f;
case BLEND_ONE:
return 1.0f;
case BLEND_SRC_ALPHA:
return srcColor.w();
case BLEND_INV_SRC_ALPHA:
return 1.0f - srcColor.w();
}
return 0;
}
uint32_t BlockRasterizer::ConvertColor(const float4& color) {
uint32_t r = (uint32_t)(color.x() * 255.0f);
uint32_t g = (uint32_t)(color.y() * 255.0f);
uint32_t b = (uint32_t)(color.z() * 255.0f);
uint32_t a = (uint32_t)(color.w() * 255.0f);
return (a << 24) | (r << 16) | (g << 8) | (b);
}
float4 BlockRasterizer::ConvertColor(uint32_t color) {
float d = 1.0f / 255.0f;
float a = (float)((color >> 24) & 0xff) * d;
float r = (float)((color >> 16) & 0xff) * d;
float g = (float)((color >> 8) & 0xff) * d;
float b = (float)((color >> 0) & 0xff) * d;
return float4(r, g, b, a);
}
+483
View File
@@ -0,0 +1,483 @@
#ifndef BlockRasterizer_h__
#define BlockRasterizer_h__
#include "Texture.h"
#include "Viewport.h"
#include "InputLayout.h"
#include "VertexShader.h"
#include "PixelShader.h"
#include <assert.h>
#include <math.h>
#include "Tools.h"
#include <vector>
#include "IRenderWindow.h"
#include "static_vector.h"
#include "RasterizerSettings.h"
#include <array>
#include "Debug.h"
#include "RegisterBlock.h"
#include <LMath/lmath.h>
using namespace lm;
enum PRIMITIVE_TYPE
{
PT_TRIANGLE_LIST = 0,
PT_TRIANGLE_STRIP = 1,
PT_LINE_LIST = 2,
PT_LINE_STRIP = 3,
PT_POINT_LIST = 4
};
enum BLEND_SOURCE
{
BLEND_ZERO = 0,
BLEND_ONE = 1,
BLEND_SRC_ALPHA = 3,
BLEND_INV_SRC_ALPHA = 4
};
enum BLEND_OP
{
BLEND_OP_ADD = 0
};
struct BlendState
{
BLEND_SOURCE SrcAlpha;
BLEND_SOURCE DstAlpha;
BLEND_OP AlphaOperation;
bool BlendEnable;
};
enum NDCZone
{
ZONE_ZERO = 0,
ZONE_LEFT = 1,
ZONE_RIGHT = 2,
ZONE_BOTTOM = 3,
ZONE_TOP = 4,
ZONE_FAR = 5,
ZONE_NEAR = 6
};
static constexpr const char* NDCZoneStr[7]{
"ZONE_ZERO",
"ZONE_LEFT",
"ZONE_RIGHT",
"ZONE_BOTTOM",
"ZONE_TOP",
"ZONE_FAR",
"ZONE_NEAR"
};
struct ClipFace
{
RegisterBlock v0;
RegisterBlock v1;
RegisterBlock v2;
};
class BlockRasterizer {
public:
typedef Plane<float> RasterizerPlane;
typedef Static_vector<ClipFace, 9> ClipVector;
BlockRasterizer();
~BlockRasterizer();
bool ClipToFrustumPlane(RasterizerPlane plane, ClipVector& src, ClipVector& dst, size_t regCount);
void ClipToFrustum(ClipFace face, ClipVector& dst, size_t regCount);
Texture* GetBackBuffer();
Texture* GetDepthBuffer();
void setColorBuffer(Texture* buffer);
void setDepthBuffer(Texture* buffer);
void SetPrimitiveType(int type);
void Draw(size_t offset, size_t length);
void DrawIndexed(size_t index_count, size_t start_index_location);
void FixupMapping();
void SetVertexBuffer(Buffer* vb, size_t slot, size_t stride);
void SetIndexBuffer(Buffer* ib, size_t slot);
void SetInputLayout(IInputLayout* layout);
void SetPixelShader(PixelShader* shader);
void SetVertexShader(VertexShader* shader);
void SetBlendState(BlendState* state);
float GetBlendAlpha(BLEND_SOURCE src, const float4& srcColor, const float4& dstColor);
private:
ClipVector cv1, cv2;
void draw_impl(void* v0, void* v1, void* v2);
IRenderWindow* render_window;
std::array<RasterizerPlane, 6> NDCPlanes;
uint32_t ConvertColor(const float4& color);
float4 ConvertColor(uint32_t color);
template<size_t _BlockSize, typename _Var>
inline void CalcDerivatives(
int dy10, int dy20,
int dx10, int dx20,
_Var z0, _Var z1, _Var z2, _Var& ddx, _Var& ddy) {
const auto dc10 = z1 - z0;
const auto dc20 = z2 - z0;
//(iy1 - iy0)
auto A = dc20 * dy10 - dc10 * dy20;
auto B = dc10 * dx20 - dc20 * dx10;
int C = dy20 * dx10 - dx20 * dy10;
ddx = A / (float)-C;
ddy = B / (float)-C;
}
template<typename ColorDataAccessor>
void DrawTriangle(RegisterBlock r0_src, RegisterBlock r1_src, RegisterBlock r2_src) {
float scrW_h = (float)(backBuffer->Desc().Width / 2);
float scrH_h = (float)(backBuffer->Desc().Height / 2);
RegisterBlock* p0 = &r0_src;
RegisterBlock* p1 = &r1_src;
RegisterBlock* p2 = &r2_src;
//p1->reg[0].W = abs(p1->reg[0].W);
float iw0 = 1.0f / p0->reg[0].w();
float iw1 = 1.0f / p1->reg[0].w();
float iw2 = 1.0f / p2->reg[0].w();
//transform vertices to viewport space
p0->reg[0].x() = (p0->reg[0].x() * iw0) * scrW_h + scrW_h;
p0->reg[0].y() = (p0->reg[0].y() * iw0) * scrH_h + scrH_h;
p0->reg[0].z() = (p0->reg[0].z() * iw0);
p1->reg[0].x() = (p1->reg[0].x() * iw1) * scrW_h + scrW_h;
p1->reg[0].y() = (p1->reg[0].y() * iw1) * scrH_h + scrH_h;
p1->reg[0].z() = (p1->reg[0].z() * iw1);
p2->reg[0].x() = (p2->reg[0].x() * iw2) * scrW_h + scrW_h;
p2->reg[0].y() = (p2->reg[0].y() * iw2) * scrH_h + scrH_h;
p2->reg[0].z() = (p2->reg[0].z() * iw2);
float3 camZ(p0->reg[0].z(), p1->reg[0].z(), p2->reg[0].z());
bool disableCulling = false;
if (disableCulling)
if (((p1->reg[0].x() - p0->reg[0].x()) * (p2->reg[0].y() - p0->reg[0].y()) - (p1->reg[0].y() - p0->reg[0].y()) * (p2->reg[0].x() - p0->reg[0].x()) <= 0)) {
RegisterBlock* pTmp = p0;
p0 = p2;
p2 = pTmp;
}
const int x0 = (int)std::round(16.0f * p0->reg[0].x());
const int x1 = (int)std::round(16.0f * p1->reg[0].x());
const int x2 = (int)std::round(16.0f * p2->reg[0].x());
const int y0 = (int)std::round(16.0f * p0->reg[0].y());
const int y1 = (int)std::round(16.0f * p1->reg[0].y());
const int y2 = (int)std::round(16.0f * p2->reg[0].y());
const int Dx01 = x0 - x1;
const int Dx12 = x1 - x2;
const int Dx20 = x2 - x0;
const int Dy01 = y0 - y1;
const int Dy12 = y1 - y2;
const int Dy20 = y2 - y0;
const int FDx01 = Dx01 << 4;
const int FDx12 = Dx12 << 4;
const int FDx20 = Dx20 << 4;
const int FDy01 = Dy01 << 4;
const int FDy12 = Dy12 << 4;
const int FDy20 = Dy20 << 4;
//bounding rectangle
int minX = ((std::min)((std::min)(x0, x1), x2) + 0xF) >> 4;
int maxX = ((std::max)((std::max)(x0, x1), x2) + 0xF) >> 4;
int minY = ((std::min)((std::min)(y0, y1), y2) + 0xF) >> 4;
int maxY = ((std::max)((std::max)(y0, y1), y2) + 0xF) >> 4;
const int ix0 = (x0 + 0xf) >> 4;
const int ix1 = (x1 + 0xf) >> 4;
const int ix2 = (x2 + 0xf) >> 4;
const int iy0 = (y0 + 0xf) >> 4;
const int iy1 = (y1 + 0xf) >> 4;
const int iy2 = (y2 + 0xf) >> 4;
const int diy20 = iy2 - iy0;
const int dix20 = ix2 - ix0;
const int diy10 = iy1 - iy0;
const int dix10 = ix1 - ix0;
const int area = dix10 * diy20 - dix20 * diy10;
if (area == 0) return;
if (maxY < 0)
return;
if (minY >= (int)backBuffer->Desc().Height)
return;
if (maxX < 0)
return;
if (minX >= (int)backBuffer->Desc().Width)
return;
if (minY < 0)
minY = 0;
if (maxY >= (int)backBuffer->Desc().Height)
maxY = (int)backBuffer->Desc().Height - 1;
if (minX < 0)
minX = 0;
if (maxX >= (int)backBuffer->Desc().Width)
maxX = (int)backBuffer->Desc().Width - 1;
int blockSize = 8;
minX &= ~(blockSize - 1);
minY &= ~(blockSize - 1);
auto bbPtr = reinterpret_cast<typename ColorDataAccessor::PixelDataType*>(backBuffer->LockWrite());
auto dbPtr = reinterpret_cast<float*>(depthBuffer->LockWrite());
bbPtr += minY * backBuffer->Desc().Width;
dbPtr += minY * depthBuffer->Desc().Width;
int C1 = Dy01 * x0 - Dx01 * y0;
int C2 = Dy12 * x1 - Dx12 * y1;
int C3 = Dy20 * x2 - Dx20 * y2;
//top-left fill convention fix
if (!(Dy01 < 0 || (Dy01 == 0 && Dx01 > 0))) C1--;
if (!(Dy12 < 0 || (Dy12 == 0 && Dx12 > 0))) C2--;
if (!(Dy20 < 0 || (Dy20 == 0 && Dx20 > 0))) C3--;
RegisterBlock triDerivX;
RegisterBlock triDerivY;
RegisterBlock invRegs[3];
for (int i = 1; i < REG_COUNT; i++) {
invRegs[0].reg[i] = p0->reg[i] * iw0;
invRegs[1].reg[i] = p1->reg[i] * iw1;
invRegs[2].reg[i] = p2->reg[i] * iw2;
}
for (int i = 1; i < REG_COUNT; i++) {
CalcDerivatives<8, float4>(diy10, diy20, dix10, dix20, invRegs[0].reg[i], invRegs[1].reg[i], invRegs[2].reg[i], triDerivX.reg[i], triDerivY.reg[i]);
}
float2 derivZW_X;
float2 derivZW_Y;
float2 p0zw = p0->reg[0].zw();
p0zw.y() = 1.0f / p0zw.y();
float2 p1zw = p1->reg[0].zw();
p1zw.y() = 1.0f / p1zw.y();
float2 p2zw = p2->reg[0].zw();
p2zw.y() = 1.0f / p2zw.y();
CalcDerivatives<8, float2>(diy10, diy20, dix10, dix20, p0zw, p1zw, p2zw, derivZW_X, derivZW_Y);
//scan all blocks
for (int y = minY; y < maxY; y += blockSize) {
for (int x = minX; x < maxX; x += blockSize) {
//find block corners
int x0 = x << 4;
int x1 = (x + blockSize - 1) << 4;
int y0 = y << 4;
int y1 = (y + blockSize - 1) << 4;
//evaluate half space functions for each corner
bool a00 = C1 + Dx01 * y0 - Dy01 * x0 < 0;
bool a01 = C1 + Dx01 * y0 - Dy01 * x1 < 0;
bool a10 = C1 + Dx01 * y1 - Dy01 * x0 < 0;
bool a11 = C1 + Dx01 * y1 - Dy01 * x1 < 0;
int a = (a00 << 0) | (a10 << 1) | (a01 << 2) | (a11 << 3);
bool b00 = C2 + Dx12 * y0 - Dy12 * x0 < 0;
bool b01 = C2 + Dx12 * y0 - Dy12 * x1 < 0;
bool b10 = C2 + Dx12 * y1 - Dy12 * x0 < 0;
bool b11 = C2 + Dx12 * y1 - Dy12 * x1 < 0;
int b = (b00 << 0) | (b10 << 1) | (b01 << 2) | (b11 << 3);
bool c00 = C3 + Dx20 * y0 - Dy20 * x0 < 0;
bool c01 = C3 + Dx20 * y0 - Dy20 * x1 < 0;
bool c10 = C3 + Dx20 * y1 - Dy20 * x0 < 0;
bool c11 = C3 + Dx20 * y1 - Dy20 * x1 < 0;
int c = ((uint32_t)c00 << 0) | ((uint32_t)c10 << 1) | ((uint32_t)c01 << 2) | ((uint32_t)c11 << 3);
//Skip entire block if all it's 4 corners outside of triangle edges
if (a == 0 || b == 0 || c == 0)
continue;
auto colorBuffer = bbPtr;
auto zBuffer = dbPtr;
RegisterBlock var00;
//interpolate registers
for (int r = 1; r < REG_COUNT; r++) {
var00.reg[r] = invRegs[0].reg[r] + triDerivX.reg[r] * (x - ix0) + triDerivY.reg[r] * (y - iy0);
}
//Whole block is inside triangle!
if (a == 0xf && b == 0xf && c == 0xf) {
for (int by = 0; by < blockSize; by++) {
for (int bx = x; bx < (x + blockSize); bx++) {
//compute interpolation weights
auto ddx0 = (bx - ix0);
auto ddy0 = (y + by - iy0);
float2 zw = p0zw + derivZW_X * ddx0 + derivZW_Y * ddy0;
//interpolate Z
float z_interp = zw.x();
if (zBuffer[bx] > z_interp)
{
zBuffer[bx] = z_interp;
//interpolate registers
for (int r = 1; r < REG_COUNT; r++) {
r_ps.reg[r] = (var00.reg[r] + triDerivX.reg[r] * (bx - x)) / zw.y();
}
/*for (int r = 1; r < REG_COUNT; r++) {
r_ps.reg[r] = invRegs[0].reg[r] + triDerivX.reg[r] * ddx0 + triDerivY.reg[r] * ddy0;
}*/
float4 pixel_color = ps->Execute(&r_ps.reg[0]);
if (blendState.BlendEnable) {
uint32_t dc = colorBuffer[bx];
float4 dstColor = ColorDataAccessor::ConvertColor(dc);
//get source alpha
float srcAlpha = GetBlendAlpha(blendState.SrcAlpha, pixel_color, dstColor);
float dstAlpha = GetBlendAlpha(blendState.DstAlpha, pixel_color, dstColor);
pixel_color = pixel_color * srcAlpha + dstColor * dstAlpha;
}
//colorBuffer[bx] += 0x00606060;
colorBuffer[bx] = ColorDataAccessor::ConvertColor(pixel_color);
}
}
colorBuffer += backBuffer->Desc().Width;
zBuffer += depthBuffer->Desc().Width;
//increment Y variables
for (int r = 1; r < REG_COUNT; r++) {
var00.reg[r] = var00.reg[r] + triDerivY.reg[r];
}
}
}
else //Partially covered block
{
int CY1 = C1 + Dx01 * y0 - Dy01 * x0;
int CY2 = C2 + Dx12 * y0 - Dy12 * x0;
int CY3 = C3 + Dx20 * y0 - Dy20 * x0;
for (int by = y; by < (y + blockSize); by++) {
int CX1 = CY1;
int CX2 = CY2;
int CX3 = CY3;
for (int bx = x; bx < (x + blockSize); bx++) {
if (CX1 < 0 && CX2 < 0 && CX3 < 0) {
auto ddx0 = bx - ix0;
auto ddy0 = (by - iy0);
float2 zw = p0zw + derivZW_X * ddx0 + derivZW_Y * ddy0;
float z_interp = zw.x();
if (zBuffer[bx] > z_interp) {
zBuffer[bx] = z_interp;
//interpolate registers
for (int r = 1; r < REG_COUNT; r++) {
r_ps.reg[r] = invRegs[0].reg[r] + triDerivX.reg[r] * ddx0 + triDerivY.reg[r] * ddy0;
r_ps.reg[r] /= zw.y();//add perspective correction
}
float4 rst;
rst = ps->Execute(&r_ps.reg[0]);
//UINT texcolor = ConvertColor(rst);
if (blendState.BlendEnable) {
uint32_t dc = colorBuffer[bx];
float4 dstColor = ColorDataAccessor::ConvertColor(dc);
float srcAlpha;
float dstAlpha;
//get source alpha
srcAlpha = GetBlendAlpha(blendState.SrcAlpha, rst, dstColor);
dstAlpha = GetBlendAlpha(blendState.DstAlpha, rst, dstColor);
rst = rst * srcAlpha + dstColor * dstAlpha;
}
//colorBuffer[bx] += 0x00606060;
colorBuffer[bx] = ColorDataAccessor::ConvertColor(rst);
}
}
CX1 -= FDy01;
CX2 -= FDy12;
CX3 -= FDy20;
}
CY1 += FDx01;
CY2 += FDx12;
CY3 += FDx20;
colorBuffer += backBuffer->Desc().Width;
zBuffer += depthBuffer->Desc().Width;
}
}
}
bbPtr += backBuffer->Desc().Width * blockSize;
dbPtr += depthBuffer->Desc().Width * blockSize;
}
}
std::array<float4*, REG_COUNT> r0_in;
std::array<float4*, REG_COUNT> r1_in;
std::array<float4*, REG_COUNT> r2_in;
RegisterBlock r0_out;
RegisterBlock r1_out;
RegisterBlock r2_out;
RegisterBlock rA_out;
RegisterBlock rB_out;
RegisterBlock r_ps;
BlendState blendState;
IInputLayout* geomLayout;
std::array<int, REG_COUNT> regMapping;
struct vertex_buffer_slot{
Buffer* buffer;
size_t stride;
};
std::array<vertex_buffer_slot, 8> vbSlots;
std::array<Buffer*, 8> ibSlots;
VertexShader* vs;
PixelShader* ps;
int primitiveType;
Texture* backBuffer;
Texture* depthBuffer;
};
#endif // BlockRasterizer_h__
+31
View File
@@ -0,0 +1,31 @@
#ifndef Buffer_h__
#define Buffer_h__
#include <string.h>
#include <cstdint>
#include "Debug.h"
class Buffer {
public:
constexpr Buffer()
{
}
virtual ~Buffer() = default;
void Write(void* src, size_t offset, size_t length){
SGL_ASSERT(src != nullptr, "Invalid pointer");
SGL_ASSERT((offset + length) <= Size(), "Invalid pointer");
memcpy((uint8_t*)GetPointer() + offset, src, length);
}
void Read(void* dst, size_t offset, int length){
memcpy(dst, (uint8_t*)GetPointer() + offset, length);
}
virtual void* GetPointer() = 0;
virtual size_t Size() = 0;
virtual size_t ItemSize()
{
return 1;
}
};
#endif // Buffer_h__
+17
View File
@@ -0,0 +1,17 @@
#ifndef Debug_h__
#define Debug_h__
#include <cstdio>
#include <cassert>
#if defined(DEBUG) || defined(_DEBUG)
#define SGL_DEBUG
#define SGL_ASSERT(__expr, __text) assert(__expr && __text);
#else
#define SGL_ASSERT(__expr, __text)
#endif
#define DebugInfo(...) printf("Info: "); printf(__VA_ARGS__); printf("\n");
#define DebugError(...) printf("Error: "); printf(__VA_ARGS__); printf("\n");
#endif // Debug_h__
+13
View File
@@ -0,0 +1,13 @@
#ifndef DisplayMode_h__
#define DisplayMode_h__
#include <cstdint>
struct DisplayMode {
uint32_t width;
uint32_t height;
uint32_t refreshRate;
uint32_t bpp;
};
#endif // DisplayMode_h__
+69
View File
@@ -0,0 +1,69 @@
#pragma once
#include <chrono>
template<size_t AveragingFramesCount = 20>
class FpsCounter
{
public:
using Clock = std::chrono::steady_clock;
using Duration = std::chrono::steady_clock::duration;
using TimePoint = std::chrono::steady_clock::time_point;
FpsCounter():position(0),avgFps(0) {
_lastClock = Clock::now();
timeElapsed = timeElapsed.zero();
for (size_t i = 0; i < AveragingFramesCount; ++i) {
_buffer[i] = {};
}
}
~FpsCounter()
{
}
void ComputeFPS(){
auto nowTime = Clock::now();
timeElapsed = nowTime - _lastClock;
_lastClock = nowTime;
_buffer[position] = timeElapsed;
position = (position + 1) % AveragingFramesCount;
Duration sum = {};
for (size_t i = 0; i < AveragingFramesCount; ++i) {
sum += _buffer[i];
}
auto us = std::chrono::duration_cast<std::chrono::microseconds>(sum).count() / AveragingFramesCount;
if (us == 0) {
avgFps = 0.0f;
} else {
avgFps =1.0f / ( (float)us / 1000000.0f);
}
}
float PreciseFPS() {
float time = GetFrameTimeSeconds();
if (time <= 0.0f) {
return 0.0f;
}
return 1.0f / time;
}
float AverageFPS()
{
return avgFps;
}
float GetFrameTimeSeconds() const {
return (float)std::chrono::duration_cast<std::chrono::microseconds>(timeElapsed).count() / 1000000.0f;
}
Duration GetTimeElapsed() const {
return timeElapsed;
}
private:
TimePoint _lastClock;
Duration timeElapsed;
float avgFps;
Duration _buffer[AveragingFramesCount];
int position;
};
+66
View File
@@ -0,0 +1,66 @@
#pragma once
#include <SoftGL/PixelShader.h>
#include <SoftGL/BRDF/lighting_core.h>
class PsNormalMap : public PixelShader {
public:
float3 camPosition;
float4 diffuse;
Texture* diffuse_map;
Texture* normal_map;
Texture* ao_map;
float ior = 1.5f;
float M = 0.7f;
PsNormalMap() :diffuse_map(nullptr), normal_map(nullptr), diffuse(0) {
}
float4 Execute(float4* input) {
//return float4(1, 1, 0, 1);
//return float4(input[1].x, input[1].y, 0, 1);
float3 lightColor = float3(1.0f, 1.0f, 0.9f);
float3 ambientColor = float3(0.1f, 0.1f, 0.25f);
float4 normal_tbn = tex2D(normal_map, input[1].x(), input[1].y(), TextureFilter::Bilinear);
auto tmp = normal_tbn.y();
normal_tbn.y() = normal_tbn.z();
normal_tbn.z() = tmp;
float4 ao = tex2D(ao_map, input[1].x(), input[1].y(), TextureFilter::Bilinear);
//return float4(normal_tbn.x, normal_tbn.y, normal_tbn.z, 1);
float3 N = lm::normalize(normal_tbn.xyz() * 2.0f - 1.0f); //lm::normalize(input[2].xyz);
float3 L = lm::normalize(float3(1, 1, 1));
float3 V = lm::normalize(camPosition - input[3].xyz());
float3 H = normalize(L + V);
float NdotL = std::max<float>(0, lm::dot(N, L));
float NdotV = std::max<float>(0, lm::dot(N, V));
float LdotH = lm::dot(L, H);
float F = Fresnel(LdotH, ior);
float G = G_Cook_Torrance(N, H, V, L);
float D = D_Beckmann(H, N, M);
float r_microfacet = (F * G * D) / (4 * NdotL * NdotV + 1.0e-7) * MATH_PI* NdotL;
float4 diffuse = tex2D(diffuse_map, input[1].x(), input[1].y(), TextureFilter::Bilinear);
float3 result = float3(0, 0, 0);
result = diffuse.xyz() * (lightColor * diffuse.xyz()) * NdotL + lightColor * r_microfacet + ambientColor * diffuse.xyz() * ao.x();
result = lm::saturate(result);
float4 retval;
retval.xyz() = result;
retval.w() = diffuse.w();
return retval;
}
};
+62
View File
@@ -0,0 +1,62 @@
#pragma once
#include <LMath/lmath.h>
#include "gameobject.h"
class Camera {
public:
Camera(Game_object* object):
_fov(3.1415f/4.0f), _zNear(0.3f), _zFar(100.0f), _aspect(1.0f), _object(object){
UpdateProjection();
}
lm::float4x4 world_to_camera_matrix(){
auto tf = _object->transform.get_global_transform();
return lm::inverse(tf, false);
}
Game_object* GameObject()
{
return _object;
}
float4x4 GetProjection() const{
return _projection;
}
float GetFov() const{
return _fov;
}
void SetFov(float fov) {
_fov = fov;
UpdateProjection();
}
float GetAspect() const {
return _aspect;
}
void SetAspect(float aspect) {
_aspect = aspect;
UpdateProjection();
}
float GetZNear() const {
return _zNear;
}
void SetZNear(float zNear) {
_zNear = zNear;
UpdateProjection();
}
float GetZFar() const {
return _zFar;
}
void SetZFar(float zFar) {
_zFar = zFar;
UpdateProjection();
}
private:
void UpdateProjection(){
_projection = lm::matrix4x4Perspective(_fov, _aspect, _zNear, _zFar);
}
float _fov;
float _zNear;
float _zFar;
float _aspect;
float4x4 _projection;
Game_object* _object;
};
@@ -0,0 +1,53 @@
#pragma once
#include "camera.h"
#include <LFramework/Input/Input.h>
#include <LMath/lmath.h>
class CameraController{
public:
float mouse_speed;
float move_speed = 3.0f;
static constexpr float pi = 3.14159265358979f;
CameraController(Camera* camera) : mouse_speed(0.01f), _camera(camera) {
_angle_x = _angle_y = 0.0f;
}
void Tick(float deltaTime) {
auto mice = Input::Instance()->mice();
auto mouse = mice[1];
if(mouse->GetKeyState(1)){
_angle_x += mouse_speed * mouse->GetDx();
_angle_y += mouse_speed * mouse->GetDy();
_angle_y = clamp(_angle_y, -pi / 2.0f, pi / 2.0f);
auto rv = lm::Quaternion_f::angleAxis(_angle_y, lm::float3(1, 0, 0));
auto rh = lm::Quaternion_f::angleAxis(_angle_x, lm::float3(0, 1, 0));
_camera->GameObject()->transform.set_local_rotation(lm::mul(rh, rv));
}
auto keyboard = Input::Instance()->keyboards()[3];
auto& tf = _camera->GameObject()->transform;
if (keyboard->GetKeyState(0x57)) {
tf.SetLocalPosition(tf.GetLocalPosition() + tf.Forward() * (deltaTime * move_speed));
}
if (keyboard->GetKeyState(0x53)) {
tf.SetLocalPosition(tf.GetLocalPosition() - tf.Forward() * (deltaTime * move_speed));
}
if (keyboard->GetKeyState(0x41)) {
tf.SetLocalPosition(tf.GetLocalPosition() - tf.right() * (deltaTime * move_speed));
}
if (keyboard->GetKeyState(0x44)) {
tf.SetLocalPosition(tf.GetLocalPosition() + tf.right() * (deltaTime * move_speed));
}
}
private:
Camera* _camera;
float _angle_x;
float _angle_y;
};
+91
View File
@@ -0,0 +1,91 @@
#pragma once
#include "imesh.h"
#include <LMath/lmath.h>
#include <iostream>
using namespace lm;
template<typename TVertex, typename TIndex>
struct CubeGenerator {
static constexpr size_t VertexCount = 24;
static constexpr size_t IndexCount = 36;
static constexpr float4 Corner(size_t id) {
return float4(id % 2 == 0 ? -1.0f : 1.0f, id < 4 ? 1.0f : -1.0f, (id % 4) < 2 ? 1.0f : -1.0f, 1.0f);
}
static bool Generate(IMesh* m) {
if (m == nullptr) {
return false;
}
auto vb = m->GetVertexBuffer();
if (vb == nullptr || (vb->Size() / vb->ItemSize()) < VertexCount) {
return false;
}
auto ib = m->GetSubmeshBuffer(0);
if (ib == nullptr || (ib->Size() / ib->ItemSize()) < IndexCount) {
return false;
}
static constexpr float extent = 0.5f;
// 0-1
//2-3
//
// 4-5
//6-7
static constexpr std::array<size_t, 4> sides[6] = {
{ 3,1,5,7 },
{ 0,2,6,4 },
{ 0,1,3,2 },
{ 6,7,5,4 },
{ 1,0,4,5 },
{ 2,3,7,6 }
};
static constexpr std::array<float3, 6> normals = {
float3(1.0f,0.0f,0.0f),
float3(-1.0f,0.0f,0.0f),
float3(0.0f,1.0f,0.0f),
float3(0.0f,-1.0f,0.0f),
float3(0.0f,0.0f,1.0f),
float3(0.0f,0.0f,-1.0f)
};
static constexpr float2 uvs[4] = {
float2(0.0f,0.0f),
float2(1.0f,0.0f),
float2(1.0f,1.0f),
float2(0.0f,1.0f)
};
static constexpr size_t indexMap[6] = {
0,1,3,3,1,2
};
auto vertices = (TVertex*)vb->GetPointer();
auto indices = (TIndex*)ib->GetPointer();
for(size_t i = 0; i < 6; ++i){
//update vertices
for (size_t j = 0; j < 4; ++j) {
auto& vertex = vertices[i * 4 + j];
vertex.Position = Corner(sides[i][j]);
vertex.Normal = normals[i];
vertex.UV0 = uvs[j];
}
auto indexBase = i * 4;
for (size_t j = 0; j < 6; ++j) {
indices[i * 6 + j] = indexBase + indexMap[j];
}
}
return true;
}
};
+10
View File
@@ -0,0 +1,10 @@
#ifndef fresnel_h__
#define fresnel_h__
#include <cmath>
inline float Fresnel(float c, float ior) {
float g = std::sqrt(ior*ior + c*c - 1);
return 0.5f * std::pow(g - c, 2) / std::pow(g + c, 2) * (1 + std::pow(c*(g + c) - 1, 2) / std::pow(c*(g - c) + 1, 2));
}
#endif // fresnel_h__
+14
View File
@@ -0,0 +1,14 @@
#ifndef gameobject_h__
#define gameobject_h__
#include "transform.h"
class Game_object {
public:
Transform transform;
Game_object():transform(this)
{
}
};
#endif // gameobject_h__
+11
View File
@@ -0,0 +1,11 @@
#pragma once
#include <SoftGL/Buffer.h>
#include <SoftGL/static_vector.h>
class IMesh {
public:
virtual Buffer* GetVertexBuffer() = 0;
virtual size_t GetSubmeshCount() const = 0;
virtual Buffer* GetSubmeshBuffer(size_t id) const = 0;
};
+29
View File
@@ -0,0 +1,29 @@
#ifndef mesh_h__
#define mesh_h__
#include "imesh.h"
#include <array>
template<size_t SubmeshCount>
class Mesh : public IMesh {
public:
Buffer* vertexBuffer;
std::array<Buffer*, SubmeshCount> submeshes;
virtual Buffer* GetVertexBuffer() override {
return vertexBuffer;
}
virtual size_t GetSubmeshCount() const override {
return SubmeshCount;
}
virtual Buffer* GetSubmeshBuffer(size_t id) const override {
return submeshes[id];
}
};
#endif // mesh_h__
+70
View File
@@ -0,0 +1,70 @@
#pragma once
#include "imesh.h"
#include <LMath/lmath.h>
using namespace lm;
template<typename TVertex, typename TIndex>
struct PlaneGenerator {
static constexpr size_t VertexCount = 4;
static constexpr size_t IndexCount = 6;
static constexpr float4 Corner(size_t id) {
return float4(id % 2 == 0 ? -1.0f : 1.0f, 0.0f, (id % 4) < 2 ? 1.0f : -1.0f, 1.0f);
}
static bool Generate(IMesh* m) {
if (m == nullptr) {
return false;
}
auto vb = m->GetVertexBuffer();
if (vb == nullptr || (vb->Size() / vb->ItemSize()) < VertexCount) {
return false;
}
auto ib = m->GetSubmeshBuffer(0);
if (ib == nullptr || (ib->Size() / ib->ItemSize()) < IndexCount) {
return false;
}
static constexpr std::array<float3, 6> normals = {
float3(1.0f,0.0f,0.0f),
float3(-1.0f,0.0f,0.0f),
float3(0.0f,1.0f,0.0f),
float3(0.0f,-1.0f,0.0f),
float3(0.0f,0.0f,1.0f),
float3(0.0f,0.0f,-1.0f)
};
static constexpr float2 uvs[4] = {
float2(0.0f, 0.0f),
float2(1.0f, 0.0f),
float2(0.0f, 1.0f),
float2(1.0f, 1.0f)
};
static constexpr size_t planeIndices[6] = {
0,1,2,2,1,3
};
auto vertices = (TVertex*)vb->GetPointer();
auto indices = (TIndex*)ib->GetPointer();
//update vertices
for (size_t j = 0; j < 4; ++j) {
auto& vertex = vertices[j];
vertex.Position = Corner(j);
vertex.Normal = float3(0.0f, 1.0f, 0.0f);
vertex.UV0 = uvs[j];
}
for (size_t j = 0; j < 6; ++j) {
indices[j] = planeIndices[j];
}
return true;
}
};
@@ -0,0 +1,18 @@
#pragma once
#include <SoftGL/PixelShader.h>
class PSTexturedNoLit : public PixelShader {
public:
Texture* diffuseMap;
PSTexturedNoLit() :diffuseMap(nullptr) {}
float4 Execute(float4* input) {
float4 diffuse = float4(0, 0, 0, 0);
if (diffuseMap != nullptr) {
diffuse = tex2D(diffuseMap, input[1].x(), input[1].y(), TextureFilter::Bilinear);
}
return diffuse;
}
};
+84
View File
@@ -0,0 +1,84 @@
#pragma once
#include <LMath/lmath.h>
using namespace lm;
class Game_object;
class Transform {
public:
Transform* parent;
lm::Quaternion_f _rotation;
float3 _position;
float3 _scale;
Transform(Game_object* game_object)
:parent(nullptr), _scale(1, 1, 1), _position(0, 0, 0), _rotation(0, 0, 0, 1), _game_object(game_object) {
}
std::wstring class_name() const {
return L"Transform";
}
void SetLocalPosition(const float3& position) {
_position = position;
}
float3 GetLocalPosition() {
return _position;
}
float3 Forward() const {
return get_global_transform()[2].xyz();
}
float3 right() const {
return get_global_transform()[0].xyz();
}
float3 up() const {
return get_global_transform()[1].xyz();
}
void set_local_rotation(const Quaternion_f& rotation) {
_rotation = rotation;
}
Quaternion_f get_local_rotation() {
return _rotation;
}
void set_local_scale(const float3& scale) {
_scale = scale;
}
float3 get_local_scale() {
return _scale;
}
float4x4 get_local_transform() const {
float4x4 scaleMatrix = matrix4x4Scale(_scale);
float4x4 rotationMatrix = matrix4x4RotationQuaternion(_rotation);
float4x4 positionMatrix = matrix4x4Translation(_position);
return lm::mul(lm::mul(scaleMatrix, rotationMatrix), positionMatrix);
}
float4x4 get_global_transform() const {
if (parent == nullptr) {
return get_local_transform();
}
return lm::mul(get_local_transform(), parent->get_global_transform());
}
float3 get_global_position() {
auto tf = get_global_transform();
return float3(tf[3][0], tf[3][1], tf[3][2]);
}
void RotateLocal(const Quaternion_f& rotation) {
_rotation = lm::mul(_rotation, rotation);
}
private:
Game_object* _game_object;
};
+108
View File
@@ -0,0 +1,108 @@
#ifndef Graphics2D_h__
#define Graphics2D_h__
#include "Texture.h"
struct TextureWriter {
Texture* texture;
size_t width() {
return texture->Desc().Width;
}
size_t height() {
return texture->Desc().Height;
}
template<typename Color>
void setPixel(int32_t x, int32_t y, Color color) {
if (x < 0 || y < 0) {
return;
}
if (x >= (int64_t)width() || y >= (int64_t)height()) {
return;
}
uint8_t* data = ((uint8_t*)texture->LockWrite()) + (y * width() + x) * sizeof(color);
memcpy(data, &color, sizeof(color));
}
};
template<typename PixelWriter, typename Color>
void clear(PixelWriter& writer, const Color& color) {
for (size_t y = 0; y < writer.height(); ++y) {
for (size_t x = 0; x < writer.width(); ++x) {
writer.setPixel(x, y, color);
}
}
}
template<typename PixelWriter, typename Color>
void drawCircle(int X1, int Y1, int R, PixelWriter& writer, const Color& color) {
int x = 0;
int y = R;
int delta = 1 - 2 * R;
int error = 0;
while (y >= 0) {
writer.setPixel(X1 + x, Y1 + y, color);
writer.setPixel(X1 + x, Y1 - y, color);
writer.setPixel(X1 - x, Y1 + y, color);
writer.setPixel(X1 - x, Y1 - y, color);
error = 2 * (delta + y) - 1;
if ((delta < 0) && (error <= 0)) {
delta += 2 * ++x + 1;
continue;
}
error = 2 * (delta - x) - 1;
if ((delta > 0) && (error > 0)) {
delta += 1 - 2 * --y;
continue;
}
x++;
delta += 2 * (x - y);
y--;
}
}
template<typename PixelWriter, typename Color>
void drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, PixelWriter& writer, const Color& color) {
int32_t steep = abs(y1 - y0) > abs(x1 - x0);
if (steep) {
std::swap(x0, y0);
std::swap(x1, y1);
}
if (x0 > x1) {
std::swap(x0, x1);
std::swap(y0, y1);
}
int32_t dx = x1 - x0;
int32_t dy = abs(y1 - y0);
auto err = dx / 2;
int32_t ystep;
if (y0 < y1) {
ystep = 1;
}
else {
ystep = -1;
}
for (; x0 <= x1; x0++) {
if (steep) {
writer.setPixel(y0, x0, color);
}
else {
writer.setPixel(x0, y0, color);
}
err -= dy;
if (err < 0) {
y0 += ystep;
err += dx;
}
}
}
#endif // Graphics2D_h__
+51
View File
@@ -0,0 +1,51 @@
#pragma once
#include "LString.h"
#include "DisplayMode.h"
#include <cstdint>
#include <cstddef>
#include "Texture.h"
class IRenderWindow{
public:
virtual ~IRenderWindow(void) {}
virtual void Update() = 0;
virtual void SetCaption(const String& caption) = 0;
virtual std::size_t GetWindowHandle() = 0;
virtual int GetWidth() = 0;
virtual int GetHeight() = 0;
virtual int GetTop() = 0;
virtual int GetLeft() = 0;
virtual void SetPosition(int top, int left) = 0;
virtual void SetSize(int w, int h) = 0;
virtual const String& GetCaption() = 0;
virtual bool IsFullScreen() = 0;
virtual void SetFullScreen(bool state) = 0;
virtual bool SwitchMode(bool fullscreen) = 0;
virtual void SetFullscreenMode(DisplayMode mode) = 0;
virtual const DisplayMode& GetFullscreenMode()
{
return fsMode;
}
virtual void Present(Texture* tex) = 0;
virtual void OnActivate() = 0;
virtual void OnDeactivate() = 0;
virtual void OnResize() = 0;
virtual bool IsActive() = 0;
virtual bool IsModeSwitching() = 0;
virtual void SetCursorVisible(bool state) = 0;
virtual bool IsCursorVisible() = 0;
virtual void CenterWindow() = 0;
protected:
bool bCursorVisible;
bool bModeSwitching;
bool bFullscreen;
bool bActive;
int width;
int height;
String caption;
DisplayMode fsMode;
};
+45
View File
@@ -0,0 +1,45 @@
#ifndef IShader_h__
#define IShader_h__
#include "LString.h"
#include <vector>
#include <LMath/lmath.h>
using namespace lm;
using namespace std;
class IShader
{
protected:
typedef std::vector<String> RegisterList;
RegisterList inputs;
public:
int RegisterCount()
{
return inputs.size();
}
int FindRegister(const String& name)
{
int cnt = inputs.size();
if(!cnt) return -1;
RegisterList::iterator it = inputs.begin();
for(int i = 0; i < cnt; i++)
{
if((*it) == name) return i;
it++;
}
return -1;
}
IShader()
{
}
virtual ~IShader()
{
}
};
#endif // IShader_h__
@@ -0,0 +1,26 @@
#pragma once
#include <LMath/lmath.h>
#include <cstdint>
class ImageDataAccessorR5G6B5 {
public:
using PixelDataType = std::uint16_t;
static constexpr bool HasAlpha = true;
static PixelDataType ConvertColor(const lm::float4& color) {
PixelDataType r = (uint32_t)(color.x() * 0x1f);
PixelDataType g = (uint32_t)(color.y() * 0x3f);
PixelDataType b = (uint32_t)(color.z() * 0x1f);
return (r << 11) | (g << 5) | (b);
}
static lm::float4 ConvertColor(PixelDataType color) {
float r = (float)(color >> 11) / 0x1f;
float g = (float)((color >> 5) & 0x3f) / 0x3f;
float b = (float)((color >> 0) & 0x1f) / 0x1f;
return lm::float4(r, g, b, 1.0f);
}
};
@@ -0,0 +1,31 @@
#pragma once
#include <LMath/lmath.h>
#include <cstdint>
class ImageDataAccessorR8G8B8 {
public:
using PixelDataType = std::uint32_t;
static constexpr bool HasAlpha = true;
static uint32_t ConvertColor(const lm::float4& color) {
uint32_t r = (uint32_t)(color.x() * 255.0f);
uint32_t g = (uint32_t)(color.y() * 255.0f);
uint32_t b = (uint32_t)(color.z() * 255.0f);
uint32_t a = (uint32_t)(color.w() * 255.0f);
return (a << 24) | (r << 16) | (g << 8) | (b);
}
static lm::float4 ConvertColor(uint32_t color) {
float d = 1.0f / 255.0f;
float a = (float)((color >> 24) & 0xff) * d;
float r = (float)((color >> 16) & 0xff) * d;
float g = (float)((color >> 8) & 0xff) * d;
float b = (float)((color >> 0) & 0xff) * d;
return lm::float4(r, g, b, a);
}
};
+6
View File
@@ -0,0 +1,6 @@
#ifndef IndexBuffer_h__
#define IndexBuffer_h__
#endif // IndexBuffer_h__
+59
View File
@@ -0,0 +1,59 @@
#ifndef InputLayout_h__
#define InputLayout_h__
#include "LString.h"
#include "RasterizerSettings.h"
#include "Debug.h"
#include <array>
enum class RegType {
float1 = 0,
float2 = 1,
float3 = 2,
float4 = 3
};
struct InputElement {
char name[InputElementNameLength];
uint8_t Offset;
RegType type;
uint8_t StreamId;
InputElement() :name{0}, Offset(0), type(RegType::float1), StreamId(0){
}
InputElement(const char* _name, uint8_t offset, RegType t, uint8_t stream) {
SGL_ASSERT(strlen(_name) < InputElementNameLength, "Too long name for InputElement");
strcpy(name, _name);
Offset = offset;
type = t;
StreamId = stream;
}
};
class IInputLayout {
public:
virtual size_t Size() = 0;
virtual InputElement* GetElement(size_t id) = 0;
int FindElement(const char* name) {
auto size = Size();
for (size_t i = 0; i < size; i++) {
if (strcmp(GetElement(i)->name, name) == 0)
return i;
}
return -1;
}
};
template<size_t _Size>
class StaticInputLayout : public IInputLayout {
public:
std::array<InputElement, _Size> elements;
virtual size_t Size() override {
return _Size;
}
virtual InputElement* GetElement(size_t id) override {
return &elements[id];
}
};
#endif // InputLayout_h__
+109
View File
@@ -0,0 +1,109 @@
#ifndef InputSystem_h__
#define InputSystem_h__
#include <OIS.h>
#include <sstream>
#include "RenderWindow.h"
#include "Delegate.h"
#ifdef _DEBUG
#pragma comment (lib, "OIS_static_d.lib")
#else
#pragma comment (lib, "OIS_static.lib")
#endif
using namespace OIS;
class InputSystem : public OIS::KeyListener, public OIS::MouseListener
{
public:
EVENT1(KBEvent, int);
KBEvent Event_KeyDown;
KBEvent Event_KeyUp;
EVENT4(MSEvent, int, int, int, int);
MSEvent Event_MouseMove;
InputSystem(RenderWindow* window, int sw, int sh)
{
//init Input
ParamList pl;
HWND hw = (HWND)window->GetWindowHandle();
std::ostringstream wnd;
wnd << (size_t)hw;
pl.insert(std::make_pair( std::string("WINDOW"), wnd.str() ));
bool hideCursor = false;
if( !hideCursor)
{
pl.insert(std::make_pair(std::string("w32_mouse") , std::string("DISCL_BACKGROUND" )));
pl.insert(std::make_pair(std::string("w32_mouse") , std::string("DISCL_NONEXCLUSIVE")));
}
pl.insert(std::make_pair(std::string("w32_keyboard"), std::string("DISCL_BACKGROUND")));
pl.insert(std::make_pair(std::string("w32_keyboard"), std::string ("DISCL_NONEXCLUSIVE") ));
input = InputManager::createInputSystem(pl);
keyboard = (Keyboard*)input->createInputObject(OISKeyboard,1);
mouse = (Mouse*)input->createInputObject(OISMouse,1);
mouse->getMouseState().width = sw;
mouse->getMouseState().height = sh;
keyboard->setEventCallback(this);
mouse->setEventCallback(this);
}
~InputSystem()
{
input->destroyInputObject(mouse);
input->destroyInputObject(keyboard);
InputManager::destroyInputSystem(input);
}
void Capture()
{
mouse->capture();
keyboard->capture();
}
bool keyPressed(const KeyEvent &arg)
{
Event_KeyDown.Invoke((int)arg.key);
return true;
}
bool keyReleased(const KeyEvent &arg)
{
Event_KeyUp.Invoke((int)arg.key);
return true;
}
bool mouseMoved( const MouseEvent &arg )
{
Event_MouseMove.Invoke(arg.state.X.abs, arg.state.Y.abs, arg.state.X.rel, arg.state.Y.rel);
return true;
}
bool mousePressed( const MouseEvent &arg, MouseButtonID id )
{
return true;
}
bool mouseReleased( const MouseEvent &arg, MouseButtonID id )
{
return true;
}
void SetKeyDownCallback()
{
}
private:
InputManager* input;
Keyboard* keyboard;
Mouse* mouse;
};
#endif // InputSystem_h__
+44
View File
@@ -0,0 +1,44 @@
#ifndef LSTRING_H__
#define LSTRING_H__
#include <string>
#ifdef _UNICODE
#define _text(str) L##str
typedef std::wstring String;
#define PRINT wprintf
#define STRCMP wcscmp
typedef wchar_t tchar;
#define string_size(str) (str.length() * 2)
#else
#define _text(str) str
#define PRINT printf
typedef std::string String;
typedef char tchar;
#define STRCMP strcmp
#define string_size(str) (str.length())
#endif
#ifdef WIN32
#define PATH_SPLITTER _text("\\")
#else
#define PATH_SPLITTER _text("/")
#endif
extern String GetFileName(const String& path);
extern String GetFileName(const String& path, const String& pathSplitter);
extern String GetFileNameWithoutExtention(const String& path);
extern String GetFilePath(const String& path, const String& pathSplitter);
extern void GetRootFolderS(const String& path, String& folderName, String& resultPath);
extern void GetRootFolderS(const String& path, String& folderName);
extern String GetDirectoryName(const String& path);
#define AS_STRING(omg) String(omg)
#define STR(omg) String(omg)
#endif
+65
View File
@@ -0,0 +1,65 @@
#ifndef PSDefault_h__
#define PSDefault_h__
#include "PixelShader.h"
#include <SoftGL/BRDF/lighting_core.h>
class PSDefault : public PixelShader
{
public:
float3 camPosition;
float4 diffuse;
Texture* diffuse_map;
float ior = 1.5f;
float M = 0.7f;
PSDefault():diffuse_map(nullptr), diffuse(0){
}
float4 Execute(float4* input) {
using namespace lm;
//return float4(1, 1, 0, 1);
//return float4(input[1].x, input[1].y, 0, 1);
float3 lightColor = float3(1.0f, 1.0f, 0.9f);
float3 ambientColor = float3(0.1f, 0.1f, 0.2f);
float3 N = lm::normalize(input[2].xyz());
float3 L = lm::normalize(float3(1, 1, 1));
float3 V = lm::normalize(camPosition - input[3].xyz());
float3 H = normalize(L + V);
float NdotL = std::max<float>(0, lm::dot(N, L));
float NdotV = std::max<float>(0, lm::dot(N, V));
float LdotH = lm::dot(L, H);
float F = Fresnel(LdotH, ior);
float G = G_Cook_Torrance(N, H, V, L);
float D = D_Beckmann(H, N, M);
float r_microfacet = (F * G * D) / (4 * NdotL * NdotV + 1.0e-7) * MATH_PI* NdotL;
float4 diffuse = float4(0, 0, 0, 0);
if (diffuse_map != nullptr) {
diffuse = tex2D(diffuse_map, input[1].x(), input[1].y(), TextureFilter::Bilinear);
};
float3 result = float3(0, 0, 0);
result = diffuse.xyz() * (lightColor * diffuse.xyz()) * NdotL + lightColor * r_microfacet + ambientColor * diffuse.xyz();
result = lm::saturate(result);
float4 retval;
retval.xyz() = result;
retval.w() = diffuse.w();
return retval;
}
};
#endif // PSDefault_h__
+17
View File
@@ -0,0 +1,17 @@
#pragma once
#include "PixelShader.h"
#include <SoftGL/BRDF/lighting_core.h>
class PSDefaultColor : public PixelShader
{
public:
float4 diffuse;
PSDefaultColor(): diffuse(1.0f, 1.0f, 1.0f, 1.0f){
}
float4 Execute(float4* input) {
return diffuse;
}
};
+28
View File
@@ -0,0 +1,28 @@
#ifndef PSFont_h__
#define PSFont_h__
#include "PixelShader.h"
class PSFont : public PixelShader
{
public:
float appTime;
float4 diffuse;
Texture2D* diffuseTex;
PSFont()
{
}
float4 Execute(float4* input)
{
float4 out;
tex2D(diffuseTex, &out, input[1].X, input[1].Y);
out = float4(1,1,1,1) - out;
out.W = out.X;
return out;
}
};
#endif // PSFont_h__
+37
View File
@@ -0,0 +1,37 @@
#ifndef PSTextured_h__
#define PSTextured_h__
#include "PixelShader.h"
class PSTextured : public PixelShader
{
public:
float appTime;
float4 diffuse;
Texture2D* diffuseTex;
PSTextured()
{
}
float4 Execute(float4* input)
{
/* float f = (sinf(appTime * 4.0f) * 0.5f + 0.5f);
float4 color = diffuse * (sinf((input[0].Y / 2.0f)) * 0.5f + 0.5f)* (cosf((input[0].X / 2.0f)) * 0.5f * f + 0.5f);
color.W = 0.6f;*/
//return color;
//return diffuse;
float4 out;
sample2D(diffuseTex, &out, input[1].X, input[1].Y);
//out = float4(1,1,1,1) - out;
out.W = 0.5f;
//return float4(1,1,1,1);
return out;
//return float4(1,1,0,1);
}
};
#endif // PSTextured_h__
+98
View File
@@ -0,0 +1,98 @@
#ifndef PixelShader_h__
#define PixelShader_h__
#include "IShader.h"
#include "Texture.h"
#include <cstdint>
#include <LMath/lmath.h>
using namespace lm;
enum class TextureFilter {
Point,
Bilinear,
Trilinear,
Anisotropic
};
#define CLIP -1231345391
class PixelShader : public IShader {
public:
virtual ~PixelShader() {
}
virtual float4 Execute(float4* input) = 0;
float4 tex2D(Texture* tex, float tx, float ty, TextureFilter filter) {
if (tex == nullptr) {
return float4(0, 0, 0, 0);
}
auto width = tex->Desc().Width;
auto height = tex->Desc().Height;
auto bpp = tex->Desc().BytesPerPixel;
auto tw = (float)(width - 1);
auto th = (float)(height - 1);
auto mips = tex->LockRead();
if (tx > 1.0f) {
tx = 1.0f;
}
if (tx < 0.0f) {
tx = 0.0f;
}
if (ty > 1.0f) {
ty = 1.0f;
}
if (ty < 0.0f) {
ty = 0.0f;
}
if (filter == TextureFilter::Bilinear) {
float x = (tx * tw);
float y = (ty * th);
int px = (int)x;
int py = (int)y;
float fx = x - px;
float fy = y - py;
float fx1 = 1.0f - fx;
float fy1 = 1.0f - fy;
int w1 = (int)(fx1 * fy1 * 256.0f);
int w2 = (int)(fx * fy1 * 256.0f);
int w3 = (int)(fx1 * fy * 256.0f);
int w4 = (int)(fx * fy * 256.0f);
auto mem = reinterpret_cast<const uint8_t*>(mips);
auto p1 = mem + ((py + 0)*width + (px + 0))* bpp;
auto p2 = mem + ((py + 0)*width + (px + 1))* bpp;
auto p3 = mem + ((py + 1)*width + (px + 0))* bpp;
auto p4 = mem + ((py + 1)*width + (px + 1))* bpp;
int outr = p1[0] * w1 + p2[0] * w2 + p3[0] * w3 + p4[0] * w4;
int outg = p1[1] * w1 + p2[1] * w2 + p3[1] * w3 + p4[1] * w4;
int outb = p1[2] * w1 + p2[2] * w2 + p3[2] * w3 + p4[2] * w4;
return float4(
((float)(outr >> 8)) / 255.0f,
((float)(outg >> 8)) / 255.0f,
((float)(outb >> 8)) / 255.0f,
1.0f);
} else {
tx += 0.5f / tw;
ty += 0.5f / th;
int x = (int)(tx * tw);
int y = (int)(ty * th);
auto ptr = reinterpret_cast<const uint8_t*>(mips);
ptr += (y*width + x)* bpp;
return float4(
((float)ptr[0]) / 255.0f,
((float)ptr[1]) / 255.0f,
((float)ptr[2]) / 255.0f,
1.0f);
}
}
};
#endif // PixelShader_h__
@@ -0,0 +1,202 @@
#include "RenderWindowXORG.h"
#if defined(LINUX)
#include <string.h>
#include <stdio.h>
RenderWindowXORG::RenderWindowXORG(uint16 width, uint16 height)
:img(0)
{
display_name = XOpenDisplay(NULL);
screen = DefaultScreen(display_name);
depth = DefaultDepth(display_name,screen);
connection = ConnectionNumber(display_name);
visual = DefaultVisual(display_name, 0);
if(depth == 1)
printf("You live in prehistoric times\n");
else
printf("You've got a coloured monitor with depth of %d\n",depth);
rootwindow = RootWindow(display_name,screen);
window = XCreateSimpleWindow(display_name, rootwindow,
0, 0, width, height, 1, 0, 0);
gc = XCreateGC(display_name, window, 0, NULL);
XMapWindow(display_name, window);
XFlush(display_name);
XSynchronize(display_name, 1);
}
int RenderWindowXORG::GetTop()
{
XWindowAttributes xwa;
XGetWindowAttributes(display_name, window, &xwa);
return xwa.y;
}
int RenderWindowXORG::GetLeft()
{
XWindowAttributes xwa;
XFlush(display_name);
XGetWindowAttributes(display_name, window, &xwa);
return xwa.x;
}
void RenderWindowXORG::SetPosition(int top, int left)
{
XMoveWindow(display_name, window, top, left);
XSync(display_name, 1);
XFlush(display_name);
XSynchronize(display_name, 1);
}
void RenderWindowXORG::Update()
{
}
void RenderWindowXORG::SetCaption(const String& caption)
{
XStoreName(display_name, window, caption.c_str());
XFlush(display_name);
}
int RenderWindowXORG::GetWindowHandle()
{
return -1;
}
int RenderWindowXORG::GetWidth()
{
XWindowAttributes xwa;
XGetWindowAttributes(display_name, window, &xwa);
return xwa.width;
}
int RenderWindowXORG::GetHeight()
{
XWindowAttributes xwa;
XGetWindowAttributes(display_name, window, &xwa);
return xwa.height;
}
void RenderWindowXORG::SetSize(int w, int h)
{
XResizeWindow(display_name, window, w, h);
XFlush(display_name);
XSync(display_name, 1);
}
const String& RenderWindowXORG::GetCaption()
{
return String("Not yet implemented");
}
bool RenderWindowXORG::IsFullScreen()
{
return false;
}
void RenderWindowXORG::SetFullScreen(bool state)
{
}
bool RenderWindowXORG::SwitchMode(bool fullscreen)
{
}
void RenderWindowXORG::SetFullscreenMode(DisplayMode mode)
{
}
void RenderWindowXORG::Present(Texture2D* tex)
{
// char buf[256];
if(img == 0)
{
// SetCaption("Create image!");
img = XCreateImage(display_name, visual, 24, ZPixmap, 0, (char *)tex->getBuffer()->getDataPtr(), tex->width, tex->height, 32, 0);
}
XPutImage(display_name, window, gc, img, 0, 0, 0, 0, tex->width, tex->height);
XFlushGC(display_name, gc);
XFlush(display_name);
XSync(display_name, true);
// sprintf(buf, "Data ptr = 0x%x", img->data);
// SetCaption(String(buf));
// img->data = NULL;
// XDestroyImage(img);
}
void RenderWindowXORG::OnActivate()
{
}
void RenderWindowXORG::OnDeactivate()
{
}
void RenderWindowXORG::OnResize()
{
}
bool RenderWindowXORG::IsActive()
{
return true;
}
bool RenderWindowXORG::IsModeSwitching()
{
return false;
}
void RenderWindowXORG::SetCursorVisible(bool state)
{
}
bool RenderWindowXORG::IsCursorVisible()
{
return true;
}
void RenderWindowXORG::CenterWindow()
{
int dw = DisplayWidth(display_name,screen);
int dh = DisplayHeight(display_name,screen);
int ww = GetWidth();
int wh = GetHeight();
int px = (dw - ww) / 2;
int py = (dh - wh) / 2;
SetPosition(px, py);
XFlush(display_name);
}
#endif
@@ -0,0 +1,54 @@
#ifndef RENDERWINDOWXORG_H
#define RENDERWINDOWXORG_H
#if defined(LINUX)
#include "IRenderWindow.h"
#include<X11/Xlib.h>
#include<X11/Xutil.h>
#include<stdio.h>
class RenderWindowXORG : public IRenderWindow
{
public:
RenderWindowXORG(uint16 width, uint16 height);
void Update();
void SetCaption(const String& caption);
int GetWindowHandle();
int GetWidth();
int GetHeight();
void SetSize(int w, int h);
const String& GetCaption();
int GetTop();
int GetLeft();
void SetPosition(int top, int left);
bool IsFullScreen();
void SetFullScreen(bool state);
bool SwitchMode(bool fullscreen);
void SetFullscreenMode(DisplayMode mode);
void Present(Texture2D* tex);
void OnActivate();
void OnDeactivate();
void OnResize();
bool IsActive();
bool IsModeSwitching();
void SetCursorVisible(bool state);
bool IsCursorVisible();
void CenterWindow();
private:
uint8_t* image32;
Visual *visual;
GC gc;
Display *display_name;
XImage* img;
int depth,screen,connection;
Window window, rootwindow;
};
#endif //LINUX
#endif // RENDERWINDOWXORG_H
@@ -0,0 +1,351 @@
#include "RenderWindow.h"
#include <Windows.h>
#include <WinUser.h>
RenderWindow::RenderWindow()
:UpdateCamera(false) {
bFullscreen = false;
bActive = true;
bModeSwitching = false;
bCursorVisible = true;
bAltEnterLocked = false;
width = 256;
height = 256;
g_hInst = GetModuleHandle(NULL);
g_hwnd = NULL;
//memset(&g_wndClass,0,sizeof(WNDCLASSEX));
WNDCLASSEX g_wndClass = { NULL };
g_wndClass.cbSize = sizeof(WNDCLASSEX);
g_wndClass.cbClsExtra = NULL;
g_wndClass.cbWndExtra = NULL;
g_wndClass.hbrBackground = (HBRUSH)GetStockObject(1);
g_wndClass.hCursor = (HCURSOR)LoadCursor(NULL, IDC_ARROW);
g_wndClass.hIcon = LoadIcon(g_hInst, IDI_APPLICATION);
g_wndClass.hIconSm = LoadIcon(g_hInst, IDI_APPLICATION);
g_wndClass.hInstance = g_hInst;
g_wndClass.lpfnWndProc = &RenderWindow::WndProc;
g_wndClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
g_wndClass.lpszMenuName = NULL;
g_wndClass.lpszClassName = _text("Onotole");
if (!RegisterClassEx(&g_wndClass)) {
MessageBox(g_hwnd, _text("Can not create window class! We all gonna die!!"), _text("OH SHIT!"), MB_OK);
}
//calculate window size
RECT NewWindowSize;
NewWindowSize.top = 30;
NewWindowSize.left = 300;
NewWindowSize.bottom = NewWindowSize.top + height;
NewWindowSize.right = NewWindowSize.left + width;
AdjustWindowRect(&NewWindowSize, WS_OVERLAPPEDWINDOW, false);
/*WS_MINIMIZEBOX
WS_MAXIMIZEBOX*/
if (!(g_hwnd = CreateWindowEx(NULL, _text("Onotole"), _text("LifeEngine render window"), WS_OVERLAPPEDWINDOW,
NewWindowSize.left, NewWindowSize.top, NewWindowSize.right - NewWindowSize.left, NewWindowSize.bottom - NewWindowSize.top, NULL, NULL, g_hInst, NULL))) {
MessageBox(g_hwnd, _text("Can not create window!"), _text("Can not create window!"), MB_OK);
return;
}
ShowWindow(g_hwnd, SW_SHOWNORMAL);
SetForegroundWindow(g_hwnd);
SetFocus(g_hwnd);
ZeroMemory(&mode, sizeof(DEVMODE));
mode.dmSize = sizeof(DEVMODE);
EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &mode);
RenderWindow* ptr = this;
LONG_PTR val = (LONG_PTR)ptr;
SetWindowLongPtr(g_hwnd, GWLP_USERDATA, val);
fsMode.width = 640;
fsMode.height = 480;
fsMode.refreshRate = 60;
fsMode.bpp = 4;
::ZeroMemory(&bitmapInfo, sizeof(BITMAPINFOHEADER));
bitmapInfo.biSize = sizeof(BITMAPINFOHEADER);
bitmapInfo.biWidth = width;
bitmapInfo.biHeight = -height;
bitmapInfo.biPlanes = 1;
bitmapInfo.biBitCount = 32;
bitmapInfo.biCompression = 0;
bitmapInfo.biSizeImage = width * height * 4;
info.bmiHeader = bitmapInfo;
context = ::GetDC(g_hwnd);
CenterWindow();
}
void RenderWindow::Update() {
#ifdef L_WIN32
MSG msg = { 0 };
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
switch (msg.message) {
case WM_QUIT:
event_activate();
exit(0);
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
#endif
}
void RenderWindow::SetCaption(const String& val) {
caption = val;
SetWindowText(g_hwnd, caption.c_str());
}
void RenderWindow::SetFullScreen(bool state) {
bFullscreen = state;
}
bool RenderWindow::IsFullScreen() {
return bFullscreen;
}
RenderWindow::~RenderWindow(void) {
ChangeDisplaySettings(&mode, 0);
}
void RenderWindow::OnActivate() {
bActive = true;
event_activate();
}
void RenderWindow::OnDeactivate() {
bActive = false;
event_deactivate();
}
void RenderWindow::OnResize() {
if (!IsFullScreen() || !bModeSwitching) {
RECT r;
::GetClientRect(g_hwnd, &r);
width = r.right - r.left;
height = r.bottom - r.top;
::ZeroMemory(&bitmapInfo, sizeof(BITMAPINFOHEADER));
bitmapInfo.biSize = sizeof(BITMAPINFOHEADER);
bitmapInfo.biWidth = width;
bitmapInfo.biHeight = -height;
bitmapInfo.biPlanes = 1;
bitmapInfo.biBitCount = 32;
bitmapInfo.biCompression = 0;
bitmapInfo.biSizeImage = width * height * 4;
info.bmiHeader = bitmapInfo;
}
event_resize();
}
bool RenderWindow::IsActive() {
return bActive;
}
bool RenderWindow::IsModeSwitching() {
return bModeSwitching;
}
void RenderWindow::SetCursorVisible(bool state) {
bCursorVisible = state;
}
bool RenderWindow::IsCursorVisible() {
return bCursorVisible;
}
bool RenderWindow::SwitchMode(bool fullscreen) {
bFullscreen = fullscreen;
if (bFullscreen) {
bModeSwitching = true;
DEVMODE fmode;
ZeroMemory(&fmode, sizeof(DEVMODE));
fmode.dmSize = sizeof(DEVMODE);
fmode.dmPelsWidth = fsMode.width;
fmode.dmPelsHeight = fsMode.height;
fmode.dmBitsPerPel = mode.dmBitsPerPel;
fmode.dmDisplayFrequency = fsMode.refreshRate;
fmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY;
//if(ChangeDisplaySettings(&fmode,0)!= DISP_CHANGE_SUCCESSFUL)
// return false;
SetWindowLong(g_hwnd, GWL_EXSTYLE, WS_EX_APPWINDOW | WS_EX_TOPMOST);
SetWindowLong(g_hwnd, GWL_STYLE, WS_POPUP);
SetWindowPos(g_hwnd, HWND_TOPMOST, 0, 0, fsMode.width, fsMode.height, SWP_SHOWWINDOW | SWP_FRAMECHANGED);
bModeSwitching = false;
} else {
//if(ChangeDisplaySettings(&mode_window,0)!= DISP_CHANGE_SUCCESSFUL)
// return false;
SetWindowLong(g_hwnd, GWL_EXSTYLE, WS_EX_APPWINDOW);
SetWindowLong(g_hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);
SetSize(width, height);
CenterWindow();
}
event_switch_fullscreen();
return true;
}
void RenderWindow::CenterWindow() {
int mx = GetSystemMetrics(SM_CXSCREEN);
int my = GetSystemMetrics(SM_CYSCREEN);
int nx = (mx - width) / 2;
int ny = (my - height) / 2;
SetWindowPos(g_hwnd, NULL, nx, ny, -1, -1,
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
}
void RenderWindow::SetFullscreenMode(DisplayMode _mode) {
fsMode = _mode;
}
void RenderWindow::SetSize(int w, int h) {
if (!IsFullScreen()) {
width = w;
height = h;
RECT NewWindowSize;
NewWindowSize.top = 50;
NewWindowSize.left = 50;
NewWindowSize.bottom = NewWindowSize.top + h;
NewWindowSize.right = NewWindowSize.left + w;
AdjustWindowRect(&NewWindowSize, WS_OVERLAPPEDWINDOW, false);
SetWindowPos(g_hwnd, HWND_TOP, NewWindowSize.left, NewWindowSize.top, NewWindowSize.right - NewWindowSize.left, NewWindowSize.bottom - NewWindowSize.top, SWP_SHOWWINDOW | SWP_FRAMECHANGED);
//::MoveWindow(g_hwnd,NewWindowSize.left, NewWindowSize.top, NewWindowSize.right - NewWindowSize.left, NewWindowSize.bottom - NewWindowSize.top, true);
CenterWindow();
}
}
LRESULT __stdcall RenderWindow::WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) {
switch (message) {
case WM_SIZE:
{
if (wparam != SIZE_MINIMIZED) {
LONG_PTR val = GetWindowLongPtr(hwnd, GWLP_USERDATA);
if (val) {
RenderWindow* wnd = (RenderWindow*)val;
wnd->OnResize();
}
}
}
break;
case WM_SETCURSOR:
{
static bool hiddencursor = false;
WORD ht = LOWORD(lparam);
LONG_PTR val = GetWindowLongPtr(hwnd, GWLP_USERDATA);
if (val) {
RenderWindow* wnd = (RenderWindow*)val;
if (wnd->IsCursorVisible()) {
ShowCursor(true);
} else {
if (HTCLIENT == ht && !hiddencursor) {
hiddencursor = true;
ShowCursor(false);
} else if (HTCLIENT != ht && hiddencursor) {
hiddencursor = false;
ShowCursor(true);
}
}
}
}
break;
case WM_ACTIVATE: //Catch Alt + Tab
{
switch (wparam) {
case WA_ACTIVE:
{
LONG_PTR val = GetWindowLongPtr(hwnd, GWLP_USERDATA);
if (val) {
RenderWindow* wnd = (RenderWindow*)val;
wnd->OnActivate();
}
}
break;
case WA_INACTIVE:
{
LONG_PTR val = GetWindowLongPtr(hwnd, GWLP_USERDATA);
if (val) {
RenderWindow* wnd = (RenderWindow*)val;
wnd->OnDeactivate();
}
}
break;
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
DestroyWindow(hwnd);
break;
case WM_SYSKEYDOWN:
switch (wparam) {
case VK_RETURN:
{
if (GetKeyState(VK_MENU)) //Alt + Enter
{
LONG_PTR val = GetWindowLongPtr(hwnd, GWLP_USERDATA);
if (val) {
RenderWindow* wnd = (RenderWindow*)val;
if (!wnd->IsAltEnterLocked()) {
wnd->SetAltEnterLocked(true);
wnd->SwitchMode(!wnd->IsFullScreen());
}
}
}
}
break;
}
break;
case WM_SYSKEYUP:
{
switch (wparam) {
case VK_RETURN:
{
LONG_PTR val = GetWindowLongPtr(hwnd, GWLP_USERDATA);
if (val) {
RenderWindow* wnd = (RenderWindow*)val;
wnd->SetAltEnterLocked(false);
}
}
break;
}
}
break;
case WM_KEYDOWN:
switch (wparam) {
case VK_SPACE:
{
LONG_PTR val = GetWindowLongPtr(hwnd, GWLP_USERDATA);
if (val) {
RenderWindow* wnd = (RenderWindow*)val;
wnd->UpdateCamera = !wnd->UpdateCamera;
}
}
break;
case VK_ESCAPE:
PostQuitMessage(0);
exit(0);
break;
}
}
return DefWindowProc(hwnd, message, wparam, lparam);
}
@@ -0,0 +1,123 @@
#pragma once
#ifdef _WIN32
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <SoftGL/IRenderWindow.h>
class RenderWindow : public IRenderWindow {
public:
/*virtual ~RenderWindow(void) {}
virtual void Update() = 0;
virtual void SetCaption(const String& caption) = 0;
virtual int GetWindowHandle() = 0;
virtual int GetWidth() = 0;
virtual int GetHeight() = 0;
virtual const String& GetCaption() = 0;*/
bool UpdateCamera;
RenderWindow();
~RenderWindow(void);
void Update();
void SetCaption(const String& caption);
std::size_t GetWindowHandle() { return (std::size_t)g_hwnd; }
void SetSize(int w, int h);
bool IsFullScreen();
void SetFullScreen(bool state);
bool SwitchMode(bool fullscreen);
void SetFullscreenMode(DisplayMode mode);
bool IsActive();
bool IsModeSwitching();
void SetCursorVisible(bool state);
bool IsCursorVisible();
void CenterWindow();
int GetWidth() {
return width;
}
virtual int GetHeight() {
return height;
}
const String& GetCaption() {
return caption;
}
void SetAltEnterLocked(bool state) {
bAltEnterLocked = state;
}
bool IsAltEnterLocked() {
return bAltEnterLocked;
}
virtual void event_activate() {
}
virtual void event_deactivate() {
}
virtual void event_resize() {
}
virtual void event_switch_fullscreen() {
}
virtual void Present(Texture* tex) override {
if (tex->Desc().BytesPerPixel == 4) {
SetDIBitsToDevice(
context,
0,
0,
tex->Desc().Width,
tex->Desc().Height,
0,
0,
0,
tex->Desc().Height,
tex->LockWrite(),
&info,
0
);
}else{
DebugError("Can't present not 4 bytes pixels");
}
}
protected:
bool bAltEnterLocked;
HINSTANCE g_hInst;
HWND g_hwnd;
DEVMODE mode;
private:
void OnActivate();
void OnDeactivate();
void OnResize();
static LRESULT __stdcall WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
virtual int GetTop() override {
RECT rect;
GetWindowRect(g_hwnd, &rect);
return rect.top;
}
virtual int GetLeft() override {
RECT rect;
GetWindowRect(g_hwnd, &rect);
return rect.left;
}
virtual void SetPosition(int top, int left) override {
RECT rect;
GetWindowRect(g_hwnd, &rect);
SetWindowPos(g_hwnd, NULL, left, top, GetWidth(), GetHeight(), 0);
}
BITMAPINFOHEADER bitmapInfo;
BITMAPINFO info;
HDC context;
};
#endif
+11
View File
@@ -0,0 +1,11 @@
#ifndef RasterizerSettings_h__
#define RasterizerSettings_h__
#include <cstdint>
typedef uint32_t indices_t;
#define MAX_TEX_SLOTS 16
static constexpr size_t InputElementNameLength = 16;
#endif // RasterizerSettings_h__
+22
View File
@@ -0,0 +1,22 @@
#ifndef Ray_h__
#define Ray_h__
#include "LMath.h"
class Ray
{
public:
float3 Origin;
float3 Direction;
Ray()
:Origin(0,0,0), Direction(0,0,0)
{
}
Ray(const float3& orig, const float3& dir)
{
Origin = orig;
Direction = dir;
}
};
#endif // Ray_h__
+50
View File
@@ -0,0 +1,50 @@
#ifndef RegisterBlock_h__
#define RegisterBlock_h__
#include <LMath/lmath.h>
#include <array>
using namespace lm;
#define REG_COUNT 5
struct RegisterBlock {
std::array<float4, REG_COUNT> reg;
inline static void Sub(const RegisterBlock& b1, const RegisterBlock& b2, RegisterBlock& result) {
for (int i = 0; i < REG_COUNT; i++) {
result.reg[i] = b1.reg[i] - b2.reg[i];
}
}
inline static void Add(const RegisterBlock& b1, const RegisterBlock& b2, RegisterBlock& result) {
for (int i = 0; i < REG_COUNT; i++) {
result.reg[i] = b1.reg[i] + b2.reg[i];
}
}
inline static void Mul(const RegisterBlock& b1, float val, RegisterBlock& result) {
for (int i = 0; i < REG_COUNT; i++) {
result.reg[i] = b1.reg[i] * val;
}
}
inline static void Div(const RegisterBlock& b1, float val, RegisterBlock& result) {
for (int i = 0; i < REG_COUNT; i++) {
result.reg[i] = b1.reg[i] / val;
}
}
inline static void Mul(RegisterBlock& b1, float val) {
for (int i = 0; i < REG_COUNT; i++) {
b1.reg[i] *= val;
}
}
inline static void Div(RegisterBlock& b1, float val) {
for (int i = 0; i < REG_COUNT; i++) {
b1.reg[i] /= val;
}
}
inline static void Clone(const RegisterBlock& from, RegisterBlock& to) {
for (int i = 0; i < REG_COUNT; i++) {
to.reg[i] = from.reg[i];
}
}
};
#endif // RegisterBlock_h__
+7
View File
@@ -0,0 +1,7 @@
#ifndef ResourceManager_h__
#define ResourceManager_h__
#include "Buffer.h"
#endif // ResourceManager_h__
+68
View File
@@ -0,0 +1,68 @@
TEMPLATE = lib
CONFIG += debug \
staticlib \
warn_off
DESTDIR = ../../bin
CONFIG -= release \
warn_on
HEADERS += \
VSScreenSpace.h \
VSDefault.h \
Viewport.h \
VertexShader.h \
VertexBuffer.h \
Vertex.h \
float4.h \
float3.h \
Vector2D.h \
Types.h \
Tools.h \
Timer.h \
Texture2D.h \
Scene.h \
ResourceManager.h \
RenderWindowXORG.h \
RenderWindow.h \
Renderer3D.h \
Renderer.h \
Ray.h \
Quaternion.h \
PSTextured.h \
PSFont.h \
PSDefault.h \
Primitive.h \
Plane.h \
PixelShader.h \
Mesh.h \
Matrix4x4.h \
Matrix3x3.h \
LString.h \
LMath.h \
IShader.h \
IRenderWindow.h \
InputSystem.h \
InputLayout.h \
Inline.h \
IndexBuffer.h \
FpsCounter.h \
DisplayMode.h \
Delegate_base.h \
Delegate.h \
Camera.h \
Buffer.h \
BlockRasterizer.h \
Bitmap.h \
TextureSampler.h
SOURCES += \
RenderWindowXORG.cpp \
RenderWindow.cpp \
Mesh.cpp \
BlockRasterizerTest.cpp \
BlockRasterizer.cpp
CONFIG += link_pkgconfig
PKGCONFIG += x11
+31
View File
@@ -0,0 +1,31 @@
#ifndef StaticBuffer_h__
#define StaticBuffer_h__
#include "Buffer.h"
template<typename T, size_t _Size>
struct static_buffer : public Buffer {
std::array<T, _Size> data;
static_buffer() {
//static_assert(init.size() == Size, "Incorrect number of parameters");
}
static_buffer(const std::array<T, _Size>& values):data(values){
//static_assert(init.size() == Size, "Incorrect number of parameters");
}
virtual void* GetPointer() override {
return &data[0];
}
virtual size_t Size() override {
return _Size * sizeof(T);
}
virtual size_t ItemSize() override {
return sizeof(T);
}
};
#endif // StaticBuffer_h__
+86
View File
@@ -0,0 +1,86 @@
#pragma once
#include "mip_utils.h"
#include "Texture.h"
#include <vector>
#include <array>
template<size_t _BytesPerPixel, size_t _Width, size_t _Height, size_t _MaxMip = -1, size_t CurrentMip = 0, bool _lastMip = ((_Width == 1) && (_Height == 1)) || (CurrentMip == _MaxMip)>
struct MipChain : MipChain<_BytesPerPixel, MipUtils::SmallerMipSize(_Width), MipUtils::SmallerMipSize(_Height), _MaxMip, CurrentMip + 1> {
static constexpr auto Width = _Width;
static constexpr auto Height = _Height;
static constexpr auto BytesPerPixel = _BytesPerPixel;
static_assert(MipUtils::IsValidMipSize(_Width), "Invalid MIP width, must be power of 2");
static_assert(MipUtils::IsValidMipSize(_Height), "Invalid MIP height, must be power of 2");
std::array<uint8_t, _Width * _Height * _BytesPerPixel> data;
};
template<size_t _BytesPerPixel, size_t _Width, size_t _Height, size_t _MaxMip, size_t CurrentMip>
struct MipChain<_BytesPerPixel, _Width, _Height, _MaxMip, CurrentMip, true> {
void* GetPointer() {
return &data[0];
}
const void* GetPointer() const {
return &data[0];
}
static constexpr size_t MipsCount = CurrentMip + 1;
static constexpr auto Width = _Width;
static constexpr auto Height = _Height;
static constexpr auto BytesPerPixel = _BytesPerPixel;
std::array<uint8_t, _Width * _Height * _BytesPerPixel> data;
};
struct DynamicMipChain {
DynamicMipChain(size_t width, size_t height, size_t bytesPerPixel, size_t maxMip){
size_t pixelsCount = 0;
_mipsCount = 0;
while(_mipsCount <= maxMip && (width > 0) && (height > 0)){
pixelsCount += width * height;
width >>= 1;
height >>= 1;
_mipsCount++;
}
_data.resize(pixelsCount * bytesPerPixel);
}
void* GetPointer() {
return &_data[0];
}
const void* GetPointer() const {
return &_data[0];
}
size_t Size() const{
return _data.size();
}
size_t MipsCount() const {
return _mipsCount;
}
private:
size_t _mipsCount;
std::vector<uint8_t> _data;
};
template<typename _Pointer, bool _IsConst = std::is_const<typename std::remove_pointer<_Pointer>::type>::value>
struct PointerUtils {
using raw_pointer = decltype(&(*std::declval<_Pointer>()));
static raw_pointer GetWritable(_Pointer ptr) { return (raw_pointer)ptr->GetPointer(); }
};
template<typename _Pointer>
struct PointerUtils<_Pointer, true> {
using raw_pointer = decltype(&(*std::declval<_Pointer>()));
static typename std::remove_cv<std::remove_pointer<raw_pointer>>::type* GetWritable(_Pointer ptr) { return nullptr; }
};
template<typename _DataPointer>
class StaticTexture : public Texture {
public:
StaticTexture(_DataPointer data, const TextureDescription& description) : Texture(description), _data(data) {}
virtual void* LockWrite() override { return PointerUtils<_DataPointer>::GetWritable(_data); }
virtual const void* LockRead() override { return _data->GetPointer(); }
private:
_DataPointer _data;
};
+69
View File
@@ -0,0 +1,69 @@
#ifndef Texture_h__
#define Texture_h__
#include "dynamic_buffer.h"
#include "LString.h"
#include "Bitmap.h"
#include <stdio.h>
#include "mip_utils.h"
struct Color24{
uint8_t b;
uint8_t g;
uint8_t r;
void fromColor16(uint16_t value){
b = (value & 0x1f) << 3;
g = (value & 0x7e0) >> 3;
r = (value & 0xf800) >> 8;
}
uint16_t toColor16(){
uint16_t result = b >> 3;
result |= ((uint16_t)g >> 2) << 5;
result |= ((uint16_t)r >> 3) << 11;
return result;
}
static Color24 lerp(Color24 left, Color24 right, uint16_t val, uint16_t maxVal){
Color24 result;
result.r = (int32_t)left.r + ((int32_t)(right.r - left.r) * (int32_t)val) / (int32_t)maxVal;
result.g = (int32_t)left.g + ((int32_t)(right.g - left.g) * (int32_t)val) / (int32_t)maxVal;
result.b = (int32_t)left.b + ((int32_t)(right.b - left.b) * (int32_t)val) / (int32_t)maxVal;
return result;
}
};
struct TextureDescription {
size_t Width;
size_t Height;
size_t Depth;
size_t BytesPerPixel;
size_t MipCount;
};
struct Texture {
Texture(const TextureDescription& description) : _description(description) {
_depthStride = 0;
size_t width = _description.Width;
size_t height = _description.Height;
for (size_t i = 0; i < _description.MipCount; ++i) {
_depthStride += _description.BytesPerPixel * width * height;
width = MipUtils::SmallerMipSize(width);
height = MipUtils::SmallerMipSize(height);
}
}
virtual void* LockWrite() = 0;
virtual const void* LockRead() = 0;
virtual ~Texture() = default;
const TextureDescription& Desc() const {
return _description;
}
private:
size_t _depthStride;
TextureDescription _description;
};
#endif // Texture_h__
+86
View File
@@ -0,0 +1,86 @@
#ifndef TEXTURESAMPLER_H
#define TEXTURESAMPLER_H
#include "Texture.h"
static inline uint32_t sample2D(Texture* tex, float tX, float tY)
{
if(tex == nullptr)
{
return 0;
}
tX = lm::clamp(tX, 0.0f, 1.0f);
tY = lm::clamp(tY, 0.0f, 1.0f);
tY = 1.0f - tY;
int x = static_cast<int>((tX * ((float)tex->Desc().Width - 1.0f)));
int y = static_cast<int>((tY * ((float)tex->Desc().Height - 1.0f)));
auto ptr = reinterpret_cast<const uint8_t*>(tex->LockRead());
float pX = tX * (float)tex->Desc().Width;
float pY = tY * (float)tex->Desc().Height;
uint32_t frX = (uint32_t)((pX - (float)((int)pX))* 255.0f);
uint32_t frY = (uint32_t)((pY - (float)((int)pY))* 255.0f);
auto ptr2 = reinterpret_cast<const uint32_t*>(tex->LockRead());
uint32_t color;
// if(tex->bpp < 4)
// {
uint32_t tl = 0xff000000;
/* uint32_t tr = 0xff000000;
uint32_t rl = 0xff000000;
uint32_t rr = 0xff000000;*/
memcpy(&tl, ptr+ (y*tex->Desc().Width + x)* tex->Desc().BytesPerPixel, tex->Desc().BytesPerPixel);
//memcpy(&tr, ptr+ (y*tex->width + x + 1)* tex->bpp, 3);
// memcpy(&rl, ptr+ ((y + 1)*tex->width + x)* tex->bpp, 3);
//memcpy(&rr, ptr+ ((y + 1)*tex->width + x + 1)* tex->bpp, 3);
color = tl;// blendrgb ( blendrgb ( tl, tr, frX), blendrgb ( rl, rr, frX), frY);
/* }
else
{
int32 x1 = x;
int32 x2 = x + 1;
int32 x3 = x;
int32 x4 = x + 1;
int32 y1 = y;
int32 y2 = y;
int32 y3 = (y + 1);
int32 y4 = (y + 1);
x1 = clampInt(x1, 0, tex->width - 1);
x2 = clampInt(x2, 0, tex->width - 1);
x3 = clampInt(x3, 0, tex->width - 1);
x4 = clampInt(x4, 0, tex->width - 1);
y1 = clampInt(y1, 0, tex->height - 1);
y2 = clampInt(y2, 0, tex->height - 1);
y3 = clampInt(y3, 0, tex->height - 1);
y4 = clampInt(y4, 0, tex->height - 1);
uint32_t tl = ptr2[y1 * tex->width + x1];
uint32_t tr = ptr2[y2 * tex->width + x2];
uint32_t rl = ptr2[y3 * tex->width + x3];
uint32_t rr = ptr2[y4 * tex->width + x4];
color = blendrgb ( blendrgb ( tl, tr, frX), blendrgb ( rl, rr, frX), frY);
}*/
return color;
}
#endif // TEXTURESAMPLER_H
+25
View File
@@ -0,0 +1,25 @@
#ifndef Tools_h__
#define Tools_h__
template<typename T>
void PrintBits(const T& val)
{
int countBytes = sizeof(T);
int countBits = countBytes * 8;
char* ptr = (char*)&val;
for(int i = 0; i < countBytes; i++)
{
char b = *ptr;
for(int j = 7; j >= 0; j--)
{
char val = (b & (1 << j)) >> j;
printf("%i", val);
}
printf(" ");
ptr++;
}
printf("\n");
}
#endif // Tools_h__
+40
View File
@@ -0,0 +1,40 @@
#ifndef VSDefault_h__
#define VSDefault_h__
#include "VertexShader.h"
class VSDefault : public VertexShader
{
public:
float4x4 mWorld;
float4x4 mView;
float4x4 mProj;
VSDefault(){
//declare shader inputs
inputs.push_back(String("POSITION"));
inputs.push_back(String("TEXCOORD"));
inputs.push_back(String("NORMAL"));
}
int Execute(float4** input, float4* output)
{
float4x4 wv = lm::mul(mView, mWorld);
float4x4 wvp = lm::mul(mProj, wv);
float4 position = *input[0];
position.w() = 1.0f;
float3x3 world;
world[0] = mWorld[0].xyz();
world[1] = mWorld[1].xyz();
world[2] = mWorld[2].xyz();
output[0] = lm::mul(wvp, position);
output[1] = *input[1];
output[2].xyz() = lm::mul(world, (*input[2]).xyz());
output[3].xyz() = lm::mul(mWorld, position).xyz();
return 4;
}
};
#endif // VSDefault_h__
+60
View File
@@ -0,0 +1,60 @@
#ifndef VSScreenSpace_h__
#define VSScreenSpace_h__
#include "VertexShader.h"
class VSScreenSpace : public VertexShader
{
public:
//Matrix4x4 mWorld;
//Matrix4x4 mView;
//Matrix4x4 mProj;
float width;
float height;
float pX;
float pY;
float screenWidth;
float screenHeight;
VSScreenSpace()
{
//declare shader inputs
inputs.push_back(STR("POSITION"));
inputs.push_back(STR("COLOR"));
}
int Execute(float4** input, float4* output)
{
//Matrix4x4 wv = mWorld * mView;
//Matrix4x4 wvp = wv * mProj;
float xScale = width / screenWidth;
float yScale = height / screenHeight;
float4 position = (*input)[0];
position.W = 1.0f;
position.X *= width;
position.Y *= height;
position.X += pX;
position.Y += pY;
position.X = position.X / screenWidth * 2.0f - 1.0f;
position.Y = position.Y / screenHeight * 2.0f - 1.0f;
//Output.Position.xy = Output.Position.xy/float2(bbWidth, -bbHeight)*2.0f + float2(-1.0f,1.0f);
output[0] = position;
//Vec4Transform(position, wvp);
//output[0] = position;
output[1] = (*input)[1];
return 2;
}
};
#endif // VSScreenSpace_h__
+17
View File
@@ -0,0 +1,17 @@
#pragma once
#include <LMath/lmath.h>
struct Vertex {
lm::float4 Position;
lm::float3 Normal;
lm::float2 UV0;
Vertex() {
}
Vertex(const lm::float4& pos, const lm::float2& tc) {
Position = pos;
UV0 = tc;
}
};
+18
View File
@@ -0,0 +1,18 @@
#ifndef VertexShader_h__
#define VertexShader_h__
#include "IShader.h"
class VertexShader : public IShader
{
public:
virtual ~VertexShader()
{
}
virtual int Execute(float4** input, float4* output) = 0;
};
#endif // VertexShader_h__
+23
View File
@@ -0,0 +1,23 @@
#ifndef Viewport_h__
#define Viewport_h__
#include <cstdint>
class Viewport {
public:
int32_t width;
int32_t height;
float minZ;
float maxZ;
Viewport(int32_t _width, int32_t _height, float _minZ, float _maxZ) {
width = _width;
height = _height;
minZ = _minZ;
maxZ = _maxZ;
}
~Viewport() {
}
};
#endif // Viewport_h__
+17
View File
@@ -0,0 +1,17 @@
#ifndef config_h__
#define config_h__
#if (_MSC_VER)
#include <memory>
#endif
#if (_MSC_VER)
template<typename T>
using Pointer = std::shared_ptr<T>;
#else
template<typename T>
using Pointer = T*;
#endif
#endif // config_h__
+66
View File
@@ -0,0 +1,66 @@
#ifndef dynamic_buffer_h__
#define dynamic_buffer_h__
#include "Buffer.h"
template<typename T>
struct dynamic_buffer : public Buffer{
public:
dynamic_buffer() : _size(0), _data(nullptr) {
}
dynamic_buffer(size_t count) : _size(count * sizeof(T)){
_data = new T[count];
}
dynamic_buffer(const dynamic_buffer& v) {
_size = v._size;
_data = new T[_size / sizeof(T)];
memcpy(&_data[0], &v._data[0], _size);
}
dynamic_buffer(dynamic_buffer&& v) {
_size = v._size;
_data = v._data;
v._size = 0;
v._data = nullptr;
}
dynamic_buffer& operator=(const dynamic_buffer& v) {
_size = v._size;
_data = new T[_size / sizeof(T)];
memcpy(&_data[0], &v._data[0], _size);
return *this;
}
dynamic_buffer& operator=(dynamic_buffer&& v) {
_size = v._size;
_data = v._data;
v._size = 0;
v._data = nullptr;
return *this;
}
~dynamic_buffer(){
if (_data != nullptr) {
delete[] _data;
}
}
virtual void* GetPointer() override {
return _data;
}
virtual size_t Size() override {
return _size;
}
virtual size_t ItemSize() override {
return sizeof(T);
}
private:
size_t _size;
T* _data;
};
#endif // dynamic_buffer_h__
+14
View File
@@ -0,0 +1,14 @@
#ifndef mip_utils_h__
#define mip_utils_h__
struct MipUtils {
static constexpr size_t SmallerMipSize(size_t size) {
return size > 1 ? size / 2 : size;
}
static constexpr bool IsValidMipSize(size_t size) {
return size == 0 ? false : (size == 1 ? true : (size % 2 == 0));
}
};
#endif // mip_utils_h__
+207
View File
@@ -0,0 +1,207 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Bitmap.h" />
<ClInclude Include="BlockRasterizer.h" />
<ClInclude Include="Buffer.h" />
<ClInclude Include="config.h" />
<ClInclude Include="Debug.h" />
<ClInclude Include="DisplayMode.h" />
<ClInclude Include="dynamic_buffer.h" />
<ClInclude Include="FpsCounter.h" />
<ClInclude Include="Graphics2D.h" />
<ClInclude Include="IndexBuffer.h" />
<ClInclude Include="InputLayout.h" />
<ClInclude Include="InputSystem.h" />
<ClInclude Include="IRenderWindow.h" />
<ClInclude Include="IShader.h" />
<ClInclude Include="LString.h" />
<ClInclude Include="mip_utils.h" />
<ClInclude Include="StaticTexture.h" />
<ClInclude Include="static_mip_chain.h" />
<ClInclude Include="PixelShader.h" />
<ClInclude Include="PSDefault.h" />
<ClInclude Include="PSFont.h" />
<ClInclude Include="PSTextured.h" />
<ClInclude Include="RasterizerSettings.h" />
<ClInclude Include="Ray.h" />
<ClInclude Include="RegisterBlock.h" />
<ClInclude Include="RenderWindow.h" />
<ClInclude Include="RenderWindowXORG.h" />
<ClInclude Include="ResourceManager.h" />
<ClInclude Include="StaticBuffer.h" />
<ClInclude Include="static_vector.h" />
<ClInclude Include="Texture.h" />
<ClInclude Include="TextureSampler.h" />
<ClInclude Include="texture_utils.h" />
<ClInclude Include="Tools.h" />
<ClInclude Include="Vertex.h" />
<ClInclude Include="VertexShader.h" />
<ClInclude Include="Viewport.h" />
<ClInclude Include="VSDefault.h" />
<ClInclude Include="VSScreenSpace.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="BlockRasterizer.cpp" />
<ClCompile Include="RenderWindow.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="SoftGL.pro" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{C26A3393-5100-439B-8570-45FA48819037}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>softgl</RootNamespace>
<WindowsTargetPlatformVersion>10.0.14393.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS;_CRTDBG_MAP_ALLOC</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>D:\lmath\lmath;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS;_CRTDBG_MAP_ALLOC</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>D:\lmath\lmath;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>Full</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>D:\lmath\lmath;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>D:\lmath\lmath;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
+28
View File
@@ -0,0 +1,28 @@
#ifndef mip_static_buffer_h__
#define mip_static_buffer_h__
#include <array>
struct MipUtils {
static constexpr size_t SmallerMipSize(size_t size){
return size > 1 ? size / 2 : size;
}
};
template<size_t _BytesPerPixel, size_t _Width, size_t _Height, size_t _MaxMip = -1, size_t CurrentMip = 0>
struct StaticMipChain {
public:
static constexpr uint32_t ChildWidth = MipUtils::SmallerMipSize(Width);
static constexpr uint32_t ChildHeight = MipUtils::SmallerMipSize(Height);
std::array<uint8_t, _Width * _Height * _BytesPerPixel> data;
StaticMipChain<_BytesPerPixel, ChildWidth, ChildHeight, _MaxMip, CurrentMip + 1> child;
};
template<size_t _BytesPerPixel, size_t _MaxMip = -1, size_t CurrentMip = 0>
struct StaticMipChain<_BytesPerPixel, 1, 1, _MaxMip, CurrentMip> {
};
#endif // mip_static_buffer_h__
+62
View File
@@ -0,0 +1,62 @@
#ifndef static_vector_h__
#define static_vector_h__
#include <cstdint>
#include "Debug.h"
template<typename T, size_t Capacity>
class Static_vector {
public:
Static_vector():_size(0){
}
static constexpr size_t capacity(){
return Capacity;
}
bool full() const {
return _size == Capacity;
}
bool empty() const {
return _size == 0;
}
void clear(){
_size = 0;
}
bool push_back(const T& value){
if(full()){
assert(false && "Can't push");
return false;
}
_buffer[_size++] = value;
return true;
}
void pop_back(){
if(empty()){
return;
}
--_size;
}
void remove(size_t id){
if(id >= _size){
return;
}
_buffer[id] = _buffer[_size-1];
--_size;
}
T& operator[](size_t id){
SGL_ASSERT(id < _size, "Invalid index");
return _buffer[id];
}
const T& operator[](size_t id) const{
SGL_ASSERT(id < _size, "Invalid index");
return _buffer[id];
}
size_t size() const {
return _size;
}
private:
T _buffer[Capacity];
size_t _size;
};
#endif // static_vector_h__
+176
View File
@@ -0,0 +1,176 @@
#ifndef texture_utils_h__
#define texture_utils_h__
#include <memory>
#include "StaticTexture.h"
#include "Bitmap.h"
//#include <intrin.h>
#include <LMath/lmath.h>
struct texture_utils {
template<typename SrcAccessor, typename DstAccessor>
static bool copy(Texture* src, Texture* dst) {
auto srcDesc = src->Desc();
auto dstDesc = dst->Desc();
if (srcDesc.Width != dstDesc.Width || (srcDesc.Height != dstDesc.Height)) {
return false;
}
auto* srcPtr = reinterpret_cast<const typename SrcAccessor::PixelDataType*>(src->LockRead());
auto* dstPtr = reinterpret_cast<typename DstAccessor::PixelDataType*>(dst->LockWrite());
for (size_t y = 0; y < srcDesc.Height; ++y) {
for (size_t x = 0; x < srcDesc.Width; ++x) {
lm::float4 srcDataf = SrcAccessor::ConvertColor(srcPtr[x]);
auto dstColor = DstAccessor::ConvertColor(srcDataf);
dstPtr[x] = dstColor;
}
srcPtr += srcDesc.Width;
dstPtr += srcDesc.Width;
}
return true;
}
template<typename T>
static bool fill(Texture* tex, T pixel_value) {
if (tex == nullptr) {
return false;
}
if (tex->Desc().BytesPerPixel != sizeof(T)) {
//throw std::exception("Invalid pixel value specified");
return false;
}
auto data = (T*)tex->LockWrite();
auto memsize = tex->Desc().Width * tex->Desc().Height * sizeof(pixel_value);
if((8 % (sizeof(T))) == 0 && (memsize % 8) == 0)
{
alignas(8) uint64_t block_value;
T* blockPtr = (T*)&block_value;
for (size_t i = 0; i < (8 / sizeof(T)); ++i) {
blockPtr[i] = pixel_value;
}
auto blockMem = (uint64_t*)data;
for(size_t i = 0; i < (memsize / sizeof(block_value)); ++i)
{
blockMem[i] = block_value;
}
}
/*__m256i avxBlock;
if ((sizeof(avxBlock) % (sizeof(T))) == 0 && (memsize % sizeof(avxBlock)) == 0) {
T* blockPtr = (T*)&avxBlock;
for (size_t i = 0; i < (sizeof(avxBlock) / sizeof(T)); ++i) {
blockPtr[i] = pixel_value;
}
auto blockMem = (decltype(avxBlock)*)data;
if(((size_t)blockMem % sizeof(avxBlock)) != 0)
{
throw std::exception("Memory is not SSE aligned");
}
const auto cnt = (memsize / sizeof(avxBlock));
const auto last = blockMem + cnt;
while(blockMem != last){
_mm256_store_si256(blockMem++, avxBlock);
//_mm_store_si128(blockMem++, avxBlock);
}
}*/
//generic assign
/*for (size_t i = 0; i < tex->Desc().Width * tex->Desc().Height; ++i) {
data[i] = pixel_value;
}*/
return true;
}
static Texture* LoadTexture(const std::string& path) {
FILE *filePtr; //our file pointer
BITMAPFILEHEADER bitmapFileHeader; //our bitmap file header
BITMAPINFOHEADER bitmapInfoHeader;
//open filename in read binary mode
filePtr = fopen(path.c_str(), "rb");
if (filePtr == NULL)
return nullptr;
//read the bitmap file header
int read_cnt = fread(&bitmapFileHeader, 1, sizeof(BITMAPFILEHEADER), filePtr);
if (read_cnt != sizeof(BITMAPFILEHEADER)) {
printf("EPIC FAIL!\n");
}
//verify that this is a bmp file by check bitmap id
if (bitmapFileHeader.bfType != 0x4D42) {
fclose(filePtr);
return nullptr;
}
//read the bitmap info header
fread(&bitmapInfoHeader, 1, sizeof(BITMAPINFOHEADER), filePtr);
//move file point to the begging of bitmap data
fseek(filePtr, bitmapFileHeader.bfOffBits, SEEK_SET);
auto width = bitmapInfoHeader.biWidth;
auto height = bitmapInfoHeader.biHeight;
auto bpp = bitmapInfoHeader.biBitCount / 8;
auto mips = std::make_shared<DynamicMipChain>(width, height, bpp, -1);
auto bytes_count = width * height * bpp;
auto stride = width * bpp;
auto padding = stride % 4 == 0 ? 0 : (4 - (stride % 4));
uint8_t* ptr = (uint8_t*)mips->GetPointer();
//read in the bitmap image data
for (size_t y = 0; y < height; ++y) {
auto dst_ptr = ptr + stride * (height - 1 - y);
auto result = fread(dst_ptr, 1, stride, filePtr);
if (padding != 0) {
fseek(filePtr, padding, SEEK_CUR);
}
}
fclose(filePtr);
TextureDescription desc;
desc.Width = width;
desc.Height = height;
desc.BytesPerPixel = bpp;
desc.MipCount = mips->MipsCount();
desc.Depth = 1;
return new StaticTexture<decltype(mips)>(mips, desc);
}
/*auto bb = rasterizer.GetBackBuffer();
uint32_t* pixels = (uint32_t*)bb->getBuffer()->getDataPtr();
for (size_t y = 0; y < bb->height; ++y) {
for (size_t x = 0; x < bb->width; ++x) {
uint32_t xVal = (x * 0xff) / bb->width;
uint32_t yVal = (y * 0xff) / bb->height;
pixels[y * bb->width + x] = ((xVal & 0xff) << 16) | ((yVal & 0xff) << 8);
}
}*/
};
#endif // texture_utils_h__
+5
View File
@@ -0,0 +1,5 @@
TEMPLATE = subdirs
SUBDIRS += \
Demo_TexturedTriangle \
SoftGL