I'm trying to apply a custom effect using the DirectXTK. The effect is supposed to be an "unlit" shader with just one texture. But for some reason, the texture is stretched across the model. I looked in renderdoc and the texturecoordinates appear to be loaded correctly so i'm not sure what's going on.
UnlitEffect.h
#pragma once
#include <vector>
class UnlitEffect : public DirectX::IEffect, public DirectX::IEffectMatrices
{
public:
explicit UnlitEffect(ID3D11Device* device);
UnlitEffect() = default;
virtual void Apply(_In_ ID3D11DeviceContext* deviceContext) override;
virtual void GetVertexShaderBytecode(_Out_ void const** pShaderByteCode, _Out_ size_t* pByteCodeLength) override;
void SetTexture(ID3D11ShaderResourceView* value);
void XM_CALLCONV SetWorld(DirectX::FXMMATRIX value) override;
void XM_CALLCONV SetView(DirectX::FXMMATRIX value) override;
void XM_CALLCONV SetProjection(DirectX::FXMMATRIX value) override;
void XM_CALLCONV SetMatrices(DirectX::FXMMATRIX world, DirectX::CXMMATRIX view, DirectX::CXMMATRIX projection) override;
struct __declspec(align(16)) UnlitEffectConstants
{
DirectX::XMMATRIX MVP;
};
DirectX::ConstantBuffer<UnlitEffectConstants> m_constantBuffer;
protected:
Microsoft::WRL::ComPtr<ID3D11VertexShader> m_vs;
Microsoft::WRL::ComPtr<ID3D11PixelShader> m_ps;
Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> m_texture;
std::vector<uint8_t> m_vsBlob;
DirectX::SimpleMath::Matrix m_World;
DirectX::SimpleMath::Matrix m_View;
DirectX::SimpleMath::Matrix m_Projection;
DirectX::SimpleMath::Matrix m_MVP;
uint32_t m_dirtyFlags;
};
UnlitEffect.cpp
#include "pch.h"
#include "UnlitEffect.h"
#include "ReadData.h"
namespace
{
constexpr uint32_t DirtyConstantBuffer = 0x1;
constexpr uint32_t DirtyMVPMatrix= 0x2;
}
UnlitEffect::UnlitEffect(ID3D11Device* device)
:m_constantBuffer(device),m_dirtyFlags(uint32_t(-1))
{
m_vsBlob = DX::ReadData(L"Shaders/UnlitVS.cso");
DX::ThrowIfFailed(
device->CreateVertexShader(m_vsBlob.data(), m_vsBlob.size(), nullptr, m_vs.ReleaseAndGetAddressOf())
);
auto ps_blob = DX::ReadData(L"Shaders/UnlitPS.cso");
DX::ThrowIfFailed(
device->CreatePixelShader(ps_blob.data(), ps_blob.size(), nullptr, m_ps.ReleaseAndGetAddressOf())
);
}
void UnlitEffect::Apply(_In_ ID3D11DeviceContext* deviceContext)
{
if(m_dirtyFlags & DirtyMVPMatrix)
{
m_MVP = m_World * m_View;
m_MVP = m_MVP * m_Projection;
m_dirtyFlags &= ~DirtyMVPMatrix;
m_dirtyFlags |= DirtyConstantBuffer;
}
if(m_dirtyFlags & DirtyConstantBuffer)
{
UnlitEffectConstants constants;
constants.MVP = m_MVP.Transpose();
m_constantBuffer.SetData(deviceContext, constants);
m_dirtyFlags &= ~DirtyConstantBuffer;
}
auto cb = m_constantBuffer.GetBuffer();
deviceContext->VSSetConstantBuffers(0, 1, &cb);
deviceContext->PSSetShaderResources(0, 1, m_texture.GetAddressOf());
deviceContext->VSSetShader(m_vs.Get(), nullptr, 0);
deviceContext->PSSetShader(m_ps.Get(), nullptr, 0);
}
void UnlitEffect::GetVertexShaderBytecode(_Out_ void const** pShaderByteCode, _Out_ size_t* pByteCodeLength)
{
assert(pShaderByteCode != nullptr && pByteCodeLength != nullptr);
*pShaderByteCode = m_vsBlob.data();
*pByteCodeLength = m_vsBlob.size();
}
void UnlitEffect::SetTexture(ID3D11ShaderResourceView* value)
{
m_texture = value;
}
void XM_CALLCONV UnlitEffect::SetWorld(DirectX::FXMMATRIX value)
{
m_World = value;
m_dirtyFlags |= DirtyMVPMatrix;
}
void XM_CALLCONV UnlitEffect::SetView(DirectX::FXMMATRIX value)
{
m_View = value;
m_dirtyFlags |= DirtyMVPMatrix;
}
void XM_CALLCONV UnlitEffect::SetProjection(DirectX::FXMMATRIX value)
{
m_Projection = value;
m_dirtyFlags |= DirtyMVPMatrix;
}
void XM_CALLCONV UnlitEffect::SetMatrices(DirectX::FXMMATRIX world, DirectX::CXMMATRIX view, DirectX::CXMMATRIX projection)
{
m_View = view;
m_World = world;
m_Projection = projection;
m_dirtyFlags |= DirtyMVPMatrix;
}
Unlit.hlsli
#ifndef __UNLINT_HLSLI__
#define __UNLINT_HLSLI__
cbuffer UnlitConstants : register(b0)
{
float4x4 MVP;
}
struct VSOutput
{
float4 PositionPS : SV_Position;
float2 TexCoord : TEXCOORD0;
};
struct VSInput
{
float4 Position : SV_Position;
float2 TexCoord : TEXCOORD0;
};
#endif
UnlitPS.hlsl
#include "Unlit.hlsli"
Texture2D BaseColor : register(t0);
SamplerState SampleType : register(s0);
float4 main(VSOutput vout) : SV_TARGET0
{
return BaseColor.Sample(SampleType, normalize(vout.TexCoord));
}
UnlitVS.hlsl
#include "Unlit.hlsli"
VSOutput main(VSInput vin)
{
VSOutput vout;
vout.PositionPS = mul(vin.Position, MVP);
vout.TexCoord = vin.TexCoord;
return vout;
}
here is the result
Chuck Walbourn was correct. My issue was that I was normalizing my texture coordinates in the pixel shader.
The correct code is
return BaseColor.Sample(SampleType, vout.TexCoord);
When I call sprite.getPosition() on my sprites I can clearly see that each of them has a different position, but when I draw my sprites every single one of them renders on top of each other?
Here is the full source code thus far:
(I was planning to just pick out the relevant bits, but after 5 minutes of trimming I realized I'd be including 95% of it anyway, so it ends up shorter if I just don't trim it at all)
#include <array>
#include <cassert>
#include <iostream>
#include <vector>
#include <SFML/Graphics.hpp>
sf::Texture spritesheet{};
namespace TextureRects {
std::array<std::array<sf::IntRect,2>, 3> aliens{{
{sf::IntRect{0,0,12,8}, sf::IntRect{36,0,12,8}},
{sf::IntRect{12,0,12,8}, sf::IntRect{48,0,12,8}},
{sf::IntRect{24,0,12,8}, sf::IntRect{60,0,12,8}}
}};
}
class Alien {
public:
enum class Type {
one,
two,
three,
max
};
private:
enum class AnimationState {
in,
out
};
sf::Vector2f m_position{};
Type m_type{};
sf::Sprite m_sprite{};
bool m_alive{ true };
sf::IntRect getTextureRect(AnimationState animationState) const {
return TextureRects::aliens[static_cast<std::size_t>(m_type)][static_cast<std::size_t>(animationState)];
}
void swapTexture() {
static AnimationState s_animationState{ AnimationState::in };
m_sprite.setTextureRect(getTextureRect(s_animationState));
s_animationState = static_cast<AnimationState>(!static_cast<bool>(s_animationState));// in -> out, out -> in
}
void initializeTexture() {
m_sprite.setTexture(spritesheet);
swapTexture();
}
public:
Alien() = default;
Alien(Type type) : m_type{ type } {
initializeTexture();
}
void setPosition(sf::Vector2f position) {
m_sprite.setPosition(position);
m_position = position;
std::cout << m_sprite.getPosition().x << "\n";
std::cout << m_sprite.getPosition().y << "\n";
}
void draw(sf::RenderWindow& window) const{
if (m_alive) {
window.draw(m_sprite);
}
}
void reset() {
m_alive = true;
}
};
class Swarm {
std::vector<Alien> m_aliens{};
void init() {
m_aliens.resize(55);
for (int y{ 0 }; y < 5; ++y) {
for (int x{ 0 }; x < 11; ++x) {
if (y == 0) {
m_aliens.push_back(Alien{ Alien::Type::three });
} else if (y < 3) {
m_aliens.push_back(Alien{ Alien::Type::two });
}else {
m_aliens.push_back(Alien{ Alien::Type::one });
}
}
}
reset();
}
public:
Swarm() {
init();
};
void reset() {
for (std::size_t y{ 0 }; y < 5;++y) {
for (std::size_t x{ 0 }; x < 11;++x) {
auto& alien{ m_aliens[y * 11 + x] };
alien.setPosition({ x * 20.0f, y * 20.0f });
alien.reset();
}
}
}
void draw(sf::RenderWindow& window) const{
for (const auto& alien : m_aliens) {
alien.draw(window);
}
}
};
int main() {
spritesheet.loadFromFile("spritesheet.png");
sf::RenderWindow window{sf::VideoMode{448, 512}, "Space Invaders"};// 224x256 * 2x2.5
sf::View view1{ sf::FloatRect{0,0,224,256} };
window.setView(view1);
Swarm swarm{};
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
switch (event.type) {
case sf::Event::Closed:
window.close();
break;
}
}
window.clear();
swarm.draw(window);
window.display();
}
return 0;
}
Notice that the std::cout << m_sprite.getPosition().x << "\n"; and std::cout << m_sprite.getPosition().y << "\n"; lines print out unique positions for each sprite, yet the output shows every sprite crammed into the upper left corner...
(I know the spritesheet won't load, hopefully it doesn't need to in order for the stack of white squares to be obvious.)
Here's a screenshot of the output in case it saves someone some time:
I am looking for code (any language) of a basic graphical list which can be reordered by drag and drop. So exactly this functionality http://jqueryui.com/sortable/ but written directly on the frame buffer/canvas without any frameworks (or low level 'put pixel' libraries at most) and probably not in HTML/JS (unless it's Canvas only without CSS).
The simpler the better as I will be using it in assembler and I don't want to reinvent the wheel if not needed.
heh I hate frameworks so this is easy as pie for me...
this is what I coded for my students during my lectures few years back:
http://ulozto.net/x2b7WLwJ/select-drag-drop-zip
This is the main engine code (complete project + exe is in that zip above):
//---------------------------------------------------------------------------
//--- Constants: ------------------------------------------------------------
//---------------------------------------------------------------------------
const int _select_max_l=16;
const int _select_max_ll=_select_max_l*_select_max_l;
const int _half_size=10;
const int _atoms_max=32;
//---------------------------------------------------------------------------
enum _atom_type_enum //++++
{
_atom_type_non=0,
_atom_type_kruh,
_atom_type_stvorec,
_atom_type_enum_end
};
//---------------------------------------------------------------------------
enum _editor_edit_mode_enum //****
{
_editor_edit_mode_non=0,
_editor_edit_mode_move,
_editor_edit_mode_mov,
_editor_edit_mode_add_kruh,
_editor_edit_mode_add_stvorec,
_editor_edit_mode_del,
_editor_edit_mode_enum_end
};
//---------------------------------------------------------------------------
//--- viewer: ---------------------------------------------------------------
//---------------------------------------------------------------------------
class viewer
{
public: int x0,y0;
viewer() { x0=0; y0=0; }
void world2screen(int &sx,int &sy,int wx,int wy) { sx=wx-x0; sy=wy-y0; }
void screen2world(int &wx,int &wy,int sx,int sy) { wx=sx+x0; wy=sy+y0; }
void world2screen(int &sl,int wl) { sl=wl; }
void screen2world(int &wl,int sl) { wl=sl; }
};
//---------------------------------------------------------------------------
//--- atom kruh: ------------------------------------------------------------
//---------------------------------------------------------------------------
class atom_kruh
{
public: int x,y,r; // world coordinates
TColor col0,col1,col2;
AnsiString str;
atom_kruh() { x=0; y=0; r=_half_size; str=""; col0=clBlue; col1=clAqua; col2=clWhite; }
void draw(TCanvas *scr,const viewer &view)
{
int xx,yy,rr;
view.world2screen(xx,yy,x,y);
view.world2screen(rr,r);
scr->Brush->Color=col0;
scr->Pen ->Color=col1;
scr->Font ->Color=col2;
scr->Ellipse(xx-rr,yy-rr,xx+rr,yy+rr);
scr->Brush->Style=bsClear;
xx-=scr->TextWidth(str)>>1;
yy-=scr->TextHeight(str)>>1;
scr->TextOutA(xx,yy,str);
scr->Brush->Style=bsSolid;
}
bool select(int &ll,int wx,int wy)
{
int qq,xx,yy;
xx=wx-x; xx*=xx;
yy=wy-y; yy*=yy;
qq=xx+yy;
if ((qq<=_select_max_ll)&&((qq<=ll)||(ll<0))) { ll=qq; return true; }
return false;
}
};
//---------------------------------------------------------------------------
//--- atom kruh: ------------------------------------------------------------
//---------------------------------------------------------------------------
class atom_stvorec
{
public: int x,y,r; // world coordinates
TColor col0,col1,col2;
AnsiString str;
atom_stvorec() { x=0; y=0; r=_half_size; str=""; col0=clBlue; col1=clAqua; col2=clWhite; }
void draw(TCanvas *scr,const viewer &view)
{
int xx,yy,rr;
view.world2screen(xx,yy,x,y);
view.world2screen(rr,r);
scr->Brush->Color=col0;
scr->Pen ->Color=col1;
scr->Font ->Color=col2;
scr->Rectangle(xx-rr,yy-rr,xx+rr,yy+rr);
scr->Brush->Style=bsClear;
xx-=scr->TextWidth(str)>>1;
yy-=scr->TextHeight(str)>>1;
scr->TextOutA(xx,yy,str);
scr->Brush->Style=bsSolid;
}
bool select(int &ll,int wx,int wy)
{
int qq,xx,yy;
xx=wx-x; xx*=xx;
yy=wy-y; yy*=yy;
qq=xx+yy;
if ((qq<=_select_max_ll)&&((qq<=ll)||(ll<0))) { ll=qq; return true; }
return false;
}
};
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
class editor
{
public: Graphics::TBitmap *bmp; // back buffer
int xs,ys;
int sel_ix,sel_tp; // actual mouse selected item
int edit_mode; // selected edit tool
viewer view; // view
bool redraw; // redraw needed?
bool locked; // edit in progress?
WORD key,key0;
int mx,my,mx0,my0;
TShiftState sh,sh0;
atom_kruh kruh[_atoms_max]; // all object lists
atom_stvorec stvorec[_atoms_max];
int kruhov;
int stvorcov;
editor();
~editor();
void resize(int _xs,int _ys); // interface with window
void draw();
void mouse(int x,int y,TShiftState s) { mx0=mx; my0=my; sh0=sh; mx=x; my=y; sh=s; edit(); }
void keys(WORD k,TShiftState s) { key0=key; sh0=sh; key=k; sh=s; edit(); }
void select(); // helper functions
void edit();
void move (bool q0,bool q1,int x,int y,int dx,int dy);
void mov (bool q0,bool q1,int x,int y,int dx,int dy);
void add_kruh (bool q0,bool q1,int x,int y,int dx,int dy);
void add_stvorec(bool q0,bool q1,int x,int y,int dx,int dy);
void del (bool q0,bool q1,int x,int y,int dx,int dy);
};
//---------------------------------------------------------------------------
editor::editor()
{
bmp=new Graphics::TBitmap;
resize(1,1);
sel_ix=-1;
sel_tp=_atom_type_non;
edit_mode=_editor_edit_mode_non;
key=0; key0=0;
mx=0; mx0=0;
my=0; my0=0;
locked=false;
kruhov=0;
stvorcov=0;
}
//---------------------------------------------------------------------------
editor::~editor()
{
delete bmp;
}
//---------------------------------------------------------------------------
void editor::resize(int _xs,int _ys)
{
bmp->Width=_xs;
bmp->Height=_ys;
xs=bmp->Width;
ys=bmp->Height;
redraw=true;
}
//---------------------------------------------------------------------------
void editor::draw()
{
int i;
if (!redraw) return;
redraw=false;
bmp->Canvas->Brush->Color=clBlack;
bmp->Canvas->FillRect(Rect(0,0,xs,ys));
//++++
for (i=0;i<kruhov ;i++) kruh[i] .draw(bmp->Canvas,view);
for (i=0;i<stvorcov;i++) stvorec[i].draw(bmp->Canvas,view);
}
//---------------------------------------------------------------------------
void editor::select()
{
int i,wx,wy,ll;
int sel_tp0=sel_tp; sel_tp=_atom_type_non;
int sel_ix0=sel_ix; sel_ix=-1;
view.screen2world(wx,wy,mx,my);
//++++
ll=-1;
for (i=0;i<kruhov ;i++) if (kruh[i] .select(ll,wx,wy)) { sel_tp=_atom_type_kruh; sel_ix=i; };
for (i=0;i<stvorcov;i++) if (stvorec[i].select(ll,wx,wy)) { sel_tp=_atom_type_stvorec; sel_ix=i; };
if (sel_tp!=sel_tp0) redraw=true;
if (sel_ix!=sel_ix0) redraw=true;
}
//---------------------------------------------------------------------------
void editor::edit()
{
bool q0,q1;
int x,y,dx,dy;
x=mx; dx=mx-mx0;
y=my; dy=my-my0;
view.screen2world( x, y, x, y);
view.screen2world(dx,dx);
view.screen2world(dy,dy);
q0=sh0.Contains(ssLeft);
q1=sh .Contains(ssLeft);
if (!locked) select();
//****
if(edit_mode==_editor_edit_mode_mov) mov (q0,q1,x,y,dx,dy);
if(edit_mode==_editor_edit_mode_add_kruh) add_kruh (q0,q1,x,y,dx,dy);
if(edit_mode==_editor_edit_mode_add_stvorec)add_stvorec (q0,q1,x,y,dx,dy);
if(edit_mode==_editor_edit_mode_del) del (q0,q1,x,y,dx,dy);
q0=sh0.Contains(ssRight);
q1=sh .Contains(ssRight);
if (!locked) move(q0,q1,x,y,dx,dy);
}
//---------------------------------------------------------------------------
void editor::move (bool q0,bool q1,int x,int y,int dx,int dy)
{
if ((sel_ix>=0)&&(sel_tp!=_atom_type_non)) return;
if (q1)
{
view.x0-=dx;
view.y0-=dy;
redraw=true;
}
}
//---------------------------------------------------------------------------
void editor::mov (bool q0,bool q1,int x,int y,int dx,int dy)
{
if ((!locked)&&((sel_ix<0)||(sel_tp==_atom_type_non))) return;
locked=false;
if ((q1)||((q0)&&(!q1)))
{
//++++
if (sel_tp==_atom_type_kruh)
{
kruh[sel_ix].x=x;
kruh[sel_ix].y=y;
}
if (sel_tp==_atom_type_stvorec)
{
stvorec[sel_ix].x=x;
stvorec[sel_ix].y=y;
}
locked=true;
}
if (!q1) locked=false;
redraw=true;
}
//---------------------------------------------------------------------------
void editor::add_kruh (bool q0,bool q1,int x,int y,int dx,int dy)
{
if ((!locked)&&(sel_ix>=0)&&(sel_tp!=_atom_type_non)) return;
locked=false;
if (kruhov>=_atoms_max) return;
if ((!q0)&&( q1))
{
sel_tp=_atom_type_kruh;
sel_ix=kruhov;
kruhov++;
kruh[sel_ix].x=x;
kruh[sel_ix].y=y;
kruh[sel_ix].str=kruhov;
locked=true;
}
if (( q0)&&( q1))
{
kruh[sel_ix].x=x;
kruh[sel_ix].y=y;
locked=true;
}
if (( q0)&&(!q1))
{
kruh[sel_ix].x=x;
kruh[sel_ix].y=y;
}
if ((!q0)&&(!q1))
{
}
redraw=true;
}
//---------------------------------------------------------------------------
void editor::add_stvorec(bool q0,bool q1,int x,int y,int dx,int dy)
{
if ((!locked)&&(sel_ix>=0)&&(sel_tp!=_atom_type_non)) return;
locked=false;
if (stvorcov>=_atoms_max) return;
if ((!q0)&&( q1))
{
sel_tp=_atom_type_stvorec;
sel_ix=stvorcov;
stvorcov++;
stvorec[sel_ix].x=x;
stvorec[sel_ix].y=y;
stvorec[sel_ix].str=stvorcov;
locked=true;
}
if (( q0)&&( q1))
{
stvorec[sel_ix].x=x;
stvorec[sel_ix].y=y;
locked=true;
}
if (( q0)&&(!q1))
{
stvorec[sel_ix].x=x;
stvorec[sel_ix].y=y;
}
if ((!q0)&&(!q1))
{
}
redraw=true;
}
//---------------------------------------------------------------------------
void editor::del (bool q0,bool q1,int x,int y,int dx,int dy)
{
locked=false;
if ((sel_ix<0)||(sel_tp==_atom_type_non)) return;
if ((!q0)&&( q1))
{
//++++
if (sel_tp==_atom_type_kruh)
if (kruhov>0)
{
kruhov--;
kruh[sel_ix]=kruh[kruhov];
}
if (sel_tp==_atom_type_stvorec)
if (stvorcov>0)
{
stvorcov--;
stvorec[sel_ix]=stvorec[stvorcov];
}
sel_ix=-1;
sel_tp=_atom_type_non;
}
redraw=true;
}
//---------------------------------------------------------------------------
sorry for that its not entirely in English
kruh means circle
stvorec means square
This is code for window (BDS2006 VCL style)
//$$---- Form CPP ----
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
#include "editor.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
editor edit;
int x0,y0;
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void draw() // redraw app screen
{
edit.draw();
Form1->Canvas->Draw(x0,y0,edit.bmp);
// here just some info print outs
int dy=16,x=x0,y=y0-dy;
Form1->Canvas->Font->Color=clAqua;
Form1->Canvas->Brush->Style=bsClear;
Form1->Canvas->TextOutA(x,y+=dy,AnsiString().sprintf("locked: %i",edit.locked));
Form1->Canvas->TextOutA(x,y+=dy,AnsiString().sprintf("Key: %d",edit.key));
Form1->Canvas->TextOutA(x,y+=dy,AnsiString().sprintf("sel_tp: %i",edit.sel_tp));
Form1->Canvas->TextOutA(x,y+=dy,AnsiString().sprintf("sel_ix: %i",edit.sel_ix));
Form1->Canvas->TextOutA(x,y+=dy,AnsiString().sprintf("kruhov: %i",edit.kruhov));
Form1->Canvas->TextOutA(x,y+=dy,AnsiString().sprintf("stvorcov: %i",edit.stvorcov));
Form1->Canvas->Brush->Style=bsSolid;
}
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner) // init app
{
// select tool on app start
bt_tool_kruhClick(this);
}
//--- window events: ---------------------------------------------------------
void __fastcall TForm1::FormPaint(TObject *Sender) { draw(); }
void __fastcall TForm1::FormResize(TObject *Sender) { x0=pan_top->Left; y0=pan_top->Height; edit.resize(ClientWidth-x0,ClientHeight-y0); draw(); }
void __fastcall TForm1::FormActivate(TObject *Sender) { draw(); }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift) { edit.keys(Key,Shift); draw(); }
void __fastcall TForm1::FormMouseMove(TObject *Sender, TShiftState Shift, int X, int Y) { edit.mouse(X-x0,Y-y0,Shift); draw(); }
void __fastcall TForm1::FormMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y){ edit.mouse(X-x0,Y-y0,Shift); draw(); }
void __fastcall TForm1::FormMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { edit.mouse(X-x0,Y-y0,Shift); draw(); }
//---------------------------------------------------------------------------
void __fastcall TForm1::bt_tool_kruhClick(TObject *Sender) // event on any tool button click
{
// select editor tool mode ...
edit.edit_mode=_editor_edit_mode_non;
if (bt_tool_kruh ->Down) edit.edit_mode=_editor_edit_mode_add_kruh;
if (bt_tool_stvorec->Down) edit.edit_mode=_editor_edit_mode_add_stvorec;
if (bt_tool_move ->Down) edit.edit_mode=_editor_edit_mode_mov;
if (bt_tool_delete ->Down) edit.edit_mode=_editor_edit_mode_del;
}
//---------------------------------------------------------------------------
Window has only 4 tool buttons (locked together by same guid so only one can be down at a time)
add circle tool
add square tool
move tool
delete tool
Everything is statically allocated for simplicity
[edit1] more info
create gfx object data type/class (atom_xxxx)
it should hold the size,position,shape of visual gfx representation of object. Add connection variables (object type and object index to what it should be connected). Add the real object/data inside
object ID
I am using int tp,ix;
tp means type of object
ix means index in list of object of type tp
editor engine
this should be also class or set of variables and functions. It should hold the whole edited world (lists of objects):
visualization variables like screen/backbufer bitmap or rendering context, mouse position, selection list
add functions/events like onmouse, onkey, draw,...
add edit function it should be able to select,add,del,move (drag&drop) objects. Ideally controlled by set of command to ease up the undo/redo operation
add undo/redo
add save,load
add your desired simulation functionality
and that is all if I did not forgot something.
create Application GUI interface
so create window, add panel with buttons for each tool,menu and whatever you need. Add events for mouse,keyboard,repaint,resize,drag&drop,... My example looks like this:
Add editor edit; to it globally or as a member of it. Member option is better if you want to have MDI later. Add events interface between edit and window (the second source code).
[Notes]
++++ marks part of code where you need add changes if any atom type is added to the system
**** marks part of code where you need add changes if any edit mode is added to the system
Sorry for not add more commented code if you need clarify something comment me.
Hope it helps a little ...