console command feature restored

used in dev i guess, restored sending command ability, no screenshot tho
This commit is contained in:
Fisual
2022-02-16 09:15:00 +07:00
parent dc33f31fb2
commit 9ddd3f1f1a
14 changed files with 13989 additions and 84 deletions

View File

@@ -8,19 +8,19 @@
#include "host_state.h"
//#define CON_COMMAND_SERVER_SUPPORT
#define CON_COMMAND_SERVER_SUPPORT
#include "tier2/tier2.h"
#include "materialsystem/imaterialsystemhardwareconfig.h"
#ifdef CON_COMMAND_SERVER_SUPPORT
#include <algorithm>
#include "socketlib/socketlib.h"
#include "../public/socketlib/socketlib.h"
#define MINIZ_NO_ARCHIVE_APIS
#include "../../thirdparty/miniz/miniz.c"
#include "../../thirdparty/miniz/simple_bitmap.h"
#include <WinUser.h>
#define STBI_NO_STDIO
#include "../../thirdparty/stb_image/stb_image.c"
//#include "../../thirdparty/stb_image/ml_stb_image.c"
#include "ivideomode.h"
#endif
@@ -101,9 +101,9 @@ public:
void close(void);
const simple_bgr_bitmap& frameBuffer(void) const { return m_frame_buffer; }
const int& frameBuffer(void) const { return m_frame_buffer; }
simple_bgr_bitmap& frameBuffer(void) { return m_frame_buffer; }
int& frameBuffer(void) { return m_frame_buffer; }
private:
int m_width, m_height;
@@ -115,7 +115,7 @@ private:
char m_bitmap_info[16 + sizeof(BITMAPINFO)];
BITMAPINFO* m_pBitmap_hdr;
HDC m_windowHDC;
simple_bgr_bitmap m_frame_buffer;
int m_frame_buffer;
static frame_buf_window* m_pCur_app;
user_window_proc_ptr_t m_pWindow_proc;
@@ -179,7 +179,7 @@ void frame_buf_window::update(void)
void frame_buf_window::close(void)
{
m_frame_buffer.clear();
//m_frame_buffer.clear();
if (m_window)
{
@@ -192,41 +192,7 @@ void frame_buf_window::close(void)
void frame_buf_window::create_window(const char* pTitle)
{
memset( &m_window_class, 0, sizeof( m_window_class ) );
m_window_class.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
m_window_class.lpfnWndProc = static_window_proc;
m_window_class.cbWndExtra = sizeof(DWORD);
m_window_class.hCursor = LoadCursor(0, IDC_ARROW);
m_window_class.lpszClassName = pTitle;
m_window_class.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH); //GetStockObject(NULL_BRUSH);
RegisterClass(&m_window_class);
RECT rect;
rect.left = rect.top = 0;
rect.right = m_width * m_scale_x;
rect.bottom = m_height * m_scale_y;
AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, 0);
rect.right -= rect.left;
rect.bottom -= rect.top;
m_orig_x = (GetSystemMetrics(SM_CXSCREEN) - rect.right) / 2;
m_orig_y = (GetSystemMetrics(SM_CYSCREEN) - rect.bottom) / 2;
m_orig_width = rect.right;
m_orig_height = rect.bottom;
m_pCur_app = this;
m_window = CreateWindowEx(
0, pTitle, pTitle,
WS_OVERLAPPEDWINDOW,
m_orig_x, m_orig_y, rect.right, rect.bottom, 0, 0, 0, 0);
SetWindowLong(m_window, 0, reinterpret_cast<LONG>(this));
m_pCur_app = NULL;
ShowWindow(m_window, SW_NORMAL);
}
void frame_buf_window::create_bitmap(void)
@@ -247,8 +213,8 @@ void frame_buf_window::create_bitmap(void)
m_windowHDC = GetDC(m_window);
m_frame_buffer.init( m_width, m_height );
m_frame_buffer.cls( 30, 30, 30 );
// m_frame_buffer.init( m_width, m_height );
//m_frame_buffer.cls( 30, 30, 30 );
//m_frame_buffer.draw_text( 50, 200, 2, 255, 127, 128, "This is a test!" );
}
@@ -266,19 +232,6 @@ LRESULT frame_buf_window::window_proc(HWND hWnd, UINT message, WPARAM wParam, LP
{
case WM_PAINT:
{
if (m_frame_buffer.is_valid())
{
RECT window_size;
GetClientRect(hWnd, &window_size);
StretchDIBits(m_windowHDC,
0, 0, window_size.right, window_size.bottom,
0, 0, m_width, m_height,
m_frame_buffer.get_ptr(), m_pBitmap_hdr,
DIB_RGB_COLORS, SRCCOPY);
ValidateRect(hWnd, NULL);
}
break;
}
case WM_KEYDOWN:
@@ -522,7 +475,7 @@ public:
m_bHasNewScreenshot = false;
m_nScreenshotID = 0;
m_screenshot.clear();
//m_screenshot.clear();
m_bReceivedNewCameraPos = false;
memset( &m_NewCameraPos, 0, sizeof( m_NewCameraPos ) );
@@ -623,7 +576,7 @@ public:
bool HasNewScreenshotFlag() const { return m_bHasNewScreenshot; }
void ClearNewScreenshotFlag() { m_bHasNewScreenshot = false; }
uint GetScreenshotID() const { return m_nScreenshotID; }
simple_bitmap &GetScreenshot() { return m_screenshot; }
int &GetScreenshot() { return m_screenshot; }
bool HasNewConVarDumpFlag() const { return m_bHasNewConVarDump; }
void ClearHasNewConVarDumpFlag() { m_bHasNewConVarDump = false; }
@@ -644,7 +597,7 @@ private:
bool m_bReceivedNewCameraPos;
SetCameraPosPacket_t m_NewCameraPos;
simple_bitmap m_screenshot;
int m_screenshot;
bool m_bHasNewScreenshot;
uint m_nScreenshotID;
@@ -716,7 +669,7 @@ private:
videomode->ReadScreenPixels( 0, 0, nWidth, nHeight, s_pBuf, IMAGE_FORMAT_RGB888 );
size_t nPNGSize = 0;
void *pPNGData = tdefl_write_image_to_png_file_in_memory( s_pBuf, nWidth, nHeight, 3, &nPNGSize, true );
void *pPNGData = tdefl_write_image_to_png_file_in_memory( s_pBuf, nWidth, nHeight, 3, &nPNGSize );
if ( pPNGData )
{
@@ -771,9 +724,9 @@ private:
else
{
int nWidth = 0, nHeight = 0, nComp = 3;
unsigned char *pImageData = stbi_load_from_memory( reinterpret_cast< stbi_uc const * >( pPNGData ), nPNGDataSize, &nWidth, &nHeight, &nComp, 3);
//unsigned char *pImageData = stbi_load_from_memory( reinterpret_cast< stbi_uc const * >( pPNGData ), nPNGDataSize, &nWidth, &nHeight, &nComp, 3);
if ( !pImageData )
//if ( !pImageData )
{
Warning( "CONCMDSRV: Failed unpacking PNG screenshot!\n" );
return false;
@@ -782,14 +735,14 @@ private:
m_bHasNewScreenshot = true;
m_nScreenshotID = replyPacket.m_nScreenshotID;
if ( ( (int)m_screenshot.width() != nWidth ) || ( (int)m_screenshot.height() != nHeight ) )
{
m_screenshot.init( nWidth, nHeight );
}
//if ( ( (int)m_screenshot.width() != nWidth ) || ( (int)m_screenshot.height() != nHeight ) )
//{
// m_screenshot.init( nWidth, nHeight );
//}
memcpy( m_screenshot.get_ptr(), pImageData, nWidth * nHeight * 3 );
//memcpy( m_screenshot.get_ptr(), pImageData, nWidth * nHeight * 3 );
stbi_image_free( pImageData );
//stbi_image_free( pImageData );
}
break;
@@ -1073,7 +1026,7 @@ public:
bool bHasUpdatedScreenshot = false;
simple_bgr_bitmap &frameBuf = m_pFrameBufWindow->frameBuffer();
//simple_bgr_bitmap &frameBuf = m_pFrameBufWindow->frameBuffer();
for ( int i = 0; i < cMaxClients; i++ )
{
@@ -1096,7 +1049,7 @@ public:
{
client.ClearNewScreenshotFlag();
simple_bitmap &clientScreenshot = client.GetScreenshot();
//simple_bitmap &clientScreenshot = client.GetScreenshot();
if ( ccs_remote_screenshots_delta.GetBool() )
{
@@ -1107,20 +1060,21 @@ public:
uint nScreenWidth = videomode->GetModeWidth();
uint nScreenHeight = videomode->GetModeHeight();
if ( ( m_screenshot.width() != nScreenWidth ) || ( m_screenshot.height() != nScreenHeight ) )
{
m_screenshot.init( nScreenWidth, nScreenHeight );
}
//if ( ( m_screenshot.width() != nScreenWidth ) || ( m_screenshot.height() != nScreenHeight ) )
//{
// m_screenshot.init( nScreenWidth, nScreenHeight );
//}
videomode->ReadScreenPixels( 0, 0, nScreenWidth, nScreenHeight, m_screenshot.get_ptr(), IMAGE_FORMAT_RGB888 );
//videomode->ReadScreenPixels( 0, 0, nScreenWidth, nScreenHeight, m_screenshot.get_ptr(), IMAGE_FORMAT_RGB888 );
}
uint mx = MIN( clientScreenshot.width(), m_screenshot.width() );
mx = MIN( mx, frameBuf.width() );
//uint mx = MIN( clientScreenshot.width(), m_screenshot.width() );
//mx = MIN( mx, frameBuf.width() );
uint my = MIN( clientScreenshot.height(), m_screenshot.height() );
my = MIN( my, frameBuf.height() );
//uint my = MIN( clientScreenshot.height(), m_screenshot.height() );
//my = MIN( my, frameBuf.height() );
/*
for ( uint y = 0; y < my; ++y )
{
const uint8 *pSrc1 = clientScreenshot.get_scanline( y );
@@ -1149,11 +1103,11 @@ public:
pDst += 3;
}
}
*/
}
else
{
frameBuf.blit( 0, 0, (simple_bgr_bitmap &)clientScreenshot, true );
//frameBuf.blit( 0, 0, (simple_bgr_bitmap &)clientScreenshot, true );
}
}
}
@@ -1259,7 +1213,7 @@ private:
CConCommandConnection m_Clients[cMaxClients];
frame_buf_window *m_pFrameBufWindow;
simple_bitmap m_screenshot;
int m_screenshot;
int m_nViewEndpointIndex;
void AcceptNewConnections()

4916
thirdparty/miniz/miniz.c vendored Normal file

File diff suppressed because it is too large Load Diff

1350
thirdparty/miniz/miniz.h vendored Normal file

File diff suppressed because it is too large Load Diff

9
thirdparty/stb_image/.gitignore vendored Normal file
View File

@@ -0,0 +1,9 @@
*.annot
*.cmo
*.cma
*.cmi
*.a
*.o
*.cmx
*.cmxs
*.cmxa

1
thirdparty/stb_image/.merlin vendored Normal file
View File

@@ -0,0 +1 @@
PKG result

117
thirdparty/stb_image/LICENSE vendored Normal file
View File

@@ -0,0 +1,117 @@
CC0 1.0 Universal
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator and
subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for the
purpose of contributing to a commons of creative, cultural and scientific
works ("Commons") that the public can reliably and without fear of later
claims of infringement build upon, modify, incorporate in other works, reuse
and redistribute as freely as possible in any form whatsoever and for any
purposes, including without limitation commercial purposes. These owners may
contribute to the Commons to promote the ideal of a free culture and the
further production of creative, cultural and scientific works, or to gain
reputation or greater distribution for their Work in part through the use and
efforts of others.
For these and/or other purposes and motivations, and without any expectation
of additional consideration or compensation, the person associating CC0 with a
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
and publicly distribute the Work under its terms, with knowledge of his or her
Copyright and Related Rights in the Work and the meaning and intended legal
effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not limited
to, the following:
i. the right to reproduce, adapt, distribute, perform, display, communicate,
and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or likeness
depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data in
a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation thereof,
including any amended or successor version of such directive); and
vii. other similar, equivalent or corresponding rights throughout the world
based on applicable law or treaty, and any national implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention of,
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
and Related Rights and associated claims and causes of action, whether now
known or unknown (including existing as well as future claims and causes of
action), in the Work (i) in all territories worldwide, (ii) for the maximum
duration provided by applicable law or treaty (including future time
extensions), (iii) in any current or future medium and for any number of
copies, and (iv) for any purpose whatsoever, including without limitation
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
the Waiver for the benefit of each member of the public at large and to the
detriment of Affirmer's heirs and successors, fully intending that such Waiver
shall not be subject to revocation, rescission, cancellation, termination, or
any other legal or equitable action to disrupt the quiet enjoyment of the Work
by the public as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason be
judged legally invalid or ineffective under applicable law, then the Waiver
shall be preserved to the maximum extent permitted taking into account
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
is so judged Affirmer hereby grants to each affected person a royalty-free,
non transferable, non sublicensable, non exclusive, irrevocable and
unconditional license to exercise Affirmer's Copyright and Related Rights in
the Work (i) in all territories worldwide, (ii) for the maximum duration
provided by applicable law or treaty (including future time extensions), (iii)
in any current or future medium and for any number of copies, and (iv) for any
purpose whatsoever, including without limitation commercial, advertising or
promotional purposes (the "License"). The License shall be deemed effective as
of the date CC0 was applied by Affirmer to the Work. Should any part of the
License for any reason be judged legally invalid or ineffective under
applicable law, such partial invalidity or ineffectiveness shall not
invalidate the remainder of the License, and in such case Affirmer hereby
affirms that he or she will not (i) exercise any of his or her remaining
Copyright and Related Rights in the Work or (ii) assert any associated claims
and causes of action with respect to the Work, in either case contrary to
Affirmer's express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or warranties
of any kind concerning the Work, express, implied, statutory or otherwise,
including without limitation warranties of title, merchantability, fitness
for a particular purpose, non infringement, or the absence of latent or
other defects, accuracy, or the present or absence of errors, whether or not
discoverable, all to the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without limitation
any person's Copyright and Related Rights in the Work. Further, Affirmer
disclaims responsibility for obtaining any necessary consents, permissions
or other rights required for any use of the Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to this
CC0 or use of the Work.
For more information, please see
<http://creativecommons.org/publicdomain/zero/1.0/>

6
thirdparty/stb_image/META vendored Normal file
View File

@@ -0,0 +1,6 @@
name="stb_image"
version="0.5"
description="OCaml bindings to stb_image, a public domain image loader"
requires="result"
archive(byte)="stb_image.cma"
archive(native)="stb_image.cmxa"

62
thirdparty/stb_image/Makefile vendored Normal file
View File

@@ -0,0 +1,62 @@
OCAMLC=ocamlfind c
OCAMLOPT=ocamlfind opt
OCAMLMKLIB=ocamlfind mklib
EXT_DLL=$(shell $(OCAMLC) -config | grep ext_dll | cut -f 2 -d ' ')
EXT_LIB=$(shell $(OCAMLC) -config | grep ext_lib | cut -f 2 -d ' ')
EXT_OBJ=$(shell $(OCAMLC) -config | grep ext_obj | cut -f 2 -d ' ')
CFLAGS=-O3 -std=gnu99 -ffast-math
all: stb_image.cma stb_image.cmxa
ml_stb_image$(EXT_OBJ): ml_stb_image.c
$(OCAMLC) -c -ccopt "$(CFLAGS)" $<
dll_stb_image_stubs$(EXT_DLL) lib_stb_image_stubs$(EXT_LIB): ml_stb_image$(EXT_OBJ)
$(OCAMLMKLIB) -o _stb_image_stubs $<
stb_image.cmi: stb_image.mli
$(OCAMLC) -package result -c $<
stb_image.cmo: stb_image.ml stb_image.cmi
$(OCAMLC) -package result -c $<
stb_image.cma: stb_image.cmo dll_stb_image_stubs$(EXT_DLL)
$(OCAMLC) -package result -a -custom -o $@ $< \
-dllib dll_stb_image_stubs$(EXT_DLL) \
-cclib -l_stb_image_stubs
stb_image.cmx: stb_image.ml stb_image.cmi
$(OCAMLOPT) -package result -c $<
stb_image.cmxa stb_image$(EXT_LIB): stb_image.cmx dll_stb_image_stubs$(EXT_DLL)
$(OCAMLOPT) -package result -a -o $@ $< \
-cclib -l_stb_image_stubs
.PHONY: clean install uninstall reinstall
clean:
rm -f *$(EXT_LIB) *$(EXT_OBJ) *$(EXT_DLL) *.cm[ixoa] *.cmxa
DIST_FILES= \
stb_image$(EXT_LIB) \
stb_image.cmi \
stb_image.cmo \
stb_image.cma \
stb_image.cmx \
stb_image.cmxa \
stb_image.ml \
stb_image.mli \
lib_stb_image_stubs$(EXT_LIB) \
dll_stb_image_stubs$(EXT_DLL)
install: $(DIST_FILES) META
ocamlfind install stb_image $^
uninstall:
ocamlfind remove stb_image
reinstall:
-$(MAKE) uninstall
$(MAKE) install

29
thirdparty/stb_image/README.md vendored Normal file
View File

@@ -0,0 +1,29 @@
Stb\_image is an OCaml binding to stb\_image from Sean Barrett, [Nothings](http://nothings.org/):
stb\_image.h: public domain C image loading library
The OCaml binding is released under CC-0 license. It has no dependency beside
working OCaml and C compilers (stb\_image is self-contained).
```shell
$ make
$ make install
```
## CHANGELOG
Version 0.5, Fri Jun 28 19:45:20 CEST 2019
Bug fix in C-bindings, fixed by @LaurentMazare
Version 0.4, Wed Jan 17 20:52:19 JST 2018
Image specification can now contain offset and stride (BREAKING CHANGE).
Add filtering primitives (blur and mipmap)
Version 0.3, Thu Nov 3 18:26:45 CET 2016
Update to stb\_image.h v2.12
Version 0.2, Sun Dec 13 15:18:39 CET 2015
Make use of result package
Version 0.1, Fri Sep 18 20:53:03 CET 2015
Initial release

475
thirdparty/stb_image/ml_stb_image.c vendored Normal file
View File

@@ -0,0 +1,475 @@
#include <assert.h>
#include <stdio.h>
#include <caml/mlvalues.h>
#include <caml/memory.h>
#include <caml/alloc.h>
#include <caml/bigarray.h>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
static int Channels_val(value channel)
{
CAMLparam1(channel);
int ret = 0;
if (channel != Val_unit)
ret = Long_val(Field(channel, 0));
CAMLreturn(ret);
}
static value return_image(void *data, int ty, int x, int y, int n)
{
CAMLparam0();
CAMLlocal3(ret, tup, ba);
ba = caml_ba_alloc_dims(ty | CAML_BA_C_LAYOUT, 1, data, x * y * n);
tup = caml_alloc(6, 0);
Store_field(tup, 0, Val_long(x));
Store_field(tup, 1, Val_long(y));
Store_field(tup, 2, Val_long(n));
Store_field(tup, 3, Val_long(0));
Store_field(tup, 4, Val_long(x * n));
Store_field(tup, 5, ba);
/* Result.Ok tup */
ret = caml_alloc(1, 0);
Store_field(ret, 0, tup);
CAMLreturn(ret);
}
static value return_failure(void)
{
CAMLparam0();
CAMLlocal3(ret, str, err);
str = caml_copy_string(stbi_failure_reason());
/* `Msg "str" */
err = caml_alloc(2, 0);
Store_field(err, 0, Val_long(3854881));
Store_field(err, 1, str);
/* Result.Error (`Msg "str") */
ret = caml_alloc(1, 1);
Store_field(ret, 0, err);
CAMLreturn(ret);
}
CAMLprim value ml_stbi_load(value channels, value filename)
{
CAMLparam2(channels, filename);
CAMLlocal1(ret);
int x, y, n, n0;
n0 = Channels_val(channels);
unsigned char* image_data = stbi_load(String_val(filename), &x, &y, &n, n0);
if (n0 != 0) n = n0;
if (image_data)
ret = return_image(image_data, CAML_BA_UINT8, x, y, n);
else
ret = return_failure();
CAMLreturn(ret);
}
CAMLprim value ml_stbi_loadf(value channels, value filename)
{
CAMLparam2(channels, filename);
CAMLlocal1(ret);
int x, y, n, n0;
n0 = Channels_val(channels);
float* image_data =
stbi_loadf(String_val(filename), &x, &y, &n, n0);
if (n0 != 0) n = n0;
if (image_data)
ret = return_image(image_data, CAML_BA_FLOAT32, x, y, n);
else
ret = return_failure();
CAMLreturn(ret);
}
CAMLprim value ml_stbi_load_mem(value channels, value mem)
{
CAMLparam2(channels, mem);
CAMLlocal1(ret);
int x, y, n, n0;
n0 = Channels_val(channels);
unsigned char* image_data =
stbi_load_from_memory(Caml_ba_data_val(mem),
caml_ba_byte_size(Caml_ba_array_val(mem)),
&x, &y, &n, n0);
if (n0 != 0) n = n0;
if (image_data)
ret = return_image(image_data, CAML_BA_UINT8, x, y, n);
else
ret = return_failure();
CAMLreturn(ret);
}
CAMLprim value ml_stbi_loadf_mem(value channels, value mem)
{
CAMLparam2(channels, mem);
CAMLlocal1(ret);
int x, y, n, n0;
n0 = Channels_val(channels);
float* image_data =
stbi_loadf_from_memory(Caml_ba_data_val(mem),
caml_ba_byte_size(Caml_ba_array_val(mem)),
&x, &y, &n, n0);
if (n0 != 0) n = n0;
if (image_data)
ret = return_image(image_data, CAML_BA_FLOAT32, x, y, n);
else
ret = return_failure();
CAMLreturn(ret);
}
CAMLprim value ml_stbi_image_free(value ba)
{
CAMLparam1(ba);
void *data = Caml_ba_data_val(ba);
assert (data);
stbi_image_free(data);
Caml_ba_data_val(ba) = NULL;
CAMLreturn(Val_unit);
}
#define POUT(x,n) pout[x] = (pin[x] + pin[n + x] + pin[w * n + n] + pin[w * n + x]) / 4
#define POUTf(x,n) pout[x] = (pin[x] + pin[n + x] + pin[w * n + n] + pin[w * n + x]) / 4.0f
#define LOOP(w,h,n) \
for (unsigned int y = 0, w2 = (w) / 2, h2 = (h) / 2; \
y < h2; ++y, pin0 += sin, pin = pin0, pout0 += sout, pout = pout0) \
for (unsigned int x = 0; x < w2; ++x, pin += 2 * n, pout += n)
CAMLprim value ml_stbi_mipmap(value img_in, value img_out)
{
CAMLparam2(img_in, img_out);
unsigned char *pin, *pout,
*pin0 = Caml_ba_data_val(Field(img_in, 5)),
*pout0 = Caml_ba_data_val(Field(img_out, 5));
assert (pin0 && pout0);
pin0 += Long_val(Field(img_in, 3));
pout0 += Long_val(Field(img_out, 3));
unsigned int
sin = Long_val(Field(img_in, 4)),
sout = Long_val(Field(img_out, 4)),
w = Long_val(Field(img_in, 0)),
h = Long_val(Field(img_in, 1));
switch (Long_val(Field(img_in, 2))) {
case 1:
LOOP(w, h, 1) { POUT(0, 1); }
break;
case 2:
LOOP(w, h, 2) { POUT(0, 2); POUT(1, 2); }
break;
case 3:
LOOP(w, h, 3) { POUT(0, 3); POUT(1, 3); POUT(2, 3); }
break;
case 4:
LOOP(w, h, 4) { POUT(0, 4); POUT(1, 4); POUT(2, 4); POUT(3, 4); }
break;
}
CAMLreturn(Val_unit);
}
CAMLprim value ml_stbi_mipmapf(value img_in, value img_out)
{
CAMLparam2(img_in, img_out);
float *pin, *pout,
*pin0 = Caml_ba_data_val(Field(img_in, 5)),
*pout0 = Caml_ba_data_val(Field(img_out, 5));
assert (pin0 && pout0);
pin0 += Long_val(Field(img_in, 3));
pout0 += Long_val(Field(img_out, 3));
unsigned int
sin = Long_val(Field(img_in, 4)),
sout = Long_val(Field(img_out, 4)),
w = Long_val(Field(img_in, 0)),
h = Long_val(Field(img_in, 1));
switch (Long_val(Field(img_in, 2))) {
case 1:
LOOP(w, h, 1) { POUTf(0, 1); }
break;
case 2:
LOOP(w, h, 2) { POUTf(0, 2); POUTf(1, 2); }
break;
case 3:
LOOP(w, h, 3) { POUTf(0, 3); POUTf(1, 3); POUTf(2, 3); }
break;
case 4:
LOOP(w, h, 4) { POUTf(0, 4); POUTf(1, 4); POUTf(2, 4); POUTf(3, 4); }
break;
}
CAMLreturn(Val_unit);
}
static void memswap(void *i0, void *i1, size_t count)
{
unsigned char *p0 = i0, *p1 = i1;
for (size_t i = 0; i < count; ++i)
{
unsigned char tmp = p0[i];
p0[i] = p1[i];
p1[i] = tmp;
}
}
CAMLprim value ml_stbi_vflip(value img)
{
CAMLparam1(img);
unsigned char *ptop = Caml_ba_data_val(Field(img, 5));
assert (ptop);
ptop += Long_val(Field(img, 3));
unsigned int
w = Long_val(Field(img, 0)),
h = Long_val(Field(img, 1)),
n = Long_val(Field(img, 2)),
stride = Long_val(Field(img, 4)),
row = w * n;
unsigned char *pbot = ptop + (stride * h - stride);
w = w * n;
for (unsigned int y = 0; y < h; y++)
{
memswap(ptop, pbot, row);
ptop += stride;
pbot -= stride;
}
CAMLreturn(Val_unit);
}
CAMLprim value ml_stbi_vflipf(value img)
{
CAMLparam1(img);
float *ptop = Caml_ba_data_val(Field(img, 5));
assert (ptop);
ptop += Long_val(Field(img, 3));
unsigned int
w = Long_val(Field(img, 0)),
h = Long_val(Field(img, 1)),
n = Long_val(Field(img, 2)),
stride = Long_val(Field(img, 4)),
row = w * n * sizeof(float);
float *pbot = ptop + (stride * h - stride);
w = w * n;
for (unsigned int y = 0; y < h; y++)
{
memswap(ptop, pbot, row);
ptop += stride;
pbot -= stride;
}
CAMLreturn(Val_unit);
}
// Based on Exponential blur, Jani Huhtanen, 2006
// and [https://github.com/memononen/fontstash](fontstash), Mikko Mononen, 2014
#define APREC 16
#define ZPREC 7
#define APPROX(alpha, reg, acc) \
((alpha * (((int)(reg) << ZPREC) - acc)) >> APREC)
#define BLUR0(reg, acc) int acc = (int)(reg) << ZPREC
#define BLUR(reg, acc) \
do { \
acc += APPROX(alpha, reg, acc); \
reg = (unsigned char)(acc >> ZPREC); \
} while (0)
#define OUTERLOOP(var, ptr, bound, stride) \
for (unsigned char *_limit = ptr + bound * stride, *var = ptr; var < _limit; var += stride)
#define INNERLOOP(var, bound, stride, BODY) \
do { \
int var; \
for (var = stride; var < bound * stride; var += stride) BODY; \
for (var = (bound - 2) * stride; var >= 0; var -= stride) BODY; \
for (var = stride; var < bound * stride; var += stride) BODY; \
for (var = (bound - 2) * stride; var >= 0; var -= stride) BODY; \
} while (0)
static void expblur4(unsigned char* ptr, int w, int h, int stride, int alpha)
{
OUTERLOOP(dst, ptr, h, stride)
{
BLUR0(dst[0], acc0);
BLUR0(dst[1], acc1);
BLUR0(dst[2], acc2);
BLUR0(dst[3], acc3);
INNERLOOP(x, w, 4,
{
BLUR(dst[x+0], acc0);
BLUR(dst[x+1], acc1);
BLUR(dst[x+2], acc2);
BLUR(dst[x+3], acc3);
});
}
OUTERLOOP(dst, ptr, w, 4)
{
BLUR0(dst[0], acc0);
BLUR0(dst[1], acc1);
BLUR0(dst[2], acc2);
BLUR0(dst[3], acc3);
INNERLOOP(y, h, stride,
{
BLUR(dst[y+0], acc0);
BLUR(dst[y+1], acc1);
BLUR(dst[y+2], acc2);
BLUR(dst[y+3], acc3);
});
}
}
static void expblur3(unsigned char* ptr, int w, int h, int stride, int alpha)
{
OUTERLOOP(dst, ptr, h, stride)
{
BLUR0(dst[0], acc0);
BLUR0(dst[1], acc1);
BLUR0(dst[2], acc2);
INNERLOOP(x, w, 3,
{
BLUR(dst[x+0], acc0);
BLUR(dst[x+1], acc1);
BLUR(dst[x+2], acc2);
});
}
OUTERLOOP(dst, ptr, w, 3)
{
BLUR0(dst[0], acc0);
BLUR0(dst[1], acc1);
BLUR0(dst[2], acc2);
INNERLOOP(y, h, stride,
{
BLUR(dst[y+0], acc0);
BLUR(dst[y+1], acc1);
BLUR(dst[y+2], acc2);
});
}
}
static void expblur2(unsigned char* ptr, int w, int h, int stride, int alpha)
{
OUTERLOOP(dst, ptr, h, stride)
{
BLUR0(dst[0], acc0);
BLUR0(dst[1], acc1);
INNERLOOP(x, w, 2,
{
BLUR(dst[x+0], acc0);
BLUR(dst[x+1], acc1);
});
}
OUTERLOOP(dst, ptr, w, 2)
{
BLUR0(dst[0], acc0);
BLUR0(dst[1], acc1);
INNERLOOP(y, h, stride,
{
BLUR(dst[y+0], acc0);
BLUR(dst[y+1], acc1);
});
}
}
static void expblur1(unsigned char* ptr, int w, int h, int stride, int alpha)
{
OUTERLOOP(dst, ptr, h, stride)
{
BLUR0(dst[0], acc0);
INNERLOOP(x, w, 1,
{
BLUR(dst[x+0], acc0);
});
}
OUTERLOOP(dst, ptr, w, 1)
{
BLUR0(dst[0], acc0);
INNERLOOP(y, h, stride,
{
BLUR(dst[y+0], acc0);
});
}
}
static void expblur(unsigned char* ptr, int w, int h, int channels, int stride, float radius)
{
int i, alpha;
float sigma;
if (radius < 0.01) return;
// Calculate the alpha such that 90% of the kernel is within the radius.
// (Kernel extends to infinity)
sigma = radius * 0.57735f; // 1 / sqrt(3)
// Improve blur quality by doing two pass
// blur(sigma1) o blur(sigma2) = blur(sqrt(sqr(sigma1)*sqr(sigma2)))
sigma = sigma * 0.707106f; // 1 / sqrt(2)
alpha = (int)((1<<APREC) * (1.0f - expf(-2.3f / (sigma + 1.0f))));
switch (channels)
{
case 1: expblur1(ptr, w, h, stride, alpha); break;
case 2: expblur2(ptr, w, h, stride, alpha); break;
case 3: expblur3(ptr, w, h, stride, alpha); break;
case 4: expblur4(ptr, w, h, stride, alpha); break;
default: abort();
}
}
CAMLprim value ml_stbi_expblur(value img, value radius)
{
CAMLparam2(img, radius);
unsigned char *ptr = Caml_ba_data_val(Field(img, 5));
assert (ptr);
ptr += Long_val(Field(img, 3));
unsigned int
w = Long_val(Field(img, 0)),
h = Long_val(Field(img, 1)),
n = Long_val(Field(img, 2)),
stride = Long_val(Field(img, 4));
expblur(ptr, w, h, n, stride, Double_val(radius));
CAMLreturn(Val_unit);
}

27
thirdparty/stb_image/opam vendored Normal file
View File

@@ -0,0 +1,27 @@
opam-version: "2.0"
name: "stb_image"
version: "0.5"
maintainer: "Frederic Bour <frederic.bour@lakaban.net>"
authors: "Frederic Bour <frederic.bour@lakaban.net>"
homepage: "https://github.com/let-def/stb_image"
bug-reports: "https://github.com/let-def/stb_image"
license: "CC0"
dev-repo: "git+https://github.com/let-def/stb_image.git"
build: [
[make]
]
install: [make "install"]
remove: ["ocamlfind" "remove" "stb_image"]
depends: [
"ocaml" {!= "4.01.0"}
"ocamlfind" {build}
"result"
]
flags: light-uninstall
synopsis: "OCaml bindings to stb_image, a public domain image loader"
description: """
Stb_image is an OCaml binding to stb_image from Sean Barrett, [Nothings](http://nothings.org/):
stb_image.h: public domain C image loading library
The OCaml binding is released under CC-0 license. It has no dependency beside working OCaml and C compilers (stb_image is self-contained)."""

6755
thirdparty/stb_image/stb_image.h vendored Normal file

File diff suppressed because it is too large Load Diff

84
thirdparty/stb_image/stb_image.ml vendored Normal file
View File

@@ -0,0 +1,84 @@
open Bigarray
type 'a result = ('a, [`Msg of string]) Result.result
type 'kind buffer = ('a, 'b, c_layout) Array1.t
constraint 'kind = ('a, 'b) kind
type 'kind t = {
width: int;
height: int;
channels: int;
offset: int;
stride: int;
data: 'kind buffer;
}
type float32 = (float, float32_elt) kind
type int8 = (int, int8_unsigned_elt) kind
external load_unmanaged : ?channels:int -> string -> int8 t result = "ml_stbi_load"
external loadf_unmanaged : ?channels:int -> string -> float32 t result = "ml_stbi_loadf"
external decode_unmanaged : ?channels:int -> _ buffer -> int8 t result = "ml_stbi_load_mem"
external decodef_unmanaged : ?channels:int -> _ buffer -> float32 t result = "ml_stbi_loadf_mem"
external ml_stbi_image_free : _ buffer -> unit = "ml_stbi_image_free"
let free_unmanaged image =
ml_stbi_image_free image.data
let clone buf =
let buf' = Array1.create (Array1.kind buf) c_layout (Array1.dim buf) in
Array1.blit buf buf';
buf'
let manage f ?channels filename =
match f ?channels filename with
| Result.Error _ as err -> err
| Result.Ok image ->
let managed = {image with data = clone image.data} in
free_unmanaged image;
Result.Ok managed
let load ?channels filename = manage load_unmanaged ?channels filename
let loadf ?channels filename = manage loadf_unmanaged ?channels filename
let decode ?channels filename = manage decode_unmanaged ?channels filename
let decodef ?channels filename = manage decodef_unmanaged ?channels filename
let image ~width ~height ~channels ?(offset=0) ?(stride=width*channels) data =
let size = Array1.dim data in
if width < 0 then
Result.Error (`Msg "width should be positive")
else if height < 0 then
Result.Error (`Msg "height should be positive")
else if channels < 0 || channels > 4 then
Result.Error (`Msg "channels should be between 1 and 4")
else if offset < 0 then
Result.Error (`Msg "offset should be positive")
else if offset + stride * height > size then
Result.Error (`Msg "image does not fit in buffer")
else
Result.Ok { width; height; channels; offset; stride; data }
let width t = t.width
let height t = t.height
let channels t = t.channels
let data t = t.data
let validate_mipmap t1 t2 =
if t1.channels <> t2.channels then
invalid_arg "mipmap: images have different number of channels";
if t1.width / 2 <> t2.width || t1.height / 2 <> t2.height then
invalid_arg "mipmap: second image size should exactly be half of first image"
external mipmap : int8 t -> int8 t -> unit = "ml_stbi_mipmap"
external mipmapf : float32 t -> float32 t -> unit = "ml_stbi_mipmapf"
let mipmap t1 t2 = validate_mipmap t1 t2; mipmap t1 t2
let mipmapf t1 t2 = validate_mipmap t1 t2; mipmapf t1 t2
external vflip : int8 t -> unit = "ml_stbi_vflip"
external vflipf : float32 t -> unit = "ml_stbi_vflipf"
(** Blur the image *)
external expblur : int8 t -> radius:float -> unit = "ml_stbi_expblur"

120
thirdparty/stb_image/stb_image.mli vendored Normal file
View File

@@ -0,0 +1,120 @@
(*
Stb_image for OCaml by Frédéric Bour <frederic.bour(_)lakaban.net>
To the extent possible under law, the person who associated CC0 with
Stb_image for OCaml has waived all copyright and related or neighboring
rights to Stb_image for OCaml.
You should have received a copy of the CC0 legalcode along with this
work. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
Website: https://github.com/let-def/stb_image
stb_image is a public domain library by Sean Barrett,
http://nothings.org/
Version 0.1, September 2015
*)
open Bigarray
type 'a result = ('a, [`Msg of string]) Result.result
(*##############################*)
(** {1 Image representation} *)
(** [buffer] simply is an alias to a bigarray with c_layout.
The [buffer] type serves two purposes:
- representing input files,
- representing the raw pixels of an image.
Two kind of pixel buffers are manipulated:
- int8 for images with 8-bit channels
- float32 for images with floating point channels *)
type 'kind buffer = ('a, 'b, c_layout) Array1.t
constraint 'kind = ('a, 'b) kind
type float32 = (float, float32_elt) kind
type int8 = (int, int8_unsigned_elt) kind
(** A record describing an image.
The buffer contains [channels * width * height] items, in this order:
- channels are interleaved
- each pixel is made of [channels] items
- each line is made of [width] pixels
- image is made of [height] lines *)
type 'kind t = private {
width: int;
height: int;
channels: int;
offset: int;
stride: int;
data: 'kind buffer;
}
(** {2 Creating image} *)
val image : width:int -> height:int -> channels:int ->
?offset:int -> ?stride:int ->
'kind buffer -> 'kind t result
(** {2 Image accessors} *)
val width : _ t -> int
val height : _ t -> int
val channels : _ t -> int
val data : 'kind t -> 'kind buffer
(** {1 Image decoding} *)
(** Load an 8-bit per channel image from a filename.
If [channels] is specified, it has to be between 1 and 4 and the decoded image
will be processed to have the requested number of channels. *)
val load : ?channels:int -> string -> int8 t result
(** Load a floating point channel image from a filename.
See [load] for [channels] parameter. *)
val loadf : ?channels:int -> string -> float32 t result
(** Decode an 8-bit per channel image from a buffer.
See [load] for [channels] parameter. *)
val decode : ?channels:int -> _ buffer -> int8 t result
(** Decode a floating point channel image from a buffer.
See [load] for [channels] parameter. *)
val decodef : ?channels:int -> _ buffer -> float32 t result
(** {2 Low-level interface}
Functions are similar to the above one, except memory is not managed by OCaml GC.
It has to be released explicitly with [free_unmanaged] function.
You get slightly faster load times, more deterministic memory use and more
responsibility.
Use at your own risk! *)
val load_unmanaged : ?channels:int -> string -> int8 t result
val loadf_unmanaged : ?channels:int -> string -> float32 t result
val decode_unmanaged : ?channels:int -> _ buffer -> int8 t result
val decodef_unmanaged : ?channels:int -> _ buffer -> float32 t result
val free_unmanaged: _ t -> unit
(** {2 Image filtering} *)
(** Generate one level of mipmap: downsample image half in each dimension.
In [mipmap imgin imgout]:
- imgout.channels must be imgin.channels
- imgout.width must be imgin.width / 2
- imgout.height must be imgin.height / 2
- imgout.data will be filled with downsampled imgin.data
*)
val mipmap : int8 t -> int8 t -> unit
(** Downsample floating point images. See [mipmap]. *)
val mipmapf : float32 t -> float32 t -> unit
(** Flip the image vertically *)
val vflip : int8 t -> unit
(** Flip the image vertically *)
val vflipf : float32 t -> unit
(** Blur the image *)
val expblur : int8 t -> radius:float -> unit